Es común encontrar en la
mayoría de los microcontroladores una o varias usart (el Arduino
Mega lleva 4), sirven para transmitir datos en serie entre varios
dispositivos, un micro con otro micro, micro con el pc (RS232 puerto
serie), etc.. La principal diferencia con protocolos como el spi o el
i2c, es que la usart (uart en este caso) no necesita un pin de
señal de reloj entre ambos dispositivos para realizar la
comunicación. Cada dispositivo se pone de acuerdo en la
velocidad a la que se va a realizar la transmisión (se fija la
velocidad), y después de una condición de inicio cada
dispositivo muestrea los bits en el tiempo acordado, por lo que
sólo son necesarios dos pines para que el micro pueda enviar y
recibir datos.
En el siguiente paso del proyecto MiniZ se requiere transmitir datos al
pc para muestrear la respuesta del servomotor de dirección y
poder calcular su regulador, para ello se va a utilizar la usart.
La mayoría de los pcs ya no tienen puerto serie, que es el usado
para comunicarnos con la usart del micro mediante el protocolo RS232,
el Arduino Mega para soluccionar este inconveniente lleva un integrado FTDI232, que se encarga de convertir RS232 a USB. Una vez conectada la placa del Arduino Mega e instalados los drivers del FTDI232
podemos ver nuestro puerto usb convertido en uno serie (com) en el pc,
y por tanto seleccionarlo para una comunicación micro-pc
mediante programas como Hyperterminal.
Para poder realizar la comunicación, los dispositivos que se
vayan a comunicar deben conocer varios aspectos de ésta. El
primero es la velocidad a la que se va a realizar, es decir a
qué baudios se va a realizar la transmisión. La
comunicación comienza con una señal de Start, seguida de
los bits a enviar, y se pueden seleccionar entre 5 y 9 bits a mandar,
después tenemos que seleccionar si va a haber un bit de paridad
para comprobar errores y por último si tenemos uno o dos bits de
Stop. Estos parámetros han de estar configurados de igual manera
en los dos dispositivos que se van a comunicar.
Se va a realizar una comunicación asíncrona para
comunicarnos con el pc a través del integrado FTDI, por lo que
sólo necesitaremos dos pines del micro (RX y TX). Lo primero es determinar
la velocidad de transmisión, que utiliza el reloj del
microcontrolador, en este caso tenemos un reloj de 16 MHz.
Cada X tiempo una vez recibida la señal de Start el micro lee o
escribe los unos y los ceros, así con cada bit hasta recibir el
Stop. Este tiempo está determinado por el valor que almacenemos
en el registro del microcontrolador UBRRn, es un registro de 16 bits
dividido en dos de 8 bits, UBRRL y UBRRH, y lo primero es calcular este
valor. Para ello encontramos la siguiente fórmula en el
datasheet.
BAUD son los bits por segundo que queremos mandar y fosc es la
frecuencia del cristal externo que colocamos para generar la
señal de reloj del microcontrolador, el resultado de esta
operación será almacenado en el registro UBRRn, y
determinará la velocidad de las transmisión.
El problema es que el reloj del sistema no puede ser dividido por un
número (16BAUD) que de un resultado exacto si este reloj no es
múltiplo de una frecuencia determinada (1843200 Hz), por lo que
siempre vamos a obtener un pequeño error. Si tenemos un reloj de
16 MHz y queremos un BAUD de 9600 bps (tenemos que elegir entre unas
velocidades ya establecidas para comunicarnos con el pc), el valor a
almacenar en UBRRn obtenido en la fórmula es 103.166, en UBRRn
sólo podemos almacenar un número entero, por lo que si
almacenamos 103 cometemos un error del 0.16%, errores menores de +- 2%
son aceptables según Atmel para una comunicación de 8
bits, cuanto mayor sea el error menos fiable es la comunicación,
en cada bit de Start se sincroniza el reloj.
Error máximo recomendando en función del número de bits a enviar + bit de paridad.
No podemos utilizar un cristal que nos produzca un error mayor que los
recomendados en la tabla, ya que puede dar lugar a comunicaciones
erróneas.
Error para un cristal de 16 MHz en función de la velocidad seleccionada.
Copiando el datasheet encontramos el siguiente código en C para establecer el valor del registro UBRRn:
void USART_Init( unsigned int ubrr){
/* Set baud rate */
UBRRH = (unsigned char)(ubrr>>8);
UBRRL = (unsigned char)ubrr;
/* Enable receiver and transmitter */
UCSRB = (1<<RXEN)|(1<<TXEN);
/* Set frame format: 8data, 2stop bit */
UCSRC = (1<<USBS)|(3<<UCSZ0);
} // USART_Init
Por lo que sólo tendremos que establecer la frecuencia de
nuestro cristal en el primer #define, a las dos últimas
instrucciones aún no se ha llegado. Poniendo los defines podemos
cambiar facilmente el BAUD sin necesidad de hacer cálculos ni
poner números mágicos, el resultado de la fórmula
lo pasamos en MYUBRR a la función y ésta lo almacena en
los dos registros de 8 bits que forman el registro de 16 UBRR.
UCSRB = (1<<RXEN)|(1<<TXEN);
/* Set frame format: 8data, 2stop bit */
UCSRC = (1<<USBS)|(3<<UCSZ0);
Con
las dos últimas instrucciones acabamos de configurar la USART
para una comunicación no basada en interrupciones, la primera
habilitaría los módulos de transmisión y
recepción de la USART, pasando los pines TXn y RXn del
microcontrolador a realizar esta actividad. La segunda configura el
frame que vamos a usar, es decir el número de bits, bit de
paridad, stop, se verán las distintas opciones más
adelante.
Una vez que se ha inicializado la USART enviar y recibir datos es muy
sencillo, sólo hay que leer y escribir en un registro para que
comience la transmisión, y comprobar los flags que indican que
ésta se ha realizado.
Para transmitir un dato podemos ver el siguiente código de ejemplo en el datasheet:
void USART_Transmit( unsigned char data ) { /* Wait for empty transmit buffer */ while ( !( UCSRnA & (1<<UDREn)) ) ; /* Put data into buffer, sends the data */ UDRn = data; }
Tenemos que escribir un dato en el registro UDRn,
comprobando antes que el registro esté libre, es decir que si
estaba transmitiendo un dato, comprobar que la transmisión ya haya finalizado.
Para recibir un dato lo hacemos de igual forma, sólo tenemos que
leer este registro cuando nos indiquen que ha llegado un dato.
unsigned char USART_Receive( void ) { /* Wait for data to be received */ while ( !(UCSRnA & (1<<RXCn)) ) ; /* Get and return received data from buffer */ return UDRn; }
El registro UDRn tiene un doble buffer y se comporta de manera
diferente cuando escribimos en el (mandamos el dato cargado por el pin TX) que
cuando leemos (leemos el dato recibido por el pin RX).
En el microcontrolador encontramos los siguientes registros
relacionados con la USART que debemos configurar para realizar una
transmisión. Se van a comentar para una comuniación
asíncrona sin interrupciones.
El registro anteriormente comentado, donde escribimos el dato a mandar
y leemos el dato recibido. Para transmisiones de 5, 6 y 7 bits, los
bits superiores son ignorados por TX cuando los enviamos, y son
leídos como cero en el dato recibido.
Bit 7 - RXCn: USART Receive Complete: se pone a uno cuando hay datos
sin leer en el buffer de entrada (UDRn) y se pone a cero cuando
está vacío.
Bit 6 – TXCn: USART Transmit Complete: se pone a uno cuando todos
los datos cargados en el buffer de salida (UDRn) han sido enviados y no
hay nuevos datos a enviar.
Bit 5 – UDREn: USART Data Register Empty: indica poniendose a uno
si UDRn está listo para recibir nuevos datos a enviar.
Bit 4 – FEn: Frame Error: nos indica un error en la recepción con un 1.
Bit 3 – DORn: Data OverRun: se pone a uno cuando se produce una
situación de desbordamiento, el buffer y el registro de entrada
están llenos y se detecta una nueva condición de Start,
permanece a uno hasta que se lee el registro de entrada.
Bit 2 – UPEn: USART Parity Error: a uno cuando tenemos un error en el bit de paridad.
Bit 1 – U2Xn: Double the USART Transmission Speed: poniendo este
bit a uno entramos en un modo de comunicación asíncrona
al doble de velocidad, usaremos el normal.
Bit 0 – MPCMn: Multi-processor Communication Mode: habilita este modo.
Los 3 primeros bits están relacionados con las interrupciones,
sirven para habilitarlas y se corrresponden con los 3 primeros bits del
registro anterior.
Bit 4 – RXENn: Receiver Enable n: habilita el módulo de
recepción de la USART pasando a utilizar el pin RxDn para tal
fin.
Bit 3 – TXENn: Transmitter Enable n: igual que el anterior pero para la parte de transmisión.
Bit 2 – UCSZn2: Character Size n: junto con otros bits establece el número de bits a enviar.
Bit 1 – RXB8n: Receive Data Bit 8 n: en una frame de 9 bits de
datos éste es el noveno y el de mayor peso, se debe leer antes
que los del registro UDRn.
Bit 0 – TXB8n: Transmit Data Bit 8 n: el noveno bit a enviar en
el frame de 9 bits de datos, se debe escribir antes que los del
registro UDRn.
Con estos dos bits seleccionamos el modo de funcionamiento de la USART, en este caso 00.
• Bits 5:4 – UPMn1:0: Parity Mode: establecen la paridad, 00 en este caso.
Bit 3 – USBSn: Stop Bit Select: establece el número de
bits de stop que generará el transmisor, 0 para 1 bit, un uno
para dos.
Establecen el número de bits de datos que se van a enviar en cada frame.
Bit 0 – UCPOLn: Clock Polarity: selecciona entre el flanco de subida y de bajada del reloj para el modo síncrono.
Para
probar todo lo anterior se va a desarrollar el programa más
simple, y que será necesario para el proyecto MiniZ, que
consiste en mandar bytes desde el micro y recibirlos en el pc a
través de Hyperterminal para su posterior análisis.
Para la prueba se va a mandar al pc desde el microcontrolador la
dirección "www.jmnlab.com" una letra cada segundo. El
código de prueba según lo anterior es el siguiente:
void USART_Transmit( unsigned char data )
{
/* Wait for empty transmit buffer */
while ( !( UCSR0A & (1<<UDRE0)) );
/* Put data into buffer, sends the data */
UDR0 = data;
}
Para recibir los datos en el pc podemos usar Hyperterminal, antes se debe configurar una conexión.
Abrimos el programa y damos nombre a una nueva conexión y aceptar.
Seleccionamos el puerto serie donde nos aparece nuestro dispositivo
FTDI, si no se sabe cuál es se puede mirar en el panel de
control o se desconecta el Arduino y nos fijamos en que puerto estaba
antes y ahora no.
Configuramos los parámetros de la conexión para que sean iguales que los establecidos en el microcontrolador.
Le damos a aceptar y ya tenemos a nuestro microcontrolador mandando el
mensaje al pc, y podemos ver como éste va apareciendo en la
pantalla.
Si conectamos un analizador lógico a la línea TX entre el micro y el integrado FTDI, podemos ver lo siguiente:
Como se mandan 8 bits cada segundo.
Y si nos acercamos podemos ver el dato mandado, en este caso el valor j.
Utilizar la USART para pasarle datos al pc desde el microcontrolador es
algo muy sencillo y que resulta muy útil si queremos analizar
datos recogidos por el micro en el pc. También nos puede servir
para controlar el micro desde el pc mandando datos también
mediante Hyperterminal.