Hallo, im Anhang ist mein C-Code für einen ATmega16. Was das Programm machen soll ist recht simpel. Ein Timer-Compare-Interrupt bildet die Zeitbasis von 1ms. In der Mainschleife kann ich unabhängig voneinander 2 LEDs über 2 Taser einschalten. Beim Einschalten wird wird jede LED eine Variable auf 3000 gestellt, die in der ISR dekrementiert wird. Wird der Wert 0 erreicht (also nach 3s) soll die dazugehörige LED gelöscht werden. Zur entprellung und um das ganze zu Strukturieren steuert eine 3. Variable die Hauptschleife, so dass diese immer 100ms pro durchlauf benötigt. Soweit zur Theorie. Meine Beobachtung ist leider ne ganz andere. Aktiviere ich eine LED durch Drücken des Tasters, leuchtet diese zunächst "für immer". Beim Aktivieren der 2. LED leuchtet diese für immer, dafür geht die vorherige nach 3s aus. Da setzt mein Verständniss völlig aus, wie kann den ein Taster die LED des anderen Taster auf einmal irgendwie triggern? Oder hab ich ein völlig falsches Verständniss der Timer und ISR? Und dann noch eine eher allgemeine Frage. Wie sieht den eigentlich eine "gute Programmstruktur" aus? Da ich mir bisher alles selbst beigebracht habe mit diversen Tuts weis ich nicht wie guter Programmierstil eigentlich ausschaut. Bei mir ists eher auf Funktionalität ausgelegt :) Wie liest man denn am besten Taster ein? Mainschleife? ISR? Funktion die ab und zu aufgerufen wird? Wo löscht man am sinnvollsten LEDs? usw. Hoffe ihr könnt mir weiterhelfen, Danke schon mal, MfG Luge
Wie schalten deine Taster? Nach Masse oder nach Vcc? (Was ist der Grundzustand der Bits an denen die Taster hängen. 0 oder 1?) Wie schalten deine LED ein? Portbit auf 0 oder 1 für einschalten?
Luge schrieb: > Und dann noch eine eher allgemeine Frage. > Wie sieht den eigentlich eine "gute Programmstruktur" aus? Deine Programmstruktur ist nicht schlecht. > Da ich mir bisher alles selbst beigebracht habe mit diversen Tuts weis > ich nicht wie guter Programmierstil eigentlich ausschaut. Ist ok. Für einen Autodidakten eigentlich sogar ziemlich gut. > Wie liest man denn am besten Taster ein? Mainschleife? ISR? Funktion die > ab und zu aufgerufen wird? Über die PeDa Tastenentprellung :-) http://www.mikrocontroller.net/articles/Entprellung#Komfortroutine_.28C_f.C3.BCr_AVR.29 > Wo löscht man am sinnvollsten LEDs? So wie du das hast, ist das schon ok.
Eingänge: 0 = GND 1 = VCC Ausgänge: 0 = GND 1 = VCC Aber ich spiel schon seit Tagen mit den LEDs und Tastern herum, geht alles, die Makros funken auch. Denke irgendwo im Timer oder in der ISR liegt der Fehler. Der uC arbeitet aber mit 16Mhz (ausprobiert mit _delay_ms()). Die ISR wird auch wirklich jede 1ms aufgerufen. (Ausprobiert durch toggeln einer LED in der Hauptschleife im 5s Intervall und mit Stoppuhr :)) Aber Danke dir schon mal!
Luge schrieb: > Eingänge: > 0 = GND > 1 = VCC > > Ausgänge: > 0 = GND > 1 = VCC > :-) Lol das hab ich mir schon gedacht, dass 0 einem GND Pegel entspricht. Ich formuliere anders: Wenn du nichts drückst, liefert dann der Tasterpin eine 0 oder eine 1? Zusatzfrage: Bist du dir da ganz sicher? Bonuspunkte: Kannst du mal die externe Beschaltung in Form eines (nicht von dir gezeichneten) Schaltbildes zeigen bzw. wenn es ein fertiges Board ist den Namen des Boards nennen? > Aber ich spiel schon seit Tagen mit den LEDs und Tastern herum, geht > alles, die Makros funken auch. Das muss nicht unbedingt etwas heißen, Wenn du alle Logik rumdrehst funktionieren die meisten Programme bei denen es nur um Taste gedrückt/nicht_gedrückt und Led_an/Led_aus geht, völlig gleich. > Denke irgendwo im Timer oder in der ISR liegt der Fehler. Sieht ok aus.
Sry dann hab ich deine Frage falsch verstanden :) Also, grad nachgemessen. Bei gedrücktem Taster liegen am Eingangspin 5V an. Ausserdem schaltet dann das Register PINB von 0x00 auf zb 0x10 bei Taster 5. (getestet über UART und Terminalprogramm, sowas erleichtert die Fehlersuche echt ungemein wenn man kein JTAG hat :))
Luge schrieb: > Sry dann hab ich deine Frage falsch verstanden :) > > Also, grad nachgemessen. Bei gedrücktem Taster liegen am Eingangspin 5V > an. > Ausserdem schaltet dann das Register PINB von 0x00 auf zb 0x10 bei > Taster 5. (getestet über UART und Terminalprogramm, sowas erleichtert > die Fehlersuche echt ungemein wenn man kein JTAG hat :)) OK Ich such weiter
Danke dir! ich hatte schon Angst dass meine ISR zu lang ist. Aber bei 16Mhz dauert ein Takt ja grad mal ~60 nS, das reicht eigentlich dicke. Aber ich kanns mir nur so erklären dass die ISR teilweise nicht aufgerufen wird/unvollständig ausgeführt wird. Ich hab mir auch die 2 Timerstände mal aufs Terminal ausgegeben. Da stand dann zB timer_a = 0, trotzdem hat die LED geleuchtet. Und das obwohl die Bedingung jede mS ja geprüft wird!
Da ist der erste Fehler
1 | #define LED_AUS(LED) ((OUTPORT) &= (1 << (LED)))
|
muss heissen
1 | #define LED_AUS(LED) ((OUTPORT) &= ~(1 << (LED)))
|
Luge schrieb: > Danke dir! > > ich hatte schon Angst dass meine ISR zu lang ist. Aber bei 16Mhz dauert > ein Takt ja grad mal ~60 nS, das reicht eigentlich dicke. Du sagst es > Aber ich kanns mir nur so erklären dass die ISR teilweise nicht > aufgerufen wird/unvollständig ausgeführt wird. Nein. Du machst den Kardinalfehler: Bei Fehlern kannst du zu 99% davon ausgehen, dass DU einen Programmfehler gemacht hast, und nicht dass CPU oder Compiler irgendetwas schräges treiben.
Jetzt hab ichs;)
> TIMSK |= (1<<OCF0);
OCF0 gibts nicht in TIMSK. Das Ding heisst OCIE0.
holger schrieb: > Jetzt hab ichs;) > >> TIMSK |= (1<<OCF0); > > OCF0 gibts nicht in TIMSK. Das Ding heisst OCIE0. Prinzipiell richtig. Nur leider nicht das Problem :-) (korrigier erst mal die fehlende ~) OCIE ist ein #define auf 1 OCF0 ist ein #define auf 1 d.h. in beiden Fällen steht dort TIMSK |= ( 1 << 1 ); und das schaltet den Compare Match Interrupt ein :-) D.h. Obwohl du die falsche Bitbezeichnung genommen hast passiert trotzdem das richtige.
Nächster Fehler
1 | if TASTER(T5){ |
2 | LED_AN(LED1); |
3 | timer_a = 3000; |
4 | |
5 | }
|
hier ist die Reihenfolge falsch, bzw. überhaupt der Zugriff. Was ist das Problem: Dein Code schaltet zb die LED ein. Und genau wie es der Teufel haben will, kommt der Compare Match Interrupt noch ehe timer_a auf 3000 gesetzt wird. Die Folge: da die ISR abläuft, ehe timer_a auf 3000 gesetzt wird, schaltet die ISR die LED wieder aus :-( Da allerdings timer_a sowieso eine 16 Bit Variable ist, muss man den Zugriff atomic machen, also ein cli() / sei() Pärchen drumm herum legen.
1 | if TASTER(T5){ |
2 | cli() |
3 | timer_a = 3000; |
4 | LED_AN(LED1); |
5 | sei(); |
6 | }
|
Für die andere Taste und den anderen Zähler genau gleich
@ Holger: 1. Ich will den Interrupt ja nicht bei Overflow (bei 8 Bit nach 255) sondern bei Compare Match. Deshalb beleg ich das Compare-Register ja auch mit 249, das entspricht bei 64er-Prescaler und 16Mhz genau eine mS. 2. Ups, mit dem OCF0 hast du recht! Peinlich peinlich! Daran liegts aber trotzdem nicht, weil zufällig OCF0 und OCIE0 genau jeweils Bit# 1 sind und deswegen in der include-Datei auch jeweils den Wert 1 enthalten :) Aber danke für den Hinweiß! @ Karl Heinz: Danke dir, werd ich sofort ausprobieren. Nur wie gesagt, bei Spielereien ohne Timer und ISR gabs nie Probleme. Evtl werd ich auch das Timer-Zeugs aufschieben und erstmal eine geprüfte Routine zur Entprellung einbauen, damit ich mir Fehler von den Tastern sicher ausschliesen kann. Hab das Gefühl die prellen ordentlich :) Pollin oO Danke euch beiden!
Luge schrieb: > @ Karl Heinz: > Danke dir, werd ich sofort ausprobieren. Nur wie gesagt, bei Spielereien > ohne Timer und ISR gabs nie Probleme. Das lässt nur einen Schluss zu: Du hast ganz einfach die falschen Dinge getestet. (Durch Testen kann man immer nur das Vorhandensein von Fehlern nachweisen. Nie das Fehlen. Wenn also ein Programm so tut als ob, heißt das noch lange nicht das alles richtig ist) > Evtl werd ich auch das Timer-Zeugs Dein Problem ist nicht der Timer! der arbeitet einwandfrei. Das Problem ist dein Drumherum :-) > aufschieben und erstmal eine geprüfte > Routine zur Entprellung einbauen, in dem Fall hättest du überhaupt keine Entprellung benötigt :-)
Nachtrag: (Sry fürn Doppelpost) @ Karl Heinz: Danke dir, klingt einleuchtend! Achja, und 16Bit Variablen, da war ja auch was... Wird auch geändert. Nur, mal im Ernst, wie groß ist die Chance dass der Interrupt immer genau nach dem Einschalten, bzw zwischen den Takten die für die Variablenzuweisung nötig sind, auftritt? Naja geändert wirds trotzdem. Falls das nicht klappt, siehe vorherigen Post, dann wird das Thema erstmal aufgeschoben. Danke euch trotzdem!
Luge schrieb: > Wird auch geändert. Nur, mal im Ernst, wie groß ist die Chance dass der > Interrupt immer genau nach dem Einschalten, bzw zwischen den Takten die > für die Variablenzuweisung nötig sind, auftritt? Ist uninteressant. Passieren kanns (und ist mir auch in der Simulation passiert, ich habe allerdings andere Timereinstellungen benutzt, damit ich nicht ewig davor sitze) und damit muss es behandelt werden. Mit den beiden Änderungen verhält sich dein Pgm in der Simulation so wie gewünscht. Hauptschuldiger war die fehlende ~
Danke dir nochmal, alles Bestens jetzt! Wieder was gelernt. Letzte Woche hatte ich solche Spielereien getestet: if (TASTER(T1)) LED_TOGGLE(LED1); ... if (Taster(T8)) LED_TOGGLE(LED8); Seltsam dass sich die fehlende ~ da nicht bemerkbar gemacht hatte. Sonst wär ich nicht so überzeugt gewesen dass meine Makros stimmen. Wie auch immer, langsam wirds! :)
Luge schrieb: > Danke dir nochmal, alles Bestens jetzt! > > Wieder was gelernt. > > Letzte Woche hatte ich solche Spielereien getestet: > > if (TASTER(T1)) > LED_TOGGLE(LED1); Ja und. LED_TOGGLE ist ja ein ganz anderes Makro als LED_aus
Achja, mir is da noch ne blöde Frage eingefallen: Dadurch dass die Anweisungen bei Tasterdruck jetzt durch cli() und sei() atomar sind kann es ja sein dass sich meine ISR um einige hundert Nanosekunden verschiebt. Im schlimmsten Fall bei jedem Durchlauf der Hauptschleife. An sich hier nicht tragisch. Aber was wäre zB, wenn ich eine Uhr oder sowas in der Richtung bauen will? Irgendwann würden sich ja die Zeiten doch soweit addieren, dass die Uhr immer mehr falsch gehen würde? Sehe ich das richtig? Also nur aus Interesse, ich bau mir so schnell keine Uhr :)
Achja, natürlich ist Toggle was andres als Aus. Kopf -> Tisch. Ich glaub für heute reichts, ich hock scho wieder zulange davor :)
Luge schrieb: > Dadurch dass die Anweisungen bei Tasterdruck jetzt durch cli() und sei() > atomar sind kann es ja sein dass sich meine ISR um einige hundert > Nanosekunden verschiebt. Das kann sein. Ja > Im schlimmsten Fall bei jedem Durchlauf der > Hauptschleife. An sich hier nicht tragisch. > > Aber was wäre zB, wenn ich eine Uhr oder sowas in der Richtung bauen > will? > Irgendwann würden sich ja die Zeiten doch soweit addieren, Nur solange du nicht einen ISR Aufruf überhaupt verpasst. Der Timer läuft ja im Hintergrund unbeeinflusst weiter. Lediglich der eine ISR Aufruf kommt dann ein klein wenig später. Aber der nächste passt dann wieder, weil der Aufruf ja nur vom Timer selbst abhängt und nicht davon, wann die ISR zuletzt aufgerufen wurde. Diese kleinen Fehler summieren sich also nicht auf. Lediglich die Zeitabstände der ISR Aufrufe sind ein wenig unregelmässig. Aber wenn ein Aufruf ein klein wenig zu spät erfolgt, kommt dafür der nächste ein klein wenig früher und alles gleicht sich wieder aus.
Luge schrieb: > Hab das Gefühl die prellen ordentlich :) > Pollin oO Hast Du zufällig das Pollin-Board? Sind die Taster richtig angeklemmt?
Ja, hab ich, + Erweiterungsboard. Bereue es auch nicht, lediglich die Kondensatoren an den Tastern musste ich auslöten. Seitdem läufts! (zumindest Hardwaremäsig, aber der größte Fehler sitzt halt immer noch zwischen Lehne und Bildschirm :) )
Luge schrieb: > lediglich die Kondensatoren an den Tastern musste > ich auslöten. genau. Ich kann auch nicht meckern. Für das Geld kann man mit dem Board nichts falsch machen.
Den Artikel kennst du? Beitrag "Re: Pollin AVR Board Fehler beim drücken der Taster / Qualität der Bauteile" Besonders ganz unten.
Karl heinz Buchegger schrieb: > Den Artikel kennst du? Den hab ich noch nicht gekannt. Es giebt aber wirklich viele hier mit dem Thema "Pollin Schalter". Die Kondensatoren sind bei mir auch ausgelötet. Mein Gedanke war ja, das bei Luge der Fehler mit daran liegen könnte.
Ich kannte den Artikel. Den Umbau im vorletzten Beitrag auf aktiv-low fand ich bisl overkill, wenns doch durch auslöten auch klappt :) Wie heißts, never touch a running system. Und zumindest hardwaremäsig runnts bei mir :) Der letzte Tipp aber mit den kleineren Kapazitäten klingt interessant. Evtl mal probiern, nur hab ich zZ keine rumliegen. Naja, und so tuts ja auch.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.