Estoy trabajando con un Atmega328p, ejecutando el oscilador interno de 8MHz, dividido por 8 para producir un reloj de 1MHz. Puse los fusibles de acuerdo con la calculadora aquí . Confirmando esto con avrdude:
avrdude -p m328p -c usbasp
avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.00s
avrdude: Device signature = 0x1e950f (probably m328p)
avrdude: safemode: Fuses OK (E:FF, H:D9, L:62)
El tiempo parece ser correcto: parpadear un LED encendido y apagado cada 1000 ms toma ca. 1 segundo, como se esperaba.
Estoy confundido cuando se trata de configurar la comunicación en serie con mi computadora. No importa lo que intente, la conexión está establecida en 1200. El programa que estoy usando es:
#include <avr/io.h>
#include <util/delay.h>
#include <USART.h>
int main(void) {
DDRB |= 0b0000001;
initUSART();
while (1) {
printString("\n\r==== Looping ====\n\r");
PORTB = 0b00000001;
_delay_ms(750);
PORTB = 0b00000000;
_delay_ms(250);
}
return (0);
}
Donde USART es del Elliott Willams '. Incluye lo siguiente:
#include <avr/io.h>
#include "USART.h"
#include <util/setbaud.h>
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 */
}
// more code follows, not included here
Mi Makefile genera los siguientes comandos:
avr-gcc -Os -g -std=gnu99 -Wall -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -ffunction-sections -fdata-sections -DF_CPU=1000000UL -DBAUD=9600UL -I. -I../../AVR-Programming-Library -mmcu=atmega328p -c -o blinkLED.o blinkLED.c
avr-gcc -Wl,-Map,blinkLED.map -Wl,--gc-sections -mmcu=atmega328p blinkLED.o ../../AVR-Programming-Library/USART.o -o blinkLED.elf
avr-objcopy -j .text -j .data -O ihex blinkLED.elf blinkLED.hex
avrdude -c usbasp -p atmega328p -P /dev/ttyACM0 -U flash:w:blinkLED.hex
Baud se establece en el Makefile, en este caso a 9600UL. Si lo pongo a 19200UL, todo funciona igual. En cualquier caso, todo se comporta como debería, pero cuando me conecto a la línea serie de mi computadora (a través de screen /dev/ttyUSB0
), la salida está distorsionada a menos que especifique BAUD = 1200. (es decir, screen /dev/ttyUSB0 1200
).
He estado luchando en un montón de páginas web, el libro de Williams y la hoja de datos de atmega, pero todavía no entiendo esto. ¿Se ha fijado la velocidad de transmisión para este chip? Si no, ¿cómo lo configuro a una tasa superior a 1200?
En este punto, en realidad necesito hacerlo más alto, pero me gustaría entender cómo se supone que funciona y en qué me estoy equivocando.
Actualizar
Tenga en cuenta que he establecido explícitamente BAUD y F_CPU con los indicadores avr-gcc: -DF_CPU=1000000UL -DBAUD=9600UL
. Incluso si configuro estas macros en el código (como #define BAUD 9600UL
y #define F_CPU 1000000UL
como las primeras líneas en el archivo, todavía estoy atascado con BAUD de 1200.
Actualización 2
He aislado el problema al archivo setbaud.h. Si configuro la velocidad en baudios 'a mano', es decir, utilizando el siguiente código en lugar de la llamada a initUSART();
anterior, funciona como se esperaba: el BAUD está configurado correctamente en 9600. Esto establece el valor de preescala en 12 (0b00001100 ) y habilita USE_2X. Así que mi problema debe ser que estoy usando setbaud.h
de manera incorrecta, pero no puedo ver cómo.
UBRR0H = 0;
UBRR0L = 0b00001100;
UCSR0A |= (1 << U2X0);
/* Enable USART transmitter/receiver */
UCSR0B = (1 << TXEN0) | (1 << RXEN0);
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); /* 8 data bits, 1 stop bit */