Hallo, ich verzweifle seit einem Tag an einem Problem mit meinem Mega16. Ich habe ein simples Protokoll implementiert und alle Befehle funktionieren; mit der Kommunikation uC <-> PC gibts keine Porbleme. Ich habe den Eindruck, dass das Hauptprogramm nicht normal lauft, Es werden offensichtlich Befehle ausgefuehrt, die nicht in der Endlosschleife sind... Ich denke nicht, dass es ungewuenschte "eigenstaendige resets" gibt, da ich einen MAX705 Ueberwacher habe und bislang alles einwandfrei funktioniert hat. Hier das Hauptprogramm: int main(void) { /*= Initialisation ========*/ // Initialising port settings DDRC = 0x00; DDRC |= 0xBB; DDRB = 0xFF; //used for tracing PORTB = 0x00; //setting signals. PORTC |= (1<<CSn1); PORTC |= (1<<CLK1); PORTC &= ~(1<<MODE1); //Initialising UART: setting baudrate and enabling TXD,RXD UBRRH=(uint8_t)(UART_BAUD_CALC(UART_BAUD_RATE,F_CPU)>>8); UBRRL=(uint8_t)UART_BAUD_CALC(UART_BAUD_RATE,F_CPU); UCSRB |= (1<<RXEN) | (1<<TXEN); UCSRB |= (1<<TXCIE)| (1<<RXCIE); //Enabling the INTERRUPT0 GICR |= (1<<INT0); MCUCR |= (1<<ISC11); MCUCR &= ~(1<<ISC10); get_AS_data(); //dies ist eine funktion die Daten aus einem Sensor ausliest (das tut sie auch ganz gut) position_zero = 1008; //volatile uint16_t variable bytecountSen = 0; sendComplete = 1; request = 0; sei(); //enabling interrupts globally /* ==== main loop ==== */ while(1) { SREG &= ~(1<<SREG_I); get_AS_data(); //nicht unterbrechen SREG |= (1<<SREG_I); if (sendComplete && request) { generate_command(); // generate the protocol string bytecountSen = 0; sendComplete = 0; UCSRB |= (1<<UDRIE); //generate UDRE-Interrupt request=0; }//if } //while(1) } So also die Struktur des main Programms. In der Funktion generate_command() veraendere ich die Variable position_zero, die dann im Protokoll uebertragen wird. Die funktioniert auch richtig; wenn ich allerdings diese Variable uebers Protokoll schicken lasse, ohne sie in dieser Funktion veraendert zu haben hat sie immer den Wert 1008 aus der Initialisierung!!! Wie ist das moeglich?!? einmal in der while(1) Schleife kann man doch unmoeglich wider in die Initialisierung?!?! Es sieht mir nach Reset aus, allerdings ist elektrisch alles total stabil, ich hab den MAX705 drin, auf meinem FLUKE Multimeter ist keine Bewegung der reset-Spannungen zu entdecken... Wie kann man ein reset anzeigen oder speichern? Oszi hab ich leider keines... Hat jemand schonmal aehnliche Probleme gehabt? Bin dankbar fuer jeden Tip!! macht's gut, Johannes
Hi, kontrollier Deine Interruptfunktionen. Wenn da was nicht stimmt, kann der Stack durcheinandergeraten und es gibt einen Software-Reset. Erzeuge Dir einen lo/high/lo -Wechsel an einem freien Port direkt nachdem main() startet. Überwach den Pin mit dem Oszi und Du kannst zumindest rausfinden, ob es wirklich einen Reset gab. Ist nur so eine Idee... Ciao Thomas.
Kann es sein, daß deine Funktion generate_command() in einem include-file steht? Gruß, Magnetus
Hi Thomas, Oszi hab ich leider keines... Hi Magnus, generate_command() hab ich selber geschrieben. Im gleichen c file oberhalb von main(). Ich hab jetzt ins EEPROM eine Variable geschrieben, die mit 0 initialisiert wird beim Flashen des uC. Ich lese sie in der initialisierung aus und inkrementier sie. Es geschieht folgendes: jedesmal wenn ich einen Befehl schicke ('a', 'b' usw) lasse ich mir diese Variable im Protokoll anzeigen. Sie wird bei jedem Sende-Empfang Vorgang um 1 incrementiert. Es muss an meinen Funktionen liegen, ich komm aber beim besten willen nicht drauf, wie es zu einem Reset kommen kann... hier meine ISRs zum Senden und Empfangen: SIGNAL(SIG_UART_DATA) //ISR for transmitting via serial Interface { if (bytecountSen >= PLENGTH) { bytecountSen=0; UCSRB &= ~(1<<UDRIE); // UDRE-Interrupt wieder sperren sendComplete = 1; } else { UDR = cmd[bytecountSen++]; // Daten senden } } SIGNAL(SIG_UART_RECV) // ISR for receiving a sign via serial Interface { switch (UDR) { case 'a': request = 'a'; break; case 'b': request = 'b'; break; case 'c': request = 'c'; break; case 'd': request = 'd'; break; case 'e': request = 'e'; break; case 'i': request = 'i'; break; default : request = 0; break; } } Wie kann es hier passieren, dass es zu einem Reset kommt?!?!? mg, Johannes
Wurden "bytecountSen" und "sendComplete" als volatile deklariert?
Variablendeklaration: volatile uint16_t position,position_zero; volatile uint8_t flags, request; volatile uint8_t cmd[PLENGTH],bytecountSen,sendComplete; volatile uint8_t reset EEMEM = 123; volatile uint8_t myByte; alles was veraendert in verschiedenen Funktionen veraendert wird ist als volatile gleich nach den #defines deklariert. Johannes
Bist Du dir sicher, daß dein µC resetet? Zur Kontrolle könntest Du direkt vor der while(1) Schleife ein definiertes Zeichen senden, welches sonst nirgends im Protokoll vorkommt. Wenn der µC wirklich resetet müsstest Du das am PC feststellen können (weil dann ja immer das "böse" Zeichen kommt) Gruß, Magnetus
tja, so eine einfache idee, ich hatte sie sogar schonmal verwendet, aber in meiner verzweiflung bin ich heut nicht drauf gekommen... der uC resettet tatsaechlich, und zwar hab ich den eindruck, dass er immer dann resettet wenn ich UDRIE zu Null setz, sprich jeweils nach der Uebertragung des letzten bytes des Protokolls... Vor diesem Test hat er offensichtlich nach jedem uebertragenen Protokoll (7byte) resettiert. Jetzt resettiert er nachdem er uebertragen hat und kommt wieder beim uebertragen an... und kommt dadurchgar nicht zur Endlosschleife... nach diesem Befehl oder eben am Ende meiner SIG_UART_DATA ISR wird resettiert: UCSRB &= ~(1<<UDRIE); // UDRE-Interrupt wieder sperren Der Reset kommt also nicht ueber die Hardware (haette mich auch sehr gewundert). Aber woher kommt er nun?!? wo in der Software kann sowas passieren. @ Magnetus: danke schonmal fuer das Gluehbirnchen. Immerhin bin ich jetzt einen Schritt voran gekommen. mg, Johannes
Schau dir mal das Register MCUCSR an. Da stehen eine Reihe von Flags drin, die nach einem Reset benutzt werden können, um die Reset-Quelle zu lokalisieren. Wenn Du die am Anfang abfragst und dann löschst, kannst Du den Fehler vielleicht eingrenzen.
Hallo, Abschnitt aus dem Mega16 Datenblatt (Seite 42): "13 $018 USART, UDRE USART Data Register Empty" Der Vector nummer 13 ist also der USART DataRegisterEmpty vector Abschnitt aus iom16.h " /* USART Data Register Empty */ #define USART_UDRE_vect _VECTOR(12) #define SIG_USART_DATA _VECTOR(12) #define SIG_UART_DATA _VECTOR(12) " ?!?!?! ich probier mal ob es daran liegt, das kommt mir aber sehr komisch vor... mg, Johannes
Hallo, hab folgendes probiert: if(MCUCSR & (1<<EXTRF)) PORTB |=0x01; Anstelle von EXTRF(external reset flag) hab ich auch WDRF(watchdog reset flag) probiert. Leuchten tut meine LED nur bei EXTRF... Also kommt von Extern irgendwoher ein reset?!?!? Ob mein MAX705 in der Schaltung drin ist oder nicht spielt dabei keine Rolle, die LED leuchtet unabhaengig davon auf. :((( Ich hab die Versorgungsspannung mit dem Resetpin probeweise verbunden. Die external reset flag LED leuchtet immer noch auf ?!?!? grrrrrrrrrrrrrrrrrr mein Gemuetszustand faellt in immer tiefere Abgruende.... mg, Johannes
Hallo Leute, ich hab eine Variante gefunden um das Problem einfach zu umgehen. Ich hab die ISR zum senden einfach geaendert. Anstatt SIGNAL(SIG_UART_UDRE) verwende ich SIGNAL(SIG_UART_TRANS). Das ergibt eine kleine Aenderung im Programmcode und die ISR abarbeitung ist anders, da nach jedem gesendeten Zeichen noch in der Sende-ISR das Interruptflag fuer das naechste Zeichen gesendet wird, bis man beim letzten Zeichen ankommt... Das isr ISR technisch nicht die schoenste Loesung, ich weis. Aber es funktioniert. Hier noch einmal die ISR die nach dem Senden des letzten Zeichens ein Interrupt erzeugt, das der uC ATMega16 mir als EXTRF (external reset flag) anzeigt. SIGNAL(SIG_UART_DATA) //ISR for transmitting via serial Interface { if (bytecountSen >= PLENGTH) //PLENGTH = Protocol length { bytecountSen=0; UCSRB &= ~(1<<UDRIE); // UDRE-Interrupt wieder sperren sendComplete = 1; } else { UDR = cmd[bytecountSen++]; // Daten senden } } Mit all meinen uC-Kuensten und euren Tips bin ich recht eindeutig zu dieser Erkenntnis gekommen. Trotzdem scheint sie mir recht zweifelhaft, weil ich in ihr keine Logik erkennen kann. Wieso wird in dieser Sende-ISR ein "externer Interrupt" erzeugt?!?!?!? Falls jemand versteht wie es evtl dazu kommen koennte bitte ich auch um Benachrichtigung. mg, Johannes
Hallo Johannes, die ganze Interrupt-an-und-abschalterei ist m.E. nicht notwendig, wenn Du: - einen Pufferspeicher für zu sendende Bytes einrichtest und getrennte Schreib und Lesezeiger für den Zugriff benutzt - eine Funktion putchar(unsigned char c) nutzt, um das Byte in UDR zu schreiben, falls UDRE gesetzt ist, anderenfalls in den Puffer mit Erhöhung des entsprechenden Schreibzeigers - eine Interrupt-Routine SIGNAL (SIG_UART_TRANS) verwendest, die immer dann automatisch aufgerufen wird, wenn ein byte den AVR "verlassen" hat. Die Funktion muss schauen, ob noch ein weiteres Byte vom Puffer nach UDR zu kopieren ist. Anderenfalls tut sie einfach nichts. Das Prinzip funzt in meinen Projekten sehr gut. Ciao ThomasB
Hallo Johannes, ich habe mich heute auf dem Arbeitsweg etwas intensiver mit dem Fehler beschäftigt (die Geschichte hat mir einfach keine Ruhe gelassen) und bin nach vielen (eigentlich unnötigen) Simulationen auf die Fehlerursache gestossen. Ich zitiere an dieser Stelle einmal deine UART-Initialisierung: <c> //Initialising UART: setting baudrate and enabling TXD,RXD UBRRH=(uint8_t)(UART_BAUD_CALC(UART_BAUD_RATE,F_CPU)>>8); UBRRL=(uint8_t)UART_BAUD_CALC(UART_BAUD_RATE,F_CPU); UCSRB |= (1<<RXEN) | (1<<TXEN); UCSRB |= (1<<TXCIE)| (1<<RXCIE); </c> Der Fehler versteckt sich in der Zeile <c> UCSRB |= (1<<TXCIE)| (1<<RXCIE); </c> Du gibst zusätzlich zum RX-Complete-Interrupt auch den TX-Complete-Interrupt frei, ohne für diesen einen Interrupthandler bereit zu stellen. Wenn der TXC-Interrupt auftritt (und dies ist am Ende des Datenpakets der Fall) springt der Controller in einen "Catch-all Interrupthandler", welcher netterweise den Resetvektor aufruft. Auszug aus "avr_libc_user_manual.pdf": "Catch-all interrupt vector: If an unexpected interrupt occurs (interrupt is enabled and no handler is installed, which usually indicates a bug), then the default action is to reset the device by jumping to the reset vector" Wenn Du also <c> UCSRB |= (1<<TXCIE)| (1<<RXCIE); </c> durch <c> UCSRB |= (1<<RXCIE); </c> ersetzt, dürfte das Problem beseitigt sein. Gruß, Magnetus
Hmmm.... das mit dem Syntax-Highlighting hat wohl nicht richtig funktioniert... deswegen jetzt nochmal (hoffentlich mit richtigem Syntax-Highlighting): Hallo Johannes, ich habe mich heute auf dem Arbeitsweg etwas intensiver mit dem Fehler beschäftigt (die Geschichte hat mir einfach keine Ruhe gelassen) und bin nach vielen (eigentlich unnötigen) Simulationen auf die Fehlerursache gestossen. Ich zitiere an dieser Stelle einmal deine UART-Initialisierung:
1 | //Initialising UART: setting baudrate and enabling TXD,RXD
|
2 | UBRRH=(uint8_t)(UART_BAUD_CALC(UART_BAUD_RATE,F_CPU)>>8); |
3 | UBRRL=(uint8_t)UART_BAUD_CALC(UART_BAUD_RATE,F_CPU); |
4 | |
5 | UCSRB |= (1<<RXEN) | (1<<TXEN); |
6 | UCSRB |= (1<<TXCIE)| (1<<RXCIE); |
Der Fehler versteckt sich in der Zeile
1 | UCSRB |= (1<<TXCIE)| (1<<RXCIE); |
Du gibst zusätzlich zum RX-Complete-Interrupt auch den TX-Complete-Interrupt frei, ohne für diesen einen Interrupthandler bereit zu stellen. Wenn der TXC-Interrupt auftritt (und dies ist am Ende des Datenpakets der Fall) springt der Controller in einen "Catch-all Interrupthandler", welcher netterweise den Resetvektor aufruft. Auszug aus "avr_libc_user_manual.pdf": "Catch-all interrupt vector: If an unexpected interrupt occurs (interrupt is enabled and no handler is installed, which usually indicates a bug), then the default action is to reset the device by jumping to the reset vector" Wenn Du also
1 | UCSRB |= (1<<TXCIE)| (1<<RXCIE); |
durch
1 | UCSRB |= (1<<RXCIE); |
ersetzt, dürfte das Problem beseitigt sein. Gruß, Magnetus
Hallo Thomas und Magnetus! vielen Dank fuer eure Tips und Erklaerungen... die Erklaerung von Magnetus klingt plausibel. Vielen Dank fuer die Aufklaerung. Ich werd sie mir fett hinter die Ohren schreiben. Ich hab letzte Nacht tatsaechlich schlechter geschlafen :) weil ich den Fehler bis zuletzt nicht verstanden hatte. mg, Johannes
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.