Cómo establecer la velocidad en baudios para la comunicación en serie en ATmega32u4

Tengo una placa Teensy 2.0 y estoy tratando de usarla para controlar esta pantalla LCD a través de TTL en serie.

Conseguí que funcionara bien con mi Arduino uno y un código Arduino de muestra, pero quiero hacerlo con el lenguaje Teensy y C.

El adolescente usa el ATmega32u4 y aquí está la hoja de datos de ese chip.

En la hoja de datos, a partir de la página 186, está la sección sobre USART. En la página 192 hay un ejemplo de código de lenguaje C sobre cómo inicializar el USART. Estoy confundido en un par de líneas y me vendría bien un poco de ayuda.

void USART_Init( unsigned int baud )
{
  /* Set baud rate */
  UBRRHn = (unsigned char)(baud>>8);
  UBRRLn = (unsigned char)baud;

  /*rest of code here*/
}

Primero, no tengo claro cuál debería ser el número de velocidad en baudios. Mi LCD pide 9600 baudios con 1 bit de inicio, 1 bit de parada, sin bit de paridad y 8 bits de datos. En la página 189 de la hoja de datos del ATmega32u4, hice el cálculo de cuál debería ser la velocidad en baudios, que en el caso de la combinación de diminuto y LCD debería ser 103 porque la frecuencia del chip es 16 MHz y la velocidad en baudios es 9600. Esto también coincide con el número en el gráfico en la página 213 de la hoja de datos del ATmega32u4. Entonces, ¿es este el número correcto que se pasaría a la función USART_Init para la variable baudios?

También estoy confundido con las dos líneas que establecen la velocidad en baudios. Entiendo que, según la página 209 de la hoja de datos del ATmega32u4, los registros de velocidad en baudios se dividen en un registro bajo y alto, pero solo se usan los bits 8:10 en el registro alto, lo que lo convierte en un registro combinado de 12 bits. Entonces, volviendo al código, no entiendo algunas cosas:

  1. ¿Por qué se está encasillando en un carácter sin firmar porque asumo que UBRRHn debería estar en notación binaria?
  2. Tampoco entiendo la parte (baudios>>8) porque si completas 103 para baudios, obtienes (103>>8) y eso no es correcto. ¿Alguien puede explicarme esta línea? Gracias.
UBRRHn = (unsigned char)(baud>>8);<br/>
UBRRLn = (unsigned char)baud;
  1. ¿Debería ser baudios la versión binaria de 12 bits de 103, que es 00001100111? Si es así, ¿cómo se escribiría el código?

Además, encontré un código de muestra (http://www.pjrc.com/teensy/uart.html) en el sitio web de Teensy que configura el UART y configura la velocidad en baudios de esta manera:

void uart_init(uint32_t baud)
{
    cli();
    UBRR1 = (F_CPU / 4 / baud - 1) / 2;

    /*rest of code here*/
}

Si conecto los números se vería así:

UBRR1 = (16000000 / 4 / 9600 - 1) / 2; /* Which would equal 208 */
  1. El numero 208 es diferente al 103 asi que no entiendo de donde sacan la ecuacion para calcularlo.
  2. UBRRn solo se menciona en la hoja de datos de ATmega32u4 en las páginas 188 y 189. Parece que tiene el valor de UBRRHn y UBRRLn. El código anterior parece estar tratando de configurar ambos al mismo tiempo pero como un int. Estoy tan confundido, ¿no es necesario que esté en notación binaria?

Bueno, tengo muchas ganas de superar este bache y pasar a hacer que mi LCD baile. :)

Hay un fusible que divide el reloj del sistema por 8. ¿El tuyo está habilitado? Eso haría que su reloj sea de 2 MHz en lugar de 16 MHz. No sé cuál es la configuración de fusibles de Teensy tal como se envió. Esto podría ser una causa de dolor de cabeza para usted si la pantalla LCD no funciona.
Hola a todos, gracias a su ayuda con esta pregunta, oficialmente logré que la pantalla LCD funcionara. Muchas gracias por ayudarme a superar ese obstáculo. ¡¡Estoy tan feliz!! Gracias.

Respuestas (2)

Para comprender todo esto, eche un vistazo a la "Tabla 18-1. Ecuaciones para calcular la configuración del registro de velocidad en baudios" de la hoja de datos en la página 189. La ecuación que sugirió que encontró en algún código de ejemplo

UBRR1 = (F_CPU / 4 / baud - 1) / 2;

... está un poco cerca de la ecuación para el modo asíncrono de doble velocidad (U2Xn = 1)... pero no exactamente.

Si conoce la velocidad en baudios y la velocidad del cristal a la que pretende operar, simplemente sacaría la configuración del registro de la "Tabla 18-9. Ejemplos de configuración UBRRn para frecuencias de oscilador de uso común" en la página 210 de la hoja de datos y lo llamaría un día. La única razón para usar cualquiera de esas ecuaciones es si desea poder cambiar la configuración dinámicamente en tiempo de ejecución por algún motivo (o si desea hacer cosas "elegantes" en el software, prefiero compilar la certeza del tiempo para algo como esto para quitar dudas).

Para la configuración que describió en su pregunta, eso sería:

UCSR1A = 0;                         // importantly U2X1 = 0
UCSR1B = 0;                         // interrupts enabled in here if you like
UCSR1C = _BV(UCSZ11) | _BV(UCSZ10); // no parity, 8 data bits, 1 stop bit
UCSR1D = 0;                         // no cts, no rts
UBRR1  = 103;                       // 9600 baud @ 16MHz XTAL with U2X1 = 0    

Como nota al margen, mientras que el hardware almacena el registro de velocidad en baudios (UBBRn) como dos registros de 8 bits, en el software no es necesario tratarlo como tal. Puede acceder a los registros Alto y Bajo (por ejemplo, UBRR1H y UBRR1L respectivamente), pero también puede asignar (o leer) el registro "combinado" nombrado como si fuera un registro de 16 bits .

UBRR1 = 0x0343;es funcionalmente equivalente aUBRR1H = 0x03; UBRR1L = 0x43;

Hola vicatcu, Eso me ayuda mucho. Tiene sentido que simplemente pueda asignar UBRR1 como un único registro de 16 bits. Entonces, ¿eso significa que podría escribirlo de varias maneras? UBRRH1 = (carácter sin signo)(103>>8); UBRRL1 = (carácter sin signo)(103); O UBRR1 = 103; O UBRR1 = 0x67; O UBRR1 = ob00001100111; Suponiendo que estoy usando 103 como configuración de velocidad en baudios. Gracias.
@rayjamesfun sí, así es, es la magia del compilador :). Sin embargo, lo alentaría a usar la asignación de 16 bits, ya que el compilador debería "hacer lo correcto" si el orden de asignación es importante.

Un unsigned chardebe ser siempre de 8 bits o de un solo byte. Olvídese de que es un 'carácter' sino más bien un tipo de dato numérico que tiene el mismo tamaño que nuestros registros. Dado que estamos pasando un número que posiblemente podría tener un tamaño de 12 bits, nuestra función acepta un tipo de datos que es lo suficientemente grande para baud( unsigned int). Esto podría ser de 32 o 16 bits (no importa en este caso) dependiendo de nuestra arquitectura.

Para esta arquitectura, nuestros registros UBRRHny UBRRLnson de 1 byte cada uno. No tenemos un solo registro que sea lo suficientemente grande para tomar ese valor de 12 bits, por lo que tenemos dos registros de 8 bits y, como mencionaste, dividimos ese número de 12 bits en cada uno. UBRRHntoma los 4 bits superiores, mientras que UBRRLntoma los 8 inferiores.

Desplazamos las unsigned int8 posiciones hacia abajo para obtener esos 4 bits superiores. Tomemos un ejemplo trivial con todos los bits '1':

baud = 4095;
UBRRHn = (unsigned char)(baud>>8);
// our shift: 0b0000111111111111 >> 8 == 0b0000000000001111
// after cast & assignment, UBRRHn == 0b00001111
UBRRLn = (unsigned char)baud;
// after cast & assignment, UBRRLn == 0b11111111

Nuestro elenco unsigned chartomará los 8 bits inferiores ya que unsigned chares un tipo de datos de 8 bits.

No tengo tiempo para repasar el otro código de muestra, pero podría ser que esté usando alguna macro o algo así en tiempo de compilación para dividirlo por él. Puede profundizar más y encontrar dónde se define UBBR1. Si no confías en él, no lo uses. Primero haga lo que sabe que es cierto para su configuración de hardware y pruébelo.

Hola Jon, gracias por la respuesta. Tiene mucho más sentido ahora.
@rayjamesfun, bueno... gracias por tomarse el tiempo de leer la hoja de datos. Es refrescante ver a alguien hacer buenas preguntas específicas mientras se asegura de que también se haya informado de antemano y haya hecho un esfuerzo.
Gracias Jon, la hoja de datos me está empezando a ser útil y estoy empezando a entender lo que estoy leyendo. Fue muy lento al principio porque tuve que buscar casi cada palabra y aprender el concepto detrás de ella. Todavía tengo un buen viaje, pero ustedes ya lo han hecho más fácil. Gracias.