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!
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.
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.
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
ifTASTER(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 :)
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.
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.
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.