So stellen Sie die Baudrate für die serielle Kommunikation in ATmega32u4 ein

Ich habe ein winziges 2.0-Board und versuche, damit dieses LCD über serielles TTL zu steuern.

Ich habe es mit meinem Arduino uno und einigen Arduino-Beispielcodes zum Laufen gebracht, aber ich möchte es mit der Teensy- und der C-Sprache machen.

Der Teensy verwendet den ATmega32u4 und hier ist das Datenblatt für diesen Chip.

Im Datenblatt ab Seite 186 befindet sich der Abschnitt über USART. Auf Seite 192 finden Sie einen Beispielcode in C-Sprache zum Initialisieren des USART. Ich bin in ein paar Zeilen verwirrt und könnte etwas Hilfe gebrauchen.

void USART_Init( unsigned int baud )
{
  /* Set baud rate */
  UBRRHn = (unsigned char)(baud>>8);
  UBRRLn = (unsigned char)baud;

  /*rest of code here*/
}

Erstens ist mir nicht klar, wie die Baudratenzahl lauten soll. Mein LCD fordert 9600 Baud mit 1 Startbit, 1 Stoppbit, kein Paritätsbit und 8 Datenbits. Auf Seite 189 des Datenblatts des ATmega32u4 habe ich die Berechnung durchgeführt, wie hoch die Baudrate sein sollte, die im Fall der Teensy- und LCD-Kombination 103 sein sollte, da die Chipfrequenz 16 MHz und die Baudrate 9600 beträgt. Dies entspricht auch der Zahl in das Diagramm auf Seite 213 des Datenblatts des ATmega32u4. Ist dies also die richtige Zahl, die an die USART_Init-Funktion für die Variable Baud übergeben würde?

Ich bin auch verwirrt über die beiden Zeilen, die die Baudrate einstellen. Ich verstehe, dass die Baudratenregister gemäß Seite 209 des Datenblatts des ATmega32u4 in ein niedriges und ein hohes Register aufgeteilt sind, aber nur die Bits 8:10 im hohen Register verwendet werden, was es zu einem kombinierten 12-Bit-Register macht. Also, zurück zum Code, ich verstehe einige Dinge nicht:

  1. Warum wird es in ein Zeichen ohne Vorzeichen umgewandelt, weil ich annehme, dass UBRRHn in binärer Notation sein sollte.
  2. Ich verstehe auch den Teil (Baud>>8) nicht, denn wenn Sie 103 für Baud eingeben, erhalten Sie (103>>8) und das ist nicht richtig. Kann mir jemand diese Zeile erklären? Danke.
UBRRHn = (unsigned char)(baud>>8);<br/>
UBRRLn = (unsigned char)baud;
  1. Sollte Baud die 12-Bit-Binärversion von 103 sein, die 00001100111 ist? Wenn ja, wie würde der Code geschrieben werden?

Außerdem habe ich auf der Teensy-Website einen Beispielcode (http://www.pjrc.com/teensy/uart.html) gefunden, der den UART einrichtet und die Baudrate wie folgt einrichtet:

void uart_init(uint32_t baud)
{
    cli();
    UBRR1 = (F_CPU / 4 / baud - 1) / 2;

    /*rest of code here*/
}

Setze ich die Zahlen ein, sieht das so aus:

UBRR1 = (16000000 / 4 / 9600 - 1) / 2; /* Which would equal 208 */
  1. Die Zahl 208 ist anders als 103, also verstehe ich nicht, woher sie die Gleichung bekommen, um sie zu berechnen.
  2. UBRRn wird nur im Datenblatt von ATmega32u4 auf den Seiten 188 und 189 erwähnt. Es sieht so aus, als ob das den Wert von UBRRHn und UBRRLn enthält. Der obige Code scheint zu versuchen, beide gleichzeitig zu setzen, aber als int. Ich bin so verwirrt, muss das nicht in binärer Schreibweise sein?

Nun, ich freue mich darauf, diesen Buckel zu überwinden und meinen LCD-Bildschirm zum Tanzen zu bringen. :)

Es gibt eine Sicherung, die die Systemuhr durch 8 teilt. Ist Ihre aktiviert? Das würde Ihren Takt 2 MHz statt 16 MHz machen. Ich weiß nicht, wie die Sicherungskonfiguration des Teensy im Auslieferungszustand ist. Dies kann Ihnen Kopfschmerzen bereiten, wenn das LCD nicht funktioniert.
Hallo allerseits, aufgrund Ihrer Hilfe bei dieser Frage habe ich den LCD-Bildschirm offiziell zum Laufen gebracht. Vielen Dank, dass du mich über diesen Buckel gebracht hast. Ich bin so glücklich!! Danke.

Antworten (2)

Um all diese Dinge zu verstehen, werfen Sie einen Blick auf "Tabelle 18-1. Gleichungen zur Berechnung der Baudratenregistereinstellung" aus dem Datenblatt auf Seite 189. Die Gleichung, die Sie vorgeschlagen haben, haben Sie in einem Beispielcode gefunden

UBRR1 = (F_CPU / 4 / baud - 1) / 2;

... kommt der Gleichung für den asynchronen Double-Speed-Modus (U2Xn = 1) ziemlich nahe ... aber nicht genau.

Wenn Sie die Baudrate und Quarzgeschwindigkeit kennen, mit der Sie arbeiten möchten, würde ich einfach die Registereinstellungen aus "Tabelle 18-9. Beispiele für UBRRn-Einstellungen für häufig verwendete Oszillatorfrequenzen" auf Datenblatt Seite 210 entnehmen und Schluss machen. Der einzige Grund, eine dieser Gleichungen zu verwenden, ist, wenn Sie die Einstellungen aus irgendeinem Grund zur Laufzeit dynamisch ändern möchten (oder wenn Sie dies "elegant" in der Software tun möchten, bevorzuge ich die Gewissheit der Kompilierzeit für so etwas wie dies, um Zweifel auszuräumen).

Für die Einstellungen, die Sie in Ihrer Frage skizziert haben, wären das:

UCSR1A = 0;                         // importantly U2X1 = 0
UCSR1B = 0;                         // interrupts enabled in here if you like
UCSR1C = _BV(UCSZ11) | _BV(UCSZ10); // no parity, 8 data bits, 1 stop bit
UCSR1D = 0;                         // no cts, no rts
UBRR1  = 103;                       // 9600 baud @ 16MHz XTAL with U2X1 = 0    

Nebenbei bemerkt, während die Hardware das Baudratenregister (UBBRn) als zwei 8-Bit-Register speichert, muss es in der Software nicht als solches behandelt werden. Sie können auf die High- und Low-Register (z. B. UBRR1H bzw. UBRR1L) zugreifen, aber Sie können auch einfach dem benannten "kombinierten" Register zuweisen (oder daraus lesen), als wäre es ein 16-Bit-Register.

UBRR1 = 0x0343;ist funktional äquivalent zuUBRR1H = 0x03; UBRR1L = 0x43;

Hallo Vicatcu, das hilft mir sehr. Es macht Sinn, dass Sie UBRR1 einfach als einzelnes 16-Bit-Register zuweisen könnten. Bedeutet das also, dass ich es auf verschiedene Arten schreiben könnte? UBRRH1 = (Zeichen ohne Vorzeichen)(103>>8); UBRRL1 = (Zeichen ohne Vorzeichen)(103); ODER UBRR1 = 103; ODER UBRR1 = 0x67; ODER UBRR1 = ob00001100111; Angenommen, ich verwende 103 als Baudrateneinstellung. Danke.
@rayjamesfun ja, das stimmt - es ist Compiler-Magie :). Ich würde Sie jedoch ermutigen, die 16-Bit-Zuweisung zu verwenden, da der Compiler "das Richtige tun" sollte, wenn die Reihenfolge der Zuweisung wichtig ist.

Ein unsigned charsollte immer 8 Bit oder ein einzelnes Byte sein. Vergessen Sie, dass es sich um ein "Zeichen" handelt, sondern nur um einen Zahlendatentyp, der die gleiche Größe wie unsere Register hat. Da wir eine Zahl übergeben, die möglicherweise 12 Bit groß sein könnte, akzeptiert unsere Funktion einen Datentyp, der groß genug für baud( unsigned int) ist. Dies kann je nach unserer Architektur entweder 32 oder 16 Bit sein (spielt in diesem Fall keine Rolle).

Für diese Architektur sind unsere UBRRHnund UBRRLnRegister jeweils 1 Byte groß. Wir haben kein einziges Register, das groß genug ist, um diesen 12-Bit-Wert aufzunehmen, also haben wir zwei 8-Bit-Register, und wie Sie erwähnt haben, teilen wir diese 12-Bit-Zahl in jedes auf. UBRRHnnimmt die oberen 4 Bits, während UBRRLndie unteren 8 verwendet werden.

Wir verschieben die unsigned int8 Positionen nach unten, um diese oberen 4 Bits zu erhalten. Nehmen wir ein triviales Beispiel mit allen '1'-Bits:

baud = 4095;
UBRRHn = (unsigned char)(baud>>8);
// our shift: 0b0000111111111111 >> 8 == 0b0000000000001111
// after cast & assignment, UBRRHn == 0b00001111
UBRRLn = (unsigned char)baud;
// after cast & assignment, UBRRLn == 0b11111111

Unsere Umwandlung in unsigned charnimmt die unteren 8 Bits, da unsigned chares sich um einen 8-Bit-Datentyp handelt.

Ich habe keine Zeit, den anderen Beispielcode durchzugehen, aber es könnte sein, dass er zur Kompilierzeit ein Makro oder etwas anderes verwendet, um ihn für ihn aufzuteilen. Sie könnten tiefer graben und herausfinden, wo UBBR1 definiert ist. Wenn Sie ihm nicht vertrauen, verwenden Sie ihn nicht. Tun Sie zuerst das, was Sie für Ihre Hardwarekonfiguration als wahr kennen, und testen Sie es.

Hallo Jon, danke für die Antwort. Macht jetzt viel mehr Sinn.
@rayjamesfun, gut ... danke, dass Sie sich die Zeit genommen haben, das Datenblatt tatsächlich zu lesen. Es ist erfrischend zu sehen, wie jemand gute spezifische Fragen stellt und gleichzeitig sicherstellt, dass er sich auch vorher informiert und sich Mühe gegeben hat.
Danke Jon, das Datenblatt beginnt mir nützlich zu werden und ich fange an zu verstehen, was ich lese. Am Anfang war es sehr langsam, weil ich fast jedes Wort nachschlagen und das Konzept dahinter lernen musste. Ich habe noch eine ziemliche Reise vor mir, aber ihr habt es schon einfacher gemacht. Danke.