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
In Zeile 42 liegt die Lösung all Deiner und unserer Probleme... Anmerkung: Ohne Quelltext artet das hier in einer wilden Raterei aus.
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 | }
|
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
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.
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?
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
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.
Nachdem sich der Counter wieder auf 0 gestellt hat erscheint gleich die Meldung der Empfangenen Bytes.
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
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.