Ich verwende ein FTDI-Kabel und verbinde es mit meinem Mac. Ich kann mich über das Kabel erfolgreich mit meinem seriellen Terminal auf meinem Mac verbinden und Text auf meiner Tastatur eingeben, der an den AVR übertragen werden soll. Wenn das Programm startet, erwarte ich, dass eine "Hello World"-Meldung auf meinem seriellen Terminal erscheint. Aber stattdessen erhalte ich diese Ausgabe auf dem Bildschirm:
Die Terminaleinstellungen sind
Geben Sie hier die Bildbeschreibung ein
Der Code ist dieser:
// ------- Preamble -------- //
#include <avr/io.h>
#include <util/delay.h>
#include "pinDefines.h"
#include "USART.h"
int main(void) {
char serialCharacter;
// -------- Inits --------- //
LED_DDR = 0xff; /* set up LEDs for output */
initUSART();
printString("Hello World!\r\n"); /* to test */
// ------ Event loop ------ //
while (1) {
serialCharacter = receiveByte();
transmitByte(serialCharacter);
LED_PORT = serialCharacter;
/* display ascii/numeric value of character */
} /* End event loop */
return 0;
}
Die USART.c-Datei enthält:
#include <avr/io.h>
#include "USART.h"
#include <util/setbaud.h>
#define BAUD 9600
void initUSART(void) { /* requires BAUD */
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 */
}
void transmitByte(uint8_t data) {
/* Wait for empty transmit buffer */
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = data; /* send data */
}
uint8_t receiveByte(void) {
loop_until_bit_is_set(UCSR0A, RXC0); /* Wait for incoming data */
return UDR0; /* return register value */
}
/* Here are a bunch of useful printing commands */
void printString(const char myString[]) {
uint8_t i = 0;
while (myString[i]) {
transmitByte(myString[i]);
i++;
}
}
void readString(char myString[], uint8_t maxLength) {
char response;
uint8_t i;
i = 0;
while (i < (maxLength - 1)) { /* prevent over-runs */
response = receiveByte();
transmitByte(response); /* echo */
if (response == '\r') { /* enter marks the end */
break;
}
else {
myString[i] = response; /* add in a letter */
i++;
}
}
myString[i] = 0; /* terminal NULL character */
}
void printByte(uint8_t byte) {
/* Converts a byte to a string of decimal text, sends it */
transmitByte('0' + (byte / 100)); /* Hundreds */
transmitByte('0' + ((byte / 10) % 10)); /* Tens */
transmitByte('0' + (byte % 10)); /* Ones */
}
void printWord(uint16_t word) {
transmitByte('0' + (word / 10000)); /* Ten-thousands */
transmitByte('0' + ((word / 1000) % 10)); /* Thousands */
transmitByte('0' + ((word / 100) % 10)); /* Hundreds */
transmitByte('0' + ((word / 10) % 10)); /* Tens */
transmitByte('0' + (word % 10)); /* Ones */
}
void printBinaryByte(uint8_t byte) {
/* Prints out a byte as a series of 1's and 0's */
uint8_t bit;
for (bit = 7; bit < 255; bit--) {
if (bit_is_set(byte, bit))
transmitByte('1');
else
transmitByte('0');
}
}
char nibbleToHexCharacter(uint8_t nibble) {
/* Converts 4 bits into hexadecimal */
if (nibble < 10) {
return ('0' + nibble);
}
else {
return ('A' + nibble - 10);
}
}
void printHexByte(uint8_t byte) {
/* Prints a byte as its hexadecimal equivalent */
uint8_t nibble;
nibble = (byte & 0b11110000) >> 4;
transmitByte(nibbleToHexCharacter(nibble));
nibble = byte & 0b00001111;
transmitByte(nibbleToHexCharacter(nibble));
}
uint8_t getNumber(void) {
// Gets a numerical 0-255 from the serial port.
// Converts from string to number.
char hundreds = '0';
char tens = '0';
char ones = '0';
char thisChar = '0';
do { /* shift over */
hundreds = tens;
tens = ones;
ones = thisChar;
thisChar = receiveByte(); /* get a new character */
transmitByte(thisChar); /* echo */
} while (thisChar != '\r'); /* until type return */
return (100 * (hundreds - '0') + 10 * (tens - '0') + ones - '0');
}
Ich bin auf dasselbe Problem gestoßen, und die Antwort von @bence_kaulics hat mich durchgebracht, mit einem zusätzlichen Punkt:
Ich bin in der gleichen Situation wie @secs360:
Bestätigen Sie zuerst, dass ich die Uhr richtig eingestellt habe:
Sicherungen OK (E:FF, H:D9, L:62)
Wenn ich diese mit einem Sicherungsrechner vergleiche , sehe ich, dass es sich um die Standardwerte handelt: Die MCU ist so eingestellt, dass sie den internen RC-Oszillator bei 1 MHz verwendet.
Das heißt, ich sollte die CPU-Geschwindigkeit einstellen (in diesem Fall im Makefile für die Kapitelübungen):
F_CPU = 1000000UL
Ich kann auch den BAUD-Wert an derselben Stelle einstellen. 9600 sollte funktionieren:
BAUD = 9600UL
So weit, ist es gut. Das Buch verwendet jedoch eine andere Formel zur Berechnung der UBRRn-Registerwerte. @bence_kaulics liefert die Formel aus dem Datenblatt.
(Vielleicht liegt der Unterschied daran, dass das Buch für atmega168-Chips geschrieben wurde? Ich weiß es nicht. Aber unabhängig von der Quelle müssen wir hier den richtigen Wert verwenden.)
Es gibt noch eine Information! Wenn wir 9600 BAUD verwenden wollen, haben wir laut Datenblatt bei Standard-Übertragungsgeschwindigkeit einen Fehler von -7%. Wenn wir die Übertragungsgeschwindigkeit verdoppeln, sinkt unser Fehler auf 0,2 %. Dazu verwenden wir nicht die von @bence_kaulics bereitgestellte Formel, sondern verwenden stattdessen ((F_CPU)/(BAUD*8UL)-1)
, und setzen das U2X0
Bit.
Ich habe das getan, indem ich die initUSART
Funktion in der Datei USART.c geändert habe:
void initUSART(void) { /* requires BAUD */
#define BAUDRATE ((F_CPU)/(BAUD*8UL)-1) // set baud rate value for UBRR
UBRR0H = (BAUDRATE>>8); // shift the register right by 8 bits to get the upper 8 bits
UBRR0L = BAUDRATE; // set baud rate
UCSR0A |= (1 << U2X0); // double transmission speed
/* Enable USART transmitter/receiver */
UCSR0B = (1 << TXEN0) | (1 << RXEN0);
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); /* 8 data bits, 1 stop bit */
}
Die Originalversion aus dem Buch verwendet Logik in der Datei setbaud.h, um zu bestimmen, ob die Übertragungsgeschwindigkeit verdoppelt werden soll oder nicht. Ich verstehe nicht alles und bin mir daher nicht sicher, ob das Problem an der Formel liegt, die für , BAUDRATE
oder USE_2X
, oder beide verwendet wird. Was auch immer es ist, der obige Code hat meinen atmega328p endlich dazu gebracht, richtig über die serielle Schnittstelle zu sprechen.
Der erste Schritt sollte die Überprüfung Ihrer Uhrenkonfiguration sein. Sie sagten, es gibt keinen externen Kristall, und Ihr Code wird jetzt definitiv ausgeführt, sodass die Sicherungsbits CKSEL [3: 0] sicher sind 0010
, der interne RC-Oszillator ist ausgewählt. Tabellen aus dem Datenblatt .
Überprüfen Sie nun auch das Fuse-Bit CKDIV8, um zu wissen, ob der interne RC-Oszillator durch 8 geteilt ist oder nicht.
Es ist standardmäßig programmiert. Wenn Sie also noch nie die Sicherungsbits berührt haben, läuft Ihre MCU wahrscheinlich mit 1 MHz.
Wenn CKDIV8 0 ist, definieren Sie Ihre CPU-Frequenz wie folgt:
#define F_CPU 1000000UL
und wenn es 1 ist, dann:
#define F_CPU 8000000UL
Der nächste Schritt ist die Berechnung des Wertes des BAUD-Ratenregisters, was mit den folgenden Makros erfolgen kann.
#define BAUD 9600 // desired baud
#define BAUDRATE ((F_CPU)/(BAUD*16UL)-1) // set baud rate value for UBRR
Dadurch erhalten Sie den korrekten Wert in BAUDRATE
. Gleichung ist im Datenblatt angegeben.
Übergeben Sie dies in Ihrer UART-Init-Funktion an die Register UBBRH
und UBBRL
.
UBRR0H = (BAUDRATE>>8); // shift the register right by 8 bits to get the upper 8 bits
UBRR0L = BAUDRATE; // set baud rate
Die Lösung wird eine der folgenden sein
Tom Tischler
Marko Buršič
sesc360
Rohat Kılıç
Pau Coma Ramírez
sesc360
Tom Tischler
sesc360
Olin Lathrop
Bence Kaulics
Pau Coma Ramírez
sesc360
sesc360
Pau Coma Ramírez
sesc360
#define BAUD 9600
oben in der USART.c hinzugefügtPau Coma Ramírez
sesc360
Pau Coma Ramírez
Krähe
Krähe