Estoy usando un cable FTDI y lo conecté con mi mac. Puedo conectarme con éxito con mi terminal serial en mi mac a través del cable y puedo ingresar texto en mi teclado para transmitirlo al AVR. Cuando se inicia el programa, espero que aparezca un mensaje "Hello World" en mi terminal serie. Pero en cambio, recibo este resultado en la pantalla:
ingrese la descripción de la imagen aquí
El código es este:
// ------- 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;
}
El archivo USART.c contiene:
#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');
}
Me encontré con este mismo problema, y la respuesta proporcionada por @bence_kaulics es lo que me ayudó a superarlo, con un punto adicional:
Estoy en la misma situación que @secs360:
Primero, confirme que he configurado el reloj correctamente:
Fusibles correctos (E:FF, H:D9, L:62)
Al compararlos con una calculadora de fusibles , veo que son los valores predeterminados: la MCU está configurada para usar el oscilador RC interno a 1 MHz.
Esto significa que debo configurar la velocidad de la CPU (en el archivo MAKE para los ejercicios del capítulo en este caso):
F_CPU = 1000000UL
También puedo configurar el valor BAUD en la misma ubicación. 9600 debería funcionar:
BAUD = 9600UL
Hasta ahora, todo bien. Sin embargo, el libro usa una fórmula diferente para calcular los valores del registro UBRRn. @bence_kaulics proporciona la fórmula, de la hoja de datos.
(¿Tal vez la diferencia se deba a que el libro se escribió para chips atmega168? No lo sé. Pero cualquiera que sea la fuente, necesitamos usar el valor correcto aquí).
¡Hay un dato más! Si queremos usar 9600 BAUD, tendremos un error de -7% con velocidad de transmisión estándar, según la hoja de datos. Si duplicamos la velocidad de transmisión, nuestro error baja al 0,2%. Para hacer esto, no usamos la fórmula provista por @bence_kaulics, sino que usamos ((F_CPU)/(BAUD*8UL)-1)
y configuramos el U2X0
bit.
Lo hice modificando la initUSART
función en el archivo USART.c:
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 */
}
La versión original del libro usa la lógica en el archivo setbaud.h para determinar si duplicar o no la velocidad de transmisión. No lo entiendo todo, por lo que no estoy seguro de si el problema es la fórmula utilizada para BAUDRATE
, o USE_2X
, o para ambos. Sea lo que sea, el código anterior finalmente hizo que mi atmega328p hablara correctamente a través de la interfaz serial.
El primer paso debe ser verificar la configuración de su reloj. Usted dijo que no hay cristal externo, y su código definitivamente se ejecuta ahora, por lo que los bits del fusible CKSEL [3: 0] son ciertamente 0010
, el oscilador RC interno está seleccionado. Tablas tomadas de la hoja de datos .
Ahora, revisa también el bit del fusible CKDIV8, para saber si el oscilador RC interno está dividido por 8 o no.
Está programado de forma predeterminada, por lo que si nunca ha tocado los bits del fusible, su MCU probablemente funcione en 1 MHz.
Si CKDIV8 es 0, defina la frecuencia de su CPU de la siguiente manera:
#define F_CPU 1000000UL
y si es 1, entonces:
#define F_CPU 8000000UL
El siguiente paso es calcular el valor del registro de tasa BAUD, que se puede hacer con las siguientes macros.
#define BAUD 9600 // desired baud
#define BAUDRATE ((F_CPU)/(BAUD*16UL)-1) // set baud rate value for UBRR
Esto le dará el valor correcto en BAUDRATE
. La ecuación se da en la hoja de datos.
En su función de inicio de UART, pase esto a los UBBRH
registros UBBRL
.
UBRR0H = (BAUDRATE>>8); // shift the register right by 8 bits to get the upper 8 bits
UBRR0L = BAUDRATE; // set baud rate
La solución será cualquiera de las siguientes
tom carpintero
Marko Bursic
sesc360
Rohat Kılıç
Pau Coma Ramírez
sesc360
tom carpintero
sesc360
olin lathrop
Bence Kaulics
Pau Coma Ramírez
sesc360
sesc360
Pau Coma Ramírez
sesc360
#define BAUD 9600
en la parte superior de USART.cPau Coma Ramírez
sesc360
Pau Coma Ramírez
cuervo
cuervo