Forum: Mikrocontroller und Digitale Elektronik Programmabsturz bei Verwendung des USARTs


von Tobias (Gast)


Angehängte Dateien:

Lesenswert?

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 ;)

von holger (Gast)


Lesenswert?

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.

von holger (Gast)


Lesenswert?

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 ->

von holger (Gast)


Lesenswert?

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;

von Oliver J. (skriptkiddy)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Tobias (Gast)


Lesenswert?

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!

von Tobias (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.