Forum: Mikrocontroller und Digitale Elektronik AVR USART_RX interrupt macht RESET / Sprung zum Anfang


von Chr. R. (cress)


Lesenswert?

Hallo, ich habe ein Problem mit dem USART_RX Interrupt beim ATmega128. 
Der spingt nämlich immmer an den Anfang der main() zurück?

Ich sende Zeichen via RS232 die ich später verwenden will und wollte
diese zum Test dann erstmal zurückschicken. Kommt aber leider immer nur
mein Initialwert 00 zurück.

Die ISR von USART0_RX_vect springt also jedesmal zum Anfang der main() 
zurück und somit ist meine frisch gespeicherte Variable auch futsch. Den 
erhaltenen Wert gebe ich am PortD auf LEDs aus.

AVR-Studio in Version 4.14.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <inttypes.h>
4
#include <stdio.h>
5
#ifndef F_CPU
6
  #define F_CPU 14745600UL
7
#endif
8
#include <util/delay.h>
9
#define BAUD 115200UL
10
#define UBRR_BAUD (F_CPU/(16UL*BAUD))-1
11
12
volatile unsigned char temp =0x00;
13
14
void delay_ms(uint16_t ms)
15
{
16
  for(;ms>0;ms--)_delay_ms(1);
17
} 
18
19
void USART_Init(unsigned int ubrr)
20
{  
21
  UBRR0H = (unsigned char)(ubrr>>8);
22
  UBRR0L = (unsigned char)ubrr;
23
  UCSR0B |= (1<<TXEN0)|(1<<RXEN0)|(1<<RXCIE0);
24
}
25
26
void USART_Transmit( unsigned char data )
27
{
28
  while (!( UCSR0A &(1<<UDRE0)) );
29
  UDR0 = data;
30
}
31
32
int main(void)
33
{  
34
  USART_Init(UBRR_BAUD);
35
  
36
  DDRD = 0xFF;//Bit0 Ausgang
37
  PORTD |= (1<<PD0); //LED Test
38
  delay_ms(500);
39
  PORTD &=~(1<<PD0);
40
   
41
  sei();
42
  while(1)
43
  {
44
    PORTD=0x00;//LEDs aus
45
    USART_Transmit(temp);
46
    delay_ms(200);
47
  }
48
}  
49
50
ISR (USART0_RX_vect)
51
{
52
  temp=UDR0;
53
  PORTD=temp;
54
}
Kenn mich ´noch nicht so sehr aus und bin für jede Hilfe dankbar.

Was mach ich falsch???

(Hatte das auch schon mal zu einem anderen Beitrag geschrieben, aber da 
hatte ich mich im Datum verguckt, da wird wohl niemand mehr antworten - 
und sonst habe ich auch schon mal ähnliche Probleme durchgesucht, aber 
nix passendes für mich gefunden)

von Patrick (Gast)


Lesenswert?

>Ich vermisse den Interrupthandler.
Der steht doch ganz unten.

von michel (Gast)


Lesenswert?

muss er evtl den Stackpointer initialisieren, zumindest in asm muss man 
das ja, wenn man mit interrupts arbeitet

von Stefan B. (stefan) Benutzerseite


Lesenswert?

ISR habe ich jetzt auch gesehen. Ich habe den üblicherweise in meinen 
Sourcen ziemlich am Anfang und daher überlesen.

Ich kann deine Schlussfolgerung (Die ISR von USART0_RX_vect springt also 
jedesmal zum Anfang der main() zurück ) nicht nachvollziehen.

Empfängst du auf dem AVR NIE ein anderes Zeichen als 0x00 per RX?

Sendest du auf dem AVR IMMER ein 0x00 per TX?

Empfängst du auf dem PC NIE ein anderes Zeichen als 0x00?

von Patrick (Gast)


Lesenswert?

Vielleicht solltest Du in deiner Transmit funktion am Schluss noch 
warten, bis die Daten weg sind. Also mit:
1
while (!(UCSR0A & (1<<TXC0)));

Und beim empfangen kannst Du zusätzlich noch abfragen, ob er fertig 
empfangen hat.
1
while (!(UCSR0A & (1<<RXC0)));

von Chr. R. (cress)


Lesenswert?

> Empfängst du auf dem AVR NIE ein anderes Zeichen als 0x00 per RX?

Doch natürlich, darum gehts ja. Ich sende Werte, die ich später 
verwenden will.

> Sendest du auf dem AVR IMMER ein 0x00 per TX?

Genau das ist das Problem. Die Variable ändert sich nicht. Nur in der 
ISR wo ich die Variable temp direkt auf dem Port ausgebe. Das klappt, 
aber danach ist sie in der main() wieder 00.

> Empfängst du auf dem PC NIE ein anderes Zeichen als 0x00?

Somit also nicht, weil temp ja immer wieder genullt wird.


Das ganze passiert auch bei einem externen Interrupt. Hatte mal nen 
Taster zum hochzählen. Da ist er auch immer zurück an den Anfang der 
main() gesprungen und meine Variable war auf 00.

von Bennigotchi (Gast)


Lesenswert?

Hi,

mach mal folgende Zeile (in der while schleife) raus und schau mal, ob's 
dann besser ist:
1
PORTD=0x00;//LEDs aus

von Chr. R. (cress)


Lesenswert?

Patrick wrote:
> Vielleicht solltest Du in deiner Transmit funktion am Schluss noch
> warten, bis die Daten weg sind.

Das bringt leider auch nix. Immer noch der Sprung zum Anfang.


Solche ähnlichen Probleme gabs doch schon öfters, dass die ISR immer an 
den Anfang der Interrupt-Vector-Tabelle springt. Wieso macht die das?
Die erste Adresse da ist ja RESET.

Schöne SCH... sitz da jetzt schon ne Weile dran.

von Patrick (Gast)


Lesenswert?

Ich weiss nicht, ob das was mit Deinem Problem zu tun hat, aber die main 
sollte doch so aussehen:
1
int main (void)
2
{
3
 ...
4
 return 0;
5
}

Vielleicht springt er deswegen an den Anfang zurück.

von Martin B. (bennigotchi)


Lesenswert?

Ich nochmal...

was kommt denn vom Mikrocontroller über die RS232 zurück?

Ich vermute nämlich, dass das alles funktioniert, nur ist in der main 
etwas, das wohl nicht so beabsichtigt ist.

Und zwar wird da der PortD zyklisch in der while-Schleife auf 0x00 
gesetzt.
Mach das mal raus und schau mal ob deine Bytes aufm port angezeigt 
werden:
1
  while(1)
2
  {
3
    //PORTD=0x00;//LEDs aus
4
    USART_Transmit(temp);
5
    delay_ms(200);
6
  }

von Stefan B. (stefan) Benutzerseite


Lesenswert?

> Doch natürlich, darum gehts ja. Ich sende Werte, die ich später
> verwenden will.

Also du siehst definitiv mehrere LEDS (nicht nur PD0) an PORTD 
zappeln, wenn du einen Haufen Zeichen vom PC zum AVR schickst. Nur der 
AVR schickt nicht die Zeichen als Echo zurück, sondern auf dem PC 
bekommst du immer nur 0x00 zurückgeliefert. Richtig von mir verstanden?

Du vermutest die auf dem PC empfangene 0x00 kommt daher, dass nach jedem 
Zeichen, dass der AVR empfängt, beim Verlassen der ISR ein RESET 
passiert und so beim nächsten Eintritt in die while-Schleife der 
Defaultwert von temp (0x00, schonmal einen anderen Wert probiert?) 
gesendet wird.

> Solche ähnlichen Probleme gabs doch schon öfters, dass die ISR immer an
> den Anfang der Interrupt-Vector-Tabelle springt. Wieso macht die das?
> Die erste Adresse da ist ja RESET.

Dieser Spekulation mag ich nicht folgen. Kannst du das mit dem RESET 
belegen - blitzt PORTD typisch mit PD0 einmal mit 0.5s Dauer auf?

Ich nehme eher an, dass kein RESET passiert und eine andere 
Fehlerursache vorliegt, z.B. eine Nichtbeachtung des notwendigen 
volatile

Um auszuschliessen, dass du mit einer alten Version deiner Source 
arbeitest (nämlich einer ohne volatile), würde ich mal vor dem 
Flashen/Ausprobieren die Source speichern, alle automatisch erzeugten 
Dateien löschen (make clean) und ein Rebuild All durchführen.

Und kannst du mal das frisch erzeugte Assemblerlisting (*.LSS) zeigen? 
In dem kann man nachforschen, ob der Compiler temp korrekt als 
volatile behandelt und entsprechenden Code erzeugt. Bitte gib auch an, 
welche Version der Toolchain du benutzt. Eventuell braucht man zum 
Nachvollziehen des Problems auch das Makefile oder die Projektdatei.

BTW. deine Debugausgabe ist IMHO zu leicht zu verwechseln mit der 
Debugausgabe PORTD = temp aus der ISR bei jedem empfangenen Zeichen. Ich 
würde beim RESET/Init vor dem While was anderes programmieren, öfter 
oder charakteristischer oder an einem anderen Port blinken.

ADD: Und checke auch mal die Einstellung der Fuses. Nicht dass du den 
watchdog scharf geschaltet hast...

von Chr. R. (cress)


Lesenswert?

Hi Stefan,

ja alles richtig verstanden. Meine Zahl wird wirklich immer in der ISR 
korrekt am Port angezeigt, und auch wenn PD0 nicht soll blinkt sie 
trotzdem JEDESMAL für 0.5 sek auf (so stehts ja am Anfang der main() und 
daher bin ich recht sicher, dass er immer dorthin springt).

Ich habe auch schonmal einen anderen Initialwert probiert, aber das ist 
das gleiche Problem, dann kommt eben immer der und nicht der neue.

Das volatile habe ich von Anfang an drin gehabt und das ganze auch schon 
oft mit make clean und Rebuild all durchgeführt um solche Fehler zu 
vermeiden.

> Und kannst du mal das frisch erzeugte Assemblerlisting (*.LSS) zeigen?
Das mach ich morgen früh gleich mal. Hab die Umgebung + Hardware nicht 
zu hause.

> ADD: Und checke auch mal die Einstellung der Fuses. Nicht dass du den
> watchdog scharf geschaltet hast...
Okay...das sagt mir gerade mal gar nichts aber dazu les ich dann mal fix 
im Tutorial und morgen früh gibts dann was dazu.

@bennigotchi
Das ist bloß wieder zum Ausschalten der LEDs, die werden in der ISR 
richtig angezeigt und gehen dann planmäßig aus. Ich speicher das ja in 
temp und auch nur das wird gesendet, also sollte es egal sein, was der 
PORTD dabei macht.


Danke für eure Hilfe...hoffe ich kriegs irgendwann zum laufen. Ist ja 
eigenlich ne elementare einfache Sache - theoretisch. :-)

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Beim Überprüfen der Fuses bitte auch auf die M103C Fuse achten.

Nicht dass du den Atmega128 physikalisch als Atmega103-Kompatiblen 
vorliegen hast (M103C fuse ist ab Werk gesetzt!) und versuchst den mit 
Atmega128 Register/Vektoradressen in der avr/io.h anzusprechen.

Wenn die kleinen Funktionen (USART_Init) vom Compiler als inline 
Funktionen übersetzt werden, crasht es beim ersten Senden (oder nicht 
falls inline) und garantiert beim ISR. Mehr kann man im *.LSS File 
sehen.

s. auch AVR Fuses und 
http://www.mikrocontroller.net/articles/AVR_Checkliste#Besonderheiten_bei_ATmega64_.2F_ATmega128

von Chr. R. (cress)


Lesenswert?

> Beim Überprüfen der Fuses bitte auch auf die M103C Fuse achten.

Das war ein guter Tip, jetzt bin ich happy und kann endlich richtig 
loslegen. Da wäre ich alleine nicht drauf gekommen, wusste nicht, was 
dieses Fuse-Bit bedeutet.
War das erste was ich heut morgen probiert habe und sofort hats 
funktioniert.

Danke, jetzt weiß ich ja an wen ich mich mit Problemen wenden kann. ;-)

Schönes Wochenende!!!

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.