Forum: Mikrocontroller und Digitale Elektronik UART Empfang per Interrupt


von Phillip H. (philharmony)


Lesenswert?

Wenn ich bei beendetem Empfang über den UART per Interrupt die 
Leseroutine starten möchte, dann ist das doch der

ISR_VECTOR(UART_RX_vect)

oder?
Zusätzlich muss sei() gesetzt sein.
Muß ich sonst noch was beachten?
Wenn wenn ich im AVR-Studio Simuliere und den RXCIE anklicke passiert 
erstmal nichts.
Wenn ich aber dann noch RXC aktiviere, dann springt das Program nicht 
auf die Interrupt-Routine, sondern zum Beginn der Main-Schleife...Hab 
ich was vergessen?

von Karl H. (kbuchegg)


Lesenswert?

Phillip Hommel wrote:

> auf die Interrupt-Routine, sondern zum Beginn der Main-Schleife...

Ist ein deutliches Indiz für einen Software Fehler. Und zwar
hat der Compiler nicht erkannt, dass du eine ISR schreiben
willst, bzw. du hast dich im Namen der ISR irgendwo vertan.

ISR( USART_RXC_vect )
{
  ...
}

Wenn du dir nicht sicher bist, wie der Interrupt wirklich
heissen muss, dann mach das zu deinem Prozessor gehörende
include file auf (bei einem Mega32 ist das zb. iom32.h)
und sieh da drinnen nach.


Opps:
Wir reden doch vom gcc auf einem Atmel µC, oder nicht?
(Dachte die Anfrage wäre im gcc-Forum gekommen und nicht
im M+C)

von Phillip H. (philharmony)


Lesenswert?

Aus der io8535.h demensprechend auch mein nC.
Ich benutze AVR-Studio mit gcc.

/* UART, RX Complete */
#define UART_RX_vect      _VECTOR(11)
#define SIG_UART_RECV      _VECTOR(11)

Habe es aber sicherheitshalber auch schon mit UART_RXC_vect versucht.
Gleiches Ergebnis, springt immer wieder zum anfang und ingnoriert den 
Handler total!

von Johannes M. (johnny-m)


Lesenswert?

Dass es "ISR" und nicht "ISR_VECTOR" (wo auch immer Du das her hast) 
heißen muss, ist aber jetzt klar, oder?

von Phillip H. (philharmony)


Lesenswert?

Ach mist, das war noch nicht korrigiert. Hab ich inzwischen 
entdeckt...Allerdings tuts immer noch nicht.
Nochmal zum Verständnis:
Der Hardware UART lädt das was kommt in den Puffer, wenn er fertig ist 
kommt das empfangene ins UDR.
Wenn das passiert wird das RXCIE gesetzt und damit das Interrupt 
ausgelöst, gleichzeitig geht die RXC-Falg auf 1.
Ist das soweit richtig?
Wenn ich in der Simulation nur RXC oder nur RXCIE auf 1 setze, passiert 
gar nichts, sind beide gesetzt springt das Prog. auf Anfang.
1
 
2
ISR(UART_RX_vect)
3
  {
4
     Number_of_bytes_RXD = Usart_Rx();  //erstes Paket als Number of Bytes
5
    
6
    Type_of_bytes_RXD = Usart_Rx();    //2.Paket als Type of RX, 
7
                      //0x00=PC fordert Daten an
8
                      //0x01=PC fordert nach Empfang Daten an
9
                      //0x02=PC sendet nur daten
10
                      //0xff=board resetten
11
    switch(Type_of_bytes_RXD)      //Fallunterscheidung anhand Typ
12
      {
13
      case 0x00 :  Send_To_PC(Data_to_send);break;
14
      case 0x01 : Data_Receive(Data_received_LED);Send_To_PC(Data_to_send);break;
15
      case 0x02 : Data_Receive(Data_received_LED);break;
16
      case 0xff : reset();break;          
17
      }
18
  }

Ich weiß, die Routine ist zu lang, aber das ist erstmal ein anderes 
Problem oder?

von Johannes M. (johnny-m)


Lesenswert?

Wieso rufst Du innerhalb der ISR zwei mal irgendeine Funktion 
"Usart_Rx" auf? Und was macht diese Funktion? Ich vermute, Du hast da 
was gründlich falsch verstanden. Wenn ein Byte empfangen wurde, wird 
das Flag gesetzt und (wenn der Rx-Interrupt aktiviert ist) in die ISR 
gesprungen (Du versuchst aber anscheinend, mehr als ein Byte zu lesen). 
Das Flag wird erst dann gelöscht, wenn das Datenregister UDR gelesen 
wird (und wenn im Buffer kein weiteres Zeichen wartet).

von Karl H. (kbuchegg)


Lesenswert?

Phillip Hommel wrote:
> Ach mist, das war noch nicht korrigiert. Hab ich inzwischen
> entdeckt...Allerdings tuts immer noch nicht.
> Nochmal zum Verständnis:
> Der Hardware UART lädt das was kommt in den Puffer, wenn er fertig ist
> kommt das empfangene ins UDR.
> Wenn das passiert wird das RXCIE gesetzt und damit das Interrupt
> ausgelöst, gleichzeitig geht die RXC-Falg auf 1.
> Ist das soweit richtig?

So ungefähr.
Die Reihenfolge ist anders rum.
RXC wird beim Empfang auf jeden Fall gesetzt. RXCIE
wird ebenfalls gesetzt und nur wenn der Interrupt
auch freigegeben ist, findet dann auch der AUfruf statt.

> Ich weiß, die Routine ist zu lang, aber das ist erstmal ein anderes
> Problem oder?

Für dein konkretes Problem: ja
Auf lange Sicht: nein


Es gibt noch eine Möglichkeit für deine
Beobachtung: Du hast irgendeinen anderen Interrupt freigegeben.
Wie sieht die UART Initialisierung aus.

von Phillip H. (philharmony)


Lesenswert?

Das ist richtig, habs noch nicht ganz verstanden ;)

Ich möchte im Endeffekt 16 Datenbytes + das "Type of Data"-Byte 
empfangen.
Das Hauptprogramm soll aber wenn nichts kommt andere Aufgaben erledigen, 
unter anderem auch daten verschicken.
Wenn jetzt das erste Byte ankommt, sagt mir das erstmal, wieviele Bytes 
noch kommen (für die empfangsschleife). Das zweite sagt mir dann was ich 
machen soll (nur empfangen, nur daten nochmals senden, beides, reset).
Danach kommen dann die Datenbytes und sollen zu einem Array 
zusammengebastelt werden.
Meine Idee war jetzt, das wenn ein Byte empfangen wird, ein Intterupt 
ausgelöst wird und sich der Controller jetzt nur noch mit dem Empfang 
der Daten beschäftigt, bis dieser abgeschlossen ist (darum steht eben 
auch alles im Interrupt-Handler drin).
Danach läuft das Programm normal weiter

Die Initialisierung des UART habe ich aus einem Headerfile und wird im 
main() einmal getätigt:
1
void USART_Init( unsigned int ubrr)
2
{
3
  /* Baudrate setzen */
4
  UBRRH = (unsigned char)(ubrr>>8);
5
  UBRRL = (unsigned char)ubrr;
6
 
7
  /* RX/TX einschalten */
8
  UCSRB = (1<<RXEN)|(1<<TXEN);
9
 
10
  /* Datenformat setzen: 8data, 2stop bit */
11
  UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
12
}

Ebenfalls setze ich die Interrupts natürlich zu Programmbeginn per 
sei(),
Register wird in der Simulation auch gesetzt.

Wenn ich dann die RXC und RXCIE setze, geht das SREG(7) Byte auch auf 0, 
es wird einfach mein ISR-Handler ignoriert.

von Phillip H. (philharmony)


Lesenswert?

Ok, mit ISR(VECTOR(11)) gehts, was komisch ist, denn ich habe die io.h 
ja geladen...hmm
Naja, ich erkene auch so langsam daß das was ich da tue etwas, ähm, 
ungünstig ist.
Werde mal weiter probieren und bestimmt mit der einen oder anderen Frage 
glecih wieder zur Stelle sein...
lg
Phil

edit: AUTSCH, ich hatte in der io8535.h gescuht, die is aber für den 
at90s8535...für meinen gilt die iom8535, dort heisst das ding dann nicht 
UART_RX_vect, sondern USART_RX_vect

von Phillip H. (philharmony)


Lesenswert?

Soo, läuft alles soweit, bis auf ein kleines Problem:

Wenn der Interrupt ausgelöst wird, wird im selben Takt, in dem das 
Program auf den Interrupt Handler Springt, auch das UDR gelöscht.
Wie kann ich den Wert dann noch Speichern?

von Falk B. (falk)


Lesenswert?

@ Phillip Hommel (Firma hs-bremen) (philharmony)

>Wenn der Interrupt ausgelöst wird, wird im selben Takt, in dem das
>Program auf den Interrupt Handler Springt, auch das UDR gelöscht.

Kaum.

>Wie kann ich den Wert dann noch Speichern?

my_data = UDR;

MFG
Falk

von Phillip H. (philharmony)


Lesenswert?

dann macht das nur der Simulator? ich habe das so gemacht, daß ich das 
prog. hab laufen lassen (paar mal F11 für next step bis ich im main loop 
war).
dann nen Wert ins UDR reingeklickt und RXCIE und RXC auf 1.
Beim nächsten Step springt er wie gewollt in die ISR-Routine, aber der 
UDR ist leer.

Muß ich am ende des Handlers eigentlich manuell wieder irgendwas setzen 
(sei(), RXCIE,...)?

von Falk B. (falk)


Lesenswert?

@ Phillip Hommel (Firma hs-bremen) (philharmony)

>dann macht das nur der Simulator?

Nö.

>ich habe das so gemacht, daß ich das
>prog. hab laufen lassen (paar mal F11 für next step bis ich im main loop
>war).
>dann nen Wert ins UDR reingeklickt und RXCIE und RXC auf 1.
>Beim nächsten Step springt er wie gewollt in die ISR-Routine, aber der
>UDR ist leer.

Du verarscht ja auch den Simulator nach Strich und Faden. Kein Wunder 
wenn der sich wehrt ;-)

>Muß ich am ende des Handlers eigentlich manuell wieder irgendwas setzen
>(sei(), RXCIE,...)?

NEIN!

Lies nochmal zum Thema Interrupts und Uart in den Datenblätern und im 
GCC Tutorial.

MFG
Falk

von THM (Gast)


Lesenswert?

>dann macht das nur der Simulator?

Habe ich auch so festgestellt.
Der Debugger im AVR-Studio 4.13 hat da so seine Schwächen. UDR wird 
jedesmal nach dem Beschreiben (beim nächsten Schritt) auf null gesetzt.

Auf der Hardware läuft's aber einwandfrei! ;)

von Phillip H. (philharmony)


Lesenswert?

Hmm, dann muss ich jetzt nur noch warten bis die Schieberegister per 
Post ins Haus flattern und dann verscuh ich mal obs klappt.

>Du verarscht ja auch den Simulator nach Strich und Faden. Kein Wunder
>wenn der sich wehrt ;-)
Wieso verarsche ich den sim? Gibt es eine andere Möglichkeit, 
UART-Empfang zu Simulieren?
lg

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.