Estoy aprendiendo programación AVR utilizando este libro
Pude ejecutar y obtener salida usando el código provisto junto con el libro. Uso Proteus para simular la salida, ya que no tengo el controlador en la mano.
Hoy traté de escribir un programa UART simple usando la hoja de datos.
/*
* uart.c
*
* Created: 05-09-2018 09:55:36 PM
* Author : New User
*/
#include <avr/io.h>
#include <util/delay.h>
int main(void)
{
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
UBRR0L = 6;
char data;
while (1)
{
while (!(UCSR0A & (1<<RXC0)));
data = UDR0;
while (!(UCSR0A & (1<<UDRE0)));
UDR0 = data;
}
}
Cuando simulo código en Proteus obtengo caracteres extraños en la terminal virtual:
Primeropenséquepodríadeberseaunerrorenlavelocidaddetransmisión.
Segúntengoentendido,laF_CPUpredeterminadadeATMega168esde1MHzsinousoningúnosciladordecristalexterno.Entonces,paraunatasadebaudiosde9600,U0BRR=6deestaecuación:
U0BRR=(F_CPU/(16*9600))-1=(1000000/16*9600)-1=5.51~6
Tambiénenlahojadedatos,U0BRRes6paraunavelocidadenbaudiosde9600conrelojde1MHz.
Entonces,¿quéestápasandoaquí?
IDE:AtmelStudio7
AquíestámiconfiguracióndeProteus:
¿HayalgoquedebacambiarenProteus?
Despuésdeverificarelcódigodetrabajoquevieneconellibro,utilizaunarchivodeencabezadoavr/setbaud.h
.
Siagregocódigodeesearchivodeencabezado,micódigoactualseveráasí(enlugardeagregarelarchivodeencabezado,uséelcódigocompletodirectamenteparaunamejorcomprensión)
#include<avr/io.h>#defineF_CPU1000000UL#ifndefBAUD#defineBAUD9600#endif/*Baudratetoleranceis2%unlesspreviouslydefined*/#ifndefBAUD_TOL#defineBAUD_TOL2#endif#ifdef__ASSEMBLER__#defineUBRR_VALUE(((F_CPU)+8*(BAUD))/(16*(BAUD))-1)#else#defineUBRR_VALUE(((F_CPU)+8UL*(BAUD))/(16UL*(BAUD))-1UL)#endif#if100*(F_CPU)>\(16*((UBRR_VALUE)+1))*(100*(BAUD)+(BAUD)*(BAUD_TOL))#defineUSE_2X1#elif100*(F_CPU)<\(16*((UBRR_VALUE)+1))*(100*(BAUD)-(BAUD)*(BAUD_TOL))#defineUSE_2X1#else#defineUSE_2X0#endif#ifUSE_2X/*U2Xrequired,recalculate*/#undefUBRR_VALUE#ifdef__ASSEMBLER__#defineUBRR_VALUE(((F_CPU)+4*(BAUD))/(8*(BAUD))-1)#else#defineUBRR_VALUE(((F_CPU)+4UL*(BAUD))/(8UL*(BAUD))-1UL)#endif#if100*(F_CPU)>\(8*((UBRR_VALUE)+1))*(100*(BAUD)+(BAUD)*(BAUD_TOL))#warning"Baud rate achieved is higher than allowed"
#endif
#if 100 * (F_CPU) < \
(8 * ((UBRR_VALUE) + 1)) * (100 * (BAUD) - (BAUD) * (BAUD_TOL))
# warning "Baud rate achieved is lower than allowed"
#endif
#endif /* USE_U2X */
#ifdef UBRR_VALUE
/* Check for overflow */
# if UBRR_VALUE >= (1 << 12)
# warning "UBRR value overflow"
# endif
# define UBRRL_VALUE (UBRR_VALUE & 0xff)
# define UBRRH_VALUE (UBRR_VALUE >> 8)
#endif
int main(void) {
UBRR0H = UBRRH_VALUE;
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 data;
// ------ Event loop ------ //
while (1) {
while (!(UCSR0A & (1<<RXC0)));
data = UDR0;
while (!(UCSR0A & (1<<UDRE0)));
UDR0 = data;
} /* End event loop */
return 0;
}
Hay una variable llamada BAUD_TOL
a la que se le asigna un valor como tolerancia permitida de la velocidad de transmisión especificada, es decir, 9600
Primero, calculará el valor U0BRR usando esta ecuación
U0BRR = (F_CPU/(16 * 9600)) - 1
==>U0BRR = (1000000/(16*9600))-1
esta es la parte donde calcula U0BRR
#define UBRR_VALUE (((F_CPU) + 8UL * (BAUD)) / (16UL * (BAUD)) -1UL)
Esto le dará U0BRR = 6
y luego usará este valor para calcular la velocidad en baudios (esta es nuestra velocidad en baudios calculada) y compararlo con la velocidad en baudios deseada (9600). Si la diferencia es mayor que la permitida ( BAUD_TOL
), se establecerá USE_2X = 1
.
Según la hoja de datos
Bit 1 -
U2Xn
: Duplica la velocidad de transmisión de USART Este bit solo tiene Efecto para la operación asíncrona. Escribe este bit a cero cuando utilizando la operación síncrona. Escribir este bit a uno reducirá la divisor del divisor de velocidad en baudios de 16 a 8, lo que duplica el Velocidad de transferencia para la comunicación asíncrona.
Luego recalcular U0BRR usando
U0BRR = (F_CPU/(8 * 9600)) - 1
==>U0BRR = (1000000/(8*9600))-1
Ver 16 de la ecuación anterior cambió a 8.
Luego verificará si tiene una desviación de más del 2%. Si lo hay, se activará un error o una advertencia.
Y en la función main()
establecerá U2X0
de UCSR0A
en 1
Por lo tanto, el código anterior puede reducirse aún más a
#include <avr/io.h>
#define F_CPU 1000000UL
#define BAUD 9600
#define UBRR_VALUE (((F_CPU) + 4UL * (BAUD)) / (8UL * (BAUD)) -1UL)
#define UBRRL_VALUE UBRR_VALUE
int main(void) {
// -------- Inits --------- //
UBRR0L = UBRRL_VALUE;
UCSR0A |= (1 << U2X0);
UCSR0B = (1 << TXEN0) | (1 << RXEN0);
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
// ------ Event loop ------ //
char data;
while (1) {
while (!(UCSR0A & (1<<RXC0)));
data = UDR0;
while (!(UCSR0A & (1<<UDRE0))); /* Wait for incoming data */
UDR0 = data;
}
return 0;
}
Tengo algunas dudas sobre esto. Acerca de la forma en que se encuentra la tasa de baudios de verificación de códigos en el rango aceptable y cuál es la tasa de baudios final después de habilitar U2X
No sé si puedo preguntarlo aquí.