Hallöchen zusammen ;)
Bin noch Neueinsteiger in der MicroController-Technik. Deshalb auch
solche Anfängerfragen! Ich hoffe, es nervt hier niemanden ;) Also, ich
habe hier folgenden Quellcode für ein Blinklicht:
1 | #include <reg52.h>
| 2 |
| 3 | unsigned char x=0;
| 4 | sbit led=P1^5;
| 5 | sbit schalter=P3^1;
| 6 |
| 7 | void init (void)
| 8 | {
| 9 | TMOD=0x01;
| 10 | TR0=1;
| 11 | ET0=1;
| 12 | EA=1;
| 13 | P1=0;
| 14 | }
| 15 |
| 16 | void main(void)
| 17 | {
| 18 | init();
| 19 | while(1);
| 20 | }
| 21 |
| 22 | void isr_int_T0(void) interrupt 1
| 23 | {
| 24 | x++;
| 25 | if (schalter) x++;
| 26 | if (x==14) led=1;
| 27 | if (x==28)
| 28 | {
| 29 | led=0;
| 30 | x=0;
| 31 | }
| 32 | }
|
Im Groben und Ganzen ist mir das Programm verständlich und klar. Die
Funktion der ganzen Schaltung soll sein, dass man mit Betätigung des
Schalters die Blinkfrequenz erhöhen kann. Jedoch verstehe ich ehrlich
gesagt nicht ganz wie das funktionieren soll ? Nach jedem Überlauf des
Timers erhöht sich die Zähl-Variable x ja automatisch und wird dann ab
einem Wert x = 14 erstmal gesetzt und dann jedes mal in der
Timer-Schleife zurück gesetzt, soweit auch logisch. Aber ab dem Wert
x=14 müsste sich die Blinkfrequenz dann ja automatisch erhöhen, bis zu
dem Wert 28, wo x wieder auf 0 gesetzt wird. Und wenn ich den Schalter
drücke, erhöht die Blinkfrequenz sich pro Durchgang nur schneller als
ohne Tastendruck.
Klingt vielleicht komisch, aber so konnte ich mir den Quellcode nur
erklären! Ich hoffe ihr könnt mir helfen!
MfG
Tobias D. schrieb:
> Schalters die Blinkfrequenz erhöhen kann. Jedoch verstehe ich ehrlich
> gesagt nicht ganz wie das funktionieren soll ? Nach jedem Überlauf des
> Timers erhöht sich die Zähl-Variable x ja automatisch
automatisch würde ich das so nicht nennen.
x erhöht sich, weil im Überlauf Handler ein
steht. Dadurch wird x erhöht.
> und wird dann ab
> einem Wert x = 14 erstmal gesetzt und dann jedes mal in der
> Timer-Schleife zurück gesetzt, soweit auch logisch.
Ähm.
Wovon sprichst du da.
Das was du da (etwas unbeholfen) beschreibst findet sich nicht im
Programmcode.
> Klingt vielleicht komisch, aber so konnte ich mir den Quellcode nur
> erklären! Ich hoffe ihr könnt mir helfen!
AM besten wäre es, wenn du selber Computer spielst und mit Papier und
Bleistift den Code durchsimulierst. Deine 'Analyse' ist mehr als konfus
und wenn mich nicht alles täuscht, bist du ziemlich am Holzweg, wie das
funktioniert.
Ausgangsszenario:
x habe den Wert 0. Der Schalter ist nicht gedrückt. Der Timer läuft in
den Overflow und als Folge davon wird die Overflow-ISR aufgerufen.
Was passiert im Detail und warum?
Nimm das nicht auf die leichte Schulter sondern stelle wirklich sicher,
dass du das verstehst. Das ist nämlich wichtig um zu erkennen, warum da
im Programm ein(*) schwerer Fehler enthalten ist, der die korrekte
Funktion verhindert und vor allen Dingen auch, wie man ihn beheben kann.
(*) eigentlich zwei, je nachdem wie man es sehen will.
Tobias D. schrieb:
> Im Groben und Ganzen ist mir das Programm verständlich und klar. Die
> Funktion der ganzen Schaltung soll sein, dass man mit Betätigung des
> Schalters die Blinkfrequenz erhöhen kann.
So ist es. Ohne Schalter wird je Durchlauf x um eins erhöht. Mit
Schalter um zwei. Damit verdoppelt sich die Blinkfrequenz.
Der Wert x wird durch "x++" von 0 auf 1 gesetzt. Anschließend springt
der Prozessor wieder in's MainProgramm, weil keine if-Bedingung erfüllt
ist, und somit automatisch wieder in den Timer, bis dieser überläuft und
wieder in den Interrupt springt, den Wert von 1 auf 2 erhöhrt usw...
Das ganze passiert bis die Zählvariable x auf 14 ist. Dann wird die LED
auf 1 gesetzt. Danach geht's wieder ins Main-Programm und somit in den
Timer, wo die LED wieder auf 0 gesetzt wird. Nach Überlauf wieder ins
Interrupt, x erhöhen etc. bis x auf 28 ist. Dann wird x auf 0 gesetzt
und die led auch.
So, nochmal in Ordentlich. Ich hab's oben vielleicht etwas komisch
beschrieben... Anders verstehe ich es nicht, selbst wenn ich es Zeile
für Zeile durchgehe. Jedoch verstehe ich nicht, wie man die Frequenz
dann erhöhen soll. Das hieße ja, der Schalter müsste die ganze Zeit
geschlossen sein?
Edit: Okay! Ich hab da nen kleinen Denkfehler drin gehabt. Habe die
ganze Zeit bei dem Schalter an den Taster gedacht!!! Heut ist wohl nicht
mein Tag :D
Jedoch habe ich noch eine Frage:
Wozu brauche ich EA = 1 ? ET0 = 1 sagt ja, dass der Timer nach Überlauf
in eine Interrupt-Service-Routine springen soll.
Tobias D. schrieb:
> Der Wert x wird durch "x++" von 0 auf 1 gesetzt. Anschließend springt
> der Prozessor wieder in's MainProgramm, weil keine if-Bedingung erfüllt
> ist,
ok.
> und somit automatisch wieder in den Timer, bis dieser überläuft und
> wieder in den Interrupt springt, den Wert von 1 auf 2 erhöhrt usw...
ok
> Das ganze passiert bis die Zählvariable x auf 14 ist. Dann wird die LED
> auf 1 gesetzt.
jetzt hast du es richtig ausgedrückt :-)
Im Eröffnungsposting hast du nämlich die Hälfte dessen verschluckt :-)
> Danach geht's wieder ins Main-Programm und somit in den
> Timer, wo die LED wieder auf 0 gesetzt wird.
Äh.
Warum.
Ich seh im Hauptprogramm nichts, was die LED wieder auf 0 setzen würde.
> Nach Überlauf wieder ins
> Interrupt, x erhöhen etc. bis x auf 28 ist. Dann wird x auf 0 gesetzt
> und die led auch.
Genau.
Hier wird die LED wieder ausgeschaltet und nicht im Hauptprogramm
> So, nochmal in Ordentlich. Ich hab's oben vielleicht etwas komisch
> beschrieben... Anders verstehe ich es nicht, selbst wenn ich es Zeile
> für Zeile durchgehe. Jedoch verstehe ich nicht, wie man die Frequenz
> dann erhöhen soll.
> Das hieße ja, der Schalter müsste die ganze Zeit
> geschlossen sein?
Aaaah. Hier liegt dein gedankliches Problem.
Ja, genau. Genau das heisst es. Nur solange der Schalter/Taster
geschlossen ist, wird mit doppelter Frequenz geblinkt.
Dies deshalb weil x dann nicht
0, 1, 2, 3, 4, 5 ....
zählt, sondern durch
if (schalter) x++;
hat x bei den LED Abfragen die Werte
0, 2, 4, 6, 8, 10, ....
und damit wird 14 bzw 28 dann eben jeweils doppelt so schnell erreicht.
Und da liegt jetzt auch der Fehler.
Angenommen x habe den Wert 0, und der Schalter sei nicht geschlossen.
Dann wird x nach dem ersten ISR Aufruf den Wert 1 haben. Jetzt schliesst
du den Schalter. Als Folge davon wird in der ISR x jeweils 2 mal um 1
erhöht. Ab dann zählt x daher
0, 1, 3, 5, 7, 9, 11, 13, 15, 17, ....
Huch. die 14 sind nie erreicht worden! Und auch die 28 werden nicht
erreicht werden! x wird ab jetzt nur noch ungerade Zahlen annehmen. Und
damit wird weder das hier
noch das hier 1 | if (x==28)
| 2 | {
| 3 | led=0;
| 4 | x=0;
| 5 | }
|
je true sein können. Als Folge davon hört das Blinken komplett auf.
Erst dann, wenn der Schalter wieder ausgeschaltet wird, kann x wieder in
Einzelschritten zählen und das Blinken setzt früher oder später wieder
ein. Je nachdem welchen Wert x genau hat (gerade/ungerade), wenn der
Schalter eingeschaltet wird, blinkt die LED also doppelt so schnell oder
gar nicht.
Karl heinz Buchegger schrieb:
>> Danach geht's wieder ins Main-Programm und somit in den
>> Timer, wo die LED wieder auf 0 gesetzt wird.
> Äh.
> Warum.
> Ich seh im Hauptprogramm nichts, was die LED wieder auf 0 setzen würde.
Also nicht direkt im Hauptprogramm, aber im Timer wird die LED auf 0
gesetzt, wenn ich mich nicht komplett täusche, da:
und die LED liegt ja auf dem Port P1 !
> Und da liegt jetzt auch der Fehler.
>
> Angenommen x habe den Wert 0, und der Schalter sei nicht geschlossen.
> Dann wird x nach dem ersten ISR Aufruf den Wert 1 haben. Jetzt schliesst
> du den Schalter. Als Folge davon wird in der ISR x jeweils 2 mal um 1
> erhöht. Ab dann zählt x daher
>
> 0, 1, 3, 5, 7, 9, 11, 13, 15, 17, ....
Wow, super! Das muss man erstmal bemerken ! ;)
Danke !
Tobias D. schrieb:
>> Äh.
>> Warum.
>> Ich seh im Hauptprogramm nichts, was die LED wieder auf 0 setzen würde.
>
> Also nicht direkt im Hauptprogramm, aber im Timer wird die LED auf 0
> gesetzt, wenn ich mich nicht komplett täusche, da:
>
> und die LED liegt ja auf dem Port P1 !
Schon richtig.
Aber du hast ja vom Hauptprogramm gesprochen.
Es mag dir jetzt wie Korinthenkacken vorkommen, aber gewöhn dir an, die
Dinge exakt zu beschreiben.
Bei mir ist das noch harmlos, ich kann auch erraten. Aber ein Compiler,
eine Programmiersprache, nimmt das sehr genau. Daher ist es besser du
gewöhnst dir das schludern gleich von vorne herein ab. Egal ob du im
Forum etwas erzählst, oder ob du programmierst.
Das stimmt natürlich ;)
Das ganze Programm funktioniert ja schon nicht, sobald auch nur ein ";"
fehlt.
Danke !
MfG
So, hab nochmal über das Problem nachgedacht. Als Lösung des Problemes
habe ich mir überlegt, dass der Prozessor eine Abfrage des X-Wertes nach
jeder Erhöhung machen müsste. Und das Ganze habe ich mir so gedacht:
1 | void isr_int_T0(void) interrupt 1
| 2 | {
| 3 | x++;
| 4 | if (x==14) led=1;
| 5 | if (x==28)
| 6 |
| 7 | if (schalter) x++;
| 8 | if (x==14) led=1;
| 9 | if (x==28)
| 10 | {
| 11 | led=0;
| 12 | x=0;
| 13 | }
| 14 | }
|
Es mag zwar vielleicht nicht die eleganteste Variante sein, aber es
müsste doch rein theoretisch funktionieren , oder habe ich wieder einen
Denkfehler ?
MfG
Tobias D. schrieb:
> jeder Erhöhung machen müsste. Und das Ganze habe ich mir so gedacht:
Die Lösung liegt nicht darin, noch mehr Vergleiche auf Gleichheit
einzuführen.
Die Lösung liegt darin, sich von der Vorstellung zu lösen, dass es
bestimmte Werte geben muss oder soll, an denen die LED umgeschaltet
werden soll, sondern sich zu überlegen, was für die Zahlenwerte gelten
muss, damit die LED leuchtet.
Du hast ja auch noch andere Möglichkeiten für Vergleiche, nicht nur auf
Gleichheit.
Zb soll doch die LED leuchten, wenn x kleiner als 15 ist
if (x < 15)
led = 1;
Das gilt jetzt immer. Denn egal ob die Zählerei nun
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, ...
lautet, oder ob es
0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, ....
oder gar
1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, ....
lautet, immer gibt es Zahlen die kleiner sind als 15 und es gibt welche
die nicht kleiner sind als 15. Ist x kleiner als 15 dann soll die LED
leuchten. Ist x nicht kleiner als 15 soll die LED nicht leuchten
if (x < 15)
led = 1;
else
led = 0;
Jetzt brauchst du nur noch eine Abfrage dafür, dass bei 28 wieder auf 0
zurückgeschaltet wird. Auch hier wieder: Ob das jetzt 28 oder 29 sind,
ist eigentlich nicht so wichtig. Wichtig ist, dass x irgendwann mit
Sicherheit größer als 27 wird.
> Es mag zwar vielleicht nicht die eleganteste Variante sein, aber es
> müsste doch rein theoretisch funktionieren , oder habe ich wieder einen
> Denkfehler ?
Damit erhöhst du x in einem Interrupt Aufruf um 3. Da aber der Interrupt
Aufruf im Vergleich zum Rest so gut wie keine Zeit braucht, blinkt deine
LED damit 3 mal so schnell.
>
> MfG
warum nicht einfach auf größer/gleich 14 bzw 28 testen?
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|