UART auf meinem atmega328. Datenregister auf dem USART (UCSR0A) Status nie gesetzt

Ich erlebe eine kleine Fehlerbehebung beim Versuch, Daten in den UART meines Atmega zu senden und zu empfangen. Ich weiß nicht, ob es daran liegt, dass der Taktzyklus falsch konfiguriert ist oder ob ich falsch angenommen habe, wie der Code aussehen sollte, aber ich habe ihn einem Beispielbuch entnommen.

Ich erwarte, Daten in die usart zu schreiben und sie dann einfach zurückzulesen. Ich versuche im Moment nur, eine LED auszugeben, aber sie leuchtet nie, so dass ich annehme, dass mein Code usartReadChar() nie verlässt.

Ich arbeite mit einem atmega328p und das Pin / Register-Makro stammt von iom328p. Die Taktrate ist auf 1Mh konfiguriert.

Der einzige Unterschied zum Buch besteht darin, dass er einen atmega168 verwendet.

Was ich nicht verstehe, ist, dass ich nicht für das Senden von Daten an den Usart blockiert bin (das Usart Data Register Empty (UDRE0) ist eigentlich immer leer). Aber auch das Receive-Complete-Bit (RCX0) im Statut-Register (UCSR0A) wird nie gesetzt. Als ob das Statusbit überhaupt nie funktioniert.

Ich habe versucht, die CPU-Taktrate ohne Erfolg zu ändern. Übrigens bin ich mir nicht sicher, wie ich die Baudrate meines usart berechnen soll und ich bin mir nicht sicher, ob es wirklich einen Einfluss auf meinen Code hat, da ich nur lokal Daten vom AVR sende. Muss ich es also mit meiner CPU synchronisieren?

Ich habe viele Varianten des usartInit()-Setups ausprobiert, aber sie funktionieren nie.

hier ist mein code:

#include <avr/io.h>
#include <util/delay.h>


  void initUSART(void) {

  UBRR0H = UBRRH_VALUE;                        /* defined in setbaud.h */
  UBRR0L = UBRRL_VALUE;
#if USE_2X
  UCSR0A |= (1 << U2X0);
#else
  UCSR0A &= ~(1 << U2X0);
#endif
                                  /* Enable USART transmitter/receiver */
  UCSR0B = (1 << TXEN0) | (1 << RXEN0);
  UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);   /* 8 data bits, 1 stop bit */
}

char usartReadChar(){
    while(! (UCSR0A & (1 << RXC0))){}

    return UDR0;
}

void usartWriteChar(char data){
    while(! (UCSR0A & (1 << UDRE0))){}

    UDR0 = data;
}

int main(){
    DDRB   = 0xff;

    char data;
    initUSART();
    usartWriteChar('a');

    while(1){
      data = usartReadChar();
// actually, never reach

      PORTB  = (1 << 0);
    }

    return 0;
}

Wenn ich es mit einer Baudrate von 9600 kompiliere, erhalte ich keinen Warnfehler bezüglich der Baudrate. Aber wenn ich falsche Baud wähle, bekomme ich natürlich diese Art von Warnung.

/avr/include/util/setbaud.h:227:4: Warnung: #warning "Erreichte Baudrate ist niedriger als erlaubt" [-Wcpp] # warning "Erreichte Baudrate ist niedriger als erlaubt"

Also gehe ich davon aus, dass meine Baudrate korrekt ist. Was könnte dann falsch sein? Ihre Hilfe wird sehr geschätzt. Danke.

* bearbeiten *

Ich habe es aufgegeben etwas lokal in meinen avr auszugeben. Um zu debuggen, habe ich meinen FT232R-Chip an den RX- und TX-Pin meines Atmega angeschlossen, um zu sehen, ob etwas aus dem UCSR0A-Statusregister ausgegeben werden kann, und es hat funktioniert.

Seltsam ist, dass die Debug-Funktion zum Senden von Daten in das Senderregister überhaupt nicht funktionierte, selbst wenn der UCSR0A sagte, dass er mit dem Senden von Daten beschäftigt ist.

Laut Buch müssen die vom Arduino-Programm gesendeten Daten funktionieren, aber bei mir hat es überhaupt nicht funktioniert. Aber von meinem FT232 aus funktioniert das Programm gut, als ob der USART nicht wirklich initialisiert worden wäre, als ich die Anweisung zum Senden von Daten an die US-Art aufrief. Aber da alles synchron ist, weiß ich, dass das nicht so ist.

Ich habe viele Themen zum Konfigurieren von USART auf avr gefunden, aber niemand sagt, dass man ein Debug-Programm wie in meinem Buch testen soll. Ich frage mich also, ob es sich tatsächlich um eine atmega168-spezifische Funktion handelt. Eigentlich verstehe ich nicht, warum das nicht so funktioniert, wie das Buch es erzählt.

Hast du einen Loopback-Stecker an der seriellen Schnittstelle?
Hallo Doxi. Nein, das habe ich nicht getan. Geht es darum, zwei Drähte in die rhe rx / tx-Leitung zu legen?

Antworten (1)

Ich sehe nicht, wo Sie die richtige F_CPUDefinition eingegeben haben, die für obligatorisch ist setbaud.h.

Sie müssen auch das BAUDzu verwendende Makro UBRR(L|H)_VALUEwie folgt definieren:

#define F_CPU 1e6       // 1Mhz clock
#include <avr/io.h>
#include <util/delay.h>

void initUSART(void) {
 #define BAUD 9600
 #include <util/setbaud.h> 
 UBRR0H = UBRRH_VALUE;
 UBRR0L = UBRRL_VALUE;
// ...
}

Sie können die UBRRnxWerte auch mit dieser Seite berechnen . Die Werte hängen von Ihrer Taktrate und der Prescaler-Einstellung ab. In der Standardkonfiguration ist es einfach eins, wird also nicht verwendet.

Und vergessen Sie nicht die Pull-Up-Widerstände (ca. 10K Ohm) an den TX/RX-Leitungen.

Ich hoffe das hilft.