martes, 26 de octubre de 2010

UART E INTERRUPCIONES

Al igual que en otros uC aquí lo único que hay que hacer es configurar lo necesario en los registros correspondientes (velocidad, cantidad de bits, etc.). Los registros a los que me refiero se pueden encontrar en todos los ATmega y son los siguientes:
Descargar programa.


Pasaremos a dar una pequeña explicación de la función de cada registro.


UDR es el registro en que permite acceder al byte que ha llegado al uart, y también permite escribir el valor que se enviara. Es decir que cuando se quiere enviar un dato por el uart éste debe ser escrito en UDR, y cuando se quiera leer se debe hacer la lectura de UDR. UDR pondrá o sacara el dato de buffer de transmisión (TXB) o de recepción (RXB) según sea el caso.


-RXC (Recepción Completa): Se pone a "1" cuando se ha recibido un dato y se pone a "0" cuando el buffer de recepción esta vació.

-TXC (Transmisión Completa): Se pone a "1" cuando se ha transmitido por completo una trama de bytes (o un solo byte) y ya no hay nada más por transmitir. Se pone a "0" cuando se ejecuta la interrupción por transmisión completa o también puede ser puesto a "0" por programa.

-UDRE (Registro de Datos esta Vació): Se pone a "1" cuando UDR esta vació, es decir se puede transmitir nuevos datos.

-FE (Error en trama): Se pone a "1" cuando hay errores en la trama (por ejemplo cuando el bit de stop es "0"). Éste bit es válido hasta que se lee UDR.

-DOR (Saturación de Datos): Se pone a "1" cuando el buffer de recepción está lleno (2 datos) y se detecta un bit de Start. Éste bit es válido hasta que se lee UDR.

-PE (Error de Paridad): Se pone a "1" cuando se ha detectado un error de paridad, siempre que esté habilitada esta función.

-U2X (Doble velocidad de transmisión): Éste bit sólo es válido en transmisión asíncrona y debe ser puesto a 1 para duplicar la velocidad de transmisión.

-MPCM (Modo de Comunicación Multi-Procesador): Se debe poner a "1" para activar la detección de direcciones en la transmisión con múltiples uC's.


-RXCIE (Habilitación de Interrupción por Recepción Completa). Éste bit se debe poner a "1" para habilitar dicha interrupción. Tener en cuenta que para que ocurra la interrupción el bit "I" (Interrupción Global) del registro de estado (SREG) debe estar en "1".

-TXCIE (Habilitación de Interrupción por Transmisión Completa). Éste bit se debe poner a "1" para habilitar dicha interrupción. Tener en cuenta que para que ocurra la interrupción el bit "I" (Interrupción Global) del registro de estado (SREG) debe estar en "1".

-UDRIE (Habilitación de Interrupción porque El Registro de Datos esta Vació).Éste bit se debe poner a "1" para habilitar dicha interrupción. Tener en cuenta que para que ocurra la interrupción el bit "I" (Interrupción Global) del registro de estado (SREG) debe estar en "1".

-RXEN (Habilitar Recepción). Se debe poner a "1" para habilitar la recepción. Poniendo éste bit a "0" se limpia e buffer RXB.

-TXEN (Habilitar Transmisión). Se debe poner a "1" para habilitar la transmisión.

-UCSZ2 (Tamaño del Carácter). Éste bit combinado con UCSZ1:0 del registro UCSRC permiten seleccionar el número de bits en la transmisión y recepción (5, 6, 7, 8 o 9 bits).

-RXB8 (Bit 8 del dato Recibido). Cuando se ha seleccionado 9 bits los 8 primeros llegan al registro UDR y el noveno a RXB8. Éste bit debe ser leído antes de leer UDR.

-TXB8 (Bit 8 del dato a Enviar). Cuando se ha seleccionado 9 bits los 8 primeros se deben poner al registro UDR y el noveno a TXB8. Éste bit debe ser escrito antes de escribir UDR.


-URSEL (Selección de Registro). Éste bit no sólo existe en los uC que tienen un uart (i.e ATmega8), esto ya que comparte UCSRC comparte la misma posición de I/O en la memoria con UBRRH. Éste bit debe ser "1" para poder escribir en UCSRC.

-UMSEL (Selección del modo del USART). Si se pone a "1" se activa la operación síncrona.

-UPM1:0(Tipo de Paridad). Permite seleccionar el tipo de paridad usado.


-USBS (Seleccionar Bits de Stop). Si se pone a "1" la transmisión tendrá 2 bits de stop, caso contrario 1 bit de stop.
-UCSZ1:0(Tamaño del Carácter).Éste bit combinado con UCSZ2 del registro UCSRB permiten seleccionar el número de bits en la transmisión y recepción (5, 6, 7, 8 o 9 bits).

VELOCIDAD DE OPERACIÓN.

La velocidad de operación esta dada por:


Donde UBRR=UBRRH:UBRRL, que son los registro donde se colocara el valor correspondiente a la velocidad deseada.

INTERRUPCIONES.
Las interrupciones se encuentran vectorizadas, es decir que cada interrupción tiene una posición de memoria a la que se dirigirá cuando esta ocurra. Las interrupciones del ATmega8 son las siguientes.

Ahora mostraré un pequeño ejemplo en el cual usaremos las macros creadas en post anteriores. (XTAL=16MHz)


En el ejemplo se espera el dato que llega por el uart, se le suma 1 a dicho dato y se vuelve a enviar.

Ahora haremos lo mismo pero usando Interrupciones.


El vector de interrupción por recepción completa está ubicado en la dirección 0x000B, es allí donde se dirigirá el PC cuando ocurra la interrupción, es por ello que allí debemos decirle a donde debe ir para ejecutar la rutina correspondiente. Luego al terminar la rutina se retornara con un RETI (retorno de interrupción). Tener en cuenta que se debe habilitar "I" en SREG, esto lo hace la instrucción SEI.

sábado, 9 de octubre de 2010

MÁS MACROS

Algunas de las instrucciones no tienen acceso a toda la memoria de los ATmega, como por ejemplo:

Se puede apreciar que estas instrucciones solamente tienen acceso a las 64 primeras posiciones de la RAM, luego para poder acceder al resto de posiciones tendremos que usar instrucciones como las siguientes. 
Para evitar  recordar esto podemos crear macros que nos faciliten el trabajo, así con la misma macro podremos acceder tanto a las posiciones menores a 0x40 como al resto de la RAM. Quizá se pregunten por qué no usar LDS y STS para acceder a toda la memoria, la razón para no hacer esto es que estas instrucciones ocupan el doble de espacio que IN y OUT, por ello es mejor usar estas instrucciones solamente cuando sea necesario.

Las macros son:
Ahora con un pequeño programa donde usaremos estas macros veremos cómo se comporta el compilador. 

Si desensamblamos el pequeño programas mostrado arriba veremos lo siguiente:

Cómo se puede apreciar el compilador ya discrimino y colocó la instrucción correspondiente, esto nos ahorrará mucho trabajo ya que podemos usar esta macro para acceder a los registros de configuración (SFR) y al resto de la RAM. 

Otro par de instrucciones muy importantes son:


Estas instrucciones ponen a “1” y “0”, respectivamente, un bit de un registro de la RAM que se encuentre en posiciones menores a 0x20. Aunque están hechas para operar sobre los puertos de I/O podemos extender su poder mediante las macros.

En la macro primero debemos verificar que el valor del bit se encuentre en el rango de 0 a 7, luego si el registro se encuentra en una posición mayor a 0x3F tendremos que usar instrucciones como LDS y STS, si es mayor que 0x1F y menor a 0x40 se usaran las instrucciones IN y OUT, al final si la posición de memoria es menor a 0x20 usaremos SBI o CBI según dea el caso. SBR pone a “1” el bit indicado en el registro y CBR lo pone a “0”.
Ahora usaremos estas macro y veremos su comportamiento.

En el programa mostrado se incluyen 2 errores que deben ser detectados por el compilador.
Vemos que efectivamente los errores son detectados.

Ahora corregiremos los errores y veremos el código desemsamblado.

Ahora vemos que el compilador ya remplazo las instrucciones de acuerdo a las posiciones de memoria que se especifican.



Por último haremos macros para aumentar el alcance de un par de instrucciones de salto muy importantes como son:
Las macros creadas son:
La forma de uso es igual al de las anteriores macros, teniendo en cuenta que el salto no siempre sera posible entre macros.