lex7 schrieb:> Lasse ich den counter in der ISR hochzählenvolatile uint16_t> countISRTimer1=0;>> ISR( TIMER1_COMPA_vect ) // every 10ms> {> countISRTimer1++;> }>> void setup() {> //...> }>> void loop() {> if(countISRTimer1%128==0)> Serial.println(countISRTimer1);> }>> sieht die Ausgabe so aus:> 0> 4> 128
Das Problem hier ist der nicht-atomare Zugriff auf countISRTimer1 bei
der Ausgabe. Waehrend die Teile der 16-bit Zahl gelesen werden
inkrementiert die ISR die Zahl.
S. zB. http://www.gammon.com.au/interrupts (Atomic access)
leo
lex7 schrieb:> Leider bleibt das Ergebnis wie oben.> Noch Ideen?
In der ISR die Interrupts abschalten bringt gar nix, weil sie da schon
aus sind. Sie wieder einzuschalten ist aber gefährlich. Du musst sie in
der loop abschalten.
Wie wäre es damit, aus der Variablen eine uint8_t zu machen und immer
nur bis 127 zu zählen und dann auf 0 zu setzen? Dann erledigt sich das
Problem komplett, denn 8-Bit Typen können atomar gelesen werden.
Effizienter ist es auch. Aber Vorsicht: der per println ausgegebene Wert
kann dann anders sein als der in der if Bedingung. Daher am Besten eine
lokale temporäre Kopie machen.
Dr. Sommer schrieb:> In der ISR die Interrupts abschalten bringt gar nix, weil sie da schon> aus sind
Oh, falsch gelesen! Äh, der letzte Teil meiner Aussage ist hier das
Problem - die Variable wird 2x ausgelesen, einma im if und einmal im
println. Und beim letzteren auch ohne Interrupt Sperre.
Außerdem soll die Variable als "volatile" gekennzeichnet werden, damit
bei jedem Zugriff auf das RAM zugegriffen wird und kein Caching in einem
CPU Register stattfindet.
Das hat lex7 richtig gemacht, ich wollte es in diesem Kontext nur
nochmal erklären, weil es oft vergessen wird.
Besten Dank an alle, da hatte ich wohl einen Knoten im Kopf.
hiermit bekomme ich auch eine doppelte Ausgabe:
Dr. Sommer schrieb:> Wenn aber wirklich bis 65408 gezählt werden soll, dann so:>
1
volatile
2
>uint16_tcountISRTimer1=0;
3
>
4
>ISR(TIMER1_COMPA_vect)// every 10ms
5
>{
6
>++countISRTimer1;
7
>}
8
>
9
>voidsetup(){
10
>//...
11
>}
12
>
13
>voidloop(){
14
>cli();
15
>uint16_ttemp=countISRTimer1;
16
>sei();
17
>if(temp%128==0)
18
>Serial.println(temp);
19
>}
0
0
128
128
256
256 usw.
Aber klar, die ISR wird nur alle 10ms ausgeführt, da kann der loop()
doppelt durchlaufen werden.
lex7 schrieb:> hiermit bekomme ich auch eine doppelte Ausgabe:
Die andere Version mit uint8_t liefert genauso doppelte Ausgaben - die
sind halt nur immer "0" ;-) Daher ist das println(temp) da auch etwas
sinnlos, weil temp da eh immer 0 ist.
lex7 schrieb:> Aber klar, die ISR wird nur alle 10ms ausgeführt, da kann der loop()> doppelt durchlaufen werden.
Ja, eigentlich sogar noch viel schneller. Das println bremst es
wahrscheinlich.
Dr. Sommer schrieb:> lex7 schrieb:>> hiermit bekomme ich auch eine doppelte Ausgabe:>> Die andere Version mit uint8_t liefert genauso doppelte Ausgaben - die> sind halt nur immer "0" ;-) Daher ist das println(temp) da auch etwas> sinnlos, weil temp da eh immer 0 ist.>> lex7 schrieb:>> Aber klar, die ISR wird nur alle 10ms ausgeführt, da kann der loop()>> doppelt durchlaufen werden.>> Ja, eigentlich sogar noch viel schneller. Das println bremst es> wahrscheinlich.
Sicher, aber das Grundkonzept ist schon Unsinn. Wenn man einen Vorgang
mit einer Frequenz X anstoßen will, dann DIREKT!
1
volatileuint16_tcountISRTimer1=0;
2
volatileuint8_tisr_flag=0;
3
4
ISR(TIMER1_COMPA_vect)// every 10ms
5
{
6
++countISRTimer1;
7
if((countISRTimer1&0x7F)==0)isr_flag=1;// fast modulo operation
8
}
9
10
voidsetup(){
11
//...
12
}
13
14
voidloop(){
15
16
if(isr_flag){
17
isr_flag=0;
18
cli();
19
uint16_ttemp=countISRTimer1;
20
sei();
21
Serial.println(temp);
22
}
23
}
Das ist eindeutig und laufzeitunabhängig (es sei denn, die Ausgabe per
UART läuft mit 10 Baud).
Falk B. schrieb:> Sicher, aber das Grundkonzept ist schon Unsinn. Wenn man einen Vorgang> mit einer Frequenz X anstoßen will, dann DIREKT!
Da kann man sich die ISR aber auch sparen und es direkt so machen:
1
uint8_tcountISRTimer1=0;
2
voidloop(){
3
if(TIFR&(1<<TOV1)){
4
TIFR=1<<TOV1;
5
if(countISRTimer1==128){
6
countISRTimer1=0;
7
Serial.println("Overflow\n");
8
}else
9
++countISRTimer1;
10
11
}
12
}
Spart die Fummelei mit cli/sei, volatile, Überlegung wo die ISR den
eigentlichen Programmfluss unterbrechen kann...
Dr. Sommer schrieb:> Falk B. schrieb:>> Sicher, aber das Grundkonzept ist schon Unsinn. Wenn man einen Vorgang>> mit einer Frequenz X anstoßen will, dann DIREKT!>> Da kann man sich die ISR aber auch sparen und es direkt so machen:
Naja, das geht aber nur, wenn die Überlauffrequenz eher klein ist und
die Abfrage des Überlaufbits ausreichend schnell. Das ist schon wieder
ein Sonderfall.
"Ich bin dafür, die Dinge soweit wie möglich zu vereinfachen, aber nicht
weiter."
Albert Einstein