Sei sulla pagina 1di 90

CURSO BSICO-INTERMEDIO DE

PROGRAMACIN EN C DE LOS
MICROCONTROLADORES ATMEL

Programacin en C de los microcontroladores ATMEL

Acerca del autor


Profesor del Departamento de Ingeniera Electrnica del Instituto desde 1998 a la
fecha, experiencia docente en materias de electrnica digital I y II, analgica I y III,
Instrumentacin I y II, microprocesadores I y II, electrnica industrial, fsica de
semiconductores. Ing. Electrnico por el ITM, Maestra en Ciencias en Ingeniera
Electrnica por el ITEM y Dr. En Ciencias en Ingeniera.

He sido:
Asesor en ms de 70 temas de titulacin de licenciatura y 1 de Maestra.
Sinodal en ms de 70 exmenes de titulacin de licenciatura y 6 de maestra.
17 Artculos publicados en congresos y simposios nacionales de electrnica y
computacin.
18 Ponencias en congresos y simposios nacionales de electrnica.
Participacin como asesor con proyectos en 19 eventos de creatividad en sus
distintas fases.
Asistencia en calidad de participante en 15 cursos de robtica,
instrumentacin, redes de PLCs, Paneles de Operador, termografa y
microcontroladores COP, HC08, MSP430, AVR.
Imparticin de 12 cursos de microcontroladores PIC, HC08, AVR, DSPs de
Texas Instruments, procesamiento de seales y de PLCs en eventos nacionales
7 veces jurado en eventos acadmicos de electrnica
Como estudiante particip en los concursos de Ciencias Bsicas durante 3
aos en sus distintas etapas.
Obtencin de una de las 10 becas nacionales para telecomunicaciones en
CINVESTAV Guadalajara

Experiencia profesional

5 aos de experiencia profesional en el desarrollo de proyectos de


automatizacin para empresas embotelladoras y de la transformacin, basados
en la integracin y programacin de PLCs, redes industriales, paneles de
operador, instrumentacin y control de procesos.
Amplia experiencia en programacin de PLCs de Siemens en lenguaje escalera,
FBDs, y Grafcet. Programacin de paneles de operador para diseo de

Programacin en C de los microcontroladores ATMEL

interfaces hombre-mquina (HMI), experiencia en el campo de la termografa


para anlisis de fallas en sistemas elctricos, mecnicos y estructurales basados
en el anlisis de las imgenes trmicas, conocimiento de robots PUMA y
saturno y programacin de mquinas de control numrico.
Participacin en el diseo de cajeros automticos para bancos nacionales.
Diseo electrnico de sistemas empotrados con microcontroladores

Motivacin
El motivo de este curso es para dar a conocer las nuevas tecnologas en microcontroladores,
ya que es lamentable que en las universidades e institutos de educacin superior de Mxico
y en Latinoamrica en general, se estn haciendo proyectos y programas demasiados
sencillos en las materias de microcontroladores y peor an que estn usando los
microcontroladores PIC, ya que universidades europeas y de EUA no los usen desde hace
aos por su pobre desempeo, adems de que son microcontroladores que no tiene ninguna
aplicacin industrial o comercial, sino slo para efectos didcticos.
Desde que cursaba la carrera de ingeniera electrnica a la fecha he usado los siguientes
microprocesadores, microcontroladores y DSPs:

6802, HC11 y HC08 de Motorola


PICs de Microchip
MSP30 de Texas Instruments
COP de National Semiconductors
AVR y ATMEGA de Atmel
8051 de INTEL
DSPs de Texas Instruments y Motorola

Con el conocimiento de estos microcontroladores puedo aportar mi experiencia en el uso de


estos dispositivos y que resumiendo puedo sealar que Motorola es un fabricante con
dispositivos buenos y de amplio uso industrial como PLCs que basan su CPU en sus
microcontroladores. Son usados en ambientes de mucho ruido como el automotriz y el
industrial, sin embargo a ltimas fechas ha realizado muchos cambios en el core, en las
herramientas de programacin, haciendo ms difcil conseguirlos y elevndose su costo.
Los COP son muy poco usados en el ambiente industrial, y resultan caros, adems de que
no cuentan con novedades en su diseo, los 8051 de Intel estn en plena desaparicin y los
que hay son nicamente para reemplazo.
Los microcontroladores MSP de Texas Instrumentes son econmicos, son potentes y tiene
herramientas gratuitas, sin embargo son dispositivos para uso porttil por lo que su voltaje
es de 3.3 V y son de montaje superficial lo que dificulta el diseo de prototipos.

Programacin en C de los microcontroladores ATMEL

Los microcontroladores PIC son los peores microcontroladores que existen, son muy lentos
que trabajan a baja velocidad, tiene un set de instrucciones muy pequeo que obliga a
programas muy extensos y lentos, tiene nicamente un work register cuando un procesador
RISC debe tener al menos 16 registros, de todos los microcontroladores que existen en el
mercado son los peores en el desempeo, algunas empresas comenzaron a hacer sus
equipos con estos procesadores y despus al detectrseles fallas como bloqueos o
reinicializacin por ruido sacaron del mercado sus productos. En pases desarrollados no se
usan ya que no tienen aplicacin industrial o comercial, nicamente en escuelas de pases
de latinoamrica. Estos procesadores nicamente los us por un ao y los dej de usar hace
una dcada por ser procesadores obsoletos y de mal desempeo.
Los Microcontroladores AVR de Atmel tiene 4 veces ms instrucciones que los PICs, tiene
32 registros de trabajo, el pic slo 1, el ADC es ms potente, el TIMER es mucho ms
complejo que el del PIC, y son ms econmicos. Los AVR de Atmel se usan en telfonos
celulares, en receptores satelitales, en robtica, etc. Son microcontroladores muy rpidos y
de alto desempeo y son de bajo costo, existen muchos proyectos, tutoriales y herramientas
gratuitas en la red.
A manera de conclusin dira que en orden de desempeo y calidad colocara los
procesadores as: AVR de Atmel, MSP de Texas Instruments, los 08 de Motorola el 8051
de Intel, COP de Nacional Semiconductor. Un procesador AVR o MSP puede tener un
desempeo de entre 10 y 50 veces al de un PIC con el mismo cristal externo, o en otras
palabras un PIC es entre 10 y 50 veces ms lento que un AVR o que un MSP.

Programacin en C de los microcontroladores ATMEL

CAPTULO I. PROGRAMACIN EN C
1.1 Tipos de Variables
En esta parte nicamente se ver como se manejan las instrucciones de C, quizs al
terminar este captulo algunas instrucciones no las entienda del todo bien, sin embargo
cuando programemos el microcontrolador usaremos estas instrucciones y las ir
comprendiendo de una mejor manera.
En un programa en C puede colocar comentarios usando //
unsigned char x; // x es una variable
O puede utilizar /*

*/ para poner varias lneas como comentarios

/* Aqu estamos usando estos smbolos para


ilustrar como podemos poner comentarios
en varas lneas */
Tipos de datos
Nuestras variables pueden ser del siguiente tipo:
Tipo
Bit
Char
Unsigned char
signed char
Int
short int
Unsigned int
signed int
long int
Unsigned long int
signed long int
Float

Tamao en bits
1
8
8
8
16
16
16
16
32
32
32
32

Programacin en C de los microcontroladores ATMEL

Rango
0o1
-128 a 127
0 a 255
-128 a 127
-32768 a 32767
-32768 a 32767
0 a 65535
-32768 a 32767
-2147483648 a 2147483647
0 a 4294967295
-2147483648 a 2147483647
1.75 e -38 a 3.402 e 38

Double

32

1.75 e -38 a 3.402 e 38

1.2 Declaracin de las variables


Las declaraciones de las variables se hacen de la siguiente forma:
Con signo o sin signo tipo nombre; //Comentarios
Ejemplos
unsigned char x,y,temperatura; //Con esto estoy indicando que son 3 variables sin signo y
//que son tipo char por lo que el rango que pueden manejar son desde 0 a 255
unsigned int var1;
// Es una variable entera sin signo que llamamos var1
Tambin se pueden inicializar las variables dentro de la declaracin:
signed char z=20,x=10,m;
//inicializo a ningn valor

//z inicia con un valor de 20 decimal, x con 10, m no la

Importante. Si no se inicializan las variables dentro del programa o en la declaracin de las


variables stas son inicializadas a cero.
El manejo de nmeros los puede hacer en decimal, binario, hexadecimal u octal.
Variable o constante
Decimal
Hexadecimal
Binario
Octal

Formato
Nmero
0x nmero hexadecimal
0b nmero binario
0 nmero octal

Ejemplos:
x=20;
x=0x14;
x=0b00010100;
x=024;

// x es 20 decimal
//x es 14 hexadecimal que convertido a decimal es 20 decimal
//x se manejado en binario que es equivalente a 20 decimal
//x se maneja en octal que es 20 decimal

1.3 Ubicacin de variables y constantes

Programacin en C de los microcontroladores ATMEL

Las variables deben ser ubicadas en RAM. Solamente se hace declarndolas como unsigned
o signed luego el tipo y finalmente el nombre de las variables;
unsigned long variable3;
signed char x,y,z;
De la manera anterior las variables se guardarn en RAM

Las constantes deben ser guardadas en FLASH o memoria de programa, ya que stas no
van a ser modificadas, para ello se inicia colocando la palabra const o flash ejemplo:
const int k1=60000;
Que es equivalente a:
flash int k1=60000;
Con lo anterior la constante K1 es inicializada a 60000 y se guarda en flash.
Se puede guardar un carcter en flash para ello ponemos el carcter entre comillas simples
()
const char x=a

1.4 Arreglos
Un arreglo es un conjunto de datos que pueden ser accesado a travs de un ndice. Su
declaracin se hace as:
flash o const nombre del arreglo [nmero de elementos]={elemento1, elemento2,..
elemento n }
Ejemplo
flash char arreglo1 [3]={0x0a,0x38,0x23};
Es equivalente a la siguiente declaracin:
const char arreglo1 [3]={0x0a,0x38,0x23};
flash y const son lo mismo ya que guardan los datos en flash, pero por compatibilidad con
el lenguaje C usar dentro de este manual la palabra const.

Programacin en C de los microcontroladores ATMEL

1.4.1 cmo accesar el arreglo?


El primer elemento es el 0, en la declaracin anterior del arreglo ste se defini de tres
elementos, siendo el primer elemento el 0 y el ltimo elemento el nmero 2, vea el
siguiente ejemplo:
x=arreglo1[0];
x=arreglo1[2];

// x vale 0x0a ya que acces al primer elemento del arreglo


// x vale 0x23 ya que acces al tercer elemento del arreglo

Tambin se puede hacer de la declaracin del arreglo como se muestra a continuacin


donde omitimos el tamao del arreglo que es 3 ya que al compilarse el programa ver que
son de tres elementos el arreglo.
flash char arreglo1 []={0x0a,0x38,0x23}; //Note que no se coloc el tamao del arreglo
Si no se coloca la palabra flash o const se guardar el arreglo en RAM por ejemplo
int arreglo2 [4]={100,200};
Es un arreglo de 4 elementos enteros, el primero vale 100, el segundo 200 y el tercero y
cuarto 0 ya que no fueron inicializados. Como fue un arreglo guardado en RAM se pueden
modificar. En el caso de que se guarden en FLASH no podrn ser modificados ya que sern
considerados como constantes.
Tambin podemos guardar caracteres para posteriormente mandarlos a una pantalla de
cristal lquido (LCD) ejemplo:
flash char arreglostring []=Ejemplo de caracteres;

1.4.1.1 Arreglos multidimensionales


Se puede declarar un arreglo de dos dimensiones que se interpretara como fila y columna
ejemplo:
const char arreglo_multi_dim [2,3]= {1,2,3}, {,4,5,6};

// Es un arreglo de dos filas y


//tres columnas

x=arreglo_multi_dim [1,1]; //x=5 ya que se est accesando el elemento de fila 1 y col 1

1.5. Asignndole direccin a una variable


Cuando declaramos variables el compilador decidir donde colocar las variables dentro de
RAM, pero tambin podemos nosotros decirle en qu direccin colocarla usando
@direccin por ejemplo:
Programacin en C de los microcontroladores ATMEL

unsigned char x=10 @0x80; // x vale 10 y est guardada en la direccin 0x80


Importante. Yo no recomiendo que el programador le indique al compilador donde colocar
las variables, sino que se le deje a ste la decisin de su ubicacin, ya que el compilador
colocar la variable en una ubicacin que sea la ms rpida para su acceso, e inclusive la
puede colocar en alguno los 32 registros de trabajo para hacer ms rpido su manejo.

1.6 Declaracin de bits


Podemos guardar bits de manera individual y esto se hace usando la palabra bit nombre del
bit y su valor ejemplo
bit var1=1;
bit var2=0;
bit var3=1;

//La variable Var1 es de un bit y se guarda en un registro del AVR y vale 1

Se guardan de manera individual esos bits en los registros R2 al R14 del procesador del
AVR. Recuerde que el microcontrolador AVR tiene 32 registros desde R0 hasta R31.

1.7 Conjunto de instrucciones en C


En los siguientes subtemas se vern los distintos operadores aritmticos, lgicos, de
relacin, etc. que podemos usar en el compilador, como trabajamos en lenguaje C el diseo
de programas se hace de una manera muy rpida, algo que no podemos lograr con el
lenguaje ensamblador. En la actualidad en el mbito industrial se usa el trmino de RAD
que es Rapid Application Development que traducido es Desarrollo Rpido de
Aplicaciones, este concepto indica que para poder ser competitivos se deben desarrollar
proyectos de una manera muy rpida, es por ello que ya no utilizan el lenguaje ensamblador
en las empresas para desarrollar los programas. En la industria automotriz y en el rea de
robtica los departamentos que elaboran los programas en los microcontroladores usan
solamente el lenguaje C ya que ste permite elaborar programas complejos muy
rpidamente, y adems existe la portabilidad del cdigo, ya que una vez que se ha escrito el
programa en C puede de una manera relativamente fcil cambiar de un microprocesador a
otro.
El lenguaje C reconoce instrucciones como if, for, while, etc; pero el lenguaje C no tiene
instrucciones para el manejo de puertos, de timers, del ADC, de interrupciones, etc.
Entonces para poder manejar los perifricos del microcontrolador se usan libreras donde
estn declarados esos registros y su ubicacin, aunque esto lo veremos despus.

Programacin en C de los microcontroladores ATMEL

1.7.1 Operadores aritmticos:


Smbolo
+
*
/
%

Operacin
Suma
Resta
Multiplicacin
Divisin
Divisin Mdulo, y el resultado es el
residuo

Var1=Var2/12;
Var1=Var2%12;

//Si Var2=40, Var1 ser 3;


//Si Var2=40, Var1=4 que es el residuo. til para convertir
// nmeros a BCD

1.7.2 Operadores Para manejo de Bits


Smbolo
&
|
^
<<
>>
~

Descripcin
And Bit a Bit
OR bit a Bit
Or exclusivo Bit a Bit
Corrimiento a la Izquierda
Corrimiento a la derecha
Complemento
a
unos
(inversin de bits)

Ejemplos:
Var3=Var1&Var2;
Var3=Var1<<(2);
Var3=Var1<<(Var2);
Var3=~Var1;

//Si var1=0xff, var2=0x0A, Var3 ser 0x0a


//Var1=0x20; Var3=0x08 ya que se recorre tres bits a la izq;
//Var1=0x01, Var2=0x05 Var3=0x20;
//Var1=0xf1, Var3=0x0e;

Programacin en C de los microcontroladores ATMEL

1.7.3 Operadores de relacin


Los operadores de relacin se utilizan con la instruccin if, while, do while.
Importante. No olvide poner los operadores =, | o el & dos veces en la evaluacin del if,
while o do while, ya que un sol = significa asignacin y dos veces == significa
comparacin, un slo & significa AND bit a bit y dos veces && significa Y TAMBIN a
modo de evaluacin. Si lo coloca una sla vez el programa tendr resultados inesperados.
Operador
>
>=
<
<=
==
!=
&&
||

Descripcin
Mayor que
Mayor o igual que
Menor que
Menor Igual que
Igual que
Distinto de
Y tambin si
O si

Ejemplos
if ((Var2==1)||(Var2>10))
{
Var1--;
}

//Se decrementa Var1 si var2=1

Recuerde que variable++ significa incrementar en 1 la variable y que variable-- significa


decrementar en 1 la variable.
Si lleva slo una instruccin debajo del if no es necesario las llaves: {}
If (Var2!=1)

//Se incrementa Var1 si Var2 es distinto de 1

Var1++;
If (((Var2>12)&&(Var3>=-125)) ||(Var4!=0)) //Var1 se multiplica por -1 si se cumple la
Var1=-Var1;
//Parte de (Var2 y Var3) o (Var4) o ambas

1.8 Estructura if- else

Programacin en C de los microcontroladores ATMEL

La estructura if else es: si se cumple el if se hace lo que est abajo del if y sino se cumple se
hace lo que est debajo del else
if (Var1==10)
{
Var1=0;
Var2=20;
x=14;
}
else
{
Var1=++;
x=20;
}

1.8.1 Estructura else-if


Donde se cumpla la condicin rompe las siguientes comparaciones, no evala todas, pero si
se cumple hasta abajo habr evaluado todas las comparaciones.
if (Var1==10)
Var1=0;
else if (Var1==09)
Var1=1;
else if (Var1==08)
Var1=2;
else
Var1=3;
Tambin se puede hacer el programa anterior con varios if, pero aunque se cumpla una
condicin sigue comparando las posteriores.

Errores generados por tamaos de las variables


En ocasiones los programadores principiantes generan errores como colocar variables muy
grandes cuando no se ocupan o tener tamaos de variables muy pequeos cuando se ocupan
rangos grandes.

Programacin en C de los microcontroladores ATMEL

Cuando se tiene una variable que dentro del programa va, digamos, desde 0 hasta 100
decimal, podemos declararla como unsigned char var1, pero si ponemos unsigned int var1,
tambin funcionar el programa, pero en el ltimo caso estamos apartando dos bytes (int)
cuando solo ocupamos uno slo, por lo que el programa quedar mas grande y ms lento
porque el microcontrolador deber manipular dos bytes en lugar de uno slo. Es importante
que vea cul es el rango de la variable y aparte el tamao adecuado.
Cuando una variable que ocupa un tamao grande le apartamos uno ms pequeo se puede
crear condiciones que no se cumplen, vea el siguiente ejemplo:
Note el siguiente ejemplo:
signed char var1; // var1 es signada con lo que rango va de -128 a 127
var1++;
If (var1==200)
var2=0;
La condicin del if nunca se cumplir porque var1 es tipo char unsigned, esto es que su
rango es de -128 a 127 decimal y nunca llega a ser mayor a 127.
Si se declara como tipo unsigned char o tipo int si habr un punto en el que la condicin es
vlida.

1.9 Estructura while


El while evala lo que hay entre los parntesis y mientras se cumpla ejecuta lo que est
debajo del while.
while ((porta==0x01) &&(var1==0))
{
portb++ ;
//Si porta=0 y Var1=0, se incrementa en uno el portb
}

1.10 Estructura do-while


A diferencia del while, esta instruccin ejecuta por lo menos una vez lo que est abajo del
do, despus evala el while y si es vlido ejecuta nuevamente lo que est abajo del do.
do
{
Portb++ ;
//Si porta=0 y Var1=0, se incrementa en uno el portb
}
While ((porta==0x01) &&(Var1==0))

Programacin en C de los microcontroladores ATMEL

Este programa realiza por lo menos un incremento del portb, sin importar la condicin, si la
condicin del while se cumple continua en el ciclo incrementando el portb, hasta que no sea
vlida la condicin en el while.

1.11 Estructura for


La estructura del for es (inicio; condicin de paro; incremento del ndice)
for (i=0;i<=10000,i++)
{
var1++; //i tendra que ser declarado como int para que cumpla con el rango
}

Puede utilizarse el for para generar un delay


for (i=100;i<=0;i--);

//Decrementa i desde 100 hasta 0 y cuando llega a 0 sale del


//for, note el ; donde se coloc y es porque no hay
//instrucciones que ejecutar abajo del for

1.11.1 Ciclos infinitos


for(;;)
{
Se ejecuta infinitamente las instrucciones aqu colocadas
}
Otra forma de generar ciclos infinitos:
while(1)
{
Se ejecuta infinitamente las instrucciones aqu colocadas
}

1.11.2 Ruptura de ciclos con Break


Se puede terminar un ciclo for, while y do while mediante el break sin necesidad de
terminar las iteraciones o de que se vuelva falsa la condicin.

for (i=0;i<=10000,i++)
Programacin en C de los microcontroladores ATMEL

{
var1++;
if (var2==0) //Si var2=0 se rompe ciclo, quedando el i en donde se haya cumplido el var2
break;
}
var3=i;
//Si var2 nunca es verdadera en el ciclo, var3=10000
//Si Var2 se hizo verdadera en i=25 se rompe ciclo y var3=25

1.12 Modificacin de bits de manera individual


En ocasiones es necesario poner a 1 o 0 un bit de alguna variable o de algn registro sin
alterar el estado de los otros bits. O tambin puede ser necesario probar si un bit est en 0 o
en 1. Esa prueba y modificacin de bits de manera individual la veremos a continuacin en
este apartado.
Primero recordemos que cada bit tiene un peso dentro del byte y este peso es una potencia
de 2. Por ejemplo si la variable es de 8 bits el peso de esos bits es: 128 64 32 16 8 4 2 1, el
bit menos significativo tiene un peso de 1 y el ms significativo de 128.
Si escribimos:
variable|=0x08
Es equivalente a: variable=variable|0x08
En la siguiente tabla vemos el resultado de variable|=0x08 que se utiliza para poner en 1 el
bit 3; notamos en la tabla que los otros bits de la variable no se modifican y que slo se
afecta el bit3 (columna azul), si ste estaba en 0 lo pone en 1 y si estaba ya en 1 lo deja en 1.
B7
Variable 1
0x08
0
Resultado 1
De la Or

b6
0
0
0

b5
0
0
0

b4
0
0
0

b3
0
1
1

b2
1
0
1

b1
1
0
1

b0
1
0
1

Entonces para prender bits se debe hacer lo siguiente:


variable|=0x01 para prender el bit0.
variable|=0x02 para prender el bit1.
variable|=0x04 para prender el bit2, etc,
Si deseara prender el bit0 y el bit6 al mismo tiempo sin afectar los otros bits tendra que
escribir:
variable|=0x01|0x40 para prender el bit 0 y el bit 6.
Para apagar bits se usa la expresin:

Programacin en C de los microcontroladores ATMEL

variable&=~0x01 esta expresin apaga el bit 0 y no modifica los otros bits.


variable&=~(0x02|0x08|0x40);esta expresin apaga el bit 1, el bit 3 y el bit6 y no modifica
el estado de los otros bits.
La expresin variable&=~0x01 es equivalente variable=variable&(~0x01) recordemos que
el smbolo ~ saca el compelemento a 1 que es inversin de bits.
Si suponemos que variable=0b11001011

Variable
~0x01
Resultado
De la AND

b7
1
1
1

b6
1
1
1

b5
0
1
0

b4
0
1
0

b3
1
1
1

b2
0
1
0

b1
1
1
1

b0
1
0
0

Vemos en el ejemplo anterior que apaga el b0 de la variable y los dems bits no los
modifica.

1.12.1 Probando el valor de los bits de una variable o registro


Suponga que deseara probar si el bit 0 y el bit 2 de la variable var estn en 0, entonces
deber usar el siguiente esquema:
if ((var &(0x01|0x04)==0) //Se est probando que los bit 0 y 2 estn en 0
Vemos que el resultado no se guarda en ningn lado, sino solamente se prueba si estn en 0
esos bits.
Suponga que desea probar si el bit 1 de la variable var est en 1 deber escribir:
if ((var &(0x02)==0x02) //Se prueba que el bit 1 est en 1 por eso se compara con 0x02
Para probar los bits 0,1,2,3,4,5,6 y 7 se usan sus pesos que son 0x01, 0x02, 0x04, 0x08,
0x10, 0x20,0x40 y 0x80.
Pero es ms fcil si en vez de usar sus pesos usamos definiciones, que es lo que usaremos
en este curso, ejemplo:
#define elbit0 0x01
#define elbit1 0x02
#define elbit2 0x04
Programacin en C de los microcontroladores ATMEL

#define elbit3 0x08


#define elbit4 0x10
#define elbit5 0x20
#define elbit6 0x40
#define elbit7 0x80
De la manera anterior estamos diciendo que la etiqueta elbit0 =0x01, que el bit1=0x02, etc.
Aunque podemos usar cualquier etiqueta, slo hay que tener cuidado de no usar las
palabras reservadas para instrucciones, es por ello que no us la palabra bit que est
reservada, y por eso utilice una etiqueta que llam elbit1, etc.
En los apartados anteriores us: variable|=0x01|0x64 para prender el bit 0 y bit 7 de la
variable. Pero si colocamos dentro del programa las definiciones anteriores podemos usar:
variable|=elbit0|elbit6 entonces de esta maneras vemos ms fcil que estamos modificando
los bits 0 y 6.
Para probar si estn en 0 los bits 0 y 2 us:
if ((var &(0x01|0x04)==0) //Se est probando que los bit 0 y 2 estn en 0
Pero si utilizamos las definiciones podemos usar:
if ((var &(elbit0|elbit2)==0) //Se est probando que los bit 0 y 2 estn en 0

1.12.2 Accesando bits de los registros


Hasta este momento no hemos usado ningn registro del microcontrolador, por ejemplo
uno de estos registros es el del puerto A del microcontrolador, vamos a suponer que ya
configur el puerto como salida, entonces si escribe: porta=0x0f; est indicando que los 4
primeros pines del microcontrolador los ponga en 1 lgico, es decir, 5 Volts y los 4 ms
significativos los ponga en 0 lgico, que es 0 Volts.
Pero si desear afectar un slo pin, sin modificar a los otros puede utilizar lo que se vio en
los subtemas anteriores del 1.12.1 y 1.12.2, pero el compilador que usaremos (codevision)
permite modificar de una forma ms fcil los bits de los registros y se hace de la siguiente
manera:
Nombre_del_registro.x=valor
Donde: Nombre_del_registro, es el nombre del registro como aparece en la hoja de datos
x, es el nmero del bit que va desde 0 hasta 7
valor, es el valor lgico que le asignaremos ya sea 1 o 0
Por ejemplo si deseamos poner a 1 el pin 6 del puerto A, sin modificar los otros debemos
escribir:
porta.6=1;

Programacin en C de los microcontroladores ATMEL

Con lo anterior estamos poniendo a 1 el pin 6 del puerto sin modificar los otros pines, y
esta manera de manejar bits de manera individual lo podemos usar con los primeros 32
registros, cualquier registro mapeado arriba de la direccin 0x1F se hace con las tcnicas
mostradas en los subtemas 1.12 y 1.12.1.
La instruccin if (pina.0==0); Prueba que el pin0 del porta est en 0 (si es que lo
configuramos como entrada).

1.13 Manejo de las funciones


Una funcin es un conjunto de instrucciones que puede ser llamada en el momento que se
desee. Las funciones son tiles por dos razones:
1. Permiten estructurar el programa, por ejemplo se puede utilizar una funcin para
inicializar variables, otra funcin para inicializar el hardware, otra funcin para
inicializar el timer, etc. As podemos visualizar de una forma ms rpida el
funcionamiento del programa.
2. Permiten ahorrar cdigo, si por ejemplo dentro del programa va hacer
constantemente una multiplicacin de dos operandos, en vez de poner
continuamente el cdigo de multiplicacin de los operandos, mejor se usa una
funcin que haga la multiplicacin y cada vez que se vaya a utilizar se manda
llamar la funcin, as de esta manera ahorramos cdigo.
Las funciones pueden o no enviar parmetros y puede o no haber retorno de parmetros.
Cuando se va a utilizar una funcin hay que declararla en la parte superior del programa
(esto se conoce como prototype definition o definicin prototipo) para que la reconozca el
compilador y sepa que vamos a utilizar dichas funciones.
Ejemplos de declaracin de funciones:
//prototype definition
void ejemplofuncion1 (void)
void ejemplofuncion2 (char, char)
int ejemplofuncion3 (void)
char ejemplofuncion4 (int)
En la parte anterior se definieron 4 funciones, el nombre que les di son: ejemplofuncion1,...,
ejemplofuncion4 aunque el nombre puede ser cualquiera. La palabra void significa que no
recibe nada, por ejemplo void ejemplofuncion (void) significa que la funcin no recibe nada
y que tampoco se le enva ningn parmetro. La segundo funcin void ejemplofuncion2
(char, char) indica que no retorna ningn valor la funcin y que se le envan dos
parmetros tipo char. La tercera funcin int ejemplofuncion3 (void) indica que retorna un
valor tipo int y que no se le enva ningn parmetro. La ltima funcin no retorna ningn
valor y se le enva un parmetro tipo int.

Programacin en C de los microcontroladores ATMEL

La parte anterior slo es la definicin de las funciones que utilizar el programa. El llamado
de las funciones dentro del programa se hace as:
ejemplofuncion1 ();
ejemplofuncion2 (variable1,variable2);
En el llamado de la funcin1 no se coloc nada entre los parntesis porque la funcin
dentro de la definicin le indicamos que no se le iba a enviar ningn parmetro.
En el llamado de la funcin 2 le colocamos entre parntesis dos variables que llamamos
variable1 y 2, que previamente debimos definir. Estas dos variables las recibir la funcin
para que realice operaciones entre ellas.
variablex=ejemplofuncion3 ();
En el llamado de esta funcin colocamos variablex=funcin porque en la definicin del
prototipo le indicamos que iba a retornar la funcin una variable tipo int, entre los
parntesis no se le coloca nada porque se indic que no iba a enviar ningn parmetro.
En la funcin 4 se retorna un valor tipo char y se enva un parmetro tipo int, y su llamado
se hara as:
variabley=elemplofuncion4(variable1);
Hasta este punto se ha visto cmo se declaran las funciones y cmo se llaman, falta
nicamente cmo se estructura la funcin.
En el caso de la primer funcin:
void ejemplofuncion1(void)
{
//Cdigo de usuario
}
La funcin lleva void al inicio y entre parntesis porque esa funcin no recibe parmetros
ni retorna ningn parmetro o valor.
La segunda funcin debera colocarse as:
void ejemplofuncion2(char a, char b)
{
//Cdigo de usuario
}
Aqu lleva void al inicio indicando que no retorna parmetro y entre parntesis se coloca a
y b que indica que son los parmetros que se reciben, cuando se hizo el llamado se hizo as:
ejemplofuncion2 (variable1,variable2); entonces la funcin enva dos parmetros variable1
Programacin en C de los microcontroladores ATMEL

y variable2, que recibe la funcin en a y b, entonces a=variable1 y b=variable2; Se


asignan segn su posicin.
La tercera funcin debe escribirse as:
int ejemplofuncion3(void)
{
//Cdigo de usuario
return variable
}
Cuando se hizo el llamado de la funcin se coloc: variablex=ejemplofuncion3 (); entonces
cuando se ejecute la funcin se retorna un valor a travs de return variable si
variable=0x30 por ejemplo, entonces variablex=0x30.

La funcin 4 debe escribirse as:


char ejemplofuncion4(int a)
{
//Cdigo de usuario
return variable
}
Aqu se indica que la funcin regresar un char y que recibe un parmetro int en a, ya que
en el llamado de la funcin se escribi: variabley=elemplofuncion4(variable1);
Entonces a recibir el valor de variable1 y variabley tomar el valor de variable por el
return variable.
Hemos visto slo el envo de parmetros que son variables, pero pueden enviarse tambin
arreglos, o punteros.
Resumen de las funciones
Declaracin de la funcin
void ejemplofuncion1 (void)

Llamado de la funcin
ejemplofuncion1 ();

void ejemplofuncion2 (char, char)

ejemplofuncion2 (variable1,variable2);

int ejemplofuncion3 (void)

variablex=ejemplofuncion3 ();

char ejemplofuncion4 (int)

variabley=elemplofuncion4(variable1);

Estructura de la funcin
void ejemplofuncion1(void)

Programacin en C de los microcontroladores ATMEL

{
//Cdigo de usuario
}
void ejemplofuncion2(char a, char b)
{
//Cdigo de usuario
}
int ejemplofuncion3(void)
{
//Cdigo de usuario
return variable
}
char ejemplofuncion4(int a)
{
//Cdigo de usuario
return variable
}

Estos fueron ejemplos de funciones, el nombre se le puede cambiar, se usaron


variables con determinados nombres pero stos pueden cambiar.

Cuando no se enva parmetros se coloca la palabra void, cuando no hay retorno de


valor de la funcin se coloca la palabra void.

Cuando se envan parmetros se reciben en las funciones en otras variables segn su


posicin.

El valor que regresar la funcin se hace con return nombre_de_variable.

En la definicin del prototipo se le indica al compilador si la funcin va o no a


enviar parmetros, y si va o no a retornar algn valor la funcin, en el caso de que
en el prototipo se le indique que va a enviar parmetros y no se enve parmetros en
el llamado de la funcin se va a marcar error a la hora de la compilacin porque no
concuerda la definicin con la forma en que se est manejando la funcin. Entonces
el manejo de la funcin debe hacerse como se declar en la definicin del prototipo.

En los ejemplos que coloqu enve como parmetros variables, pero tambin pueden
ser constantes. ejemplofuncion2(char a, 200); En este ejemplo se enva el valor de
la variable a y se enva la constante 200.

El retorno del valor de la funcin que puse como ejemplo fue el retorno de una
variable, pero tambin puede retornarse una constante como return 100;

Importante. Dentro de la funcin cuando se colocaron las variables a y b, stas NO se


declaran ya que son consideradas variables locales, es decir, que slo tienen validez
dentro de la funcin, cuando el programa sale de la funcin desaparecen. O en otras
Programacin en C de los microcontroladores ATMEL

palabras esas variables slo existen dentro de la funcin. Le puse el nombre de a y b,


pero puede ponerle el nombre que quiera.
Importante. Los PICs y los HC08 slo tienen un slo registro de trabajo, el PIC le llama
Work Register y el HC08 le llama acumulador y recomiendan que no use variables
locales en los programas, ya que las variables locales se guardan en la pila a travs de
instrucciones de PUSH y PULL, haciendo el manejo de variables locales muy lentas, en
cambio los AVR tienen 32 registros de trabajo, y es ah donde se guardan las variables
locales hacindose ms rpido el manejo de este tipo de variables. En los programas
que haga con estos microcontroladores AVR trate de usar siempre variables
locales en lugar de variables globales, por las siguientes razones: el programa se ejecuta
ms rpido, es ms compacto y no usa la RAM. El manejo de variables locales es de 4 a
8 veces ms rpido el manejo en los AVR que en los PICs o que en los HC08.

CAPITULO 2. PROGRAMACIN BSICA DEL


MICROCONTROLADOR.
2.1 Introduccin
La compaa ATMEL fabrica memorias flash y microcontroladores, es la principal
fabricante de estos dispositivos para uso comercial e industrial. ATMEL nombra a sus
microcontroladores de 8 bits AVR y ATMEGA, los primeros son microcontroladores de
pocos pines y los ATMEGA son microcontroladores basados en el mismo core que los
AVR pero con ms pines de entrada/salida y con ms perifricos.
El microcontrolador que se utilizar en este curso es el ATMEGA48-20 PU, es un
microcontrolador de la serie ATMEGA. Sin embargo la informacin mostrada en este curso
sirve para cualquier microcontrolador AVR o ATMEGA de ATMEL.
El compilador que se usar es el CODEVISION AVR que es un compilador que permite al
programador inicializar los perifricos a travs de un Wizard (asistente) indicndole solo el
programador a travs de clicks cmo quiere que configure el microcontrolador y el
compilador generar todo el cdigo ahorrando tiempo y costo para el desarrollo de
aplicaciones. Adems este compilador puede generar el cdigo para el manejo de LCDs o
generar el cdigo para la comunicacin I2C para comunicacin de dispositivos seriales
como memorias, Real Time Clocks, etc.

Programacin en C de los microcontroladores ATMEL

El ATMEL es un microcontrolador tipo RISC (Reduced Instruction Set Computer) lo cual


significa que el conjunto de instrucciones es reducido con 131 instrucciones, las cuales se
ejecutan en su mayora en un slo ciclo, tiene multiplicador por hardware y tiene 32
registros de trabajo lo cual permite la ejecucin de instrucciones muy rpido ya que muchas
instrucciones y operaciones las realiza entre estos registros ejecutndose de manera muy
rpida y eficiente. Si lo comparamos con otro microcontrolador RISC como el PIC vemos
lo siguiente: el PIC tiene slo 33 instrucciones, lo cual obliga a que los programas sean mas
grandes y lentos debido a lo pobre de sus instrucciones (cosa que no sucede con el AVR ya
que tiene un conjunto de instrucciones 4 veces mas grande), el PIC slo tiene un solo
registro de trabajo y el AVR tiene 32. El PIC al tener un slo registro de trabajo obliga que
los operandos se guarden en RAM haciendo mas instrucciones y ms lento los programas,
en cambio los ATMEL tienen 32 registros de trabajo con lo cual los operandos pueden
guardarse en ellos haciendo que el programa sea ms reducido y ms rpido. Los
microcontroladores ATMEL son procesadores optimizados para trabajar con C, el PIC no,
ya que es un core muy viejo, lento, reducido en instrucciones, con pocos registros de
trabajo, en cambio el AVR al tener un conjunto de instrucciones muy grande y con muchos
registros de trabajo puede compilar los programas realizados en C de manera muy eficiente,
ya que si se usan funciones con variables locales stas son guardadas en los registros de
trabajo, en cambio si se tiene un microprocesador ya sea RISC o CISC con pocos registros
de trabajo obliga a que las variables locales definidas en funciones sean guardadas en pila
resultando en instrucciones adicionales de Push y Pull en stack.
Un ATMEL y un PIC trabajando a la misma frecuencia de operacin y con el mismo
programa tendra un mejor desempeo el ATMEL pudiendo ocupar entre 6 y 15 veces
menos memoria el ATMEL por el conjunto de instrucciones ms amplio, y ejecutando el
programa entre 20 y 60 veces ms rpido. Operaciones de punto flotante en el PIC de la
serie 16fxx no se pueden realizar ya que por lo pobre de las instrucciones que tiene no es
posible, adems de que no tiene capacidad de memoria para poder realizar este tipo de
operaciones.
Los modos de direccionamiento del AVR es ms amplio, pudiendo inclusive manejar
direccionamientos con post y pre incrementos, lo cual eficienta el manejo de tablas y
programas.
De los microcontroladores AVR y ATMEGA de ATMEL existen muchas familias, pero
nosotros nos enfocaremos al ATMEGA48 pero si desea programar cualquier otro AVR o
ATMEGA puede hacerlo con los conocimientos que adquiera con este manual.
Primero veamos en la figura 2.1 cmo est fsicamente el microcontrolador ATMEGA48.

Programacin en C de los microcontroladores ATMEL

Figura 2.1 Pines del Microcontrolador ATMEGA48.

2.1 Caractersticas del microcontrolador


Es un microcontrolador de 28 pines, con tres puertos B, D de 8 bits y el C de 7 bits, todos
esos pines pueden ser configurados como entradas o salidas de manera individual, note que
todos los pines pueden configurarse con funciones alternas por ejemplo pueden
configurarse como entrada o salida de datos, como entrada del ADC, como fuente de
interrupcin, como terminal de comunicaciones, etc.
El microcontrolador tiene un oscilador interno que trabaja a 8 MHz que viene dividido por
8 de fbrica, as que trabaja a 1MHz interno, pero puede colocar un cristal externo en las
terminales 7 y 8, y en ese caso tendra que seleccionar que esos pines no sean entradas o
salidas de datos sino que sean configurados como terminales donde se colocar el cristal
externo que puede ser de hasta 20 MHz, pero para nuestras aplicaciones y para reducir
costos, diseo del PCB, reduccin de componentes, etc, se trabajar con el oscilador interno
de fbrica cuya frecuencia interna es de 1 MHz, aunque puede operar hasta 8 Mhz y si se
desea una velocidad ms alta deber colocar un cristal externo que puede ser hasta de 20
MHz. Debe tener en cuenta que a mayor velocidad se incrementa el consumo de energa. Si
se coloca el cristal de 20MHz puede trabajar a 20 MHz internos, recuerde que otros

Programacin en C de los microcontroladores ATMEL

microcontroladores como los PICs, los HC08 de motorola, etc. la velocidad interna es el del
cristal dividido entre 4. As que de entrada tenemos que el ATMEL es 4 veces ms rpido
que cualquier otro microcontrolador trabajando con el mismo cristal.

2.2 Instalacin del software


Deber instalar estos tres programas (primero descomprima el CVAVRE que abrir un
SET-UP)

Figura 2.2 Programas a Instalar


En el tema 1.7 se explic que el lenguaje C no tiene instrucciones para manejar timers,
ADC, puertos de entrada-salida, etc, es decir, los perifricos del microcontrolador, entonces
para poder manejarlos se usan las libreras donde se incluyen las declaraciones de estos
registros y su manejo. Es precisamente el programa Code Vision AVR quien tiene esas
libreras. El primer programa instala el AVR Studio que es el simulador, el segundo
(WinAVR-20071221 ) instala el programador y el tercer SET-UP instala el compilador.
Importante. Use slo estas versiones, ya que estn probadas, versiones ms nuevas o viejas
pueden tener problemas con el programador, compilador y/o simulador. En el caso de que
tenga probados versiones mejores incluir el link para su descarga en mi
pgina www.comunidadatmel.com

2.3 Puertos de entrada y salida


A travs de los puertos de entrada y salida es como el procesador se comunica con el
mundo exterior. Este microcontrolador en particular tiene tres puertos el B, C y D que
deben ser configurados para decirle cmo va a funcionar los pines del puerto si como
entrada o como salida. Se puede configurar de manera independiente cada pin de un puerto
como salida o como entrada.
Por ejemplo con el registro DDRB especificamos la direccin del pin correspondiente, un 0
es para indicar que el pin es de entrada y un 1 de salida. Por ejemplo si se quiere que los
primeros cuatro pines del puerto A sean entrada y los 4 ms significativos sean de salida se
programa as: DDRB=0xf0; aunque recordemos que esta configuracin la realiza el
codevision.
Importante. Cuando son configurados como entradas las terminales de un circuito integrado
deben colocarse resistencias de pull-up para evitar que queden flotadas (sin conectarse),
porque de quedarse flotadas el C.I. consume mayor corriente y el estado del pin oscilar
vea el primer caso de la figura 4, lo correcto es poner una resistencia de pull-up (segundo
Programacin en C de los microcontroladores ATMEL

caso), si el interruptor no se presiona leer el pin un 1 lgico por la resistencia conectada a


5V, si se presiona el interruptor leer un 0 lgico, pero este microcontrolador permite al
diseador ahorrar hardware ya que tiene resistencias de pull-up internas que pueden ser
habilitadas.

Figura 2.3 Conexin de resistencias de Pull-up


.
Importante. Si ha manejado otros microcontroladores habr notado que nicamente tienen
asociados un slo registro al puerto de entrada/salida, pero en este microcontrolador tiene
asociados dos registros al puerto de entrada/salida, si quiere escribir al puerto B deber
hacerlo as PORTB=dato; pero si desea leer el estado de los pines de ese puerto deber
hacer dato=PINB; es decir deber usar PORTB, PORTC o PORTD para escribir al puerto,
y deber usar variable=PINB, variable=PINC o variable=PIND para leer el valor del
puerto de entrada.
Cualquier otro microcontrolador de otros fabricante slo tienen un slo registro para leer o
escribir al puerto, pero en elcaso de ATMEL se tienen dos dando la ventaja de que de esa
forma el acceso a puertos es ms rpido cuando se va usar como entrada un determinado
pin y posteriormente se va usar como salida, es otra ventaja que tenemos con este tipo de
arquitectura.
Importante. Limitantes Fsicas de los pines: Mximo pueden dar 40 mA por pin, pero el
Circuito Integrado mximo debe manejar 200mA, es decir que sumando la corriente de los
pines y la que consume el microcontrolador no deben exceder ms de 200mA.

Programacin en C de los microcontroladores ATMEL

Programa 1. Leer el puerto B y escribirlo al puerto D, activando las resistencias de


pull-up en las entradas del puerto B.

Figura 2.4 conexin del P1


Vea el video_p1 que se anexa en este CD para que aprecie cmo se inicializa el
microcontrolador y su simulacin.
El siguiente listado es lo que gener el codewizard, inicializando el microcontrolador y lo
que est en azul es lo que ud deber agregar al programa generado para que funcione de
acuerdo a las especificaciones del programa 1.
/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.7a Evaluation
Automatic Program Generator
Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project :
Version :
Date : 13/09/2008
Author : Freeware, for evaluation and non-commercial use only
Company :
Comments:

Chip type

: ATmega48

Programacin en C de los microcontroladores ATMEL

Clock frequency : 1,000000 MHz


Memory model
: Small
External SRAM size : 0
Data Stack size : 128
*****************************************************/
#include <mega48.h>
// Declare your global variables here
void main(void)
{
// Declare your local variables here
// Crystal Oscillator division factor: 8
#pragma optsizeCLKPR=0x80;
CLKPR=0x03;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
// Input/Output Ports initialization
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=P State6=P State5=P State4=P State3=P State2=P State1=P State0=P
PORTB=0xFF;
DDRB=0x00;
// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0x00;
DDRC=0x00;
// Port D initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTD=0x00;
DDRD=0xFF;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;

Programacin en C de los microcontroladores ATMEL

ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;
// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x00;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x00;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;
while (1)
{
PORTD=PINB;
//Se lee el valor del Puerto A y se escribe en PORTB
//El Puerto B es de entrada por lo que se accesa usando el registro PINB
//El puerto D es de salida por lo que se accesa usando el registro PORTD
// Place your code here
};
}

Programa 2. Haga un contador binario en el puerto B, el cual deber contar desde 0


hasta 255 y regresar a cero. Para ello coloque un retardo de 1 segundo entre cada
cuenta, ya que de no colocar ningn retardo el conteo sera muy rpido no pudiendo
apreciarse el conteo en el puerto por la velocidad.

Programacin en C de los microcontroladores ATMEL

Figura 2.5 Conexin del programa 2


Importante. Hay funciones de retardo llamadas delay_us(dato); y delay_ms(dato); que son
funciones en microsegundos y en milisegundos, y el dato es un nmero o una variable de
hasta 16 bits. Pero para poder utilizar estas funciones deber colocar la librera
#include<delay.h>, ya que de no hacerlo no reconocer las funciones el compilador
marcando error.
Vea el video_p2 para que vea la forma en que se hace este programa y vea tambin su
simulacin.
El siguiente listado lo generar el codewizard para inicializar el microcontrolador y lo que
est en azul es lo que ud deber escribir en el programa para que ejecute lo que se pide en el
programa 2.
/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.7a Evaluation
Automatic Program Generator
Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project :
Version :
Date : 14/09/2008
Author : Freeware, for evaluation and non-commercial use only

Programacin en C de los microcontroladores ATMEL

Company :
Comments:

Chip type
: ATmega48
Clock frequency : 1,000000 MHz
Memory model
: Small
External SRAM size : 0
Data Stack size : 128
*****************************************************/
#include <mega48.h>
#include <delay.h> //Esta libreria hay que colocarla para poder utilizar las funciones de retardo

// Declare your global variables here


void main(void)
{
// Declare your local variables here
// Crystal Oscillator division factor: 8
#pragma optsizeCLKPR=0x80;
CLKPR=0x03;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
// Input/Output Ports initialization
// Port B initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTB=0x00;
DDRB=0xFF;
// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0x00;
DDRC=0x00;
// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off

Programacin en C de los microcontroladores ATMEL

// Compare A Match Interrupt: Off


// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;
// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x00;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x00;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;
while (1)
{
PORTB++;
// Incrementa en una unidad el valor del Puerto B
delay_ms(1000); //Se hace un retraso de 1 segundo
// Place your code here
};
}

Programa 3. Hacer un convertidor de BCD a 7 segmentos. En este programa se desea


que cuando se introduzca un 0 en el puerto B se dibuje un 0 en el display de 7
segmentos que se conectar en el puerto B, si se introduce un 1 se deber dibujar en el
display de 7 segmentos ese nmero, etc.
El diagrama de este programa se muestra en la figura 2.6

Programacin en C de los microcontroladores ATMEL

Figura 2.6 Conexin del programa 3 convertidor de BCD a 7 segmentos


Consideraremos tambin que el B0 va conectado al segmento a, el B1 a b, B2 a c, B3 a d,
B4 a e, B5 a f y B6 a g. En la tabla 2.1 se aprecia la combinacin que deber ponerse para
dibujarse en el display los nmeros, por ejemplo para el 1 debe encenderse el segmento b y
c. Estas combinaciones son si se trata de un display de ctodo comn, en el caso de que sea
de nodo comn slo deberan invertirse los 1 y los 0.

Tabla 2.1 Conexin del convertidor de BCD a 7 Segmentos


Nmero
Combinacin digital
Combinacin
g f e d c b a
Hexadecimal
B7 B6 B5 B4 B3 B2 B1 B0
0
0 0 1 1 1 1 1 1
0x3f
1
0 0 0 0 0 1 1 0
0x06
2
0 1 0 1 1 0 1 1
0x5b
3
0 1 0 0 1 1 1 1
0x4f
4
0 1 1 0 0 1 1 0
0x66
5
0 1 1 0 1 1 0 1
0x6d
6
0 1 1 1 1 1 0 0
0x7c
7
0 0 0 0 0 1 1 1
0x07
8
0 1 1 1 1 1 1 1
0x7f
Programacin en C de los microcontroladores ATMEL

0 1 1 0

1 1 1

0x6f

Para este programa deberemos configurar todo el Puerto B como salida, y los pines C0, C1,
C2 y C3 como entradas con sus resistencias de pull-up, ya que cuando no se cierre el
interruptor quedar a 1 lgico el pin por la resistencia de pull-up interna, y cuando se cierre
el interruptor leer 0 el pin.
En los cursos que he dado normalmente los participantes dicen que una forma de hacer el
programa es con if para probar todas las combinaciones y quizs es la forma que se le ha
ocurrido para hacerlo. Es decir algo de esta forma:
if (PINC==0)
PORTB=0x3f;

//Si el puerto C=0 entonces imprime el 0 en el port B

if (PINC==0)
PORTB=0x06;

//Si el puerto C=1 entonces imprime el 1 en el port B

Etc...
if (PINC==9)
PORTB=0x6f;

//Si el puerto C=1 entonces imprime el 1 en el port B

//As se haran las 8 pruebas restantes


La forma descrita no es incorrecta, pero tiene los siguientes puntos en contra: ocupa
demasiadas instrucciones ya que se deben probar todas las posibilidades que es que el
puerto C valga 0 hasta que valga 9, ocupando mucha memoria, haciendo lento el programa.
La forma que se puede hacer es a travs de una tabla, por ejemplo se define una tabla en
flash donde estarn todas las combinaciones anteriores:
const char tabla7segmentos [10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7c,0x07,0x7f,0x6f};
y dentro del programa principal colocar lo siguiente:
PORTB=tabla7segmentos[PINC];
Y con esa nica instruccin ya tenemos un convertidor de BCD a 7 segmentos, si el puerto
C que leemos con PINC es igual a 0 sacar de la tabla el elemento 0 que es el que dibuja el
0 en el display, si vale 9 sacar de la tabla el elemento 9 que es el que dibuja el 9 en el
display y lo mandar al Puerto B.
De la manera anterior logramos que el programa quede ms compacto, y mucho ms rpido
que usando instrucciones de if.
Vea el video_p3 donde se muestra la configuracin del microcontrolador y su simulacin.

Programacin en C de los microcontroladores ATMEL

La parte en azul es la que deber agregar al programa generado por el codewizard.


/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.7a Evaluation
Automatic Program Generator
Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project :
Version :
Date : 14/09/2008
Author : Freeware, for evaluation and non-commercial use only
Company :
Comments:

Chip type
: ATmega48
Clock frequency : 1,000000 MHz
Memory model
: Small
External SRAM size : 0
Data Stack size : 128
*****************************************************/
#include <mega48.h>
unsigned char variable;
const char tabla7segmentos [10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7c,0x07,0x7f,0x6f};
// Declare your global variables here
void main(void)
{
// Declare your local variables here
// Crystal Oscillator division factor: 8
#pragma optsizeCLKPR=0x80;
CLKPR=0x03;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
// Input/Output Ports initialization
// Port B initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTB=0x00;
DDRB=0xFF;
// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=P State2=P State1=P State0=P
PORTC=0x0F;
DDRC=0x00;
// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x00;

Programacin en C de los microcontroladores ATMEL

TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;
// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x00;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x00;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;
while (1)
{
variable=PINC&0x0f;

//Enmascaramos los 4 bits menos significativos


//del puerto A ya que los dems no interesan.

if (variable<10)
PORTB=tabla7segmentos[variable];

Programacin en C de los microcontroladores ATMEL

if (variable>=10)
PORTB=0x3f;
// Place your code here
};

//Si lo que leemos es mayor o igual de 10 que dibuje en el display un 0

Explicacin del Programa


Explicacin de la instruccin variable=PINC&0x0f; suponga que en el puerto C (que es de
7 bits) existen estos datos C=110,0110 pero a nosostros nos interesan solo los 4 menos
significativos, esto es el 0110 y los otros no, por lo que debemos quitarlos as que con el
and de 110,0110 & 0000,1111 nos da el resultado de 0000,0110, es decir ya slo nos asign
a la variable el valor de los 4 bits que nos interesan. Entonces donde se desea que haya un 0
como es el caso de los bits superiores hacemos el and colocando 0 en esas posiciones, y
donde queremos que no se modifiquen los bits como en los 4 bits menos significativos
hacemos el and con 1 lgico en esa posicin para que nos d como resultado un 1 donde
haba un 1 y un 0 donde haba un 0, es decir, lo mismo que haba se queda sin alterarse.
Se agreg una instruccin que prueba si el Puerto C tiene un nmero mayor o igual a 10 y
en caso de que as sea va a dibujar un 0 en el display. Ya que con 4 bits se pueden
representar nmeros desde 0 hasta 15, pero solamente nos interesan los nmeros del 0 al 9
ya que es el tamao de la tabla, en caso de no haberse puesto esas instrucciones, entonces
mostrara basura cuando variable>9, ya que esos elementos no estn definidos en la tabla.

Programa 4 Cuando se presione el botn conectado al pin C0 se incrementar el


nmero mostrado en el display que ser conectado al puerto B.

Programacin en C de los microcontroladores ATMEL

Figura 2.7 Conexiones para los programas 4, 5 y 6


Configuracin: C0 como entrada con resistencia de pull-up activada, los pines B0 a B7
como salida que es donde se conectar el display.
/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.7a Evaluation
Automatic Program Generator
Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project :
Version :
Date : 14/09/2008
Author : Freeware, for evaluation and non-commercial use only
Company :
Comments:

Chip type
: ATmega48
Clock frequency : 1,000000 MHz
Memory model
: Small
External SRAM size : 0
Data Stack size : 128
*****************************************************/
#include <mega48.h>
#define boton PINC.0
const char tabla7segmentos [10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7c,0x07,0x7f,0x6f};
unsigned char var1;
// Declare your global variables here
void main(void)
{
// Declare your local variables here

Programacin en C de los microcontroladores ATMEL

// Crystal Oscillator division factor: 8


#pragma optsizeCLKPR=0x80;
CLKPR=0x03;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
// Input/Output Ports initialization
// Port B initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTB=0x00;
DDRB=0xFF;
// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=T State2=T State1=T State0=P
PORTC=0x01;
DDRC=0x00;
// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;

Programacin en C de los microcontroladores ATMEL

TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;
// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x00;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x00;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;
while (1)
{
if (boton==0)
var1++;
if (var1==10)
var1=0;
PORTB=tabla7segmentos [var1];
// Place your code here
};
}

Explicacin del programa:


Un solo bit de un registro se puede accesar nombre_de_registro.nmero_de_bit
El registro del Puerto C es PINC y el bit que deseamos accesar es el 0, entonces PINC.0 es
accesar el bit 0 del PINC, que es la terminal C0
Se desea que cuando se presione el botn conectado al pin C0 se incremente el contador,
entonces podramos escribir as:
if (PINC.0==0) //Cuando se presiona vale 0
var++;
//Se incrementa la variable en 1
Pero es ms fcil escribir, interpretar un programa con nombres ms claros, por ejemplo el
C0 es donde est conectado el botn as que en se defini en la parte superior una etiqueta
donde iguala boton a PINC.0, para que sea ms fcil interpretar el programa.
Programacin en C de los microcontroladores ATMEL

#define boton PINC.0


Con lo anterior boton=PINC.0 as que si utilizo en el programa PINC.0 o boton el
compilador lo interpreta igual, y es ms fcil ubicar la palabra boton que PINC.0. Suponga
que tenga conectados leds, botones, etc. podra hacer esa definicin de
#define led_rojo PORTB.1
#define led_verde PORTB.2
#define borrado PINC.1
etc.
Cuando el botn se presiona, es decir que vale 0, ya que cuando no est presionado lee 1
lgico debido a la resistencia de pull-up, incrementa en 1 la variable var1
if (boton==0)
var1++;
Se utiliza una variable que se nombr var1, aunque puede ser cualquier nombre. Como se
est utilizando la tabla que convierte a 7segmentos el nmero, slo se pueden desplegar
nmeros de 0 hasta 9, as que si la var1 es igual a 10 se regresa a 0, porque nmeros
superiores al 10 desplegaran basura ya que no existen en la tabla accesando localidades no
inicializadas.
if (var1==10)
var1=0;
Y finalmente el valor de var1 que va desde 0 hasta 9 va indexando la tabla con la
instruccin PORTB=tabla7segmentos [var1];
Cuando programe el microcontrolador y arme el circuito ver que cuando presione el botn
se incrementar muy rpidamente el display y la razn de eso es porque el programa
detecta el nivel de 0, es decir, cuando valga 0 el pin se incrementar el valor a mostrar en el
display; aunque nosotros presionemos y soltemos el botn muy rpido el programa leer en
es pequeo lapso de tiempo miles de veces un nivel lgico de 0.
Si deseramos que se modificara el valor slo una vez cuando se presione el botn deber
hacerse que funcione por flancos, es decir cuando cambie el pin de 1 a 0. Vea el diagrama
de la figura 2.8.

Programacin en C de los microcontroladores ATMEL

Figura 2.8 Deteccin de flancos


Para poder trabajar por flancos es necesario tener el valor del botn anterior y del botn
actual, por ejemplo en 1 y 2 el botn pasado vale 1 y el botn actual vale 1, con eso
sabemos que no ha sido presionado el botn; ahora en el punto 2 y 3 el punto 2 es botn
pasado y el 3 es botn actual y ambos valen 1, as que no ha sido presionado el botn; en el
punto 3 y 4 el botn pasado vale 1 y el botn actual vale 0 eso significa que se presion el
botn y que hubo un flanco de bajada de 1 a 0 ese cambio nos sirve, por ejemplo, para
incrementar la variable. Despus el punto 4 vale 0 y el punto 5 vale 0 que son botn pasado
y actual respectivamente eso significa que no hay cambio de flanco, cuando est en los
puntos 7 y 8 tanto botn pasado como actual valen 0 por lo que no hay cambio, en el punto
8 y 9 el botn pasado y actual valen 0 y 1 ese es un cambio de flanco de subida; en el punto
9 y 10 los valores de botn pasado y actual valen 1 por lo que no hay cambio de flanco.
Ahora en el programa se har que el valor en el display se incremente solamente en 1 sin
importar cunto dure presionado el botn, es decir, que funcionar por flanco, y lo haremos
que se incremente en 1 cuando cambia de 1 a 0 el valor del pin, es por ello que debemos
tener dos valores: botona y botonp que guardarn los valores que tuvo el botn actual y el
botn pasado.
Programa 5. Programa que incrementa el valor del contador BCD conectado al
puerto B cada vez que se presiona el interruptor conectado al pin C0. Este funcionar
por nivel de bajada, es decir, solo cuando se presione el interruptor se incrementar el
conteo.
Configuracin. Puerto B de salidas, pin C0 de entrada con resistencia de pull-up activada.
El circuito a aramar es el mismo de la figura 2.7.
La inicializacin se har igual que el programa anterior, vea el video_p5 donde est cmo
se inicializa el microcontrolador.
/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.7a Evaluation
Automatic Program Generator
Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Programacin en C de los microcontroladores ATMEL

Project :
Version :
Date : 14/09/2008
Author : Freeware, for evaluation and non-commercial use only
Company :
Comments:

Chip type
: ATmega48
Clock frequency : 1,000000 MHz
Memory model
: Small
External SRAM size : 0
Data Stack size : 128
*****************************************************/
#include <mega48.h>
// Declare your global variables here
#define boton PINC.0
bit botonp;
bit botona;
unsigned char var;
const char tabla7segmentos [10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7c,0x07,0x7f,0x6f};

void main(void)
{
// Declare your local variables here
// Crystal Oscillator division factor: 8
#pragma optsizeCLKPR=0x80;
CLKPR=0x03;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
// Input/Output Ports initialization
// Port B initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTB=0x00;
DDRB=0xFF;
// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=T State2=T State1=T State0=P
PORTC=0x01;
DDRC=0x00;
// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
// Timer/Counter 1 initialization

Programacin en C de los microcontroladores ATMEL

// Clock source: System Clock


// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;
// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x00;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x00;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;
while (1)
{
// Place your code here
if (boton==0)
botona=0;
else
botona=1;
if ((botona==0)&&(botonp==1)) //hubo cambio de flanco de 1 a 0
var++;
//Se incrementa la variable
if (var==10)
var=0;

Programacin en C de los microcontroladores ATMEL

PORTB=tabla7segmentos [var];
botonp=botona;

};
}

Explicacin del Programa.


Cuando el boton (que es pin Co por el define) sea 0 se har la variable tipo bit botona=0, si
boton es 1 entonces botona=1. Es decir slo copia el valor del pin y se asigna a esa variable
tipo bit
if (boton==0)
botona=0;
else
botona=1;
En la parte de abajo del programa se tiene
botonp=botona;
Esto es porque el valor del botona (botn actual) se convierte en el valor del botonp (botn
pasado), cuando regrese a la parte de arriba del programa se leer el valor del botona (boton
actual) entonces de esta manera tenemos el valor actual (botona), as como el valor pasado
inmediato (botonp). Cuando llegue a la parte de abajo el botona (botn actual) ser el valor
pasado, porque despus se leer el valor del botn actual, y as consecutivamente.
Ya que se tiene el valor actual y pasado del botn se tienen las instrucciones de y con el
primer if se prueba si hubo cambio de flanco de 1 a 0 ya que se prueba si botonp==1 y que
botona==0, con estas dos pruebas sabemos que hubo cambio de flanco de 1 a 0, y si lo
hubo se incrementa la variable, entonces solo cuando se presiona el botn se incrementar
la variable, sin importar cunto dure en 0, ya que funciona el programa por flanco de bajada
y no de subida.
if ((botona==0)&&(botonp==1)) //hubo cambio de flanco de 1 a 0
var++;
//Se incrementa la variable
if (var==10)
var=0;

Cuando programe el microcontrolador y arme el circuito ver que en ocasiones cuando


presiona el interruptor o cuando lo suelta se incrementa en varias unidades el display, y es
porque el interruptor genera rebotes, ya que el cerrado y la apertura no es instantneo
generndose rebotes (vea la figura 2.9). A continuacin explicar como eliminar los
rebotes.

Programacin en C de los microcontroladores ATMEL

Eliminacin de rebotes en un interruptor


vea el siguiente diagrama donde se aprecia que cuando se presiona un interruptor, ste se
abre y cierra varias veces por que el cerrado no es instntaneo; de la misma forma cuando
se abre el interruptor se generan rebotes y stos se pueden generar hasta por 40 mS.

Figura 2.9 Rebotes en un interruptor mecnico


Si hiciramos un programa que cada vez que se presiona una tecla incrementara un valor y
no quitramos los rebotes y se generar los rebotes del diagrama anterior veramos que se
incrementara la variable 5 veces en lugar de 1 vez debido a que los rebotes generan varios
cambios de nivel de 1 a 0 y de 0 a 1 tanto al presionar el interruptor como al soltarlo.
En ocasiones los diseadores colocan circuitos externos (filtros pasabajas o circuitos
integrados) para eliminar los rebotes, pero esto no es necesario ya que se puede hacer por
software. La forma de eliminar los rebotes es detectar cuando hubo cambio de flanco tanto
de bajada como de subida y poner un retardo de 40 mS para evitar que detecte los otros
flancos.

Programacin en C de los microcontroladores ATMEL

Programa 6. Cada vez que se presione el botn conectado al pin C0 deber


incrementarse el valor que se muestra en el display que se conectar en el Puerto B,
eliminndose los rebotes que se generan en el cierre y en la apertura del interruptor.
Configuracin: Pin C0 de entrada y con resistencia de pull-up activada, B0 a B6 de salidas.
Vea el video_p6 donde se muestra la configuracin del microcontrolador. A continuacin
est el listado del programa completo, lo que est en azul es el cdigo que deber agregar al
cdigo generado con el codewizard.
/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.7a Evaluation
Automatic Program Generator
Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project :
Version :
Date : 14/09/2008
Author : Freeware, for evaluation and non-commercial use only
Company :
Comments:

Chip type
: ATmega48
Clock frequency : 1,000000 MHz
Memory model
: Small
External SRAM size : 0
Data Stack size : 128
*****************************************************/
#include <mega48.h>
#include <delay.h>
// Declare your global variables here
#define boton PINC.0
bit botonp;
bit botona;
unsigned char var;
const char tabla7segmentos [10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7c,0x07,0x7f,0x6f};
void main(void)
{
// Declare your local variables here
// Crystal Oscillator division factor: 8
#pragma optsizeCLKPR=0x80;
CLKPR=0x03;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
// Input/Output Ports initialization
// Port B initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTB=0x00;
DDRB=0xFF;
// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=T State2=T State1=T State0=P
PORTC=0x01;

Programacin en C de los microcontroladores ATMEL

DDRC=0x00;
// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;
// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x00;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;

Programacin en C de los microcontroladores ATMEL

// Timer/Counter 2 Interrupt(s) initialization


TIMSK2=0x00;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;
while (1)
{
if (boton==0)
botona=0;
else
botona=1;
if ((botonp==1)&&(botona==0))
//hubo cambio de flanco de 1 a 0
{
var++;
//Se incrementa la variable
if (var==10)
var=0;
delay_ms(40); //Se coloca retardo de 40mS para eliminar rebotes
}

if ((botonp==0)&&(botona==1))
//hubo cambio de flanco de 0 a 1
delay_ms(40); //Se coloca retardo de 40mS para eliminar rebotes
PORTB=tabla7segmentos [var];
botonp=botona;
};
}

Explicacin del programa


La diferencia con respecto al programa 5 es que en las instrucciones donde detecta el flanco
de 1 a 0 se coloc la instruccin de delay_ms(40); esa instruccin dura 40 mS y ah se
queda ese tiempo el programa, entonces cuando vuelva a checar el valor del botn ya los
rebotes ya no existen porque ya pasaron 40mS
if ((botonp==1)&&(botona==0))
//hubo cambio de flanco de 1 a 0
{
var++;
//Se incrementa la variable
if (var==10)
var=0;
delay_ms(40); //Se coloca retardo de 40mS para eliminar rebotes
}
Tambin se agreg las siguientes instrucciones:
if ((botonp==0)&&(botona==1))
//hubo cambio de flanco de 0 a 1
delay_ms(40); //Se coloca retardo de 40mS para eliminar rebotes
Recuerde que cuando se abre el interruptor (en el flanco de 0 a 1) tambin se pueden
generar rebotes, por lo tanto cuando se detecta que se abri el interruptor se coloca un
Programacin en C de los microcontroladores ATMEL

retardo de 40mS para que se quede ah ciclado el programa y cuando salga de ah, ya los
rebotes no existirn porque ya pasaron 40 mS.

Teclado Matricial
Si deseara manejar digamos 16 botones y lo hiciera poniendo un botn en cada pin gastara
16 pines del microcontrolador, en vez de esto se puede hacer un teclado matricial, el cual
ahorra pines. Por ejemplo una matriz de 4*4 puede manejar 16 teclas, una matriz de 5*5
puede manejar 25 teclas. En el primer caso se ocuparan 4 pines de salida y 4 de entrada, en
el segundo se ocupan 5 pines de salida y 5 de entrada. Aqu vemos el ahorro, para 16 teclas
se ocupan 8 pines en lugar de 16 pines si se hiciera el teclado conectando cada pin a un
botn, y el ahorro es mayor cuando se ocupan 25 teclas, ya que se ocupan 10 pines en total
en lugar de 25 pines si se conecta cada botn con cada pin.
Diagrama de un teclado matricial

Figura 2.10 Diagrama de un teclado matricial de 3*3


En la figura 2.10 se muestra un teclado matricial de 9 teclas, aqu se ocupan 3 pines de
salida que son los 3 pines superiores, los 3 pines inferiores se ocupan como entradas, es
importante sealar que a los pines de entrada SE LES CONFIGURA LA RESISTENCIA
DE PULL-UP INTERNA.
Si no se presiona ningn botn marcado de B1 a B9 los 3 pines leeran 111 ya que leen el
1 por la Resistencia de pull-up interna.
El funcionamiento del teclado matricial se basa en escaneos, es decir, se va probando
columna por columa. Por ejemplo si en los 3 pines de salida se enva 011 se va a probar la
primera columna donde estn B1,B2 y B3, si se presiona B1 en los pines de entrada se leer
011, si se presiona B3 se leer 110, si no se presiona ningn botn se leer 111. Note

Programacin en C de los microcontroladores ATMEL

que si en los pines de salida se enva 011 y se presiona un botn de B4 a B9 no se va a


leer ningn cero en los 3 pines de entrada porque se est probando la columna 1.
Para probar la segunda columna se enva en los pines de salida 101 y si no se presiona
ninguna tecla se leer en la entrada 111, pero si se presiona el boton 5 se leer 101, si
se presiona el botn 6 se leer 110. Si se presiona los botones B1 a B3 o B7 a B9 se
leern en los 3 pines de entrada 111 debido a que se est probando la segunda columna.
Las resistencias de 100 ohms que se ponen a la salida de los 3 pines es para prevenir cortos
circuitos y daar el puerto del microcontrolador, suponga que no se pusiera esas
resistencias y que se enva el dato 101 y se presiona al mismo tiempo el botn B1 y B4
vemos que en B1 hay 1 (5 volts) y en B4 hay 0 (0 Volts) entonces se generara un corto
circuito. Pero al poner esa resistencia de 100 ohms no sucede el corto ya que se limita la
corriente por ese resistor.
Resumen del teclado matricial:
Para probar la primera columna (botones B1 a B3) se enva en los pines de salida 011
Para probar la segunda columna (botones B4 a B6) se enva en los pines de salida 101
Para probar la tercera columna (botones B7 a B9) se enva en los pines de salida 110
Si se envi el cdigo 011 y se lee en los pines de entrada 011 entonces se presion el
botn B1.
Si se envi el cdigo 011 y se lee en los pines de entrada 101 entonces se presion el
botn B2.
Si se envi el cdigo 011 y se lee en los pines de entrada 110 entonces se presion el
botn B3.
Si se envi el cdigo 101 y se lee en los pines de entrada 011 entonces se presion el
botn B4.
Si se envi el cdigo 101 y se lee en los pines de entrada 101 entonces se presion el
botn B5.
Si se envi el cdigo 101 y se lee en los pines de entrada 110 entonces se presion el
botn B6.
Si se envi el cdigo 110 y se lee en los pines de entrada 011 entonces se presion el
botn B7.
Si se envi el cdigo 110 y se lee en los pines de entrada 101 entonces se presion el
botn B8.
Si se envi el cdigo 110 y se lee en los pines de entrada 110 entonces se presion el
botn B9.
Si cuando se envan los cdigos 011, 101 y 110 no se presiona ningn botn se leer
en los pines de entrada 111
En el teclado matricial a los pines de entrada hay que activarles la resistencia de pull-up
para que cuando no se presione ningn botn se lea 1 lgico en cada pin y no quede flotado

Programacin en C de los microcontroladores ATMEL

el pin, que recordando cuando un pin queda flotado comienza a oscilar leyendo 0 y 1 de
manera aleatoria debido al ruido.
Las resistencias de 100 ohms a la salida de los pines que son los que envan el cdigo son
para proteger contra corto circuitos, por ejemplo si se enviara en la primera columna un 0 y
en la segunda un 1 y se presionar el botn 1 y 4 habra un corto ya que en una lnea hay 5
volts y en el otro 0, as que al tener la resistencia de 100 Ohms la corriente se ve limitada y
no sucede nada al presionar dos teclas al mismo tiempo.
Como son botones los que estn conmutando a tierra hay que quitarle los rebotes, tal y
como lo hicimos en el programa 6. Aunque en este programa que se har no se quitarn los
rebotes.
Este ejemplo de 3*3 se puede usar como base para disear cualquier teclado matricial 5*5,
6*6, etc.
Programa 7. Diseo de un teclado matricial de 3*3, con despliegue a display a 7
segmentos. Los pines C0, C1 y C2 sern los pines de salida por donde se enviarn los
cdigos de saceneo, los pines C3, C4 y C5 sern los pines de entrada donde se leern
los botones presionados.
Configuracin: C0, C1 y C2 de salida, C3, C4 y C5 de entrada con resistencia de pull-up
interna activada. B0 a B7 de salida que es donde se conectar el display.

Figura 2.11 Conexiones para el programa 7


/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.7a Evaluation
Automatic Program Generator
Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Programacin en C de los microcontroladores ATMEL

Project :
Version :
Date : 14/09/2008
Author : Freeware, for evaluation and non-commercial use only
Company :
Comments:

Chip type
: ATmega48
Clock frequency : 1,000000 MHz
Memory model
: Small
External SRAM size : 0
Data Stack size : 128
*****************************************************/
#include <mega48.h>

// Declare your global variables here


unsigned char tecla,lectura;
const char tabla7segmentos [10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7c,0x07,0x7f,0x6f};
void main(void)
{
// Declare your local variables here
// Crystal Oscillator division factor: 8
#pragma optsizeCLKPR=0x80;
CLKPR=0x03;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
// Input/Output Ports initialization
// Port B initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTB=0x00;
DDRB=0xFF;
// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=Out Func1=Out Func0=Out
// State6=T State5=P State4=P State3=P State2=1 State1=1 State0=1
PORTC=0x3F;
DDRC=0x07;
// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh

Programacin en C de los microcontroladores ATMEL

// OC1A output: Discon.


// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;
// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x00;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x00;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;
while (1)
{
//C0 A C2 son de salida y son para
//Probar las 3 columnas
//Se prueba la primera columna se enva 110
PORTC=0b00111110;
//C3, C4 y C5 son las entradas del teclado
//Por eso se enmascaran con 00111000
lectura=PINC&0b00111000;
if (lectura==0b00110000)
tecla=7;
if (lectura==0b00101000)
tecla=8;
if (lectura==0b00011000)
tecla=9;

Programacin en C de los microcontroladores ATMEL

//se prueba segunda columna se enva 101


PORTC=0b00111101;
//C3, C4 y C5 son las entradas del teclado
//Por eso se enmascaran con 00111000
lectura=PINC&0b00111000;
if (lectura==0b00110000)
tecla=4;
if (lectura==0b00101000)
tecla=5;
if (lectura==0b00011000)
tecla=6;
//se prueba tercera columna se enva 011
PORTC=0b00111011;
//C3, C4 y C5 son las entradas del teclado
//Por eso se enmascaran con 00111000
lectura=PINC&0b00111000;
if (lectura==0b00110000)
tecla=1;
if (lectura==0b00101000)
tecla=2;
if (lectura==0b00011000)
tecla=3;
PORTB=tabla7segmentos [tecla];
// Place your code here
};
}

Programacin en C de los microcontroladores ATMEL

2.5 MEMORIA EEPROM


Este microcontrolador ATMEGA48 tiene 256 Bytes de memoria no voltil EEPROM, el
manejo de la EEPROM se hace a travs de varios registros: EEARH, EEARL, EEDR, y
EECR. Donde hay que especificar la direccin, escribir el dato a guardar, y unos bits de
control, etc. Pero no es necesario conocer y manejar esos registros, ya que el codevision nos
permite manejar los datos en eeprom como variables y l se encarga de manejar los
registros, as que solamente hay que escribir la variable o arreglo como lo hemos hecho en
temas anteriores pero antecediendo la palabra eeprom y de esa manera el compilador
guardar ese dato en la memoria eeprom
Ejemplos:
eeprom unsigned char var1;
eeprom unsigned int var1, var2, calibracin, hora;
eeprom unsigned char tabla [5]={0x01,0x02,0x04,0x03,0x10};
Programa 8. Haga un programa en el cual con un botn conectado al pin C0
incrementar el valor en el display conectado en el puerto B y cuando se presione el
botn C1 lo guardar. Despus de descargar el programa desconecte el
microcontrolador de la energa elctrica y vulvalo a conectar para que observe que el
dato se qued guardado.

Figura 2.12 Conexiones para el programa 8


Configuracin: C0 y C1 de entrada con resistencia de pull-up activada y es donde se
conectarn los botones; B0 a B6 de salida para conectar el display.

Programacin en C de los microcontroladores ATMEL

/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.7a Evaluation
Automatic Program Generator
Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project :
Version :
Date : 14/09/2008
Author : Freeware, for evaluation and non-commercial use only
Company :
Comments:

Chip type
: ATmega48
Clock frequency : 1,000000 MHz
Memory model
: Small
External SRAM size : 0
Data Stack size : 128
*****************************************************/
#include <mega48.h>
#include <delay.h>
#define boton PINC.0
#define boton_guarda PINC.1
bit botonp;
bit botona;
unsigned char var; //Ahora la variable se guarda en eeprom
const char tabla7segmentos [10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7c,0x07,0x7f,0x6f};
eeprom char datoaguardar;
void checa_boton (void); // Aqu se declaran todas las funciones que se van usar

// Declare your global variables here


void main(void)
{
// Declare your local variables here
// Crystal Oscillator division factor: 8
#pragma optsizeCLKPR=0x80;
CLKPR=0x03;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
// Input/Output Ports initialization
// Port B initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTB=0x00;
DDRB=0xFF;
// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=T State2=T State1=P State0=P
PORTC=0x03;
DDRC=0x00;
// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x00;

Programacin en C de los microcontroladores ATMEL

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;
// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x00;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x00;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;

Programacin en C de los microcontroladores ATMEL

ADCSRB=0x00;

if (datoaguardar>10)
datoaguardar=0;
var=datoaguardar;
while (1)
{
checa_boton();
PORTB=tabla7segmentos [var];
if (boton_guarda==0) //Si se presiona el botn de guardar
datoaguardar=var; //se grabara la eeprom con el valor de var
// Place your code here
};
}
void checa_boton (void)
{
if (boton==0)
botona=0;
else
botona=1;
if ((botonp==1)&&(botona==0))
//hubo cambio de flanco de 1 a 0
{
var++;
//Se incrementa la variable
if (var>=10)
var=0;
delay_ms(40); //Se coloca retardo de 40mS para eliminar rebotes
}
if ((botonp==0)&&(botona==1))
//hubo cambio de flanco de 0 a 1
delay_ms(40); //Se coloca retardo de 40mS para eliminar rebotes
botonp=botona;
}

Explicacin del Programa


En este programa se est utilizando una funcin que llam checa_boton, pero esta funcin
se debe declarar en la parte de arriba, esta funcin no regresa, ni enva parmetros por lo
que se coloca void checa_boton(void); Para entender mejor esto regrese a la seccin del
primer captulo donde se explica las funciones.
void checa_boton (void); // Aqu se declaran todas las funciones que se van usar
Despus en el programa se llama la funcin y se coloca:
checa_boton();
Cuando la funcin se ejecuta, regresa a la instruccin que est debajo de checa_boton();
que es PORTB=tabla7segmentos [var];
En una parte del programa se tiene:
if (datoaguardar>10)
Programacin en C de los microcontroladores ATMEL

datoaguardar=0;
La razn de ello es que si el datoaguardar que es una variable eeprom tiene un valor inicial
mayor a 10 la hacemos 0, y esto sucedera una sola vez, ya que cuando se guarde un dato el
dato estar entre 0 y 9. Pero un microcontrolador nuevo tiene en la memoria eeprom puros
0xff en todas las localidades, entonces la primera vez har que ese dato de 0xff se haga 0.
Importante. Si dentro de un programa utiliza una variable eeprom como una variable RAM
pude suceder que dae esa localidad de memoria eeprom, ya que una eeprom tiene una vida
til de 100,000 ciclos de escritura y lectura, pero si usa esa variable eeprom como una
variable RAM puede suceder que en custin de segundos sucedan esos 100,000 ciclos de
escritura y lectura porque un programa en el microcontrolador ejecuta el cdigo miles de
veces en un segundo, entonces al reescribir esa variable en el programa miles de veces en
un segundo se va a cabar la vida til de la localidad de memoria. En el programa vemos que
la eeprom slo se escribe cuando se presiona un botn.

2.6 Configuracin del Convertidor de Analgico a Digital (ADC)


Las caractersticas del ADC que tiene el microcontrolador AVR son:

Tiene 6 canales con 10 bits de resolucin


Capaz de obtener 15,000 muestras por segundo a la mxima resolucin
Voltaje de referencia internos de 1.1V
Voltaje de referencia externo de 0 a Vcc del ADC
Capacidad de detener el CPU para minimizar el ruido y mejorar el resultado de la
conversin

2.6.1 Funcionamiento de un ADC


Un ADC convierte una seal analgica a un dato digital de manera lineal, para ello es
necesario identificar tres aspectos importantes y stos son: el voltaje de referencia (Vref), el
nmero de bits y si es unipolar o bipolar el ADC.
2.6.1.1 Conversin unipolar
En la conversin unipolar el voltaje que se introduce a los canales del convertidor es
solamente positivo, y pudiendo ser la conversin del ADC de 10 bits o de 8 bits, si es de 10
bits significa que identifica hasta 210 combinaciones que son 1024; si es de 8 bits tiene 28
combinaciones esto es 256 combinaciones. Obviamente entre ms bits sean es mejor el
ADC aunque en ocasiones no es necesario una resolucin tan elevada. El voltaje de
referencia es el valor con el que se comparar el voltaje de entrada analgico y con base en
ello se determina la combinacin de salida. La forma de obtener la combinacin digital en
funcin del voltaje de entrada es:
Programacin en C de los microcontroladores ATMEL

conversin=(Vin*1024)/Vref .....................................................................................ec(2.1)
Donde Vin es el voltaje que se aplica, vref es el voltaje de referencia y conversin es el
valor digital.
Por ejemplo si Vref=5 y el vin que va a medir es de 2.5 dar como salida 512 segn la
ecuacin 2.1; si ahora el vin es de 1 volt la conversin que dar ser de 204.
En el caso de que se seleccione una conversin de 8 bits, la frmula a utilizar es:
conversin=(Vin*256)/Vref ......................................................................................ec(2.2)
Sustituyendo en la ec 2.2 los valores de vin=2.5 el resultado de la conversin es 128, si el
vin=1el resultado de la conversin ser 51

En el circuito integrado identifiquemos las terminales asociadas al ADC

Figura 2.13 Pines del microcontrolador ATMEGA48


En la figura 2.13 vemos que en las terminales 22 y 20 dicen GND y AVCC, ests son las
trminales de tierra y alimentacin del perifrico del convertidor de analgico a digital.
Normalmente los microcontroladores de otros fabricantes el ADC se alimenta con el mismo
voltaje del microcontrolador, pero en los de ATMEL son alimentados por separado para
disminuir los efectos del ruido. Aunque en nuestro caso y para los programas que vamos a
realizar el AVCC y VCC los conectaremos juntos y los GND tambin sern conectados
juntos. Pero recuerde que si en su aplicacin requiere de una conversin ms exacta puede
alimentar el microcontrolador y el perifrico del ADC por separado. Solamente tenga en

Programacin en C de los microcontroladores ATMEL

cuenta que si los va alimentar por separado el voltaje del perifrico del ADC no debe ser
mayor al del microcontrolador, por ejemplo si el microcontrolador lo va alimentar con dos
pilas y el voltaje es de 3 Volts, el ADC debe ser alimentado con 3 volts como mximo
tambin.
El vref que se encuentra en las ecuaciones 2.1 y 2.2 puede ser de tres tipos:
1. Vref=Vcc del microcontrolador, en este caso Aref no se conecta (pin 21)
2. Vref=Aref (pin 21). En este caso se tiene una referencia externa y puede ser
cualquier voltaje, siempre y cuando no sea superior al Vcc del microcontrolador.
3. Vref=1.1 Volts interno
Todos los casos anteriores se configuran con el codevision con clicks.
En las ecuaciones 2.1 y 2.2 se tiene un trmino llamado Vin que es el voltaje de entrada, es
decir, el voltaje que ser convertido a una combinacin digital, segn su proporcin con
Vref. Este Vin se aplica en los canales del ADC que se numeran desde ADC0 hasta ADC5
(pines del 23 al 28), entonces tenemos que esos pines tienen varias funciones ya sean como
pines de entrada o salida, o como entradas del ADC. Entonces si el pin se configura como
entrada del ADC ya no puede funcionar como entrada/salida digital, esto es que las
funciones son excluyentes.

Resumen del ADC


En este perifrico podemos tener:

Conversin unipolar donde se aplica a la entrada analgica un valor de voltaje


positivo que puede ir desde 0 hasta Vref.
o Puede ser la conversin de 8 bits donde el resultado est dado por:
conversin=(Vin*256)/Vref
o Puede ser la conversin de 10 bits donde el resultado est dado por:
conversin=(Vin*1024)/Vref
El Vref puede ser el voltaje del microcontrolador, pueder ser uno externo conectado
a la terminal Aref o uno interno de 1.1 Volts.
El Vin es el voltaje analgico que ser convertido a un combinacin digital, y ese
vin se aplica en cualquiera de los canales ADC0 hasta ADC5
El perifrcio del ADC se alimenta por separado, pero no puede ser mayor al Vcc del
microcontrolador. Aunque para estos ejemplos conecatremos las terminales de GND
y el Vcc lo conectaremos al Avcc.
Las configuraciones descritas anteriormente se realizan con clicks en el codevision,
por lo que no es necesario aprender ningn registro o bit de stos para su
configuracin.

Importante. Si va a utilizar un canal para hacer la conversin tenga la precaucin de


configurar ese pin como entrada. Ya que en ese canal va aplicar voltaje y no puede estar

Programacin en C de los microcontroladores ATMEL

configurado el pin como salida, ya que de ser as se podra daar el pin. Por ejemplo si va
utilizar el canal 0 del adc que es el pin A0 deber configurar ese pin como entrada.
Importante El Avcc no puede ser mayor al Vcc, por eso conctelos juntos
Importante El Aref no puede ser mayor al Vcc del microcontrolador.
Importante No aplique Vin mayores a Aref o a Vcc para evitar daos en el pin del ADC.

Programa 9. Haga una conversin en 8 bits sobre el canal 0 del ADC y muestre el resultado
en leds que se conectarn en el Puerto B. Configure como Vrfe el Vcc del microcontrolador.
Tabla 2.1 Canal y pin del ADC
Canal
Pin
0 ADC0
23 C0
1 ADC1
24 C1
2 ADC2
25 C2
3 ADC3
26 C3
4 ADC4
27 C4
5 ADC5
28 C5

Con el codewizard se hace la configuracin del ADC a travs de simples clicks, lo nico
que deberemos hacer en el programa es leer el valor de la conversin del canal que estemos
usando a travs de la siguiente funcin:
variable=read_adc (nmero_de_canal);
Por ejemplo si desear utilizar el canal 3, que es el pin 26 deber colocar
variable=read_adc(3);
Recuerde tambin que el ADC puede entregar la conversin en 8 o 10 bits, si selecciona
conversin en 8 bits, entonces la variable deber definirse como unsigned char variable; es
decir tipo char de 8 bits, pero si se selecciona una conversin en 10 bits deber declarar la
variable como unsigned int variable, ya que el valor de la conversin ocupa 10 bits.

Programacin en C de los microcontroladores ATMEL

El nombre que le di a la variable donde se guardar el resultado fue variable, pero puede
darle cualquier nombre.
Importante. La funcin read_adc() slo puede utilizarse si dentro del codevision se habilit
el ADC, ya que si lo usa en cualquiera de los otros programas que se han realizado y que no
han unicializado el ADC marcar error.
Programa 7. Inicialice el ADC del microcontrolador, considerando que el Vref es el Vcc,
que se va utilizar el canal 1 (Pin A1 donde deber inicializar ese pin como entrada), y que
el microcontrolador est alimentado a 5 volts, por lo que el Vrfe=5 Volts. Se utilizar el
ADC con 8 bits de resolucin y el voltaje medido se desplegar en dos displays.
Vea el video_p9 donde se muestra la forma de inicializar el ADC.
/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.7a Evaluation
Automatic Program Generator
Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project :
Version :
Date : 15/09/2008
Author : Freeware, for evaluation and non-commercial use only
Company :
Comments:

Chip type
: ATmega48
Clock frequency : 1,000000 MHz
Memory model
: Small
External SRAM size : 0
Data Stack size : 128
*****************************************************/
#include <mega48.h>
#include <delay.h>
unsigned char x;
#define ADC_VREF_TYPE 0x60
// Read the 8 most significant bits
// of the AD conversion result
unsigned char read_adc(unsigned char adc_input)
{
ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=0x40;
// Wait for the AD conversion to complete
while ((ADCSRA & 0x10)==0);
ADCSRA|=0x10;
return ADCH;
}
// Declare your global variables here
void main(void)
{
// Declare your local variables here

Programacin en C de los microcontroladores ATMEL

// Crystal Oscillator division factor: 8


#pragma optsizeCLKPR=0x80;
CLKPR=0x03;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
// Input/Output Ports initialization
// Port B initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTB=0x00;
DDRB=0xFF;
// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0x00;
DDRC=0x00;
// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;

Programacin en C de los microcontroladores ATMEL

TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;
// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x00;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x00;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;
// ADC initialization
// ADC Clock frequency: 500,000 kHz
// ADC Voltage Reference: AVCC pin
// ADC Auto Trigger Source: None
// Only the 8 most significant bits of
// the AD conversion result are used
// Digital input buffers on ADC0: On, ADC1: On, ADC2: On, ADC3: On
// ADC4: On, ADC5: On
DIDR0=0x00;
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0x81;
while (1)
{
x=read_adc(0); //Se hace la conversin sobre el canal 0 del ADC
PORTB=x;
//Se despliega en el puerto B el valor digital
// Place your code here
};
}

El programa 9 hace una conversin sobre el canal 0, pero el resultado que da, no es en
voltaje sino en un cdigo binario. Si Vin=0 volts la conversin dio 0b0000,0000; si vin=2.5
volts la conversin da 0b1000,0000 (128 decimal); si es 5 Volts=0b1111,1111 (255
decimal). Es decir nos convierte a una proporcin binaria que luego debemos interpretar,
pero ese resultado lo podemos convertir a voltaje a travs de una regla de 3.
Si Vin=5 da como resultado 0xff, es decir 255, Pero deseamos que muestre un cdigo
nuevo que sea 50 (que sera 5.0 Volts). Entonces se resuleve as:

Programacin en C de los microcontroladores ATMEL

Cdigo nuevo=Conversin*50/conversin mxima


Note, si Vin=5 Volts, la conversin dar 0b1111,1111 que es 255, que sustituyendo en la ec
1.3 da:
Cdigo nuevo=255*50/255=50 que podemos interpretar como 5.0 Volts.
Si vin=2.5 Volts, la conversin dar 0b1000,0000 que es 128
Cdigo nuevo=128*50/255 =25 que podemos interpretar como 2.5 Volts.
Entonces la ecuacin 1.3 queda:
cdigo nuevo=conversin del ADC * cdigo que deseamos.....................................ec(1.3)
conversin_Mxima.
Ejemplo suponga que conectamos un sensor de temperatura que da 5 volts cuando hay
100C, entonces ahora deseamos mostrar el resultado en grados centgrados, no en voltaje,
as que sustituyendo en la ecuacin 1.3 queda:
Cdigo nuevo=Conversin del ADC*100/Conversin Mxima (255 para 8 bits)
Si conversin=255, el cdigo nuevo=100C
Si la conversin del ADC=128, el cdigo nuevo ser 128*100/255=50, el cdigo
nuevo=50C.
Pero ese cdigo nuevo debemos separarlo en digitos para poderlo desplegar en el display de
7 segmentos o en una LCD. Esto se realiza en el programa 10.
Programa 10. Haga una conversin de 8 bits en el canal 1 y muestre el resultado en
dos displays que se conectarn al Puerto B. El Vref=Vcc=5 volts.
Usando la ecuacin 1.3 tenemos que la conversin mxima =255, el cdigo que deseamos
con esa conversin mxima=50 para mostrar 5.0 Volts.
cdigo nuevo= conversin del ADC * cdigo que deseamos
Conversin Mxima
Debemos hacer lo siguiente en el programa:
Leer la conversin del canal
x=read_adc(1);
codigonuevo=x*50/255;
Importante. x es tipo char, se multiplica por 50 pero ese resultado temporal ocupa ms de 8
bits. Para evitar esto se hace el casting, es decir, se le dice al compilador el resultado de
Programacin en C de los microcontroladores ATMEL

x*50/255 da como resultado un char, ya que no sobrepasa a 255, pero lo obliga a que en las
operaciones intermedias (sobre todo en la multiplicacin) se guarde el resultado en algn
lugar ya que ocupa ms de 8 bits. El casting se hace codigonuevo=(char)x*50/255

EL USO DEL CASTING


Ejemplo 1.
Suponga que tiene x=y+w+z; y todas son tipo char, en ese caso no existe problema ya que
si y+w+z da como resultado un nmero menor a 255 se podr guardar en x.
Ejemplo 2.
x es tipo int; y,w y z son tipo char. Y se escribe x=y+w+z; Pero se sabe que y+w+z van a
dar mas de 255, y que caben en x ya que esta es tipo int. Pero lo de la derecha y+w+z est
declarado como char, entonces cuando la suma d ms de 255 dnde quedan esas
operaciones? Entonces aqu si va existir un problema porque x=int y y+w+z son tipo char
cuya suma da mas de 8 bits y que cabe en x, pero en las sumas parciales las variables son
char y estas no pueden guardar mas de 8 bits, entonces hay que hacer un casting, obligando
al compilador a decirle todas son tipo char, pero el resultado es tipo int para que lo guarde
temporalmente en algn lugar para despus asignarlo a x.
x=(int) y+w+z; //Esto ya da un resultado correcto
x=y+w+z
//Dara un resultado errneo ya que y+w+z da mas de 8 bits y estas
variables no pueden manejar ms de 8 bits
Importante. Podemos evitar hacer clculos de las operaciones intermedias para ver si
hacemos o no el casting, y esto dejarlo al compilador. Esta opcin se selecciona en el
codevision en project-configure-C Compiler y finalmente dando click en promote char to
int como se muestra en la figura 2.5

Programacin en C de los microcontroladores ATMEL

Con lo anterior le estamos indicando al compilador si la operacin intermedia ocupa el char


un espacio de un int que lo genere para evitar errores y as ya nos olvidamos del casting.
Con las dos instrucciones anteriores ya tenemos representado en voltaje la conversin, pero
debemos separarlo en dos digitos, esto es calcularle la cantidad de decenas y las unidades.
Continuando con la explicacin del programa, si ya se calcul el codigonuevo, ahora
debemos obtener los dos digitos a desplegar ya que el 50 no se puede desplegar en un
display, debemos obtener los dos digitos, as que:
decenas=codigonuevo/10;
unidades=codigonuevo%10;
Recuerde que % es la operacin mdulo y que da como resultado el residuo. Suponga que
el cdigonuevo=48, es decir 4.8 Volts
Entonces decenas=48/10=4
Y unidades=48%10=8 (que es el residuo)
Y las decenas y unidades los mandamos desplegar en dos displays de 7 segmentos.
Importante. En cada proyecto que hagamos debemos seleccionar la casilla de promote char
to int.
Vea el video_p10 donde se muestra la inicializacin del microcontrolador junto con el
ADC.
Programacin en C de los microcontroladores ATMEL

while (1)
{
var=read_adc(2); //Se leer el valor del Canal 1 pin A1
ajusta=50*255/var;
decenas=ajusta/10;
unidades=ajusta%10;
despliega();
// Place your code here
};
}

void despliega(void)
{
PORTB=tabla7segmentos [unidades];
PINA.1=1;
delay_ms(4);
PINA.1=0;
PORTB=tabla7segmentos[decenas];
PINA.0=1;
delay_ms(4);
PINA.0=0;
}

Explicacin del programa:


En la parte superior del programa se declar una variable ajusta tipo int, ya que est va a
guardar el resultado de la multiplicacin: 50*255/var;
Se inicializ el valor de la tabla que nos dibuja los nmeros en los 7 segmentos del display
y declaramos una funcin que nombr despliega y que utilizar en el programa y que no
enva, ni recibe parmetros.
unsigned int ajusta;
const char tabla7segmentos [10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7c,0x07,0x7f,0x6f};
void despliega (void);
Recuerde que la funcin para leer el valor de conversin del ADC es read_adc(canal); que
es la primera lnea y dicho valor de la conversin se guarda en una variable llamada var que
es de 8 bits, ya que la conversin que escojimos a la hora de inicializar el ADC fue de 8 bits.
Si el voltaje que se le aplica al canal 2 es de 2.5 Volts, el valor de la conversin ser de 127,
pero nosotros queremos representarlo en voltaje, as que con la frmula que de 50*255/var
y sustituyendo var=127 nos dar como resultado 25, que ahora si podemos representar
como 2.5 Volts. Pero el 25 hay que convertirlo a dos digitos para desplegarlos en el display,
por lo que 25/10=2, y 25%10=5 (recuerde que % es la funcim mdulo hace la divisin
pero el resultado es el residuo) y esos valores se guardan en decenas y unidades para
desplegarlos en la funcin despliega(); que a su vez tiene las instrucciones de prender y
apagar transistores, etc. Algo que ya vimos en los primeros programas.
var=read_adc(2); //Se leer el valor del Canal 1 pin A1
ajusta=50*255/var;
decenas=ajusta/10;
unidades=ajusta%10;
despliega();

Programacin en C de los microcontroladores ATMEL

Programa 11. Diseo de un teclado usando el ADC.

Importante. La funcin read_adc(canal) funciona nicamente si a la hora de inicializar el


microcontrolador con el codewizard inicializa el ADC, as que si utiliza esta funcin en los
programas anteriores no funcionar e inclusive marcar erros porque no est inicializado el
perifrico del ADC.
Hasta este punto ya sabe como monejar puertos, desplegar datos en displays, guardar datos
en eeprom y adems sabe utilizar el ADC. Con esta parte se concluye la programacin
bsica-intermedia del microcontrolador. En el siguiente capitulo veremos tems avanzados
del microcontrolador como interrupciones, protocolos de comunicacin y timers.

Manejo de las pantallas de LCD


Las pantallas de cristal lquido LCD alfanumricas sin importar el fabricante se basan en un
circuito integrado de Hitachi que es el HD44780, esto significa que cualquier pantalla que
se utilice funciona de la misma manera, por lo que la programacin de la pantralla es
Programacin en C de los microcontroladores ATMEL

indistinta de la marca de la LCD. La nica diferencia es en la velocidad, ya que algunas


responden ms rpidamente a los comandos que se le mandan.
El asistente que tiene el codevision solicita que se le indique de cuntos caracteres es cada
lnea de la LCD. As mismo indica en el mismo asistente cmo conectar la LCD y a que
pines. Las pantallas se pueden conectar en un bus de datos de 8 bits o de 4, el asistente lo
coloca en un bus de 4 bits para ahorrar pines. El asistente del codevision genera todo el
cdigo necesario para inicializar la LCD y el programador slo debe preocuparse por
manejar las siguientes funciones:
Los comandos que acepta la LCD son:
_lcd_ready();
_lcd_write_data();
_lcd_write_byte(direccion,dato);
_lcd_clear();
_lcd_gotoxy(unsigned char x,unsigned char y);
_lcd_putchar(char c);
Lo primero que debe hacerse es ubicar la posicin del cursor, es decirle en cul fila y en
cual columna. Por ejemplo las LCDs de 2x16 son 2 filas por 16 caracteres. Entonces su se
desea escribir en la segunda fi
_lcd_ready();

INSTITUTO TECNOLGICO DE MORELIA

Programacin en C de los microcontroladores ATMEL

CURSO AVANZADO DE
PROGRAMACIN EN C DE
MICROCONTROLADORES AVR
POR DAVID INFANTE SNCHEZ

dinfante29@hotmail.com
dinfante@itmorelia.edu.mx

Revisin 8.0
Septiembre del 2008
CAPTULO III. TPICOS AVANZADOS
3.1 Manejo de las Interrupciones INT0 e INT1
Una interrupcin, como su nombre lo indica, interrumpe el programa principal y ejecuta
una subrutina de interrupcin donde se ejecuta el cdigo que el programador desea, el
ejemplo mas representativo es el RESET de una PC cuando se presiona ese botn se
interrumpe el programa principal y vuelve a iniciar el programa.
Existen dos tipos de interrupcin las internas o de sofware y las externas o de hardware, por
ejemplo la de reset es una externa ya que est asociada a un pin. Las de sofware son
generadas por alguna condicin en los perifricos, por ejemplo podemos habilitar una
Programacin en C de los microcontroladores ATMEL

interrupcin cuando el ADC termine de hacer la conversin, o cuando suceda overflow en


el timer, etc.
El programa CodeVision en la parte de la configuracin del chip se hace la configuracin
de la interrupcin ah se habilita la interrupcin y se programa la forma en que funcionar
la interrupcin, y el CodeVision generar una subrutina de interrupcin para esa
interrupcin en particular.
Por ejemplo hay interrupciones que son por flanco de bajada en un pin, entonces, suceder
una interrupcin cuando haya un flanco de bajada en el pin. Las subrutinas de interrupcin
son como las funciones que hemos realizado, con la excepcin de que las subrutinas de
interrupcin SON LLAMADAS POR HARDWARE, es decir el microcontrolador llama a
la subrutina de interrupcin cuando el evento sucede y que puede ser en cualquier momento,
en cambio las funciones que define el usuario son llamadas por el software segn donde
haya escrito el programador el llamado de la funcin.

Figura 3.1 Ubicacin de las interrupciones externas


En la figura 3.1 apreciamos las interrupciones externas INT0 e INT1 que estn en los pines
4 y 5 del microcontrolador. Estas interrupciones las podemos configurar para que cuando
exista un 0 (low level) se genere una interrupcin, si cuando salga de la interrupcin sigue
estando en 0 el pin volver a saltar a la interrupcin. Los otros modos de configurar esas
interrupciones es por flanco de subida (rising edge) o por flanco de bajada (falling edge) o
ambos flancos (any change).
Si se habilita la interrupcin externa INT0 el codevision generar la siguiente subrutina, si
se configura que la INT0 funcione en flanco de bajada, cada vez que en ese pin exista un
cambio de 1 a 0 saltar a esta interrupcin donde el programador deber colocar el cdigo
que deber ejecutarse en ese evento.
interrupt [EXT_INT0] void ext_int0_isr(void)
{
// Place your code here
}

Programacin en C de los microcontroladores ATMEL

Si se habilita la interrupcin externa INT1 el codevision generar la siguiente subrutina.


// External Interrupt 1 service routine
interrupt [EXT_INT1] void ext_int1_isr(void)
{
// Place your code here
}
Importante. Vimos que la INT0 e INT1 son los pines 4 y 5, y que a su vez son los puertos
D2 y D3; as que si habilitamos las funciones de interrupcin INT0 y la INT1, ya esos pines
no son pines configurables de entrada/salida; es decir ya no les podemos habilitar la
resistencia de pull-up, o no podemos habilitarlos como salida porque ahora ya no funcionan
como pines de entrada/salida sino como pines de entrada, los cuales generarn una
interrupcin cuando se detecte el evento programado en la interrupcin.
Para probar las interrupciones de INT0 e INT1 se realizarn algunos programas para
entender su funcionamiento.
Programa 11. Disee un programa que cada vez que haya un flanco de bajada en la INT0
(pin 4) incremente el valor de un display conectado al puerto B, el cual podr contar de 0 a
9.
/*****************************************************
This program was produced by the
CodeWizardAVR V2.03.6 Evaluation
Automatic Program Generator
Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project :
Version :
Date : 16/09/2008
Author : Freeware, for evaluation and non-commercial use only
Company :
Comments:

Chip type
: ATmega48
Clock frequency : 1,000000 MHz
Memory model
: Small
External RAM size : 0
Data Stack size : 128
*****************************************************/
#include <mega48.h>
const char tabla7segmentos [10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7c,0x07,0x7f,0x6f};
unsigned char var;
// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
var++;
if (var>9)
var=0;
// Place your code here

Programacin en C de los microcontroladores ATMEL

}
// Declare your global variables here
void main(void)
{
// Declare your local variables here
// Crystal Oscillator division factor: 8
#pragma optsizeCLKPR=0x80;
CLKPR=0x03;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
// Input/Output Ports initialization
// Port B initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTB=0x00;
DDRB=0xFF;
// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0x00;
DDRC=0x00;
// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=P State1=T State0=T
PORTD=0x04;
DDRD=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

Programacin en C de los microcontroladores ATMEL

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;
// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Falling Edge
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x02;
EIMSK=0x01;
EIFR=0x01;
PCICR=0x00;
// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x00;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x00;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;
// Global enable interrupts
#asm("sei")
while (1)
{
PORTB=tabla7segmentos [var];
// Place your code here
};
}

Programa 12. Disee un programa que cada vez que haya un flanco de subida o bajada en la
INT1 (pin 5) incremente el valor de un display conectado al puerto B, el cual podr contar
de 0 a 9.
/*****************************************************
This program was produced by the
CodeWizardAVR V2.03.6 Evaluation
Automatic Program Generator
Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project :
Version :
Date : 16/09/2008
Author : Freeware, for evaluation and non-commercial use only
Company :
Comments:

Programacin en C de los microcontroladores ATMEL

Chip type
: ATmega48
Clock frequency : 1,000000 MHz
Memory model
: Small
External RAM size : 0
Data Stack size : 128
*****************************************************/
#include <mega48.h>
const char tabla7segmentos [10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7c,0x07,0x7f,0x6f};
unsigned char var;

// External Interrupt 1 service routine


interrupt [EXT_INT1] void ext_int1_isr(void)
{
// Place your code here
var++;
if (var>9)
var=0;
}
// Declare your global variables here
void main(void)
{
// Declare your local variables here
// Crystal Oscillator division factor: 8
#pragma optsizeCLKPR=0x80;
CLKPR=0x03;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
// Input/Output Ports initialization
// Port B initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTB=0x00;
DDRB=0xFF;
// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0x00;
DDRC=0x00;
// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=P State2=T State1=T State0=T
PORTD=0x08;
DDRD=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock

Programacin en C de los microcontroladores ATMEL

// Clock value: Timer 1 Stopped


// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;
// External Interrupt(s) initialization
// INT0: Off
// INT1: On
// INT1 Mode: Any change
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x04;
EIMSK=0x02;
EIFR=0x02;
PCICR=0x00;
// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x00;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x00;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;
// Global enable interrupts
#asm("sei")
while (1)
{
PORTB=tabla7segmentos [var];
// Place your code here
};
}

Programacin en C de los microcontroladores ATMEL

Programa 13. Disee un programa que cuando haya un flanco de subida en INT0 se
incremente el conteo del display que podra contar de 0 a 9, y que cuando haya un nivel
lgico de 0 en INT1 se decremente el valor del display.

3.2 Interrupciones externas PCINT0-PCINT23


Adems de las interrupciones INT0 e INT1 existen otras interrupciones externas
denominadas PCINTX (Pin Change Interrupt) que son 24 interrupciones desde PCINT0 a
PCINT23, pero existen dos diferencias con respecto a las de INT0 e INT1 que son:
1. Las interrupciones PCINTX se activan unicamente en cambios de nivel, es decir
cuando el pin cambia de 1 a 0 y de 0 a 1. No pueden configurarse en ninguna otra
opcin como las INT0 e INT1 que pueden configurarse para funcionar en flanco de
subida, bajada, en ambos o nivel lgico 0.
2. Las interrupciones PCINTX solo tienen tres subrutinas de interrupcin.
Cualquier interrupcin generada de PCINT0 a PCINT7 ejecutar la siguiente subrutina de
interrupcin.
// Pin change 0-7 interrupt service routine
interrupt [PCINT0] void pin_change_isr0(void)
{
// Place your code here
}

Cualquier interrupcin generada de PCINT8 a PCINT14 ejecutar la siguiente subrutina de


interrupcin.
// Pin change 8-14 interrupt service routine
interrupt [PCINT1] void pin_change_isr1(void)
{
// Place your code here
}

Cualquier interrupcin generada de PCINT16 a PCINT23 ejecutar la siguiente subrutina


de interrupcin.
// Pin change 16-23 interrupt service routine
interrupt [PCINT2] void pin_change_isr2(void)
{
// Place your code here
}
Programacin en C de los microcontroladores ATMEL

Tomando como ejemplo esta ltima subrutina de interrupcin indica que cualquier
interrupcin generada de PCINT16 a PCINT23 ejecutar esa subrutina, pero no
necesariamente cuanda haya un cambio de nivel de 0 a 1 y de 1 a 0 en esos pines ejecutar
esa subrutina ya que podemos por el codevision habilitar solamente, por dar un ejemplo,
que se habiliten las interrupciones en PCINT16 y PCINT20. En este caso solamente cuando
haya cambio de nivel en esos pines se ejecutar la subrutina de interrupcin, es decir, que
podemos habilitar de manera individual cada pin.
En la figura 3.2 vemos que habilitamos la interrupcin de PCINT0-PCINT7, pero de todas
ellas indicamos que slo la PCINT1 y la PCINT5 generar la interrupcin.

Figura 3.2 Habilitacin de las interrupciones PCINT1 y PCINT5


Para probar estas interrupciones realizaremos el siguiente programa
Programa 14. Cuando exista cambio de nivel en PCINT0 o en PCINT7 que se incremente el
valor de un contador de 0 a 9 que se mostrar en un display conectado al puerto B, cuando
exista un cambio de nivel en PCINT8, PCINT9 o PCINT10 se decrementar el valor del
conteo y cuando exista
Por ejemplo, veamos un programa en el cual se desea detectar cada vez que haya un flanco
de bajada en el PIN 18 que es INT1 se incremente un contador BCD que estar conectado
al puerto B.
El pin 18 que es el pin A2 tiene como funcin alterna la de interrupcin externa INT1, lo
vamos a configurar como fuente de interrupcin para detectar flancos de bajada en el pin y
que se contabilice en un display conectado al puerto B.

Programacin en C de los microcontroladores ATMEL

Configuracin: Activacin de la Interrupcin externa INT1 (y por lo tanto el pin A2 de


entrada), pines B0 a B6 de salida que es donde se conectar el display.
Vea el video_P9 donde se muestra la forma de configurar el microcontrolador.
/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.7a Evaluation
Automatic Program Generator
Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project :
Version :
Date : 04/05/2008
Author : Freeware, for evaluation and non-commercial use only
Company :
Comments:

Chip type
: ATtiny461
Clock frequency : 1,000000 MHz
Memory model
: Tiny
External SRAM size : 0
Data Stack size : 64
*****************************************************/
#include <tiny461.h>

unsigned char conteo;


const char tabla7segmentos [10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7c,0x07,0x7f,0x6f};
#define tra_u PINA.1
#define tra_d PINA.0

// External Interrupt 1 service routine


interrupt [EXT_INT1] void ext_int1_isr(void)
{
//Esta es la subrutina de interrupcin INT1
conteo++;
//Note que no hay ninguna funcin que la llame
if (conteo==10) //Es porque la llama el hardware al detectar un flanco
conteo=0;
//de bajada
// Place your code here
}
// Declare your global variables here
void main(void)
{
// Declare your local variables here
// Crystal Oscillator division factor: 1
#pragma optsizeCLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
// Input/Output Ports initialization
// Port A initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTA=0x00;
DDRA=0x00;

Programacin en C de los microcontroladores ATMEL

// Port B initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTB=0x00;
DDRB=0xFF;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: 8bit top=FFh
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0H=0x00;
TCNT0L=0x00;
OCR0A=0x00;
OCR0B=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=OCR1C
// OC1A output: Discon.
// OC1B output: Discon.
// OC1C output: Discon.
// Fault Protection Mode: Off
// Fault Protection Noise Canceler: Off
// Fault Protection triggered on Falling Edge
// Fault Protection triggered by the Analog Comparator: Off
// Timer 1 Overflow Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
// Compare D Match Interrupt: Off
// Fault Protection Interrupt: Off
PLLCSR=0x00;
TCCR1A=0x00;
TCCR1B=0x00;
TCCR1C=0x00;
TCCR1D=0x00;
TCCR1E=0x00;
TC1H=0x00;
TCNT1=0x00;
OCR1A=0x00;
OCR1B=0x00;
OCR1C=0x00;
OCR1D=0x00;
DT1=0x00;
// External Interrupt(s) initialization
// INT0: Off
// INT1: On
// INT1 Mode: Falling Edge
// Interrupt on any change on pins PCINT0-7, 12-15: Off
// Interrupt on any change on pins PCINT8-11: Off
MCUCR=0x02;
PCMSK0=0x00;
GIMSK=0x80;
GIFR=0x80;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x00;
// Universal Serial Interface initialization
// Mode: Disabled
// Clock source: Register & Counter=no clk.
// USI Counter Overflow Interrupt: Off
USICR=0x00;
// Analog Comparator initialization
// Analog Comparator: Off

Programacin en C de los microcontroladores ATMEL

ACSRA=0x80;
// Hysterezis level: 0 mV
ACSRB=0x00;
// Global enable interrupts
#asm("sei")
while (1)
{
// Place your code here
PORTB=tabla7segmentos [conteo];
};
}

Explicacin
Dentro del programa principal vemos que se queda de manera infinita ciclado
PORTB=tabla7segmentos [conteo];
while (1)
{
// Place your code here
PORTB=tabla7segmentos [conteo];
};

Pero dnde o cmo se incrementa la variable conteo? Recuerde que en la inicializacin


habilitamos la interrupcin INT1 y que iba ser por flancos de bajada, esto significa que
cada vez que se genere un flanco de bajada en la terminal INT1 el hardware va a llamar a la
subrutina de interrupcin de INT1, es decir, el programador no la puede llamar, sino es
cuando suceda el evento que genera la interrupcin. La subrutina de interrupcin de INT1
es la siguiente:
interrupt [EXT_INT1] void ext_int1_isr(void)
{
//Esta es la subrutina de interrupcin INT1
conteo++;
//Note que no hay ninguna funcin que la llame
if (conteo==10) //Es porque la llama el hardware al detectar un flanco
conteo=0;
//de bajada
// Place your code here
}
Tenga en cuenta que el codewizard genera la subrutina de interrupcin esperando que el
programador llene la funcin de interrupcin dependiendo de qu es lo que se desea que se
haga cuando sucede el evento de flanco de bajada. En nuestro caso queremos que cada vez
que se genera un flanco de bajada se incremente un contador es por ello que colocamos esas
instrucciones.

Programacin en C de los microcontroladores ATMEL

La interrupcines INT0 e INT1 tienen sus propias funciones de interrupcin y pueden


programarse para que genere una interrupcin por flanco de bajada, subida, ambos o por
nivel bajo; cuando se configura por nivel bajo significa que mientras est en nivel bajo se
generar la interrupcin, y si cuando sale de la subrutina de interrupcin sigue en nivel bajo
volver a saltar a la subrutina de interrupcin. Tambin hay que hacer notar que la INT0 e
INT1 son pines distintos, pero si habilita las dos interrupciones y una la habilita por flanco
de bajada la otra quedar habilitada con la misma condicin, esto es que no se puede
habilitar una por flanco de bajada y otra por flanco de subida ya que es la misma condicin
para las dos.
Importante. En el diagrama mostrado vemos que le pusimos una resistencia de pull-up
externo en el pin de la INT1 y esto es porque ya no le podemos activar la resistencia de
pull-up interna debido a que el pin ya no es de entrada/salida digital sino que funciona
como una interrupcin externa, cuando pruebe en el circuito puede que se incremente el
conteo 1,2 o 3 veces cuando se presione el botn y es porque los interruptores mecnicos
generan rebotes, por lo que detectar varios flancos de subida y bajada cuando nosotros lo
presionemos una sla vez. Si en vez de conectar un botn conecta un generador de
funciones ya no se generaran rebotes y tampoco se necesitara la resistencia de pull-up
debido a que el generador no deja flotado el pin, ya que entrega 0 y 1 lgico.
Otra diferencia que podemos hacer con respecto a los PICs es que los PICs slo tienen un
vector de interrupcin y por tanto saltan a la misma subrutina donde el programador debe
checar cul interrupcin se gener, en cambio los AVR tienen vectores de interrupcin
distintos por lo que el manejo de interrupciones es decenas de veces ms rpido que los
PICs porque estos saltan al mismo vector que los manda a una sola subrutina donde debe
probar cada interrupcin para saber cul fue la que la gener.
Programa 20. Realizar un programa que cuando haya una interrupcin por flanco de subida
en la INT0 se prender un led, y cuando detecte un flanco de subida en INT1 se apagar. El
Led se conectar en el pin B0.

Programacin en C de los microcontroladores ATMEL

Interrupcin por cambio de estado en un pin (PIN Change Interrupt)


En el siguiente diagrama vemos que la terminal 20 tiene marcado PCINT0 hasta la terminal
10 que tiene PCINT15. Esto significa PIN CHANGE INTERRUPT X, es decir que se
puede generar una interrupcin cuando cambia de nivel lgico esos pines. Si conectaramos
a esos pines un interruptor se generara una interrupcin tanto cunado se presiona el
interruptor como cuando se suelta, ya que se generara un cambio de nivel en ambos casos.
A diferencia de las interrupciones INT0 e INT1 (pines 9 y18) los PCINTX slo funcionan
por cambio de nivel lgico es decir en flanco de subida y bajada; y los INT0 e INT1 si los
podemos configurar para que funcionen por flanco de subida, bajada, ambos o por nivel
lgico 0.
La otra diferencia es que las INT0 e INT1 tienen una subrutina de interrupcin distinta. En
cambio e la interrupcin PCINT tiene una sla que es la siguiente :
// Pin change 0-15 interrupt service routine
interrupt [PCINT] void pin_change_isr(void)
{
// Place your code here
}

Programacin en C de los microcontroladores ATMEL

Programacin en C de los microcontroladores ATMEL

INSTITUTO TECNOLGICO DE MORELIA

TPICOS SELECTOS DE
PROGRAMACIN DE
MICROCONTROLADORES AVR
POR DAVID INFANTE SNCHEZ

dinfante29@hotmail.com
dinfante@itmorelia.edu.mx

Revisin 2.0
Abril del 2008

Programacin en C de los microcontroladores ATMEL

Objetivos

Disear instrumentos virtuales como medidores y controladores de temperatura,


presin, nivel, voltaje, corriente, etc. Usando LABVIEW y los microcontroladores
de ATMEL.
Control y medicin de variables a travs de mdulos de radio frecuencia
Diseo de filtros digitales IIR usando MATLAB y su implementacin en
microcontroladores ATMEL usando matemtica de punto flotante.

Debido a la complejidad de esta parte es presencial y se incluyen los siguientes temas:

Instrumentacin Virtual

Con el software de LabView se hacen instrumentos virtuales para manipular,


alamacenas y desplegar datos en la PC usando una conexin con el puerto serie del
microcontrolador. (8 horas)
Programas
1. Osciloscopio digital con despliegue en PC
2. Medidor de temperatura y despliegue en instrumentos virtuales
3. Medidor de nivel a travs de sensores de ultrasonido y despliegue en
instrumentos virtuales

Telemetra

Control de puertos de entrada/salida del micrcontrolador a travs de mdulos de RF


(2 horas)

Adquisicin de datos y despliegue de informacin en la pantalla de la PC a travs de


instrumentos virtuales usando mdulos de radio frecuencia (2 horas).
Programas
1. Control de puertos de E/S a travs de radio frecuencia, manipulados a travs
de instrumentos virtuales diseados con LABVIEW

Programacin en C de los microcontroladores ATMEL

2. Control de la intensidad luminosa de un foco por radio frecuencia y


LABVIEW

Procesamiento digital de seales

Diseo de filtros digitales tipo IIR y su implementacin en microcontroladores de


ATMEL usando matemtica de punto flotante. El diseo de los filtros se hace a
travs del sofware de MATLAB (4 horas)
Programas
1. Diseo de un filtro digital Butterworth e implementacin en un
microcontroladore ATMEL
2. Diseo de un filtro digital Chebyshev e implementacin en un
microcontroladore ATMEL

Para este curso es necesario contar con el sofware de MATLAB, LABVIEW y CodeVision,
y el curso consta de una introduccin a LABVIEW y teora de procesamiento de seales,
as como su programacin en MATLAB para el diseo de los filtros.
Es necesario haber cubierto los temas y prcticas de los cursos anteriores

Programacin en C de los microcontroladores ATMEL

Potrebbero piacerti anche