Introducción
Instalando programas iniciales
La intención de este tutorial es mostrar mediante ejemplos simples,
la operación del
AVR-MT
utilizando un microcontrolador ATtiny 2313. Se
asume que el lector posee conocimientos básicos de C (sobretodo
manipulación de bits).
Para comenzar a trabajar con un microcontrolador AVR utilizando el lenguaje
de programación C, es necesario obtener un compilador de C para la arquitectura.
Si bien existen varios compiladores para avr, en este tutorial utilizaremos
el compilador avr-gcc, el cual es compatible con ANSI C, genera código
suficientemente bueno, posee la librería avr-libc y adicionalmente es software libre.
El compilador y ensamblador de C puede ser descargado de la página
AVR Freaks,
la cual está dedicada al desarrollo utilizando
microcontroladores AVR. Se recomienda su visita ante cualquier duda o si se
quiere profundizar más en el tema.
En el caso de que se trabaje en windows, existe un paquete llamado
WinAVR
que incluye el compilador (avr-gcc), un programador
(avrdude) y un debugger (avr-gdb).
También se instalará el entorno de desarrollo
AVR Studio, con el cual
podremos crear proyectos en C o en assembler. Una ventaja de esta aplicación
es que se puede programar y depurar si se dispone de un
J-TAG,
y adicionalmente simular el código (si es que no se posee un debugger).
Al momento de escribir estas notas, la versión actual de
AVR Studio es la 4,
y es recomendable instalar el
service pack 4
(el más reciente), que soluciona
varios bugs de la aplicación.
En el caso que se utilice un programador como el
AVR-PG1B,
será necesario instalar
el programador PonyProg2000 o utilizar el programador avrdude.
Las consideraciones generales que se debe tener al programar un microcontrolador
AVR, es que en la documentación cada vez que se refieran a que un bit está
programado, quiere decir que ese bit es 0. Si el bit no está programado
entonces vale 1. Si bien al comienzo cuesta asimilar lo anterior, es sólo
cuestión de costumbre.
Una vez instaladas las aplicaciones que utilizaremos para programar, procedemos
a crear un nuevo proyecto en AVR Studio. En la primera pantalla, se nos da la
opción de que el proyecto utilice AVR GCC. Escogemos esta opción y a continuación
damos un nombre al proyecto. Luego hacemos click en next.
En la siguiente pantalla, se nos ofrece la opción de escoger el programador/depurador
a utilizar. En nuestro caso, estamos utilizando el programador
AVR-PG1B, por
lo que no tenemos un debugger. Es por esto que simularemos nuestros programas
(en caso de necesitar depurar alguno de ellos), seleccionando la opción
AVR Simulator. Es nuestro caso particular, estamos utilizando un ATtiny 2313,
por lo que seleccionamos ese modelo en la ventana de configuración. Si usted
se encuentra usando un microcontrolador distinto al citado, por favor elija
el modelo de la lista a la hora de crear el proyecto.
Una vez creado el proyecto, se nos presenta la ventana principal del entorno. En
el editor, lo primero que haremos, será incluir la cabecera avr/io.h. Realizando
esto, nos aseguramos que el preprocesador se encargue de incluir el archivo
correcto con las definiciones necesarias para trabajar con el microcontrolador
seleccionado. En nuestro caso (y viendo el archivo io.h), se incluye indirectamente
el archivo iotn2313.h. Es una buena práctica no incluir directamente el archivo
correspondiente a nuestro microcontrolador, sino siempre incluir io.h. Si incluimos
directamente la cabecera de nuestro microcontrolador, podríamos perder definiciones
importantes realizadas en io.h.
#include <avr/io.h>
En caso de duda siempre es bueno mirar el archivo de definiciones correspondiente
al microcontrolador que se esté usando. Sobretodo cuando se tiene la duda de si
un registro o puerto está definido o cúal es su nombre.
Una vez incluido avr/io.h, escribimos nuestra función main, el punto de partida de
cualquier programa en C. La intención de un primer programa en C es ver si
todo está funcionando como debiese. Es por eso que para probar que las herramientas
de compilación se escribirá el siguiente programa,
#include <avr/io.h>
int main(void)
{
for(;;)
{
}
}
Para compilar en AVR Studio, se presiona la tecla F7 (que no solo compila, sino
que construye el proyecto completo). El mismo resultado se puede obtener
desde el menú Build, seleccionando la opción Build.
Vale notar que a esta altura, AVR Studio
ha creado un Makefile para el proyecto y que las opciones de compilación
que cambiemos a lo largo del desarrollo se verán reflejadas en él. En el caso
de proyectos de este tipo es sumamente recomendable construir un Makefile (en el
caso que no se trabaje con una herramienta que lo haga automáticamente), pues
entre presionar la tecla F7 (o escribir make en un terminal), y escribir una
línea de comando como (para nuestro proyecto que nada hace),
avr-gcc.exe -mmcu=attiny2313 -Wall -gdwarf-2 -Os -fsigned-char -MD -MP -MT Nada.o -MF dep/Nada.o.d -c ../Nada.c
avr-gcc.exe -mmcu=attiny2313 Nada.o -o Nada.elf
avr-objcopy -O ihex -R .eeprom Nada.elf Nada.hex
Es mucho más conveniente la primera opción. Si nos fijamos, el modelo
del microcontrolador se pasa al compilador por medio de la línea de comandos, así
como también el nivel de optimización. El nivel de optimización es un ajuste que
dependerá de la aplicación en desarrollo, pero en general se utiliza 0s, que
minimiza el tamaño del código (que es casi siempre el recurso más escaso).
WinAVR incluye en su distribución la utilidad make, por lo que los usuarios
de windows no deberían tener problemas
Recomendaciones
Una buena práctica es utilizar la optimización -Os ofrecida por avr-gcc, pues
se logra una notoria disminución en el tamaño del código. Por el contrario,
utilizar optimizaciones que reduzcan el tiempo de ejecución no se recomiendan,
pues en muchos casos pueden expandir el código de los ciclos lo que trae
una pérdida de espacio en la memoria de programa. Cuando se programa
en microcontroladores en general demorar unos cuantos ciclos más de reloj no
es un problema, pero sí lo es que el tamaño del programa sea extenso pues
en la mayoría de los casos es ese el recurso limitado (por ejemplo el
microcontrolador ATtiny 2313 tiene solamente 2KB de memoria).
Otro punto importante y relativo a las optimizaciones es que expresiones
del tipo
a = 0;
a = 1;
Muchas veces son reeemplazadas por la última de ellas, debido a que el compilador
desestima la primera. Pero en general en el mundo de los microcontroladores
una expresión de ese tipo puede tener algún sentido (también en un programa
con varios hilos de ejecución). Se debe entonces tener
especial cuidado de utilizar volatile en la declaración de variables sensibles
a las optimizaciones (por ejemplo en alguna variable utilizada para leer
desde un registro en una rutina de atención de interrupciones).
volatile unsigned char a;
Vale la pena mencionar que para configurar los pines de los puertos,
existen los registros DDRx, donde x es la letra del puerto. Si un bit
del registro DDRx es 1, quiere decir que el pin correspondiente a ese
número de bit será considerado como una salida. Si el bit es 0, entonces
se considera que el pin asociado es una entrada. Por ejemplo, si quisiéramos
dejar como entrada al pin 5 de PORTB y como salida al pin 2, el código sería
//pin 5 es entrada
DDRB &= ~(1 << 5);
//pin 2 es salida
DDRB |= (1 << 2);
También se debe tener en cuenta que la lectura de los pines de los puertos
se realiza a través de los registros PINx, donde x es la letra del puerto. Además,
si asignamos un valor a un pin en PORTx y luego lo leemos desde PINx, se debe
esperar un ciclo para que PINx se sincronice, por ejemplo,
unsigned char val;
PORTB = (1 << 3 | 1 << 5);
//Esperamos un ciclo para sincronización
asm volatile("nop");
//Leemos los pines
val = PINB;
|