Guten Abend liebe Gemeinde,
ich habe ein kleines Uhren Programm geschrieben was immer stehen bleibt
sobald auf der Stunden und Minuten Portseite also PORTD und PORTB
jeweils 4 PORTS gleichzeitig Low sind.
Es ist auch egal welche PORTS es sind.
Stunde Minute
E Z E Z
0 0 0 0
0 x 0 x
0 x 0 x
x x x x
0 0 0 0
0 x x 0
0 x x 0
x x x x
0 0 0 0
0 x x 0
0 x x x
x x x 0
Könnte einer von euch bitte mal einen Blick auf mein Programm werfen
danke schonmal.
1
/*
2
* Wecker_01.c
3
*
4
* Created: 15.06.2014 15:37:42
5
* Author: Werkstadt
6
*/
7
8
#include<stdio.h>
9
#include<avr/io.h>
10
#include<avr/interrupt.h>
11
#ifndef F_CPU
12
#warning "F_CPU war noch nicht definiert, wird nun mit 1000000 definiert"
13
#define F_CPU 1000000UL
14
#endif
15
#include<util/delay.h>
16
17
#define STR 4 // Schalter RUN
18
#define STP 5 // Schalter PROG
19
#define STA 00 // Schalter ALARM
20
#define TTS 00 // Taster SNOOZE
21
#define TTMIN 0 // Taster +MIN
22
#define TTST 1 // Taster +ST
23
24
intsek=0;
25
intmin=0;
26
intst=0;
27
intmin_s=0;
28
intst_s=0;
29
intp1=0;
30
intp2=0;
31
intp3=0;
32
intt01=0;
33
intRUN=0;
34
35
36
inttast=0;
37
intmin_8=0;
38
intst_8=0;
39
intfoo=0;
40
intfoo2=0;
41
42
43
44
45
voidshow(void)
46
{
47
min_s=min;
48
while(foo==0)
49
{
50
if(min_s>9)
51
{
52
min_8=(min_8+0x10);
53
min_s=(min_s-10);
54
}
55
else
56
{
57
min_8=(min_8+min_s);
58
++foo;
59
}
60
}
61
foo=0;
62
min_s=0;
63
64
st_s=st;
65
while(foo==0)
66
{
67
if(st_s>9)
68
{
69
st_8=(st_8+0x10);
70
st_s=(st_s-10);
71
}
72
else
73
{
74
st_8=(st_8+st_s);
75
++foo;
76
}
77
}
78
foo=0;
79
st_s=0;
80
81
p1=min_8;
82
min_8=~p1;// Wert Minuten invertieren
83
p2=st_8;
84
st_8=~p2;// Wert Stunden invertieren
85
86
PORTD=min_8;
87
PORTB=st_8;
88
89
min_8=0;
90
st_8=0;
91
}
92
93
voidprog(void)
94
{
95
while(foo==0)
96
{
97
if(!(PINC&(1<<0)))// Abfrage Taster +Minute
98
{
99
++min;
100
if(min>59)
101
{
102
min=0;
103
}
104
_delay_ms(2);
105
while(foo2==0)
106
{
107
if(PINC&(1<<0))// Taster entprellen
108
{
109
++foo2;
110
_delay_ms(2);
111
}
112
}
113
foo2=0;
114
}
115
116
if(!(PINC&(1<<1)))// Abfrage Taster +Stunde
117
{
118
++st;
119
if(st>=24)
120
{
121
st=0;
122
}
123
_delay_ms(2);
124
while(foo2==0)
125
{
126
if(PINC&(1<<1))// Taster entprellen
127
{
128
++foo2;
129
_delay_ms(2);
130
}
131
}
132
foo2=0;
133
}
134
show();
135
if(PINC&(1<<5))
136
{
137
++foo;
138
}
139
}
140
foo=0;
141
}
142
143
voidrun(void)// Ablauf Programm
144
{
145
146
RUN=1;
147
while(foo==0)
148
{
149
150
show();
151
if(PINC&(1<<4))
152
{
153
++foo;
154
RUN=0;
155
}
156
}
157
158
foo=0;
159
}
160
161
162
intmain(void)
163
{
164
DDRB=0b00111111;// Ausgang LED's Stunden
165
DDRD=0xFF;// Ausgang LED's Minuten
166
DDRC=0x00;// Eingang Taster / Schalter
167
PORTB=0xFF;// LED's Stunden Aus
168
PORTD=0xFF;// LED's Minuten Aus
169
PORTC=0xFF;// Eingang Pullup Aktive
170
171
ASSR|=(1<<AS2);//async operation
172
TCCR2|=(1<<CS22)|(1<<CS20);//Prescaler auf 128
173
TCNT2=0x00;//Init counter
174
TIMSK|=(1<<TOIE2);//Overflow Interrupt Enable
175
sei();
176
177
while(1)
178
{
179
180
if(!(PINC&(1<<5)))// Wenn Schalter Programmierung Gesetz ist
181
{
182
prog();
183
}
184
185
if(!(PINC&(1<<4)))// Wenn Schalter Programm Laufen Gesetz ist
Ich hab zwar die Hälfte deiner Programmlogik nicht auf Anhieb
verstanden, aber ich denke mal, du hast dich mit deinen globalen
Variablen selbst aufs Glatteis geführt.
Insbesondere foo verwendest du nach Lust und Laune und wie es dir
beliebt.
zb benutzt du hier
1
voidrun(void)// Ablauf Programm
2
{
3
4
RUN=1;
5
while(foo==0)
6
{
7
8
show();
ein foo, (ohne es mit einem vernünftigen Wert zu versehen), dasselbe foo
wird allerdings auch in show() benutzt.
Das ist immer ein und dieselbe Variable!
Damit einem genau so was nicht passiert, gibt es funktionslokale
Variablen
1
voidfoo()
2
{
3
inti;
4
5
for(i=0;i<5;i++)
6
...machwas
7
}
8
9
voidbar()
10
{
11
inti;
12
13
for(i=0;i<8;i++)
14
foo();
15
}
das i in foo() und das i in bar() sind 2 verschiedene Variablen und
kommen sich nicht in die Quere. Sie sind voneinander vollkommen
unabhängig. Eine Veränderung von i in foo() verändert nicht die Logik in
bar().
So, und jetzt muss ich mal ergründen, was du eigentlich in show()
beabsichtigst. Das hier
Sorgt dafür das ich aus z.b DEZ 46(Minuten) die in der Variable "min"
steckt den BCD Code erzeuge so das ich auf einem PORT im
oberen Nibble Zehner und im unteren die Einer stehen hab.
Zum schluss geb ich das nur auf den jeweiliegen Port aus und hab meine
Zeit.
Marvin hat ja volatile schon angemahnt.
Wenn du den Code dann vereinfachst, dann fallen auch die meisten anderen
Variablen auch alle weg.
Aber auf eines möchte ich noch eingehen.
Ich hab keine Ahnung, wo du die Sache mit dem foo her hast. Aber du
schiesst dir damit ins Knie.
So etwas
1
voidrun(void)// Ablauf Programm
2
{
3
4
RUN=1;
5
while(foo==0)
6
{
7
8
show();
9
if(PINC&(1<<4))
10
{
11
++foo;
12
RUN=0;
13
}
14
}
15
16
foo=0;
17
}
ist ausser unübersichtlich nur noch unübersichtlich. Es mag Fälle geben,
in denen man eine Schleife so abbricht und das die einfachste Lösugn
darstellt. Aber in den meisten Fällen solltest du um solche Dinge einen
Bogen machen.
Wann soll denn diese Schleife abbrechen? Na, wenn am PINC das Bit 4 auf
1 geht. D.h. die Schleife soll laufen, solange das Bit 4 am PINC auf 0
ist. Und genau so programmierst du das auch
1
voidrun(void)// Ablauf Programm
2
{
3
RUN=1;
4
5
while(!(PINC&(1<<4))
6
{
7
show();
8
}
9
10
RUN=0;
11
}
Viel simpler. Viel einfacher zu durchschauen. Wesentlich weniger
Potential, sich selbst ins Knie zu schiessen. Wenn du show mindestens 1
mal aufgerufen haben willst, dann eben so
1
voidrun(void)// Ablauf Programm
2
{
3
RUN=1;
4
5
do
6
{
7
show();
8
}while(!(PINC&(1<<4));
9
10
RUN=0;
11
}
aber nicht mit 200 Flag-Variablen, die dann auch noch global sind. Da
ist ein Schuss ins Knie quasi vorprogrammiert.
Karl Heinz schrieb:> Ach. Das soll eine BCD Zerlegung sein.>> Das kannst du viel einfacher schreiben.>>
1
>//
2
>// Aufteilen der Zahl in Zehner und Einer
3
>// Die Zehner werden in die oberen 4 Bits des Ergebnisses geschoben
4
>//
5
>uint8_ttoBCD(uint8_tdezimalWert)
6
>{
7
>uint8_tErgebnis;
8
>
9
>Ergebnis=(dezimalWert/10)<<4;
10
>Ergebnis|=(dezimalWert%10);
11
>
12
>returnErgebnis;
13
>}
14
>
15
>voidshow()
16
>{
17
>PORTD=toBCD(min);
18
>PORTB=toBCD(st);
19
>}
20
>
Danke schön ;) wenn ich da meinen weg vergleiche ist meiner viel zu
umständlich.
Also kann es durch meine Globalen Variablen dazu kommen das sie sich
überschneiden und dadurch der Programmablauf durcheinander kommt ?
Pierre Gnauck schrieb:> Also kann es durch meine Globalen Variablen dazu kommen das sie sich> überschneiden und dadurch der Programmablauf durcheinander kommt ?
Ich denke mal: ja.
Auslöser dürfte sein, dass du in show das foo erhöhst, und damit dann
aus der Schleife in run rausfällst.
Aber ich hab das nicht weiter gross analysiert. Erspars mir bitte. Du
hast da vieles in deinem Programm wesentlich zu umständlich und
langatmig gelöst, so dass es schwer ist, da noch den Überblick zu
behalten.
Karl Heinz schrieb:> Pierre Gnauck schrieb:>>> Also kann es durch meine Globalen Variablen dazu kommen das sie sich>> überschneiden und dadurch der Programmablauf durcheinander kommt ?>> Ich denke mal: ja.> Auslöser dürfte sein, dass du in show das foo erhöhst, und damit dann> aus der Schleife in run rausfällst.
Nein, ist auch nicht richtig.
Du setzt foo am Ende von show wieder auf 0.
> Erspars mir bitte.
(Gemeint ist natürlich die Analyse, was da passiert)
Gut dann werde ich mal ein wenig aufräumen, ja das mit den umständlichen
kommt denk ich mal aus der asm Welt von der ich gerade in C einsteige.
Mfg Bqube
In prog dasselbe wie in run()
Mach das nicht! Die ganzen Schleifen lassen sich alle viel einfacher
formulieren, wenn du die Abbruchbedingung direkt ins while
reinschreibst. Gleichzeitig bist du dann auch alle Kopfstände und
Kopfzerbrechen los, wer wann welche globale Variable foo oder foo2 oder
... verändert.
Aus dem hier
1
if(!(PINC&(1<<1)))// Abfrage Taster +Stunde
2
{
3
++st;
4
if(st>=24)
5
{
6
st=0;
7
}
8
_delay_ms(2);
9
while(foo2==0)
10
{
11
if(PINC&(1<<1))// Taster entprellen
12
{
13
++foo2;
14
_delay_ms(2);
15
}
16
}
17
foo2=0;
18
}
wird dann das hier
1
if(!(PINC&(1<<1)))// Abfrage Taster +Stunde
2
{
3
++st;
4
if(st>=24)
5
{
6
st=0;
7
}
8
9
_delay_ms(2);
10
11
while(PINC&(1<<1))
12
_delay_ms(2);
13
}
einfacher, kürzer, leichter zu überschauen, keine globalen Variablen
mehr (ausser st)
dann brauchst du erstens den Kommentar nicht mehr und es ist zweitens
viel leichter zu kontrollieren, dass du beim if und beim while jeweils
denselben Taster benutzt hast. Ausserdem steckt jetzt im Code ein
direkter Zusammenhang drinnen, dass du in beiden Fällen wirklich mit
voller Absicht denselben Taster gemeint hast. Diese Absicht ist auch
dann zu sehen, wenn man nicht analysiert, was das Programm hier
eigentlich macht.
Keine derartigen 'magischen Konstanten'! Dafür gibt es #define, damit
man derartigen Zahlenwerten einen 'Namen' geben kann.
Das hat dann auch den netten Nebeneffekt, dass man bei einer Änderung
des Zahlenwertes, dieses nur an einer einzigen Stelle machen muss.
Nämlich beim #define. Der Compiler passt dann alle anderen Stellen
anhand dieses #define an, in dem er den dort verwendeten Namen durch
genau diese Zahl ersetzt. Im Endeffekt wird also genau der gleiche Code
wie deiner übersetzt. Nur ist er für mich als Programmierer viel
leichter zu lesen, zu verstehen und zu ändern.
Pierre Gnauck schrieb:> Gut dann werde ich mal ein wenig aufräumen, ja das mit den umständlichen> kommt denk ich mal aus der asm Welt von der ich gerade in C einsteige.
gut.
Dann fang gleich mal damit an, zu akzeptieren, dass der Datentyp der
Wahl für ein Byte ein uint8_t ist und nicht einfach alles als int
gemacht wird.
generell alles als int zu nehmen ist auf Desktopsystemen in Ordnung.
Da du aus der Assemblerwelt kommst, ist dir geläufig, dass du deinem AVR
mit 16 Bit Arithmetik nicht unwesentlich mehr Arbeit aufhalst. Wenn also
ein Byte völlig ausreicht (weil Stunden oder Minuten nun mal locker in 1
Byte passen), dann verpasst du deinem AVR eine Fleissaufgabe, indem du
alles als int definierst, wo es ein uint8_t auch getan hätte.
So ich hab das ganze ein wenig aufgeräumt nur die DEZ zu BCD geschichte
haut mit der Funktion von dir nicht hin ?
Wenn ich es mit ihr versuche sind alle LED's an...
Hier der veränderte Teil.
1
/*
2
* Wecker_01.c
3
*
4
* Created: 15.06.2014 15:37:42
5
* Author: Werkstadt
6
*/
7
8
#include<stdio.h>
9
#include<math.h>
10
#include<avr/io.h>
11
#include<avr/interrupt.h>
12
#ifndef F_CPU
13
#warning "F_CPU war noch nicht definiert, wird nun mit 1000000 definiert"
das weiterzählen von min und st rausgenommen?
Das war keine gute Idee. Die würde ich da drinn lassen. Denn min und st
müssen auch dann weiterhin hochgezählt werden, wenn dein Programm mit
irgendwas ganz anderem stundenlang beschäftigt ist. Das Hochzählen einer
Uhr ist als 'unteilbare EInheit' anzusehen.
Karl Heinz schrieb:> das weiterzählen von min und st rausgenommen?
In diesem Sinne:
vergiss mein vorheriges Posting.
Jetzt muss sek volatile sein.
Die Variable, auf die du von der ISR und von irgendwo anders aus
zugreifst.
Pierre Gnauck schrieb:> Aber ich glaube so langsam das ist ein Hardware Problem besitzte denn> der effekt ist gleich geblieben.
NIcht so schnell.
Speck mal ordentlich ab.
1
....
2
3
intmain()
4
{
5
6
....dieganzenInitialisierungen
7
....abernochkeinsei(),alsokeineInterrupts
8
9
while(1){
10
11
min++;
12
if(min==60){
13
st++;
14
min=0;
15
if(st==24){
16
st=0;
17
}
18
}
19
20
show();
21
_delay_ms(1000);
22
}
23
}
jetzt wollen wir mal sehen, ob deine LED funktionieren.
(Nicht alles auf einmal schreiben!)
Pierre Gnauck schrieb:> Sobald ich versuche beim Zeiteinstellen auf beiden Seiten Stunden /> Minuten 4 ausgänge gleichzeitig Low setzte steht alles.
Lass uns systematisch vorgehen. OK?
Pierre Gnauck schrieb:> Wie meinst du das mit deiner Änderung sei(); ist doch bei mir vorhanden> und zwar hier
Ja.
Aber ich möchte für den ersten Test die Interrupts mal aus dem Spiel
nehmen.
Im Grunde braucht das Tetsprogramm nur die Ports und sonst nix. Ich will
dir aber nicht zumuten, dass du den Timercode da rausnimmst. Ist ja doch
etwas umfangreicher.
Daher: von mir aus soll der Timer im Hintergrund laufen. Aber er soll
mir beim Rest nicht in die QUere kommen. Beim ersten Test brauchen wir
ihn nicht. Jede Sekunde (realisiert durch _delay_ms) wird min um 1
erhöht und show aufgerufen. D.h. deine LED müssen im Sekundentakt die
Zeit hochzählen.
(1000 ist vielleicht etwas lang, 500 werdens auch tun. Wir wollen ja nur
wissen, ob irgendetwas ungewöhnliches passiert, wenn die LEDs ihre
Muster durchgehen. Zb Spannungseinbruch am Netzteil/Batterie)
Und damit sich der Timer aus dem Rest raushält, wird der sei() einfach
auskommentiert.
Pierre Gnauck schrieb:> So nun sind die Minuten an dem besagten Punkt vorbei und laufen fröhlich> vor sich hin.
gut.
Hast du Sekundentakt oder Halbsekunden Takt?
> Stunde Minute>> E Z E Z>> 0 0 0 0> 0 x 0 x> 0 x 0 x> x x x x>>> 0 0 0 0> 0 x x 0> 0 x x 0> x x x x
Ganz einfach die Nullen sind die LED's es sind immer 4 damit die Optik
Symetrisch ist ^^ und die Kreuze Stellen die situation nach (LED AN)
Ich geh mal davon aus, dass auch das nichts ungewöhnliches mehr an den
Tag bringen wird.
D.h. ich würde dann gerne mal die Stelltasten mit dazu nehmen. Interrupt
bleibt nach wie vor abgeschaltet
1
.
2
3
intmain()
4
{
5
...
6
7
while(1){
8
prog();
9
show();
10
}
11
}
Die prog Funktion hab ich durchgesehen. Aufgefallen ist mir da jetzt
nicht wirklich was schlimmes.
Wie sind deine Tasten angeschlossen.
Laut Programm: einfache Taster, die nach GND schalten. Nichts
ausergewöhnliches und auch nichts zusätzliches. Nur die Taster.
und du drückst auf den Taster am Portpin PORTC / 0
(Verezeih wenn ich alles 3 mal nachfrage. Aber ich muss mir hier ein
Bild von der Situation bei dir machen. Und bei Fehlersuche stelle ich
grundsätzlich alles in Frage)
Ich drücke jetzt PINC.1 für Stunden so lange (Beispiel) das ich DEZ
17:00 eingestellt hab
Stunde Minute
E Z E Z
0 0 0 0
0 x 0 0
0 x 0 0
x x 0 0
Nun drücke ich auf PINC.0 für Minuten so lange das ich bis zur Zeit
17:17 komme.
Stunde Minute
>> E Z E Z>> 0 0 0 0> 0 x 0 x> 0 x 0 x> x x x x
Und Jetzt passiert nix mehr.
Das gibts doch gar nicht. Hmmmmmmm
Vielleicht doch was mit der Stomversorgung.
Bei den LED Spielchen. Hattest du da den Fall, dass wirklich alle LED
geleuchet haben?
Wenn nicht, sollten wir das unbedingt ausprobieren und gezielt
herbeiführen.
Wo wir hoch gezählt hatten sind wir ja bei dieser Mischung 17:17
angekommen und weiter gekommen er bleibt echt nur beim Analogen drücken
da stehen.
Netzteil 8V 2A --> Lm317 5V --> Schaltung mit Osci überwacht... aber nix
zu erkennen.
Pierre Gnauck schrieb:> Wo wir hoch gezählt hatten sind wir ja bei dieser Mischung 17:17> angekommen und weiter gekommen er bleibt echt nur beim Analogen drücken> da stehen.
Hmm. Im Moment bin ich ratlos.
Im Code seh ich nichts, was das erklären könnte. Es ist auch die Zahl 17
nicht irgendwie jetzt aussergewöhnlich oder würde irgendwo vorkommen
oder hätte jetzt sonst irgendeinen Bezug.
Gut mein Hund schaut mich sowieso schon an als ob ich einen an der
Waffel hätte, ich würde sagen wir machen da morgen weiter.
Ich schau mir nochmal ganz genau die Schaltung an überprüfe alle und
melde mich dann gegen abend wieder.
Ich danke dir aber schonmal für deine Mühne :)
Pierre Gnauck schrieb:> Ich schau mir nochmal ganz genau die Schaltung an überprüfe alle und> melde mich dann gegen abend wieder.
Freitag abend ist bei mir eher schlecht. Werd zusehen, dass ich online
gehen kann.
> Ich danke dir aber schonmal für deine Mühne :)
Keine Ursache. Das interessiert mich jetzt selber was da los ist.
Sowas hab ich auch noch nie gesehen.
Nabend Karl Heinz,
ich habe nun endlich mal Zeit für meinen Wecker / Uhr gefunden und siehe
da es war kein Software sondern ein Hardware fehler, den (Schande über
mein Haupt) ich erst nach 2 Stunden gefunden hatte.
Ich hatte alle Ausgänge und Eingänge über 1K Widerstände miteinander
verbunden und diese sollten dann gemeinsam auf VCC gelegt werden, nur
diese Verbindung hatte ich vergessen :-).
Mfg Bqube