Forum: Compiler & IDEs UART-AtmegaAbsturz


von Richi (Gast)


Lesenswert?

Hallo

ich habe folgendes Problem:

Mein Atmega32 bekommt über UART zu unbestimmten Zeiten je 5 Bytes 
geschickt (Hintereinander). Ich nehme dafür den RXC-Interupt nehmen, in 
dem die 5 Bytes in ein Array geschrieben werden. Sobald das 5. empfangen 
empfangen wird, wird der Interupt ausgeschalten und ein Flag gesetzt.

Wenn ich nun aber mit dem PC einen großen Datenfluss sende, dürften 
eigentlich nur die ersten 5 Byte empfangen und dann über das 
Hauptprogramm auf dem LCD angezeigt werden.

Doch während des Sendens resetet sich der Atmega dauernd (sehe ich an 
einem Counter auf dem Display) bis dieser schließlich ganz den Geist auf 
gibt und nicht mehr reagiert.

Wo könnte der Fehler liegen???


Viele Grüße
Richi

von Thomas (Gast)


Lesenswert?

In Zeile 42 liegt die Lösung all Deiner und unserer Probleme...

Anmerkung:
Ohne Quelltext artet das hier in einer wilden Raterei aus.

von Richi (Gast)


Lesenswert?

Sorry, das ich das vergessen habe.

Kleine Anmerkung:
Wenn die 5 Bytes nicht annähernd hintereinander kommen, werden sie nicht 
akzeptiert. (Siehe Code).

Die LCD-Funktionen habe ich nicht mit aufgeführt, sollten aber klar 
sein.

Hoffe das Hilft (auch wenns ein bisschen viel ist)

Viele Grüße
Richi


Atmega32 mit 16MHz

1
#include "SLEEP.h"
2
#include "LCD.h"
3
#include "USART.h"
4
5
int main(void)
6
{
7
  Sleep_Init();
8
  LCD_Init(LCD_ON);
9
  Usart_Init();
10
11
  UART_Enable();
12
13
  sei();
14
15
  while(1)
16
  {
17
    Counter_Print();
18
19
    while(UART_neu)
20
    {
21
      LCD_Clear();
22
      LCD_Puts("5 Bytes:");
23
      LCD_Gotoxy(0,1);
24
      Sleep(250);
25
      for(unsigned char i = 0; i<5; i++)
26
      {
27
        LCD_Putc(Stelle(UART[i],3)+48);
28
        LCD_Putc(Stelle(UART[i],2)+48);
29
        LCD_Putc(Stelle(UART[i],1)+48);
30
      }
31
32
      Sleep(500);
33
34
      LCD_Clear();
35
36
      UART_neu = 0;
37
    }
38
39
    Sleep(20);
40
  }
41
42
  return 0;
43
}

Headers:
1
#ifndef USART_H
2
#define USART_H
3
4
#include <avr/io.h>
5
#include <avr/interrupt.h>
6
7
volatile unsigned char UART[5], UART_counter, UART_Clock, UART_neu;
8
9
#define UART_Disable() UCSRB = 0x00;
10
#define UART_Enable()  UCSRB = 0x90;
11
12
void Usart_Init(void);
13
14
void Usart_Write(unsigned char Byte);
15
16
unsigned char Usart_Read(void);
17
18
#endif
19
20
21
#ifndef SLEEP_H
22
#define SLEEP_H
23
24
#include <avr/io.h>
25
#include <avr/interrupt.h>
26
27
#include "USART.h"
28
29
volatile unsigned long count250Hz;
30
31
#define nop()  __asm__ __volatile__ ("nop" ::)
32
33
void Sleep_Init(void);
34
35
void Sleep(unsigned long time250Hz);
36
37
void Delay(void);
38
39
#endif

C-Sources:
1
#include "USART.h"
2
3
void Usart_Init(void)
4
{
5
  DDRD &= ~(1<<0);
6
  PORTD |= (1<<0);
7
8
  UCSRA = 0x00;
9
  UCSRB = 0x00;  
10
  UCSRC = 0x86;
11
  UBRRL = 103;
12
  UBRRH = 0;
13
14
  UART_neu = 0;
15
}
16
17
ISR(USART_RXC_vect)
18
{
19
  if(UART_Clock == 10)
20
  {
21
    UART_counter = 0;
22
  }
23
24
  UART_Clock = 0;
25
26
  UART[UART_counter] = UDR;
27
28
  UART_counter ++;
29
30
  if(UART_counter == 5)
31
  {
32
    UART_Disable();
33
34
    UART_counter = 0;
35
    UART_neu = 1;
36
  }
37
}
38
39
40
41
42
#include "SLEEP.h"
43
44
ISR(TIMER0_COMP_vect)
45
{
46
  count250Hz ++;
47
  
48
  if( UART_Clock < 10 )
49
  {
50
    UART_Clock ++;
51
  }
52
}
53
54
55
void Sleep_Init(void)
56
{
57
  TCCR0 = (1 << WGM01) | (1 << CS02);
58
  OCR0  = 249;
59
  TIMSK |= (1 << OCIE0);
60
}
61
62
void Sleep(unsigned long time250Hz)
63
{
64
  count250Hz = 0;
65
  while(count250Hz < time250Hz);
66
}
67
68
void Delay(void)
69
{
70
  for(unsigned char i=0;i<2;i++)
71
  {
72
    nop();
73
  }
74
}

von Oliver (Gast)


Lesenswert?

Ein "andauerndes resetten" kommt in 99% aller Fälle durch einen 
Interrupt, für den keine ISR vorhanden ist.

Da deine Interrupt-Freigaben aber etwas kryptisch sind, musst du dein 
Programm schon selber auf dieses Problem hin untersuchen.

Oliver

von Karl H. (kbuchegg)


Lesenswert?

Schmeiss mal den ganzen Sleep-Krempel raus.
Ein Programm, welches die halbe Zeit nur einen Sleep macht, will man 
sowieso nicht haben und erhöht erst mal die Übersicht durch weniger 
Code.

Für den Reset ist so erst mal keine Ursache direkt erkennbar. Bist du 
sicher, dass ein Reset erfolgt?
Am Anfang Led ein, _delay_ms(500) und Led aus. Wenn die Led die ganze 
Zeit ruhig bleibt, dann sind es keine Resets, sondern irgendwas bügelt 
über deinen Counter drüber.

von Karl H. (kbuchegg)


Lesenswert?

Nimm hier

volatile unsigned char UART[5], UART_counter, UART_Clock, UART_neu;

die Variable UART_counter aus dem Header File raus. Dieser Counter geht 
ausser der ISR niemanden etwas an.

Stattdessen wandert die ins C-File
1
#include "USART.h"
2
3
static unsigned char UART_counter;
4
5
void Usart_Init(void)
6
{
7
  DDRD &= ~(1<<0);
8
  PORTD |= (1<<0);
9
10
  UCSRA = 0x00;
11
  UCSRB = 0x00;  
12
  UCSRC = 0x86;
13
  UBRRL = 103;
14
  UBRRH = 0;
15
16
  UART_neu = 0;
17
  UART_counter = 0;   // sicherheitshalber
18
}
19
20
ISR(USART_RXC_vect)
21
{
22
  if(UART_Clock == 10)
23
  {
24
    UART_counter = 0;
25
  }
26
27
  UART_Clock = 0;
28
29
  UART[UART_counter] = UDR;
30
31
  UART_counter ++;
32
33
  if(UART_counter >= 5)
34
  {
35
    UART_Disable();
36
37
    UART_counter = 0;
38
    UART_neu = 1;
39
  }
40
}

Sicherheitshalber in der Init auf 0 setzen (auch wenn sie das als 
globale Variable sowieso sein sollte. Die Abfrage auf Buffer voll 
defensiv mit einem >= anstelle des == programmieren.

Darüber
1
#define UART_Disable() UCSRB = 0x00;
2
#define UART_Enable()  UCSRB = 0x90;
sag ich jetzt nichts. 0x90 ist so herrlich aussagekräftig, so dass man 
mit einem Blick sofort sieht, was du da einschaltest :-)

Einen Grund für Resets hab ich allerdings immer noch nicht gefunden. Was 
ist, wenn du dir die Bestätigung anstelle mit dem LCD mit ein paar LED 
geben lässt? Ev. ein Fehler in den LCD Funktionen?

von Richi (Gast)


Lesenswert?

Also: 0x90 --> (1<<RXCIE) | (1<<RXEN)

Einen Fehler in den LCD_Funktionen schließe ich aus, da sich ja der 
Counterwert, welcher angezeigt wird, ständig ändert.

Während dem Datenfluss stellt sich dieser dann plötzlich wieder auf 0.
--> Reset

von Richi (Gast)


Lesenswert?

Normalerweise müsste doch der Empfänger völlig abgeschalten sein und der 
Interrupt darf nicht mehr ausgeführt werden.

Mir ist auch aufgefallen, dass in diesem Fall die Sleep-Routinen nicht 
mehr ordentlich eingehalten werden.

von Richi (Gast)


Lesenswert?

Nachdem sich der Counter wieder auf 0 gestellt hat erscheint gleich die 
Meldung der Empfangenen Bytes.

von Michael U. (amiga)


Lesenswert?

Hallo,

ohne drüber zu schauen: Du löschst aber nach dem Ausschalten des RX-IRQ 
ein evtl. schon wieder gesetztes RXC-Flag?

Sind so meine fallen, nach dem Abschalten des Krams macht man noch was, 
dann wird die ISR beendet, die globalen IRQ wieder freigegen und es 
lauert ein RXC-Flag, weil inzwischen ein Byte eingetroffen ist, das man 
eigentlich garnicht mehr haben will...

Gruß aus Berlin
Michael

von Richi (Gast)


Lesenswert?

Hallo

Alles vorgeschlagene Nützt nichts, ich habe nun eine Extra-LED für den 
Reset eingebaut und das LCD weggelassen.

Kann es sein, dass es evtl. Probleme mit dem Data-Overrun gibt und dass 
die ISR beim Starten einmal durchlaufen wird?

Gruß
Richi

von Richi (Gast)


Lesenswert?

Ich denke mitlerweile weiß ich wo der Fehler liegt:
Wieder  einmal auf meinem Steckbrett!!!

Wenn ich die LEDs/UART über das STK500 laufen lasse, gehts einwandfrei, 
auf dem Steckbrett nicht.

Ich weiß nur noch nicht, wo genau.

Gruß
Richi

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.