Forum: Mikrocontroller und Digitale Elektronik Zugriff auf eine "volatlie" Variable aus zwei verschiedenen Interrupts möglich?


von Variable aus zwei versch. Interrupts (Gast)


Angehängte Dateien:

Lesenswert?

Hallo, vielleicht könnt ihr mir weiterhelfen.

Ich habe ein Programm für einen ATmega32 geschrieben, das auf der 
Drehencoder-Routine von Deter Dannegger beruht (hier aus der 
Codesammlung). Das einlesen der 4 Drehencoder die ich an Port A 
angeschlossen habe, funktioniert auch prima.

Jetzt zu meinem Problem: Das einlesen der Drehencoder erfolgt über den 
Timer-Overflow-Interrupt mit Timer0 (ca. 7 KHz).

Die Ausgabe der zweistelligen Zahl erfolgt mit 7-Segment-Anzeigen, von 
denen habe ich ingesamt vier Paare (Also viermal eine zweistellige 
Anzeige) die an Port C parallel angeschlossen sind. Die 
7-Segment-Anzeigen werden durch einen BCD-to-7 Segment Treiber/Latch 
angesteuert. Die Parallelen Anzeigen werden über den Latch-Eingang des 
4543 gemultiplext der auf Port B liegt.

Da es ja aber schwachsinn ist, das multiplexen mit 7 Khz zu machen, hab 
ich einen zweiten Interrupt über Timer2 realisiert, der mit 200 Hz 
arbeitet.

Das Problem: wenn ich den zweiten Interrupt benutze werden auf den 
Anzeigen nur noch Nullen angezeigt, die durch Drehen nicht verändert 
werden. Die einzige Variable im zweiten Interrupt ist die counter1_high 
und counter1_low, die ich als global und volatile deklariert habe. Diese 
wird in der ersten Interruptroutine geschrieben und in der zweiten nur 
gelesen. Mach ich da irgendwo nen Denkfehler?

Wenn ich das setzen der Anzeigen mit in die erste Routine packe wird 
alles so angezeigt wie es soll.

Ich weiß nicht mehr weiter!

Vielen Dank für alle Antworten!
MfG Matthias

von aaa (Gast)


Lesenswert?

Das Updaten eines Displays mit 7kHz ist Unsinn. Eine zweiten Timer zu 
verblasen ist auch Unsinn. Einfacher waere es das Dasplay im Ersten zu 
machen, aber zb nur jedes 1000. Mal.

von Jörg G. (joergderxte)


Lesenswert?

Das geht vielleicht besser, wenn du auch beide interrupts aktivierst 
;)
1
  TCCR0 = 1<<CS01;      //divide by 8 * 256
2
  TIMSK = 1<<TOIE0;      //enable timer interrupt
3
  
4
  TCCR2 = (1<<CS22) | (1<<CS21);  /*Timertakt= CPU-Takt/256 (nochmal
5
                  durch 256 wegen 8-Bit Timer, ist Freq. der Anzeige)*/
6
  TIMSK = (1<<TOIE2);         //Enable Timer Interrup
7
//      ^ Hier wird der erste Timer interrupt wieder abgeschaltet
8
//    '|=' waere besser

hth, Jörg

von Peter D. (peda)


Lesenswert?

aaa wrote:
> Das Updaten eines Displays mit 7kHz ist Unsinn.

Was er schon selber sagte.


> Eine zweiten Timer zu
> verblasen ist auch Unsinn.

Nein, ist es beim AVR nicht. Der hat ja keine Interruptprioritäten.
Wenn der 2. Timer-Handler länger braucht, könnte der 1. Handler 
Überläufe verlieren.
Man müßte dann tricksen (SEI im Interrupt), was gefährlich sein kann.
Daher ist ein 2. Timer durchaus sinnvoll, wenn er noch frei ist.


Peter

von oha (Gast)


Lesenswert?

Ein BCD ueber parallellatch anzusteuern braucht ja praktisch keine Zeit, 
solange man keine Float umrechnung vorschaltet. Vernuenftigerweise hat 
man die Werte im Main aufbereitet, sodass der Timerinterrupt nur noch 
laden muss.
Zwei konkurrierende Timer ersetzt man besser durch eine Statusmaschine 
im Timer.

von "10indahose (Gast)


Lesenswert?

>"Deter Dannegger"
lol :D

von Peter D. (peda)


Lesenswert?

Peter Dannegger wrote:

> Nein, ist es beim AVR nicht. Der hat ja keine Interruptprioritäten.
> Wenn der 2. Timer-Handler länger braucht, könnte der 1. Handler
> Überläufe verlieren.
> Man müßte dann tricksen (SEI im Interrupt), was gefährlich sein kann.
> Daher ist ein 2. Timer durchaus sinnvoll, wenn er noch frei ist.


Ist natürlich quatsch, was ich da geschrieben habe.
Der 2.Timer ändert kaum was.

Wenn ein Interrupt zu lange dauert, ist wurscht, ob er sich selber 
blockiert oder nen anderen.
Daher lange Sachen beim AVR möglichst im Main machen.


Peter

von Matthias (natürlich) (Gast)


Lesenswert?

Oh man, danke leute. Ist schon ganz schön doof, wenn man copy and paste 
macht ohne die zu schreibenden Registerbits zu ändern.
Ich hab noch eine weitere Frage: Das hier sollte erstmal eine primitive 
Grundversion sein, die genau das ermöglicht was ich geschrieben hab.

Ich hab auch schon über verbesserungen nachgedacht, da der erste 
Interrupt ja doch ziemlich "lang" ist. Auf der anderen Seite braucht die 
Drehencoder-Auswertung auch nicht öfter laufen, und soo kompliziert ist 
die ja auch nicht
(Dank PETER (sorry, war noch etwas fertig vorhin), großes kompliment 
dafür. Hat zwar augenblick gedauert bis so ein Anfänger wie ich das 
kapiert hatte, aber im endeffekt ist es Genial. Vielleicht solltest du 
noch mal erwähnen das der Code für drehencoder ist die pro "Raste" nur 
zwei wechsel haben. war schwer für mich den Fehler und die Behebung zu 
finden da ich einen mit 4 Zuständen hab.)

Könnte man nicht nur mit dem Interrupt die Eingänge sozusagen 
"kontrollieren" ob sich da was geändert hat, und nur dann die 
Einleseroutine laufen lassen?

In einer vorigen version hatte ich die "nebenberechnung" der counter 
(>23, <0), counter_high und counter_low variablen im Hauptprogramm 
gemacht, was ja aber auch blödsinn ist, weil die ja gar nicht so oft 
geändert werden!

Demnächt soll da noch ein externer Interrupt rein der dann die counter 
inhalte über USART verschickt. Das sollte doch ohne probleme gehen oder?

Hat irgendwer noch gröbere Schnitzer gefunden? Oder 
optimierungsvorschläge?

Trotzdem schon mal vielen Dank für die schnellen Antworten hier.
Mathhias

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
Noch kein Account? Hier anmelden.