Forum: Mikrocontroller und Digitale Elektronik Uart Interrupt Problem


von Bastler07 (Gast)


Lesenswert?

Hi
ich versuche momentan mit dem Rechner und meinem Atmega32 eine Uart 
Kommunikation aufzubauen. Nun kann ich Zeichen zum Terminalprogramm 
schicken, aber ich bekomm nichts empfangen, obwohl der Interrupt 
ausgelöst wird.
Kann mal jemand über den Code schauen. Achja, der Uart-Code kommt von 
Fleurys HP, den Interruptcode habe ich hier aus dem Tutorial und den 
uart_gets code nutze ich momentan nicht.

Vielen Dank
1
#include <stdlib.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <avr/signal.h>
5
#include <avr/pgmspace.h>
6
#include <util/delay.h>
7
8
#include "uart.h"
9
#include "lcd.h"
10
11
#ifndef F_CPU
12
#define F_CPU 16000000L
13
#endif
14
15
16
//#define ATMEGA_USART1
17
#define UART_BAUD_RATE 9600      
18
#define UART_MAXSTRLEN 10
19
 
20
volatile uint8_t uart_str_complete = 0;     // 1 .. String komplett empfangen
21
volatile uint8_t uart_str_count = 0;
22
volatile char uart_string[UART_MAXSTRLEN + 1] = "";
23
24
void uart_gets( char* Buffer, uint8_t MaxLen )
25
{
26
  uint8_t NextChar;
27
  uint8_t StringLen = 0;
28
 
29
  NextChar = uart_getc();         // Warte auf und empfange das nächste Zeichen
30
 
31
                                  // Sammle solange Zeichen, bis:
32
                                  // * entweder das String Ende Zeichen kam
33
                                  // * oder das aufnehmende Array voll ist
34
  while( NextChar != '\n' && StringLen < MaxLen - 1 ) {
35
    *Buffer++ = NextChar;
36
    StringLen++;
37
    NextChar = uart_getc();
38
  }
39
 
40
                                  // /Noch ein '\0' anhängen um einen Standard
41
                                  // C-String daraus zu machen
42
  *Buffer = '\0';
43
}
44
45
ISR(SIG_USART_RECV)
46
{
47
  uart_str_complete=1;
48
  //uart_gets((char*)uart_string,10);
49
50
  unsigned char nextChar;
51
 
52
  //nextChar = UDR;
53
  nextChar = UDR0;
54
  if( uart_str_complete == 0 ) 
55
  {  // wenn uart_string gerade in Verwendung, neues Zeichen verwerfen
56
 
57
    // Daten werden erst in string geschrieben, wenn nicht String-Ende/max Zeichenlänge erreicht ist/string gerade verarbeitet wird
58
    if( nextChar != '\n' &&
59
        nextChar != '\r' &&
60
        uart_str_count < UART_MAXSTRLEN - 1 ) 
61
  {
62
      uart_string[uart_str_count] = nextChar;
63
      uart_str_count++;
64
    }
65
    else {
66
      uart_string[uart_str_count] = '\0';
67
      uart_str_count = 0;
68
      uart_str_complete = 1;
69
    }
70
  }
71
}
72
73
int main()
74
{
75
  char Line[40];      
76
77
  Init_LCD();
78
  uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) ); 
79
  Clear_LCD();
80
81
  sei();
82
83
84
    GotoXY_LCD(0,0);
85
    LCD_PutString_P(PSTR("UART \r\n\n"));
86
  Update_LCD();
87
88
  uart_puts("T\n");
89
  
90
  while(1)
91
  {
92
    //uart_puts("T\n");
93
    if(uart_str_complete==1)
94
    {
95
      //uart_gets(Line, sizeof( Line ) );
96
      //uart_puts(Line);
97
      Clear_LCD();
98
      GotoXY_LCD(0,0);
99
        LCD_PutString((const char*)uart_string);
100
      uart_puts((const char*)uart_string);
101
      LCD_PutString_P(PSTR("\r\n"));
102
      LCD_PutString_P(PSTR("Erfolg  \r\n\n"));
103
104
      uart_puts((const char*)uart_string); 
105
      uart_str_complete=0;
106
    }
107
    
108
    Update_LCD();
109
    //_delay_ms(1000);
110
  }
111
112
   return 0;

von Bastler07 (Gast)


Lesenswert?

Nochmal genauer:
Wenn ich Zeichen vom Terminal bekomme, wird der Interrupt ausgelöst, 
aber der empfangene String wird nicht zurückgesendet und auch nicht auf 
dem LCD gezeigt. Es entsteht nur eine leere Zeile

von ... (Gast)


Lesenswert?

Das ist schon mal Mist, SIG_USART_RECV ist schon ewig deprecated ind 
passt auch nicht zu "ISR":
1
ISR(SIG_USART_RECV)
und gleich danach
1
  uart_str_complete=1;
ist genauso Mist

von Bastler07 (Gast)


Lesenswert?

das uart_str_complete=1; habe ich oben nur eingefügt, um zu wissen, ob 
der interrupt funktioniert

was ist mit ISR(SIG_USART_RECV) los? der interrupt geht doch...

von ... (Gast)


Lesenswert?

Bastler07 schrieb:
> was ist mit ISR(SIG_USART_RECV) los? der interrupt geht doch...

Ja aber nur bei wenigen alten AVRs. Bei den neueren gibt es die alten 
Namen schon nicht mehr. Korrekter wäre:
1
ISR(USART_RXC_vect)
Die alten "SIG_*" Namen stammen aus einer Zeit, als es noch kein "ISR" 
Makro gab und man statt dessen "INTERRUPT" und "SIGNAL" benutzt hat und 
jeder Neuling damit erstmal fürchterlich auf die Nase gefallen ist, weil 
er beide verwechselt hat.

von ... (Gast)


Lesenswert?

... ach so, und das
1
uart_str_complete=1;
in der ISR ist trotzdem Mist. Es sorgt dafür, das in uart_string 
generell nur ein Leerstring steht.

von Bastler07 (Gast)


Lesenswert?

okay, danke
das hilft mri schonmal weiter

habe gerade mal ISR(USART_RXC_vect) eingefügt, nun fällt mir ein, dass 
hatte ich vorher drin, aber ich bekomme immer die Meldung

../MultiPong.c:51: warning: 'UART_RXC_vect' appears to be a misspelled 
signal handler


klar, mit dem uart_str_complete=1; wird die if anweisung ja umgangen
vollkommen übersehen

kannst du mir auch noch den Fehler für das nicht empfangen des strings 
nennen?

danke nochmal

von Karl H. (kbuchegg)


Lesenswert?

Bastler07 schrieb:
> okay, danke
> das hilft mri schonmal weiter
>
> habe gerade mal ISR(USART_RXC_vect) eingefügt, nun fällt mir ein, dass
> hatte ich vorher drin, aber ich bekomme immer die Meldung
>
> ../MultiPong.c:51: warning: 'UART_RXC_vect' appears to be a misspelled
> signal handler

Der heisst auch
    USART_RXC_vect
und nicht
    UART_RXC_vect


Wenn du dir nicht sicher bist, wie der Interrupt auf deinem µC heisst, 
dann sieh in der iom32.h nach. AVR Studio müsste diese Datei unter 
"External Dependencies" führen. Dort finden sich neben vielen anderen 
Sachen, auch die Namen der INterrupt Vektoren.

Eines würde mich noch interessieren.
Wie hast du das

    nextChar = UDR0;

durch den Compiler gekriegt? Der Mega32 hat nur eine UART und bei dem 
heisst das USART Data Register UDR und nicht UDR0.

> klar, mit dem uart_str_complete=1; wird die if anweisung ja umgangen
> vollkommen übersehen
>
> kannst du mir auch noch den Fehler für das nicht empfangen des strings
> nennen?

Das

 uart_str_complete=1;

IST der Fehler der dafür verantwortlich ist. Deine Empfangsroutine 
meldet viel zu früh, dass die Zeile komplett empfangen wurde. Nämlich zu 
einem Zeitpunkt, an dem noch gar kein String zusammengebaut wurde.

von Bastler07 (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Der heisst auch
>     USART_RXC_vect
> und nicht
>     UART_RXC_vect

ich habe beides probiert, die Warnung bleibt
../MultiPong.c:51: warning: 'UART_RXC_vect' appears to be a misspelled
 signal handler


und nach dem löschen von uart_str_complete=1; gehts trotzdem noch nicht

so hatte ich es ja auch in meiner ersten Version, da dachte ich dann, er 
kommt nicht zum interrupt und habe es daher nochmal davor eingefügt

irgendwie ist da noch was falsch

von Karl H. (kbuchegg)


Lesenswert?

Bastler07 schrieb:
> Karl Heinz Buchegger schrieb:
>> Der heisst auch
>>     USART_RXC_vect
>> und nicht
>>     UART_RXC_vect
>
> ich habe beides probiert, die Warnung bleibt
> ../MultiPong.c:51: warning: 'UART_RXC_vect' appears to be a misspelled
>  signal handler

Wenn in der Fehlermeldung steht, dass UART_RXC_vect ein nicht bekannter 
Interrupt Vektor ist, dann kannst du nicht USART_RXC_vect (mit einem S 
nach U und vor A) geschrieben haben, denn dann würde die Fehlermeldung 
sagen, dass USART_RXC_vect ein unbekannter signal handler ist. Tut es 
aber nicht. Die Fehlermeldung spricht von UART_RXC_vect, ohne das S 
zwischen U und A.

Aber da du offenbar UDR0 durch den Compiler kriegst, gehe ich mal davon 
aus, dass du entweder deinen Compiler oder uns angelogen hast und 
entweder hast du im AVR-STudio keinen Mega32 eingestellt oder du hast 
keinen Mega32. Auf jeden Fall stimmt da aber was nicht.

Alle UART Register und sonstige Dinge, die mit UART zu tun haben, haben 
nur dann eine Zahl dahinter (wie bei UDR0), wenn es mehr als 1 UART 
gibt. Das ist immer so und gilt auch für alles. Wenn du also 2 USART im 
µC hast, dann hast du ein UDR0 und ein UDR1. Du hast dann aber auch 
logischerweise ein USART_RXC0_vect und einen USART_RXC1_vect.

Ein Mega32 hat aber keine 2 UART, sondern nur eine.
Daher heisst das Empfangsregister dort UDR und der Interrupt Vektor 
heißt USART_RXC_vect.


> und nach dem löschen von uart_str_complete=1; gehts trotzdem noch nicht

Dann zeig dein Programm wie es jetzt aussieht.
Aber in compilierbarer Form (keine Fehlermeldungen oder Warnungen mehr)!

von Bastler07 (Gast)


Lesenswert?

oh, da gibt es wohl ein missverständnis
ich habe den Atmega324p und dachte das ist ein Atmega32
jedenfalls habe ich bei meinem 324p 2 USARTs und möchte USART0 verwenden
1
 
2
#include <stdlib.h>
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <avr/signal.h>
6
#include <avr/pgmspace.h>
7
#include <util/delay.h>
8
9
#include "uart.h"
10
#include "lcd.h"
11
12
#ifndef F_CPU
13
#define F_CPU 16000000L
14
#endif
15
16
17
//#define ATMEGA_USART1
18
#define UART_BAUD_RATE 9600      
19
#define UART_MAXSTRLEN 10
20
 
21
volatile uint8_t uart_str_complete = 0;     // 1 .. String komplett empfangen
22
volatile uint8_t uart_str_count = 0;
23
volatile char uart_string[UART_MAXSTRLEN + 1] = "";
24
25
void uart_gets( char* Buffer, uint8_t MaxLen )
26
{
27
  uint8_t NextChar;
28
  uint8_t StringLen = 0;
29
 
30
  NextChar = uart_getc();         // Warte auf und empfange das nächste Zeichen
31
 
32
                                  // Sammle solange Zeichen, bis:
33
                                  // * entweder das String Ende Zeichen kam
34
                                  // * oder das aufnehmende Array voll ist
35
  while( NextChar != '\n' && StringLen < MaxLen - 1 ) {
36
    *Buffer++ = NextChar;
37
    StringLen++;
38
    NextChar = uart_getc();
39
  }
40
 
41
                                  // /Noch ein '\0' anhängen um einen Standard
42
                                  // C-String daraus zu machen
43
  *Buffer = '\0';
44
}
45
46
//ISR(USART0_RXC)
47
ISR(USART_RXC0_vect)
48
{
49
  unsigned char nextChar;
50
 
51
  //nextChar = UDR;
52
  nextChar = UDR0;
53
  if( uart_str_complete == 0 ) 
54
  {  // wenn uart_string gerade in Verwendung, neues Zeichen verwerfen
55
 
56
    // Daten werden erst in string geschrieben, wenn nicht String-Ende/max Zeichenlänge erreicht ist/string gerade verarbeitet wird
57
    if( nextChar != '\n' &&
58
        nextChar != '\r' &&
59
        uart_str_count < UART_MAXSTRLEN - 1 ) 
60
  {
61
      uart_string[uart_str_count] = nextChar;
62
      uart_str_count++;
63
    }
64
    else {
65
      uart_string[uart_str_count] = '\0';
66
      uart_str_count = 0;
67
      uart_str_complete = 1;
68
    }
69
  }
70
}
71
72
int main()
73
{
74
  char Line[40];      
75
76
  Init_LCD();
77
  uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) ); 
78
  Clear_LCD();
79
80
  sei();
81
82
83
    GotoXY_LCD(0,0);
84
    LCD_PutString_P(PSTR("UART \r\n\n"));
85
  Update_LCD();
86
87
  uart_puts("T\n");
88
  
89
  while(1)
90
  {
91
    //uart_puts("T\n");
92
    if(uart_str_complete==1)
93
    {
94
      //uart_gets(Line, sizeof( Line ) );
95
      //uart_puts(Line);
96
      Clear_LCD();
97
      GotoXY_LCD(0,0);
98
        LCD_PutString((const char*)uart_string);
99
      uart_puts((const char*)uart_string);
100
      LCD_PutString_P(PSTR("\r\n"));
101
      LCD_PutString_P(PSTR("Erfolg  \r\n\n"));
102
103
      uart_puts((const char*)uart_string); 
104
      uart_str_complete=0;
105
    }
106
    
107
    Update_LCD();
108
    //_delay_ms(1000);
109
  }
110
111
   return 0;

Warning:
warning: 'USART_RXC0_vect' appears to be a misspelled signal handler

Danke

von Karl H. (kbuchegg)


Lesenswert?

Bastler07 schrieb:
> oh, da gibt es wohl ein missverständnis
> ich habe den Atmega324p und dachte das ist ein Atmega32

Was eine falsche Zahl alles ausmachen kann :-)

> Warning:
> warning: 'USART_RXC0_vect' appears to be a misspelled signal handler

Ok.
In deinem Projekt Baum im AVR Studio sind alle Files aufgeführt. Da gibt 
es unter "External Dependencies" eine iom324.h
Wenn man da reinschaut sieht man, dass da die Definitionen nicht drinnen 
sind. Aber es gibt noch eine zweite iom Datei: die IOMXX4.H
Und wenn man in der nach USART sucht, dann findet sich der Interrupt 
Vektor

USART0_RX_vect

zusammen mit dem Kommentar

/* USART0, Rx Complete */

Bingo. Der ist es.

So sucht man Namen, die man nicht kennt, wenn man nicht sowieso im 
Datenblatt nachsieht. Alle prozessorspezifischen Dinge sind immer in 
einem Header File, das den Namen IOM und einen prozessorspezifischen 
Postfix trägt. Dort kann man nachsehen und mit den richtigen 
Suchbegriffen wird man meistens auch recht schnell fündig.

von Bastler07 (Gast)


Lesenswert?

Super, danke
die Warnung ist nun weg, allerdings kommen die Zeichen noch nicht an

liegt das vielleicht an einem falschen Cast?

von Helfer (Gast)


Lesenswert?

Bastler07 schrieb:

> liegt das vielleicht an einem falschen Cast?

Oder an einer falsch übersetzten Library?
Haste die Fleury Lib für den m324 compiliert?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Bastler07 schrieb:

> die Warnung ist nun weg, allerdings kommen die Zeichen noch nicht an

Erstmal ein paar Bemerkungen zu Deinem Source:

volatile uint8_t uart_str_count = 0;

Diese Variable benutzt Du nur in der ISR, Du kannst sie also in der ISR 
lokal definieren, nämlich als:

static uint8_t uart_str_count;

Die Funktion uart_gets() kann komplett weg, sie wird nicht benutzt und 
verwirrt hier nur.

Woher weisst Du, dass die ISR überhaupt aufgerufen wird? Ich sehe 
nämlich nirgendwo die Freigabe für USART0_RX_vect.

Gruß,

Frank

von Bastler07 (Gast)


Lesenswert?

Helfer schrieb:

> Oder an einer falsch übersetzten Library?
> Haste die Fleury Lib für den m324 compiliert?

Wie ist das gemeint? Habe da nichts kompiliert, habe einfach die header 
und die c datei eingebunden

Frank M. schrieb

> Woher weisst Du, dass die ISR überhaupt aufgerufen wird? Ich sehe
> nämlich nirgendwo die Freigabe für USART0_RX_vect.

Die Freigabe passiert doch über
1
if(uart_str_complete==1)
 in meiner main funktion. Diese wurde vorher mal passiert, da ich Erfolg 
auf meinem Display bekam.
1
#include <stdlib.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <avr/signal.h>
5
#include <avr/pgmspace.h>
6
#include <util/delay.h>
7
8
#include "uart.h"
9
#include "lcd.h"
10
11
#ifndef F_CPU
12
#define F_CPU 16000000L
13
#endif
14
15
16
//#define ATMEGA_USART1
17
#define UART_BAUD_RATE 9600      
18
#define UART_MAXSTRLEN 10
19
 
20
volatile uint8_t uart_str_complete = 0;     // 1 .. String komplett empfangen
21
volatile char uart_string[UART_MAXSTRLEN + 1] = "";
22
23
//ISR(USART0_RXC)
24
ISR(USART_RXC0_vect)
25
{
26
  unsigned char nextChar;
27
  static uint8_t uart_str_count;
28
29
 
30
  //nextChar = UDR;
31
  nextChar = UDR0;
32
  if( uart_str_complete == 0 ) 
33
  {  // wenn uart_string gerade in Verwendung, neues Zeichen verwerfen
34
 
35
    // Daten werden erst in string geschrieben, wenn nicht String-Ende/max Zeichenlänge erreicht ist/string gerade verarbeitet wird
36
    if( nextChar != '\n' &&
37
        nextChar != '\r' &&
38
        uart_str_count < UART_MAXSTRLEN - 1 ) 
39
  {
40
      uart_string[uart_str_count] = nextChar;
41
      uart_str_count++;
42
    }
43
    else {
44
      uart_string[uart_str_count] = '\0';
45
      uart_str_count = 0;
46
      uart_str_complete = 1;
47
    }
48
  }
49
}
50
51
int main()
52
{
53
  char Line[40];      
54
55
  Init_LCD();
56
  uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) ); 
57
  Clear_LCD();
58
59
  sei();
60
61
62
    GotoXY_LCD(0,0);
63
    LCD_PutString_P(PSTR("UART \r\n\n"));
64
  Update_LCD();
65
66
  uart_puts("T\n");
67
  
68
  while(1)
69
  {
70
    //uart_puts("T\n");
71
    if(uart_str_complete==1)
72
    {
73
      //uart_gets(Line, sizeof( Line ) );
74
      //uart_puts(Line);
75
      Clear_LCD();
76
      GotoXY_LCD(0,0);
77
        LCD_PutString((const char*)uart_string);
78
      uart_puts((const char*)uart_string);
79
      LCD_PutString_P(PSTR("\r\n"));
80
      LCD_PutString_P(PSTR("Erfolg  \r\n\n"));
81
82
      uart_puts((const char*)uart_string); 
83
      uart_str_complete=0;
84
    }
85
    
86
    Update_LCD();
87
    //_delay_ms(1000);
88
  }
89
90
   return 0;

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Bastler07 schrieb:
> Die Freigabe passiert doch über
1
if(uart_str_complete==1)
 in
> meiner main funktion.

Du hast mich falsch verstanden: Es reicht nicht, global die Interrupts 
über sei() freizuschalten, Du musst auch noch Deine ISR gezielt 
"enablen", siehe

  http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Der_UART#Empfangen_.28RX.29

(RXCIE spielt hier die Rolle)

Oder macht das bei Dir das uart_init()? Ich kann mir nicht vorstellen, 
dass die LIB, die Du benutzt, standardmäßig auf Interrupt-Betrieb 
ausgerichtet ist.

von Bastler07 (Gast)


Lesenswert?

gute idee, aber das wird eigentlich über die uart_init() erledigt. Mein 
Compiler definiert doch den Atmega, so werden die defines freigeschaltet 
und somit die if-Bedinung in der Funktion uart_init() ausgeführt.

Oder muss ich nochmal extra meinen Atmega definieren?

aus Fleury`s uart lib:
1
#elif defined(__AVR_ATmega164P__) || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega644P__)
2
 /* ATmega with two USART */
3
 #define ATMEGA_USART0
4
 #define ATMEGA_USART1
5
 #define UART0_RECEIVE_INTERRUPT   SIG_USART_RECV
6
 #define UART1_RECEIVE_INTERRUPT   SIG_USART1_RECV
7
 #define UART0_TRANSMIT_INTERRUPT  SIG_USART_DATA
8
 #define UART1_TRANSMIT_INTERRUPT  SIG_USART1_DATA
9
 #define UART0_STATUS   UCSR0A
10
 #define UART0_CONTROL  UCSR0B
11
 #define UART0_DATA     UDR0
12
 #define UART0_UDRIE    UDRIE0
13
 #define UART1_STATUS   UCSR1A
14
 #define UART1_CONTROL  UCSR1B
15
 #define UART1_DATA     UDR1
16
 #define UART1_UDRIE    UDRIE1
17
18
19
void uart_init(unsigned int baudrate)
20
{
21
    UART_TxHead = 0;
22
    UART_TxTail = 0;
23
    UART_RxHead = 0;
24
    UART_RxTail = 0;
25
    
26
#if defined( AT90_UART )
27
    /* set baud rate */
28
    UBRR = (unsigned char)baudrate; 
29
30
    /* enable UART receiver and transmmitter and receive complete interrupt */
31
    UART0_CONTROL = _BV(RXCIE)|_BV(RXEN)|_BV(TXEN);
32
33
#elif defined (ATMEGA_USART)
34
    /* Set baud rate */
35
    if ( baudrate & 0x8000 )
36
    {
37
       UART0_STATUS = (1<<U2X);  //Enable 2x speed 
38
       baudrate &= ~0x8000;
39
    }
40
    UBRRH = (unsigned char)(baudrate>>8);
41
    UBRRL = (unsigned char) baudrate;
42
   
43
    /* Enable USART receiver and transmitter and receive complete interrupt */
44
    UART0_CONTROL = _BV(RXCIE)|(1<<RXEN)|(1<<TXEN);
45
    
46
    /* Set frame format: asynchronous, 8data, no parity, 1stop bit */
47
    #ifdef URSEL
48
    UCSRC = (1<<URSEL)|(3<<UCSZ0);
49
    #else
50
    UCSRC = (3<<UCSZ0);
51
    #endif 
52
    
53
#elif defined (ATMEGA_USART0 )
54
    /* Set baud rate */
55
    if ( baudrate & 0x8000 ) 
56
    {
57
       UART0_STATUS = (1<<U2X0);  //Enable 2x speed 
58
       baudrate &= ~0x8000;
59
     }
60
    UBRR0H = (unsigned char)(baudrate>>8);
61
    UBRR0L = (unsigned char) baudrate;
62
63
    /* Enable USART receiver and transmitter and receive complete interrupt */
64
    UART0_CONTROL = _BV(RXCIE0)|(1<<RXEN0)|(1<<TXEN0);
65
    
66
    /* Set frame format: asynchronous, 8data, no parity, 1stop bit */
67
    #ifdef URSEL0
68
    UCSR0C = (1<<URSEL0)|(3<<UCSZ00);
69
    #else
70
    UCSR0C = (3<<UCSZ00);
71
    #endif 
72
73
#elif defined ( ATMEGA_UART )
74
    /* set baud rate */
75
    if ( baudrate & 0x8000 ) 
76
    {
77
      UART0_STATUS = (1<<U2X);  //Enable 2x speed 
78
      baudrate &= ~0x8000;
79
    }
80
    UBRRHI = (unsigned char)(baudrate>>8);
81
    UBRR   = (unsigned char) baudrate;
82
83
    /* Enable UART receiver and transmitter and receive complete interrupt */
84
    UART0_CONTROL = _BV(RXCIE)|(1<<RXEN)|(1<<TXEN);
85
86
#endif
87
88
}/* uart_init */

von Stefan E. (sternst)


Lesenswert?

Und was hast du mit der Receive-Interrupt-ISR vom Fleury-Code gemacht? 
Gelöscht, auskommentiert, oder was? Dass es nicht 2 ISRs zum gleichen 
Interrupt geben kann, ist dir doch klar, oder?

von Bastler07 (Gast)


Lesenswert?

Klar, den Fleury Interrupt habe ich gelöscht

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Bastler07 schrieb:
> gute idee, aber das wird eigentlich über die uart_init() erledigt.

Hast Du das _BV(RXCIE) dort reingebastelt oder war das schon drin? Wenn 
letzterers, muss es doch dort auch schon eine ISR dafür geben? Wenn ja, 
welche wird dann benutzt? die aus der Lib oder Deine eigene?

Eigentlich ist das Unsinn, dass Du eine LIB benutzt, die Du dann 
"hintenrum" durchlöcherst wie ein Schweizer Käse (wie z.B. durch eigene 
ISR bzw. durch eigenes uart_gets()).

von Bastler07 (Gast)


Lesenswert?

Stimmt, ihr habt recht. Eigentlich wollte ich mir so eben was aufbauen, 
aber damit habe ich mir wohl mehr Probleme gemacht als alles andere.

Ich bin gegen abend wieder zuhause und werde es dann mal vernünftig und 
komplett neu aufbauen.

Ich melde mich dann heute abend wieder.

Danke für die Hilfe

von Bastler07 (Gast)


Lesenswert?

der aufgräumte code, allerdings bleit das problem gleich
der atmega kann zum terminal senden, aber nicht empfangen
1
#include <stdlib.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <avr/signal.h>
5
#include <avr/pgmspace.h>
6
#include <util/delay.h>
7
8
#include "defines.h"
9
#include "twi.h"
10
#include "dataflash.h"
11
12
#ifndef F_CPU
13
#define F_CPU 16000000L
14
#endif
15
16
#define UART_MAXSTRLEN 10
17
 
18
volatile uint8_t uart_str_complete = 0;     // 1 .. String komplett empfangen
19
volatile uint8_t uart_str_count = 0;
20
volatile char uart_string[UART_MAXSTRLEN + 1] = "";
21
22
23
void uart_init(void)
24
{
25
  UBRR0 = 103;
26
  UCSR0B |= (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);  // UART RX, TX und RX Interrupt einschalten
27
  UCSR0C = (1<<USBS0)|(3<<UCSZ00);        // Asynchron 8N1 
28
29
}
30
31
int uart_putc(unsigned char c)
32
{
33
    while (!(UCSR0A & (1<<UDRE0)))  /* warten bis Senden moeglich */
34
    {
35
    }                             
36
 
37
    UDR0 = c;                      /* sende Zeichen */
38
    return 0;
39
}
40
 
41
 
42
/* puts ist unabhaengig vom Controllertyp */
43
void uart_puts (char *s)
44
{
45
    while (*s)
46
    {   /* so lange *s != '\0' also ungleich dem "String-Endezeichen" */
47
        uart_putc(*s);
48
        s++;
49
    }
50
}
51
52
53
ISR(USART0_RX_vect)
54
{
55
  unsigned char nextChar;
56
 
57
  // Daten aus dem Puffer lesen
58
  nextChar = UDR0;
59
  if( uart_str_complete == 0 ) {  // wenn uart_string gerade in Verwendung, neues Zeichen verwerfen
60
 
61
    // Daten werden erst in string geschrieben, wenn nicht String-Ende/max Zeichenlänge erreicht ist/string gerade verarbeitet wird
62
    if( nextChar != '\n' &&
63
        nextChar != '\r' &&
64
        uart_str_count < UART_MAXSTRLEN - 1 ) {
65
      uart_string[uart_str_count] = nextChar;
66
      uart_str_count++;
67
    }
68
    else {
69
      uart_string[uart_str_count] = '\0';
70
      uart_str_count = 0;
71
      uart_str_complete = 1;
72
    }
73
  }
74
}
75
76
int main()
77
{
78
  uart_init();
79
  sei();
80
81
  uart_putc('k');
82
  uart_puts("T\n");
83
  
84
  while(1)
85
  {
86
    if(uart_str_complete==1)
87
    {
88
      uart_puts((char*)uart_string);
89
      uart_str_complete=0;
90
    }
91
    
92
  }
93
94
   return 0;
95
}

von Karl H. (kbuchegg)


Lesenswert?

Bastler07 schrieb:
> der aufgräumte code, allerdings bleit das problem gleich
> der atmega kann zum terminal senden, aber nicht empfangen

Wie testest du?
Druck auf Return vergessen?

Füg hier mal ein Echo ein

> ISR(USART0_RX_vect)
> {
>   unsigned char nextChar;
>
>   // Daten aus dem Puffer lesen
>   nextChar = UDR0;

    uart_putc( nextChar );

>   if( uart_str_complete == 0 ) {  // wenn uart_string gerade in
> Verwendung, neues Zeichen verwerfen
>
>     // Daten werden erst in string geschrieben, wenn nicht
> String-Ende/max Zeichenlänge erreicht ist/string gerade verarbeitet wird
>     if( nextChar != '\n' &&
>         nextChar != '\r' &&
>         uart_str_count < UART_MAXSTRLEN - 1 ) {
>       uart_string[uart_str_count] = nextChar;
>       uart_str_count++;
>     }
>     else {
>       uart_string[uart_str_count] = '\0';
>       uart_str_count = 0;
>       uart_str_complete = 1;
>     }
>   }
> }

Jetzt schickt der µC gleich alles zurück, was über die UART reinkommt 
und du tippst nicht mehr im Dunkeln.

von Bastler07 (Gast)


Lesenswert?

hi
klasse, das war schonmal ein super hinweis, nun geht es fast komplett

ich schick test\n hin und er schickt mir test\n zurück (durch die neu 
eingefügte ausgabe, aber nicht über den interrupt)

dann schicke ich nach kurzer zeit nochmal hallo hin

dann schickt er über interrupt folgendes:
hallotest\nhal

das erste hallo kommt noch von der neuen Ausgabe, der weitere Teil ist 
dann der korrekte Teil, allerdings der vorige noch dabei und auf 10 
Zeichen begrenzt

Er wartet also immer, bis die vollen 10 Zeichen empfangen wurde und gibt 
dann erst das uart_str_complete=1 raus

Wieso nimmt er also die \n oder \r zum beenden meines Strings nicht 
wahr? Kann das am Terminalprogramm liegen? Ich nutze HTerm und shcicke 
ASC

Viele Dank

von Karl H. (kbuchegg)


Lesenswert?

Wie genau schickst du \n ?

Das ist die C Schreibweise für Return (die große Taste mit dem Haken 
drauf) und nicht für die beiden Tasten '\' und dann 'n'.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Karl Heinz Buchegger schrieb:
> Wie genau schickst du \n ?
>
> Das ist die C Schreibweise für Return (die große Taste mit dem Haken
> drauf) und nicht für die beiden Tasten '\' und dann 'n'.

Das ist nicht ganz korrekt. Standardmäßig schickt ein 
Terminal-Emulationsprogramm beim Drücken der RETURN-Taste ein CR, was 
einem '\r' entspricht. Dieses sollte man "echoen" mit "\r\n" (CRLF, also 
Wagenrücklauf mit anschließendem Zeilenvorschub). Wenn man nur das '\r' 
als Echo zurückschickt, dann hat man den hässlichen Effekt, dass der 
Cursor lediglich an den Anfang der Zeile gestellt wird, aber keine neue 
Zeile erzeugt wird.

Ein '\n' kann man in einer Terminal-Emulation nur mit STRG-J schicken, 
das entspricht dem LF (Hex 0A) und damit dem '\n'.

Wie gesagt, das gilt für die Standard-Konfiguration einer 
Terminal-Emulation. Einige kann man auch umstellen, dass beim Drücken 
der RETURN-Taste ein CRLF ("\r\n") oder nur ein LF ('\n'= geschickt 
wird. Würde ich aber nicht umstellen in der Konfiguration, denn beim 
Wechsel auf ein anderes Programm oder PC hat man das Problem wieder.

Man muss sich einfach dran gewöhnen, dass der PC ein CR schickt und man 
das als CRLF "echoen" sollte.

Gruß,

Frank

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Bastler07 schrieb:
> der aufgräumte code, allerdings bleit das problem gleich
> der atmega kann zum terminal senden, aber nicht empfangen

Eins fällt mir direkt auf: Du schneidest beim Empfang \r und auch \n ab, 
d.h. sie stehen nicht im Empfangspuffer uart_string. Beim Zurücksenden 
von uart_string vergisst du aber, diese Zeichen wieder zurückzusenden. 
Am einfachsten machst Du das in main durch:
1
     uart_puts((char*)uart_string);
2
     uart_puts("\r\n");               // CRLF hinzufügen!

Und nochmal mein Hinweis, dass Du uart_str_count direkt als 
static-Variable in der ISR definieren kannst, dann brauchst Du auch 
keine volatile-Deklaration, was Dein Programm auf jeden Fall ein 
Stückchen "effizienter" macht.

Also:
1
ISR(USART0_RX_vect)
2
{
3
    static uint8_t uart_str_count;
4
    ...

Gruß,

Frank

von Bastler07 (Gast)


Lesenswert?

ah, ich kann es im terminalprogramm einstellen
bei "Send on enter: CR" funktioniert es super

danke, die weiteren Tipps werde ich noch einbauen

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.