Uart funktioniert nicht

Gast #3629517
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?
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.
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.
Gast
>    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.
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.
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]
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.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 12 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.