Hallo. Ich habe mal eine Frage. Mein Programm hat eine Uhr eingebaut. Diese wird über einen Timer im Sekundentakt inkrementiert. Der Timer ist so eingestellt, dass er jede Sekunde einen Interrupt auslöst. In der Routine wird nur ein Flag gesetzt. Die Zeit wird in der while(1)-Schleife gebildet wenn sich das Flag ändert. Zugegeben ist die Uhr nicht die Genauste, aber für meine Zwecke reicht das. Nun frage ich in regelmäßigen Abständen (alle 2 Sekunden) drei Werte von dem µC über die RS232 mit 9600 Baud ab. Wenn ich nach einem Tag eine Auswertung in Excel mache, dann kann man erkennen, dass irgendwann ein Wert unterschlagen wurde. Meine Vermutung ist, dass der Timerinterrupt dazwischenhaut. Wie mache ich es am geschickteste, dass dieses Problem nicht mehr auftritt?
Praktikant schrieb: > Meine Vermutung ist, dass der Timerinterrupt dazwischenhaut. Wie mache > ich es am geschickteste, dass dieses Problem nicht mehr auftritt? Îndem du die serielle Kommunikation auch über eine ISR laufen läßt und in der ISR nicht "stundenlang" den µC blockierst. > Zugegeben ist die Uhr nicht die Genauste, Und was fehlt ihr? Beitrag "Die genaue Sekunde / RTC"
Mike schrieb: > in der ISR nicht "stundenlang" den µC blockierst ?Versteh ich nicht. Was willst du mir sagen? Mike schrieb: >> Zugegeben ist die Uhr nicht die Genauste, > Und was fehlt ihr? > Beitrag "Die genaue Sekunde / RTC" Den Artikel kenn ich. Für mein Projekt aber nicht von Belang. Welche serielle Kommunikation soll ich in einer ISR ablaufen lassen? Senden, oder Empfangen?
Praktikant schrieb: > Meine Vermutung ist, dass der Timerinterrupt dazwischenhaut. Wie mache > ich es am geschickteste, dass dieses Problem nicht mehr auftritt? Vielleicht. Deswegen beschreib nicht in Prosa, was das Programm machen soll, sondern zeig deinen Quelltext als angehängtes C-File. Sonst kann man nur im Nebel stochern. mfg.
1. Tue dir einen Gefallen und rechne die Uhr in der ISR fertig. Dann musst du nicht im Hauptprogramm oder der Anzeige Routine auch noch an der Uhr rumfummeln. Uhren sind ein simples 60:60:24 Getriebe und in ein paar Zeilen erledigt. 2. Wenn du die USART per Receive Interrupt betreibst, ist sicher gestellt, das sie sofort am Ende eines etwaigen anderen Interrupts behandelt wird. Wenn dein MC im Hauptprogramm rumtrödelt, wird sie sogar sofort gezündet und empfängt sicher das Zeichen. Entweder zeigst du per Flag, das da was neues im Buffer ist, oder du machst den ganzen Stringkram in der ISR. Das hängt davon ab, wie komplex die Auswertung ist.
Entschuldigung für die späte Reaktion, aber mir ist gestern was dazwischen gekommen. Sonst hätte ich mich schon eher gemeldet. Hier der Auszug meines Quelltextes: Die While Schleife:
1 | while(1) |
2 | {
|
3 | |
4 | //Timer 1 Auswertung
|
5 | if(bSekunde==1) //Nur bearbeiten, wenn der Sekunden-Interrupt ausgelöst hat |
6 | {
|
7 | bSekunde=0; //Flag zurücksetzen |
8 | sekunde++; |
9 | |
10 | if(State.bPumpOnOff==1){Laufzeit++;} //Laufzeit der Pumpe in Sekunden hochzählen |
11 | if(State.bTimerDeltaT==1){ZeitDeltaT++;}//Laufzeit der delta T Erfassung in Sekunden hochzählen |
12 | |
13 | if(sekunde == 60) |
14 | {
|
15 | minute++; |
16 | |
17 | if(State.bPumpDelay==1){ZeitPumpDelay++;} //Laufzeit der Pumpe in Minuten hochzählen |
18 | sekunde = 0; |
19 | LCD_String(1,13,itoa(minute,Zeit,10)); |
20 | }
|
21 | if(minute == 60) |
22 | {
|
23 | stunde++; |
24 | minute = 0; |
25 | LCD_String(1,10,itoa(stunde,Zeit,10)); |
26 | LCD_String(1,13," "); |
27 | }
|
28 | if(stunde == 24) |
29 | {
|
30 | stunde = 0; |
31 | LCD_String(1,10," "); |
32 | LCD_String(1,10,"0"); |
33 | }
|
34 | |
35 | Temperature1=DS18B20_Read_Addressed_Temperature(rom1,byte); |
36 | Temperature2=DS18B20_Read_Addressed_Temperature(rom2,byte); |
37 | }
|
38 | |
39 | if(sekunde%2==0) //Alle 2 Sekunden die Temperatur ausgeben |
40 | {
|
41 | LCD_String(3,13,dtostrf(Temperature1,3,1,buf)); |
42 | LCD_String(4,13,dtostrf(Temperature2,3,1,buf)); |
43 | LCD_String(2,13,dtostrf(Temperaturold,3,1,buf)); |
44 | }
|
45 | |
46 | |
47 | if((Temperature1>Temperaturold) && State.bPumpDelay==0) //Nur machen wenn ein neuer Pumpzyklus möglich ist und die Temperatur größer ist als der letzte Wert |
48 | {
|
49 | State.bTimerDeltaT=1; |
50 | }
|
51 | if(Temperature1<=Temperaturold) |
52 | {
|
53 | ZeitDeltaT=0; |
54 | Temperaturold=Temperature1; |
55 | State.bTimerDeltaT=0; |
56 | }
|
57 | |
58 | if(ZeitDeltaT>=10) |
59 | {
|
60 | if(Temperature1>Temperaturold+DELTATEMP) |
61 | {
|
62 | State.bPumpOnOff=1; //Pumpe anschalten |
63 | PumpeAn; |
64 | ZeitDeltaT=0; |
65 | State.bTimerDeltaT=0; |
66 | }
|
67 | }
|
68 | |
69 | if(Laufzeit>=LAUFZEITPUMPE) //Nach Laufzeit Pumpe aus |
70 | {
|
71 | PumpeAus; |
72 | State.bPumpOnOff=0; //Pumpe aus |
73 | Laufzeit=0; |
74 | Temperaturold=Temperature1; |
75 | State.bPumpDelay=1; //Pumpe hat Zyklus beendet und braucht die nächste Zeit nicht gestartet werden. |
76 | }
|
77 | |
78 | if(ZeitPumpDelay==PUMPDELAY){State.bPumpDelay=0;} //Ein neuer Pumpzyklus kann gestartet werden |
79 | |
80 | //RS232 Auswertung
|
81 | if(uart_str_complete == 1) //Nur abarbeiten, wenn etwas empfangen wurde |
82 | {
|
83 | if(0==strcmp(uart_string,"Read Romcode")) //Romcode eines einzelnen Fühlers auslesen |
84 | {
|
85 | DS18B20_Read_RomCode(byte); |
86 | for(i=0;i<8;i++){Send_Byte_UART(byte[i]);} //Rom Code muss Byteweise gesendet werden, da NULL enthalten sein kann |
87 | uart_str_complete=0; //Flag zurücksetzen |
88 | }
|
89 | if(0==strcmp(uart_string,"Messung")) |
90 | {
|
91 | //"<MS1>xx.x<MS2>yy.y<PS>z<EOD>";
|
92 | |
93 | strcpy(strSendBuffer,"<MS1>"); |
94 | strcat(strSendBuffer,dtostrf(Temperature1,3,1,buf)); |
95 | strcat(strSendBuffer,"<MS2>"); |
96 | strcat(strSendBuffer,dtostrf(Temperature2,3,1,buf)); |
97 | strcat(strSendBuffer,"<PS>"); |
98 | strcat(strSendBuffer,"x"); |
99 | strcat(strSendBuffer,"<EOD>"); |
100 | strSendBuffer[22]='0'+State.bPumpOnOff%10; |
101 | Send_String_UART(strSendBuffer); |
102 | uart_str_complete=0; //Flag zurücksetzen |
103 | }
|
104 | else
|
105 | {
|
106 | for(i=0;i<8;i++){strBuffer[i]=uart_string[i];} |
107 | strBuffer[8]='\0'; |
108 | if(0==strcmp(strBuffer,"Set time")) //Setzen der Uhrzeit per RS232. Befehl lautet 'Set time hh:mm:ss' |
109 | {
|
110 | |
111 | Zeit[0]=uart_string[9]; |
112 | Zeit[1]=uart_string[10]; |
113 | Zeit[2]='\0'; |
114 | stunde=atoi(Zeit); |
115 | LCD_String(1,10,Zeit); |
116 | |
117 | Zeit[0]=uart_string[12]; |
118 | Zeit[1]=uart_string[13]; |
119 | Zeit[2]='\0'; |
120 | minute=atoi(Zeit); |
121 | LCD_String(1,13,Zeit); |
122 | |
123 | Zeit[0]=uart_string[15]; |
124 | Zeit[1]=uart_string[16]; |
125 | Zeit[2]='\0'; |
126 | sekunde=atoi(Zeit); |
127 | }
|
128 | uart_str_complete=0; //Flag zurücksetzen |
129 | }
|
130 | }
|
131 | |
132 | }
|
Die Interrupt Routinen
1 | ISR(USART_RXC_vect) |
2 | {
|
3 | |
4 | uint8_t nextChar; |
5 | |
6 | // Daten aus dem Puffer lesen
|
7 | nextChar = UDR; |
8 | if( uart_str_complete == 0 ) { // wenn uart_string gerade in Verwendung, neues Zeichen verwerfen |
9 | |
10 | // Daten werden erst in uart_string geschrieben, wenn nicht String-Ende/max Zeichenlänge erreicht ist/string gerade verarbeitet wird
|
11 | if( nextChar != '\n' )//|| nextChar != '\r' || uart_str_count < 10 ) |
12 | {
|
13 | uart_string[uart_str_count] = nextChar; |
14 | uart_str_count++; |
15 | }
|
16 | else
|
17 | {
|
18 | uart_string[uart_str_count] = '\0'; |
19 | uart_str_count = 0; |
20 | uart_str_complete = 1; |
21 | }
|
22 | }
|
23 | |
24 | }
|
25 | |
26 | |
27 | |
28 | ISR (TIMER1_COMPA_vect) |
29 | {
|
30 | bSekunde=1; |
31 | }
|
Du solltest dir einen Uhrzeit-String zusammenbasteln und den am Ende der Auswertung an das LCD schicken. Die Kommunikation mit der Anzeige bremst das ganze Programm aus.
@STK500.-Besitzer Versteh ich nicht. Die Uhrzeit wird nur jede Minute und jede Stunde aktualisiert. Womit ich ein Problem habe ist scheinbar dieser Teil:
1 | if(0==strcmp(uart_string,"Messung")) |
2 | {
|
3 | //"<MS1>xx.x<MS2>yy.y<PS>z<EOD>";
|
4 | |
5 | strcpy(strSendBuffer,"<MS1>"); |
6 | strcat(strSendBuffer,dtostrf(Temperature1,3,1,buf)); |
7 | strcat(strSendBuffer,"<MS2>"); |
8 | strcat(strSendBuffer,dtostrf(Temperature2,3,1,buf)); |
9 | strcat(strSendBuffer,"<PS>"); |
10 | strcat(strSendBuffer,"x"); |
11 | strcat(strSendBuffer,"<EOD>"); |
12 | strSendBuffer[22]='0'+State.bPumpOnOff%10; |
13 | Send_String_UART(strSendBuffer); |
14 | uart_str_complete=0; //Flag zurücksetzen |
15 | }
|
Wenn hier der Timerinterrupt dazwischenhaut, dann habe ich den Murks. Ich könnte auch die Interrupts vorm Senden deaktivieren und danach wieder aktivieren. Aber mache ich mir damit die Uhr nicht noch ungenauer?
>Wenn hier der Timerinterrupt dazwischenhaut, dann habe ich den Murks.
Wie sieht dieser Murks aus?
Welchen Controller verwendest du?
Praktikant schrieb: > Versteh ich nicht. Die Uhrzeit wird nur jede Minute und jede Stunde > aktualisiert. Was macht denn die Funktion "LCDString"?
Paule H. schrieb: > Was macht denn die Funktion "LCDString"? Sie schreibt an LCDString(Zeile,Spalte,String). Aber das tut sie NUR wenn eine neue Minute berechnet wurde, bzw. NUR wenn eine neue Stunde berechnet wurde. Oder anders formuliert: NUR einmal pro Minute wird die Uhrzeit aktualisiert. holger schrieb: > Wie sieht dieser Murks aus? Ich übertrage folgenden String: <MS1>xx.x<MS2>yy.y<PS>z<EOD> (Wobei x, y und z durch Werte ersetz werden) Auf meinem PC kommt dann irgendwann folgendes an EOD><MS1>xx.x<MS2>yy.y<PS>z< Die Software die diesen String auswertet verschluckt sich daran. Ich verwende einen Atmega 8 mit 4 Mhz Quarzoszillator. Ich weiss, dass ein "Baudratenquarz" besser wäre. Ist aber nicht vorhanden
Prakitkant schrieb: > Oder anders formuliert: > NUR einmal pro Minute wird die Uhrzeit aktualisiert. und wie lange braucht sie dafür? Selbst wenn nur alle paar Stunden die Anzeige auf diese Art aktualisiert wird, braucht es eine gewisse Zeit, bis das Prozedere abgearbeitet wurde. Da kann es schon sein, dass ein, zwei oder (Uhren-)Interrupts "verloren" gehen. Kannst du mal bitte das ganze Programm als Anhang hier posten. Programme in Prosa geschrieben, sind viel länger als Quellcode...
>Auf meinem PC kommt dann irgendwann folgendes an > >EOD><MS1>xx.x<MS2>yy.y<PS>z< > >Die Software die diesen String auswertet verschluckt sich daran. Woher weisst du das nicht deine PC Software diesen Murks baut? Vieleicht ist der Atmega ja diesmal unschuldig;)
holger schrieb: > Woher weisst du das nicht deine PC Software diesen Murks baut? Weil dann zusätzlich in meinem Display totaler Müll steht. Nebenbei. Wenn mein String so aussieht "EOD><MS1>xx.x<MS2>yy.y<PS>z<" dann sieht man schon, dass noch Reste "EOD>" vom alten String übermittelt wurden und an den neuen String angehängt wurde. So als ob die vorherige Übertragung durch den Timerinterrupt unterbrochen wurde. Paule H. schrieb: > Selbst wenn nur alle paar Stunden die Anzeige auf diese Art aktualisiert > wird, braucht es eine gewisse Zeit, bis das Prozedere abgearbeitet > wurde. Versteh ich wieder nicht. Zu irgendeiner Zeit muss ich doch die Uhrzeit ausgeben. Mit meiner Methode tausche ich pro Minute nur die Minuten bzw. Stunden aus. Das ist weniger Aufwand als den kompletten Zeitstring auszugeben.
>> Woher weisst du das nicht deine PC Software diesen Murks baut? > >Weil dann zusätzlich in meinem Display totaler Müll steht. DAS wäre noch mal ne wichtige Zusatzinformation gewesen. >So als ob die vorherige Übertragung durch den >Timerinterrupt unterbrochen wurde. Das dauert nicht lange genug um die Übertragung wirklich zu unterbrechen. Hier ist eine undichte Stelle in deinem Programm: if( nextChar != '\n' )//|| nextChar != '\r' || uart_str_count < 10 ) das kann zu Bufferoverflow führen falls mal kein \n auftaucht. Dabei steht die Lösung schon daneben. Ts, ts. Was ist das für eine Pumpe die du da schaltest? Das könnte auch der Übeltäter sein wenn die Schalterei nicht richtig entstört ist. Das würde auch den Müll im Display erklären.
holger schrieb: > DAS wäre noch mal ne wichtige Zusatzinformation gewesen. Tschuldigung. holger schrieb: > Was ist das für eine Pumpe die du da schaltest? Im Moment noch Keine. Meine Pumpe ist zur Zeit nur eine LED. holger schrieb: > das kann zu Bufferoverflow führen falls mal kein \n auftaucht. > Dabei steht die Lösung schon daneben. Ts, ts. Sehe ich ein. Allerdings überträgt mein Programm ein \n. Die Lösung die daneben steht habe ich auch schon probiert (Deswegen steht es noch daneben). Allerdings besteht auch hier das Problem. Kurioserweise läuft mein Programm heute schon seit 8h 30 min, ohne Murks im Display. Jedoch auch ohne PC, der ständig die Werte abfragt. Hmmm. Liegt wohl doch irgendwie an der seriellen Übertragung
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.