Ich versuche gerade, mehrere Atmel-Mikrocontroller über einen RS485 miteinander "reden" zu lassen. Jeder µC soll dabei die Daten (Zustände der LEDs an einem Port, Zustände der Taster am anderen Port) von jedem anderen µC haben. Lasse ich einen µC alleine mit diesem Programm laufen und schließe ihn nur mit einem RS485<->USB-Adapter am PC an, dann kann ich am PC im Terminal schön die Pakete verfolgen, die der µC verschickt. Verkabel ich mehrere miteinander (derzeit 3 zum Testen), läuft das ganze für eine Weile auch ganz gut. Aber dann hängen sich die Controller nach und nach auf. Manchmal nur einer, oft zwei, manchmal alle drei. Manchmal nacheinander, manchmal gleichzeitig. Manchmal nach 0,5 Sekunden, manchmal nach 10 Sekunden. Aber früher oder später immer. Manchmal verschicken sie bis zum Komplettabstutz noch "falsche" Pakete, irgendwann senden sie einfach gar nichts mehr und die LEDs am Ausgang gehen aus. Da ich das Problem irgendwie nicht wirklich eingrenzen kann, hänge ich mal den kompletten Quellcode an. Derzeit werden ATmega8 auf 8MHz verwendet (testweise auch mal auf 16MHz). Baudrate auf dem Bus ist 19.200 Baud. Es werden MAX481 verwendet für die Umwandlung. Kann man am Quelltext so erkennen, warum mein µC sich aufhängt? Oder woran könnte man es sonst sehen? Könnte auch mit einem Oszilloskop messen - wenn ich denn wüsste, was ich messen kann ;)
In deinem Programm stinkt es quasi nach Pufferüberlauf.
1 | typedef struct |
2 | {
|
3 | unsigned char puffer[10]; //Speichern von 10 Zeichen möglich |
4 | |
5 | |
6 | ISR (USART_UDRE_vect) |
7 | //Interrupt USART Puffer frei zum Senden
|
8 | {
|
9 | unsigned char tmpstelle; |
10 | tmpstelle=sendepuffer_ascii.stelle; |
11 | UDR=sendepuffer_ascii.puffer[tmpstelle]; //Daten senden |
12 | if (tmpstelle==9) //wenn Interrupt aufgerufen und letztes Zeichen: |
13 | {
|
14 | UCSRB &= ~(1<<UDRIE); //Interrupt bei freiem Sendepuffer deaktivieren |
15 | UCSRB |= 1<<TXCIE; //Inerrupt bei abgeschlossener Sendung aktivieren |
16 | }
|
17 | tmpstelle++; |
18 | sendepuffer_ascii.stelle=tmpstelle; |
19 | }
|
Wie stellst du sicher das tmpstelle oder sendepuffer_ascii.stelle niemals über 9 kommen? Selbst wenn tempstelle == 9 ist zählst du da fleissig noch mal hoch. Beim nächsten schreiben ins Array knallt es dann wenn sendepuffer_ascii.stelle nicht unter 9 gesetzt wird. An solchen Stellen sollte man erst einmal auf die maximale Puffergrösse checken bevor etwas ins Array geschrieben wird.
Oder besser hier. Oben wird ja nichts ins Array geschrieben. Dort führt es nur zum senden von Müll.
1 | tmppuffer[stelle]=temp; //Aktuell empfangenes Zeichen in den Puffer für das ganze Paket schreiben |
2 | stelle++; //Aktuelle Stelle um eins erhöhen |
3 | if ((stelle==10) && (tmppuffer[0]==SOT) && (tmppuffer[9]==EOT)) //Puffer ist voll und hat einen gültigen Start und ein gültiges Ende -> Zur Bearbeitung freigeben |
4 | {
|
5 | if (empfangspuffer_ascii.fertig==0) //nur übergeben, wenn dort Platz ist, ansonsten verwerfen |
6 | {
|
7 | for (stelle=0; stelle<10; stelle++) empfangspuffer_ascii.puffer[stelle]=tmppuffer[stelle]; |
8 | empfangspuffer_ascii.fertig=1; //Zum Abarbeiten markieren |
9 | }
|
10 | busstatus=0; //Paket scheint vollständig, Bus erst einmal als frei markieren |
11 | }
|
12 | else if (stelle==10) stelle=0; //Puffer voll aber Paket war ungültig -> Zurück an den Start des Puffers |
Du solltest das letzte else da weglassen. if (stelle==10) stelle=0; //Puffer voll aber Paket war ungültig ->
Und es kommt noch besser;)
1 | ISR (USART_RXC_vect) |
2 | //Interrupt USART Zeichen empfangen
|
3 | {
|
4 | unsigned char temp; |
5 | static unsigned char tmppuffer[10], stelle; |
stelle ist lokal und static, bekommt aber keinen Startwert. Da kann es schon beim ersten schreiben ins Array irgendwas im RAM überschreiben. static unsigned char tmppuffer[10], stelle = 0;
holger schrieb: > stelle ist lokal und static, bekommt aber keinen Startwert. Wird eine Variable denn nicht .bss zugeordnet, wenn sie local und static ist und keinen Startwert hat? Gruß Oliver
holger schrieb: > stelle ist lokal und static, bekommt aber keinen Startwert. Stimmt nicht ganz. lokale static Variablen werden wie globale automatisch mit 0 initialisiert. Aber ansonsten: Respekt, dass du dir den Code vornimmst. Mir ist der zu unübersichtlich. Den müsste ich erst mal 1/2 Stunde umformatieren und dazu hab ich keine Lust.
Hallo holger. Danke für deine Mühe! Also zum ersten Beitrag: Du hast ja schon gesagt, da wird nichts geschrieben. Es könnte nur Müll gesendet werden. Wird aber nicht, da tmpstelle ja den Wert aus empfangspuffer_ascii.stelle übernimmt. Und der wird immer beim Füllen des Puffers mit 0 beschrieben. Erst nach dem Füllen des Puffers wird dann das Senden durch aktivieren des Interrupts aktiviert. Wenn er dann den Wert 9 erreicht, wird er zwar noch einmal erhöht, aber der Interrupt gleichzeitig schon deaktiviert. Bevor also der Puffer neu beschrieben wird, der Zähler daher den Wert 0 bekommt, wird diese Interruptroutine gar nicht wieder aufgerufen, denke ich. Zumindest werden die Daten immer korrekt gesendet, es kommt nie was nicht-ascii-hex-codiertes an. Dann müsste das doch so eigentlich funktionieren, oder? Ich könnte natürlich
1 | if (tmpstelle==9) |
in
1 | if (tmpstelle>=9) |
ändern, aber ändert das was am Ablauf? Dann zum dritten Beitrag: Stimmt, die sollte besser einen Startwert bekommen. Dann müsste das ganze aber ja beim ersten Empfang eines Pakets Probleme machen. Weil entweder sie hat gleich Müll in sich oder sie wird erhöht bis sie 10 wird und hat ab dann definierte Werte. Dann müsste das ganze aber spätestens nach ca. 0,5 Sekunden abstürzen, denn länger kann es nie dauern, bis ein Paket eingeht. In den meisten Fällen dauert es aber länger bis zum Absturz. Sollte also auch nicht der Grund sein. Hier wurde ja auch schon gesagt, dass sie automatisch mit 0 initialisiert werden müsste. Dann Beitrag zwei: Wollte gerade begründen, warum das auch immer funktionieren müsste - aber korrekt, da kann es wirklich zum Überlauf kommen! Ein Entfernen des else müsste helfen! Das probiere ich morgen in der Firma mal aus! (Bin Praktikant und das ist gerade meine Praktikanten-Bastelei). @Karl Heinz Buchegger: Ich versuche immer, meinen Code so leserlich wie möglich zu halten. Wenn man nur alle paar Jahre mal ein paar Zeilen schreibt (und das meine ich ohne Übertreibung!), fällt einem das nicht immer leicht... Was könnte man an der Lesbarkeit denn besser machen in deinen Augen? Ich bin da immer offen für Tips!
Moin Holger: DANKE!!11einseinself Das wars, es läuft :)
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.