Forum: Mikrocontroller und Digitale Elektronik Uart funktioniert nicht


von Demian M. (Gast)


Lesenswert?

Hallo!
Ich wollte eine Uart-Kommunikation zwischen zwei Atmega8 machen.

SIe sind verbunden:

RX----------TX
TX----------RX

Aber irgendwie wird mir auf dem Display nichts angezeigt, warum? Hier 
der COde:

"Server":
1
#include <avr/io.h>
2
#include <stdlib.h>
3
#include <util/delay.h>
4
#include <avr/interrupt.h>
5
6
#include "lib/uart.h"
7
#include "lib/simpleprog.h"
8
#include "lib/lcd.h"
9
10
char buffer;
11
12
ISR(USART_RXC_vect){    
13
    uart_get_string(buffer, sizeof(buffer));
14
    lcd_clear();
15
    lcd_home();
16
    lcd_string(buffer);
17
}
18
19
int main(void){
20
    pinMode(&DDRB, PB1, 1);
21
    pinMode(&DDRB, PB2, 1);
22
    uart_init();
23
    lcd_init();
24
    sei();
25
    while(1){
26
        digWrite(&PORTB, PB1, 1);  
27
        digWrite(&PORTB, PB2, 1);
28
        _delay_ms(10);
29
        digWrite(&PORTB, PB1, 0);  
30
        digWrite(&PORTB, PB2, 0);
31
        _delay_ms(1000);
32
    }
33
}

Hier der "client":
1
#include <avr/io.h>
2
#include <stdlib.h>
3
#include <util/delay.h>
4
#include <avr/interrupt.h>
5
6
#include "lib/uart.h"
7
#include "lib/simpleprog.h"
8
#include "lib/lcd.h"
9
10
char buffer;
11
12
13
int main(void){
14
    uart_init();
15
    while(1){
16
        uart_send_string("on");
17
        _delay_ms(1000);
18
        uart_send_string("off");
19
        _delay_ms(1000);
20
    }
21
}

Hier die Lib:

uart.c
1
#include <avr/io.h>
2
#include <stdlib.h>
3
#include "uart.h"
4
5
void uart_init(void){
6
    UBRRH = HIGH(USART_BAUD_CALC);
7
    UBRRL = LOW(USART_BAUD_CALC);
8
    
9
    UCSRB = (1 << RXEN) | (1 << TXEN) | (1 << RXCIE);
10
    UCSRC = (1 << UCSZ0) | (1 << UCSZ1);
11
}
12
13
void uart_send_char(unsigned char c){
14
    while(!(UCSRA & (1 << UDRE)));
15
        UDR = c;
16
}
17
18
void uart_send_string(char* s){
19
    while(*s){
20
        uart_send_char(*s);
21
        s++;
22
    }
23
}
24
25
uint8_t uart_get_char(void){
26
    while(!(UCSRA & (1 << RXC)));
27
        return UDR;
28
}
29
30
void uart_get_string(char *buffer, uint8_t MaxLen){
31
    uint8_t NextChar;
32
    uint8_t StringLen = 0;
33
    
34
    NextChar = uart_get_char();
35
    
36
    while(NextChar != '\n' && StringLen < MaxLen - 1) {
37
        *buffer++=NextChar;
38
        StringLen++;
39
        NextChar = uart_get_char();
40
    }
41
    *buffer = '\0';
42
}

uart.h
1
#ifndef UART_H
2
#define UART_H
3
4
#define F_CPU 8000000UL
5
#define USART_BAUD_RATE 9600UL
6
#define USART_BAUD_CALC (F_CPU/(USART_BAUD_RATE*16L)-1)
7
8
#define LOW(x) ((x) & 0xFF) //Lowbyte
9
#define HIGH(x) (((x) >> 8) & 0xFF) //Highbyte
10
11
void uart_init(void);
12
void uart_send_char(unsigned char c);
13
void uart_send_string(char* s);
14
uint8_t uart_get_char(void);
15
void uart_get_string(char *buffer, uint8_t MaxLen);
16
17
#endif

Was stimmt net?

von Frank B. (f-baer)


Lesenswert?

Hast du schonmal geschaut, ob deine Senderoutinen überhaupt 
funktionieren?
Landet was auf der TX-Leitung, wenn du senden möchtest? Empfängt der 
zweite Controller irgend etwas?

Die ISR ist ziemlicher Mist. Du rufst uart_get_string mit MaxLen=1 auf, 
da kannst du es auch lassen. Bau lieber um die UART einen ordentlichen 
Ringbuffer, den du dann im Hauptprogramm entsprechend auslesen kannst.

von Georg G. (df2au)


Lesenswert?

Demian M. schrieb:
> ISR(USART_RXC_vect){
>     uart_get_string(buffer, sizeof(buffer));
>     lcd_clear();
>     lcd_home();
>     lcd_string(buffer);
> }

Das ist syntaktisch in Ordnung, programmtechnisch aber extrem unschön. 
Wie lange dauert allein das Löschen und Beschreiben des LCD? Und in 
welchem Abstand kommen die Zeichen über den UART?

In der ISR holst du das eine Zeichen ab, das gekommen ist und packst 
es zwecks weiterer Verwendung in einen Ringpuffer. Den Rest erledigst du 
dann in aller Ruhe in der Hauptschleife.

von Demian M. (Gast)


Lesenswert?

Wie genau kann ich das jetzt lösen?

von Thomas E. (thomase)


Lesenswert?

>    UCSRC = (1 << UCSZ0) | (1 << UCSZ1);

Das kannst du dir ersten sparen, weil es sowieso default ist. Zweitens 
versaut es dir die Baudrateneinstellung, weil URSEL fehlt.

mfg.

von Uwe (Gast)


Lesenswert?

>    uart_get_string(buffer, sizeof(buffer));
weil sizeof(buffer) immer 1 ist !
Deine Funktionen können doch nicht wissen wie lang der String ist bzw. 
wissen es nur wenn die 0x00 gekommen ist. Kannst du garantieren das die 
Funktionen erst aufgerufen werden wenn das Null Byte schon da war ?
> ISR(USART_RXC_vect)
wird jedesmal wenn EIN Zeichen empfangen wurde (ja 1) aufgerufen und ein 
String mit der Länge EINS kann es so nicht geben weil er dann immer Leer 
sein müßte um noch Platz für die Null zu haben oder es ist ein Zeichen 
Drinn, dann ist es aber kein String mehr.

Also du brauchst ein Protokol mit Startbyte Paketlänge und Prüfsumme.

von Georg G. (df2au)


Lesenswert?

Ein weiterer Punkt:
ein Zeichen kommt an. Du springst in die ISR. Dort versuchst du, einen 
String zu sammeln. Du wartest dazu auf '\n'. Das sendest du aber nie. 
Und dein Buffer für den String ist nur 1 Zeichen groß.

Wie du das lösen kannst? Schwierige Frage. Eine Möglichkeit wäre ein 
Grundkurs in Programmieren, angefangen mit "LED blinken lassen". Eine 
andere Möglichkeit ist, nicht VHIT zu programmieren (vom Hirn ins 
Terminal), sonder sich erst ein Ablaufdiagramm zu zeichnen. Als 
praktische Lösung würde ich als erstes auf Interrupts verzichten. Das 
kann im zweiten Anlauf passieren.

Und weiter oben wurde schon geschrieben: Lass mal nur den Sender laufen 
und sieh dir an, was auf der TxD Leitung passiert. Wenn das deinen 
Erwartungen entspricht, wirf den Empfänger an.

von Hans O. (piwibit)


Lesenswert?

Demian M. schrieb:
> SIe sind verbunden:
>
> RX----------TX
> TX----------RX

Ich hoffe, die beide GND sind auch verbunden.

Grüsse
Hans

von Daniel A. (daniel-a)


Lesenswert?

Georg G. schrieb:
> Demian M. schrieb:
>> ISR(USART_RXC_vect){
>>     uart_get_string(buffer, sizeof(buffer));
>>     lcd_clear();
>>     lcd_home();
>>     lcd_string(buffer);
>> }
>
> Das ist syntaktisch in Ordnung

nein, ist es nicht, weil

Demian M. schrieb:
> void uart_get_string(char *buffer, uint8_t MaxLen){
>     uint8_t NextChar;
>     uint8_t StringLen = 0;
>
>     NextChar = uart_get_char();
>
>     while(NextChar != '\n' && StringLen < MaxLen - 1) {
>         *buffer++=NextChar;
>         StringLen++;
>         NextChar = uart_get_char();
>     }
>     *buffer = '\0';
> }
Buffer ein Pointer sein muss. Auserdem ist die schleife nie erfüllt, 
wenn maxlen 1 ist.
Ändere char buffer; nach char buffer[10]

von Georg G. (df2au)


Lesenswert?

Daniel A. schrieb:
> nein, ist es nicht

Ich bin nun zu faul, das durch den Compiler zu würgen. Aber es wird 
vermutlich ohne Fehlermeldung übersetzt werden. Warnungen sollte man ja 
ignorieren oder ausschalten (speziell als Anfänger oder bei Problemen 
mit dem Code). Ich stimme zu, dass es gehobener Unfug ist.

von Demian M. (Gast)


Lesenswert?

Klappt jetzt erstmal so, danke, also ohne Interrupt..aber wie geht das 
mit?

von Georg G. (df2au)


Lesenswert?

Demian M. schrieb:
> aber wie geht das
> mit?

Such nach Fleury und UART. Dort findest du eine vorzügliche Bibliothek, 
die sicher funktioniert.

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.