Forum: Mikrocontroller und Digitale Elektronik ATMega8: USART-RX mit Interrupt


von Zenk (Gast)


Lesenswert?

Hallo,
ich möchte mit einem ATMega8 über die USART Schnittstelle Zeichen lesen 
und das ganze im Interrupt Betrieb. Ein anderer ATMega8 sendet Zeichen, 
was ich mit dem LogicAnalyzer auch überprüft habe. Die Sendefrequenz, 
Parity, Stopbits etc sind natürlich identisch.

Hab schon in anderen Threads gestöbert aber konnte noch nicht finden 
warum das bei mir nicht funktioniert.
Hier der code:
1
#include <avr/io.h>
2
3
#define F_CPU 8000000L 
4
5
#include <util/delay.h>
6
#include <avr/interrupt.h>
7
#define BAUD 9600L
8
9
#define UBRR_VAL ((F_CPU+BAUD * 8)/(BAUD*16)-1)      //clever runde
10
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))         //reale Baudrate
11
12
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD-1000)      //Fehler in Promille
13
14
#if ((BAUD_ERROR>10)||(BAUD_ERROR<-10))
15
#error Systematischer Fehler in der Baudrate größer 1% und damit zu hoch!
16
#endif
17
18
19
ISR (USART_RXC_vect) {
20
  uint8_t dummy;
21
  dummy = UDR;
22
  PORTB ^= (1<<PB0);   
23
}
24
25
26
int main(void)
27
{
28
   
29
   UBRRH = UBRR_VAL >> 8;
30
   UBRRL = UBRR_VAL & 0xFF;
31
   
32
   
33
  UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);      //Asynchron 8N1
34
  UCSRA = (1<<U2X);
35
  UCSRB = ( 1 << RXEN ) | (1 << RXCIE);
36
  sei();
37
38
  while (1)
39
  {
40
41
  }
42
43
  return 0;                     
44
}

von Tobi (Gast)


Lesenswert?

Hi!

Jetzt ohne mal deinen Code näher zu betrachten,
du speicherst in
1
ISR (USART_RXC_vect) {
2
  uint8_t dummy;
3
  dummy = UDR;
4
  PORTB ^= (1<<PB0);   
5
}

das Datenbyte nur temporär, dann wird es wieder gelöscht.

Du müsstest z.B. ein globales Array definieren und da die Daten 
reinpacken.

z.B.
1
uint8_t volatile dummy[255];
2
uint8_t volatile Counter;
3
4
5
Counter=0;
6
...
7
8
9
while(1)
10
  {
11
  if (Counter==200)
12
    {
13
    cli(); //nur als Pseudocode zu verstehen
14
    .... //tu irgendwas mit den Daten, ist alles Fehlerfrei??
15
    Counter=0;
16
    ....
17
    sei();
18
    }
19
  }
20
21
ISR (USART_RXC_vect) 
22
{
23
  dummy[Counter] = UDR;
24
  Counter++;
25
  PORTB ^= (1<<PB0);   
26
}

von Zenk (Gast)


Lesenswert?

ich lese UDR nur aus damit das Interrupt Flag gelöscht wird, es geht mir 
erstmals nur darum die LED blinken zu sehn die an PB0 hängt ;)

von Kai B. (kaib) Benutzerseite


Lesenswert?

Hi Zenk,
wie wäre es mit dem Initialisieren von PORTB?
den UART haste jetzt schon initialisiert nur PORTB muss auch 
entsprechend konfiguriert werden.

MfG Kai

von Tobi (Gast)


Lesenswert?

OK,

dann fehlt nur noch ein
1
DDRB |= (1<<PB0);

von Zenk (Gast)


Angehängte Dateien:

Lesenswert?

hehe, man möge mir eine Tischkante reichen ;)

nun jetzt wird der Interrupt nachweislich ausgelöst, aber so ganz das 
erwünschte Ergebnis ist es noch nicht.

Ich hätte jetzt erwartet dass der Interrupt nur pro Byte und nicht pro 
Bit ausgelöst wird.

Denn wenn ich RX und PB0 am LogicAnalyzer anschaue dann sieht das sehr 
ähnlich aus. Sprich wenn sich bei Rx der logische Zustand ändert, tut 
das der beim PB auch. Ich hab mal ein Bild angehängt. Das obere sich 
verändernde Signal ist Rx, das darunter PB0.

von Tobi (Gast)


Lesenswert?

Also der Interrupt wird auch nur Byteweise ausgelöst!
Da muss was nicht stimmen.

von Kai B. (kaib) Benutzerseite


Lesenswert?

Gerade getestet: pro Byte ein Interrupt. von dem her würde ich behaupten 
das deine Messung falsch ist.
Lass mal im Interrupt hochzählen und gebe das aus dann siehste das pro 
Byte der Zähler immer um 1 hochzählt.

von Zenk (Gast)


Lesenswert?

also wenn ich eine Variable mitzählen lasse kommt dabei raus dass der 
Interrupt ca 1,6 mal zu oft aufgerufen wird.

Das hier ist der Code des anderen µC der die Bytes sendet:
1
#include <avr/io.h>
2
3
#define F_CPU 8000000L 
4
#include <util/delay.h>
5
#define BAUD 9600L
6
7
#define UBRR_VAL ((F_CPU+BAUD * 8)/(BAUD*16)-1)      //clever runde
8
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))         //reale Baudrate
9
10
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD-1000)      //Fehler in Promille
11
12
#if ((BAUD_ERROR>10)||(BAUD_ERROR<-10))
13
#error Systematischer Fehler in der Baudrate größer 1% und damit zu hoch!
14
#endif
15
16
17
int main(void)
18
{
19
   DDRB |= (1<<PB0);
20
   UBRRH = UBRR_VAL >> 8;
21
   UBRRL = UBRR_VAL & 0xFF;
22
  int i = 64;
23
   
24
   
25
  UCSRB = (1<<RXEN)|(1<<TXEN);      //UART TX einschalten
26
  UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);      //8 data, 2 stop bits
27
  
28
  while (1)
29
  {
30
31
    i++;
32
    if (i>90) i = 65;
33
34
    while (!(UCSRA & (1<<UDRE)))      //warten bis Senden möglich
35
    {
36
    }   
37
38
39
    UDR = i;                     //schreibt das Zeichen x auf die Schnittstelle
40
    PORTB ^= (1<<PB0);
41
    _delay_ms(500);
42
  }
43
44
  return 0;                     
45
}

oder kann das Problem am 8MHz Quarz liegen der bei den 9600 Baud einen 
Fehler macht?

von Spess53 (Gast)


Lesenswert?

Hi

>oder kann das Problem am 8MHz Quarz liegen der bei den 9600 Baud einen
>Fehler macht?

Wirklich Quarz?

MfG Spess

von Zenk (Gast)


Lesenswert?

Quarz?                Quarz?

ja Quarz.

was?


Damit will ich sagen: Ich hab keine Ahnung worauf du hinaus willst.

Aber zu meinem Problem, der Faktor 1,6 hat sich bei genauerer Messung 
als Faktor 2 herausgestellt und kam dadurch zustande, dass beim lesenden 
µC U2X gesetzt war, beim sendenden nicht. Tja.
Jetzt werden sogar die richtigen Zeichen erkannt...Ich bin begeistert :)

Danke für die Hilfestellung.


PS: Das LogicAnalyzer Bild erklärt sich dudurch leider dennoch nicht.

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.