Hallo, Mit meinem kleinen Beispielcode im Anhang stehe ich vor einem Rätsel. Ich möchte u.A. drei Analogwerte einlesen und einen davon über die RS232 weitersenden, dies zyklisch per Timerinterrupt gesteuert, also ständig einlesen, rumrechnen und ca alle Sekunde einmal den Analogwert senden. Lese ich in der Interruptroutine den AD-Wert zum Senden ein, habe ich kein Problem. Aber sobal ich in der main-loop die Werte einlese und im Interrupthandler versenden möchte, geht es nicht. Es sieht fuer mich so aus, als ob der main "nicht abgearbeitet" wird, irgendwie ein irq-vektor/reset das Programm wieder neu startet. Ich sehe den Denkfehler aber nicht. liebe Grüße jochen
Ich habe mir den Code jetzt nicht im Detail angesehen, aber ein CTRL-F fördert kein "volatile" zu Tage. Das wird das Problem sein. http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Datenaustausch_mit_Interrupt-Routinen
>cli(); // Interrupts nicht zulassen
Sinnfrei innerhalb einer ISR, da dort sowieso keine anderen Interrupts
zugelassen werden.
1 | SIGNAL (SIG_OVERFLOW0) |
2 | {
|
3 | cli(); // Interrupts nicht zulassen << sinnfrei |
4 | |
5 | takt--; |
6 | |
7 | if (takt == 0) { |
8 | takt = TIMERVALUE; |
9 | ucSend = 1; |
10 | |
11 | Wie lange dauert der ganze Spaß hier? |
12 | UARTPutChar(0x01); |
13 | // UARTPutChar(readAnalogValues(0)); // vor Rechen
|
14 | UARTPutChar(readAnalogValues(1)); // hinter Rechen |
15 | // UARTPutChar(ucAnalogValues[1]);
|
16 | UARTPutChar(PIND & 0xfc); |
17 | // UARTPutChar(readAnalogValues(2)); // Einsteller
|
18 | UARTPutChar(0xff); |
19 | |
20 | }
|
21 | sei(); << wenn das Sperren schon sinnfrei ist, braucht man sich um das Freigeben auch nicht mehr kümmern... |
22 | |
23 | }
|
Ich würde sagen, dass deine ISR viel zu langsam ist. Weiterhin sollte man den ADC nur ein Mal initialisieren und den ersten Messwert verwerfen. Die darauffolgenden Messwerte sind dann auch erste richtig gültig.
Warum? "takt" wird ausschließlich im Interruptcode verwendet. "ucAnalogValues" muss aber volatile sein.
In der main-loop belädst Du das Array: >ucAnalogValues[i]= readAnalogValues(i); Der Inhalt des Arrays wird aber nirgendwo verwendet... Dafür wartet die ISR >SIGNAL (SIG_OVERFLOW0) aktiv auf ADC-Ergebnisse (4x in readAnalogValues(unsigned char ucMux)):
1 | for (i=0;i<4;i++) { |
2 | ADCSRA |= (1<<ADSC); |
3 | while (ADCSRA&(1<<ADSC)) {} |
Aktives Warten auf ADC-Ergebnisse innerhalb einer Timer-ISR finde ich... ...unkonventionell.
Maddin wrote: > In der main-loop belädst Du das Array: >>ucAnalogValues[i]= readAnalogValues(i); > Der Inhalt des Arrays wird aber nirgendwo verwendet... Doch: // UARTPutChar(ucAnalogValues[1]); Die auskommentierte Zeile gehört zu dem "funktioniert nicht"-Fall.
>Die auskommentierte Zeile gehört zu dem "funktioniert nicht"-Fall.
OK, sorry...
Noch eine Bemerkung zum Datenaustausch:
Wenn das Array auf "Tasklevel" (main loop) gegeschrieben und auf
Interrupt-Level gelesen wird, muß der Schreibzugriff in "main" geschützt
werden (d.h. unter Interruptsperre), damit im Interrupt keine halb
geschriebenen Daten an die UART gesendet werden...
Sorry, aber ich denke nicht, dass das hier zwingend nötig ist. Wie kann denn ein einzelnes unsigned char "halb geschrieben" sein?
Ahh, ich glaube, es ist Zeit fürs Bett. Ich bin von 10bit-Werten ausgegangen, obwohl die Fkt. ja nur 8bit vom ADC verwendet und
1 | unsigned char |
zurückgibt.
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.