Nabend zusammen,
bei meinem Programm passt etwas nicht bzw. kann ich es nicht ganz
nachvollziehen.
Prozessor ist ein Atmega8. Hier der relevante Programmausschnitt:
1
volatileuint32_tDisplayBuffer[4];
2
volatileint32_tslDifferenz=0;
3
volatileuint32_tulTimeToCompareMatch;
4
5
//Timer1 16-bit Compare Match A Interrupt Service Routine
6
ISR(TIMER1_COMPA_vect){
7
8
DisplayBuffer[1]=OCR1A;
9
DisplayBuffer[2]=TCNT1;
10
DisplayBuffer[3]=ulTimeToCompareMatch;
11
slDifferenz=ulTimeToCompareMatch-OCR1A;
12
13
}
14
15
16
//Timer1 16-bit Overflow Interrupt Service Routine
17
ISR(TIMER1_OVF_vect){
18
19
// Flag setzen für Display aktualisierung ca. jede 1,5 Sekunden
20
overflowzaehler++;
21
if(overflowzaehler>=183){
22
displayaktualisieren=TRUE;
23
overflowzaehler=0;
24
}
25
26
}
27
28
29
intmain(void)
30
31
// hier wird noch das Compare Match stetig vorgeladen
32
{
33
34
signedcharbuffer[12];
35
36
37
init_ports();// Ports initialisieren
38
init_timer1();// Initialisiert den Timer1
39
40
// Display initialisieren
41
LCD_DDR=0xFF;
42
lcd_init();
43
44
/*Hauptschleife des Hauptprogramms*/
45
while(1){
46
47
48
if(displayaktualisieren==TRUE){
49
lcd_clear();
50
51
// Zeile 1
52
lcd_setcursor(0,0);
53
lcd_string("Diff:");
54
// umrechnen in Dezimal
55
ltoa(slDifferenz,buffer,10);
56
// ... ausgeben
57
lcd_string(buffer);
58
59
60
61
// Zeile 2
62
lcd_setcursor(0,1);
63
lcd_string("OCR:");
64
// umrechnen in Dezimal
65
ultoa(DisplayBuffer[1],buffer,10);
66
// ... ausgeben
67
lcd_string(buffer);
68
69
// Zeile 3
70
lcd_setcursor(0,2);
71
lcd_string("Timer:");
72
// umrechnen in Dezimal
73
ultoa(DisplayBuffer[2],buffer,10);
74
// ... ausgeben
75
lcd_string(buffer);
76
77
// Zeile 4
78
lcd_setcursor(0,3);
79
lcd_string("Comp:");
80
// umrechnen in Dezimal
81
ultoa(DisplayBuffer[3],buffer,10);
82
// ... ausgeben
83
lcd_string(buffer);
84
85
displayaktualisieren=FALSE;
86
}
87
88
89
}// Ende main loop
90
}// Ende Hauptprogramm
mit ulTimeToCompareMatch lade ich OCR1A vor und aktivere nach dem
Vorladen den Interrupt entsprechen mit TIMSK |= (1 << OCIE1A);
Direkt am Beginn des Interrupts lese ich folgende Register aus:
OCR1A
TCNT1
sowie meine Variable ulTimeToCompareMatch mit der ich OCR1A vorlade und
speichere Sie in den Array DisplayBuffer.
So nun lasse ich mir die Sachen auf meinem LCD im Hauptprogramm ausgeben
alle 1,5ms (die Compare Match-Zeit wird vom Programm berechnet und
ändert sich stetig).
Allerdings zeigt das Display zwischen OCR1A und ulTimeToCompareMatch
einen unterschiedlichen Wert an, obwohl OCR1A mit dieser Variable
vorgeladen wird, was ja nicht sein sollte.
Daher habe ich in das gleiche Compare Match Interrupt noch folgendes
eingefügt:
1
slDifferenz=ulTimeToCompareMatch-OCR1A;
Den Wert von slDifferenz lasse ich mir ebenfalls auf dem Display
ausgeben. Paradoxerweise ist aber die Differenz IMMER 0.
Daher verstehe ich das nicht, OCR1A und ulTimeToCompareMatch sind laut
Display-Ausgabe verschieden, rechnet das Programm aber die Differenz ist
der Wert 0.
Kann sich das jemand erklären?
Danke!
Sven schrieb:> So nun lasse ich mir die Sachen auf meinem LCD im Hauptprogramm ausgeben> alle 1,5ms (die Compare Match-Zeit wird vom Programm berechnet und> ändert sich stetig).
Da wird es interessant. Was muss man sich darunter vorstellen?
> Allerdings zeigt das Display zwischen OCR1A und ulTimeToCompareMatch> einen unterschiedlichen Wert an, obwohl OCR1A mit dieser Variable> vorgeladen wird, was ja nicht sein sollte.
Kommt drauf an.
Vom Beginn deiner Ausgabe, bis zum Zeitpunkt an dem du dann
ulTimeToCompareMatch aufs Display zauberst vergeht Zeit. In dieser zeit
können ein oder mehrere Compare Match Interrupts dazwischenfunken und
wie du im Programmlauf den OCR Wert veränderst hast du auch nicht
gezeigt.
-> die interessanten Teile fehlen wieder mal.
> Den Wert von slDifferenz lasse ich mir ebenfalls auf dem Display> ausgeben. Paradoxerweise ist aber die Differenz IMMER 0.
Das bedeutet jetzt nur, dass in der ISR alle Werte tatsächlich
zusammenpassen und auch wirklich aus derselben Messung stammen.
Etwas was du in deinem Anzeigecode nicht garantieren kannst.
Als Minimum würde ich mal die komplette Ausgabe unter Interruptsperre
laufen lassen. Und nach der Realisierung, dass das eine teure Operation
ist, am Anfang deines Ausgabecodes
1
if(displayaktualisieren==TRUE){
2
lcd_clear();
erst mal nur die aktuellen Daten unter Interruptsperre in einen 2-ten
Satz Variablen sichern.
1
if(displayaktualisieren==TRUE){
2
cli();
3
UpdateBuffer[0]=DisplayBuffer[0];
4
UpdateBuffer[1]=DisplayBuffer[1];
5
UpdateBuffer[2]=DisplayBuffer[2];
6
sei();
7
8
lcd_clear();
9
...
danach hast du alle Zeit der Welt diese Daten aus den neuen Variablen
heraus auszugeben. Dazwischenfunkende Interrupts können an diesen Kopien
jetzt nichts mehr ändern, während du ausgibst.
Guten morgen Karl Heinz Buchegger ,
erst einmal danke für die Antwort.
Daran habe ich überhaupt nicht gedacht, das bei der Ausgabe auf dem
Display zwischen den 3 Variablen ein Interrupt dazwischen Funken könnte.
Ich war bis dato der Überzeugung, das wenn ich alle 3 Variablen im
Interrupt einlesen, nicht woanders in der die DisplayBuffer-Variable
verändern lasse bis zur Ausgabe, bekomme ich auch die Werte angezeigt.
Im Interrupt-Fall, welches dazwischen funken könnte, wäre dem ja nicht
so. Ich werde heute Abend nach der Arbeit das mal versuchen Interrupt
gesperrt auf dem Display auszugeben gemäß deinem Vorschlag.
Da das Problem wie gesagt absolut sporadisch auftritt, von
schätzungsweise 20 angezeigten Werten stimmt alles überein und beim 21
ist da eine Differenz, könnte es durchaus sein, dass hier ein Interrupt
dazwischen funkt.
Ich berichte heute Abend.
Nochmals danke, selbst wenn es nicht der Fehler sein sollte, habe ich
etwas dazu gelernt..
Grüße
Sven
Hallo nochmal,
ich wollte nur Bescheid geben, dass dies der Fehler war. Habe es so
gemacht, wie du es beschrieben hattest und siehe da, die Zeiten stimmen
überein.
Danke!
Eine eigene Frage?
Dieser Thread ist über 14 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.