ATMega168 UART caracteres extraños

0

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í.

    
pregunta Athul

0 respuestas

Lea otras preguntas en las etiquetas