AVR USART Zufälliges Verhalten

Ich scheine zufällige Zeichen in meiner USART-Ausgabe mit einem ATMEGA8 zu erhalten

uart.c

#define FOSC 8000000
#define BAUD_RATE 9600
#define UBRR_VALUE (uint16_t)(FOSC/16/BAUD_RATE-1)

#include "uart.h"

volatile u8buf UART_RCV_BUFFER;
FILE uart0_str = FDEV_SETUP_STREAM(UARTSendByte, UARTReceiveByte, _FDEV_SETUP_RW);

ISR(USART_RXC_vect)
{
    //got a byte from USART. add to buffer
    volatile uint8_t data;
    scanf("%c",&data);
    if((UART_BUFFER_WRITE(&UART_RCV_BUFFER, data)==1) || (data=='.'))
    {
        //either buffer full or '.' received
        //stop the UART receiver unit + disable interrupt
        UCSRB &= ~((1<<RXEN) | (1<<RXCIE));
    }
}

ISR(USART_UDRE_vect)
{
    volatile uint8_t data;
    if(UART_BUFFER_READ(&UART_RCV_BUFFER, &data)==1)
    {
        //end of buffer reached. nothing more to transmit
        //disable RX
        UCSRB &= ~((1<<RXEN) | (1<<RXCIE));
        //reset buffer
        UART_BUFFER_INIT(&UART_RCV_BUFFER);
        //enable  RX side
        UCSRB |= ((1<<RXEN) | (1<<RXCIE));
    }
    else printf("%c",&data);
}

void UART_WRITE_STRING(char* str)
{
    //Sending a string without any command
    //disable RX/TX interrupts
    UCSRB &= ~((1<<RXCIE) | (1<<UDRIE));
    printf("%s",str);
    //re-enable RX/TX interrupts
    UCSRB |= (1<<RXCIE) | (1<<UDRIE);
}


void UART_INIT(void)
{
    UBRRH = (uint8_t)(UBRR_VALUE>>8); //set UBRR register
    UBRRL = (uint8_t)UBRR_VALUE;
    UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);//set frame format: asynchronous,8data,1stop,no parity
    UCSRB = (1<<TXEN) | (1<<RXEN) | (1<<RXCIE) | (1<<UDRIE);

    UART_BUFFER_INIT(&UART_RCV_BUFFER);
    stdin=&uart0_str;
    stdout=&uart0_str;  
}


void UART_BUFFER_INIT(volatile u8buf *buf)
{
    buf->index = 0;
}

uint8_t UART_BUFFER_WRITE(volatile u8buf *buf, volatile uint8_t data)
{
    if(buf->index<UART_RCV_BUF_SIZE)
    {
        buf->index = data;
        buf->index++;
        return 0;
    }
    else return 1;

}

uint8_t UART_BUFFER_READ(volatile u8buf *buf, volatile uint8_t *data)
{
    if(buf->index>0)
    {
        buf->index--;
        *data = buf->buffer[buf->index];
        return 0;
    }
    else return 1;
}

int UARTSendByte(char u8data, FILE *stream)
{
    if(u8data=='\n')
    {
        UARTSendByte('\r',0);
    }
    while(!(UCSRA&(1<<UDRE))){};
    UDR = u8data;
    return 0;
}

int UARTReceiveByte(FILE *stream)
{
    uint8_t data;
    // Wait for byte to be received
    while(!(UCSRA&(1<<RXC))){};
    data=UDR;
    //echo input data
    UARTSendByte(data,stream);
    // Return received data
    return data;
}

Haupt c

#include "uart.h"
#include "twi.h"



int main (void)
{
    DDRC = 0x01; //set PC0 as output
    PORTC = 0x01; //turn on PC0
    //PD0 = RXD = INPUT
    //PD1 = TXD = OUTPUT
    DDRD = 0x03;

    UART_INIT(); //initialize UART
    sei(); //Enable global interrpts

    //_delay_ms(500);   

    UART_WRITE_STRING("Hello World ! 1:)\n");
    UART_WRITE_STRING("Hello World ! 2:)\n");
    UART_WRITE_STRING("Hello World ! 3:)\n");
    for(;;)
    {

    }
}

Dies sollte mir bei der Hinrichtung gegeben werden

Hello World ! 1:)
Hello World ! 2:)
Hello World ! 3:)

Aber was ich bekomme ist

\n\nHello World ! 1:)
Hello World ! 2:)
Hello World ! 3:)

die Anzahl von \n ist zufällig. Manchmal gibt es keine, manchmal 1 oder 2 oder 3. Irgendeine Idee, was ich hier falsch mache?

@sherrellbc Einverstanden. Das ist eher eine Angewohnheit im Programmierstil, aber ich mag Ihre Abkürzung. Das sollte aber die Ursache meines Problems sein
Hast du dich irgendwie überladen printf? Ich sehe nicht, was du da gemacht hast. Ihr USART_WRITE_STRING()ruft nur an printf. Ohne die richtigen Abstände und Einrückungen ist der Code etwas schwer zu lesen. Sehen Sie sich hier eine frühere Version einer USART-Implementierung an, die ich für AtMega328p geschrieben habe . Ich glaube, ich hatte einige Probleme mit der Einstellung der Baudrate mit diesem Code, also ändern Sie einfach diesen Teil und es sollte gut funktionieren. Ich kann meine endgültige Version später posten, wenn Sie möchten, sobald ich Zugriff darauf habe. usart_writeString()Ich scheine auch an diesem Punkt ausgelassen zu haben .
.. Aber es ruft nur usart_writeByte()in einer Schleife auf, bis die char*Punkte auf '\0'da die übergebenen Zeichenfolgenliterale immer nullterminiert sind.

Antworten (1)

Es ist eine gute Angewohnheit, den seriellen Eingangspuffer auf Ihrem PC zu leeren, bevor Sie ihn verwenden, um sicherzustellen, dass Sender und Empfänger synchronisiert sind. Ein nützlicher Trick besteht darin, Ihre Rohdaten nicht zu senden, sondern sie in einen Rahmen zu kapseln, von dem Sie Anfang, Ende und Nutzlast leicht erkennen können. Wahrscheinlich möchten Sie auch eine Prüfsumme hinzufügen, damit Sie einfach überprüfen können, ob die empfangenen Daten mit den Daten übereinstimmen, die Sie senden wollten.

Nützliche ähnliche andere Fragen:

vielen Dank für die Links. Das Erhöhen der Baudrate auf 38400 und die Verwendung von 2 Stoppbits scheint das Problem gelöst zu haben