WinAvr nos permite acceder a los puertos de
entrada y salida mediante los registros DDRx,
PORTx y PINx, donde x corresponde al nombre del puerto a utilizar.
DDRx.
Es el registro que se ocupa de hacer que el
puerto sea de entrada o salida según el valor que tenga.
Si los bits de DDRx son 0 entonces será de entrada y si los bits son 1 será de
salida.
Ejemplo:
DDRA=0b00001111;
//los bits 0 a 3 del puerto A son de salida el resto son de entrada.
PORTx.
Es el registro que escribe o lee el puerto.
Si los bits de PORTx son 0 entonces en el puerto se escribirá un nivel bajo y si
los bits son 1 en puerto tendrá nivel alto.
Ejemplo:
PORTA=0b11000000;
//los bits 0 a 5 tienen nivel bajo, el resto son de nivel alto (esto si el puerto
es configurado como salida mediante el registro DDRA=0b11111111).
PINx.
Este registro se utiliza para efectuar la
lectura de un puerto configurado como entrada.
Ejemplo:
var=PINA;
//Guarda en la variable var el valor de los niveles que existe en el puerto A
(esto si se configura al puerto A como entrada mediante el registro
DDRA=0b00000000).
En WinAVR para tener acceso a los puertos de
entrada y salida se debe incluir la librería io.h del siguiente modo.
#include
<avr/io.h>
Para poder hacer uso de retardos en los
programas se tiene la librería delay.h y se la llama del siguiente modo.
#include
<util/delay.h>
Ejercicio 1.
Hacer un contador ascendente por el puerto
D con un tiempo de retardo de 200m[s].
Solución.
Se debe configurar el puerto como salida
(0b11111111=255) y luego hacer que el valor del puerto se incremente en 1.
#include <avr/io.h> //incluye la
librería para el acceso a los puertos
#include <util/delay.h> //incluye
la librería para los retardos
int main(void)
{
PORTD=0; //borra
el puerto D
DDRD=255; //configura
todo el puerto D como salida
while(1)
{
PORTD++; //el
puerto D se incrementa en 1
_delay_ms(200); //retardo
de 200ms
}
return 0;
}
Ejercicio 2.
Reflejar por el puerto D los valores
lógicos que existen el puerto C.
Solución.
Pare este caso el puerto D debe ser
configurado como salida y el puerto C como entrada y para no utilizar
resistores externos, en el puerto C activaremos los pull-up internos (estos
existen en todos los puertos del ATMEGA 32). Hay que tener cuidado de no manipular
bit 2 (PUD) del registro SFIOR.
#include <avr/io.h>
#include <avrlib/avrlibdefs.h>
#include <util/delay.h>
int main(void)
{
PORTD=0; //borra
el puerto D
PORTC=255; //habilita
el pull up en el puerto C
DDRD=255; //puerto
D como salida
DDRC=0; //puerto
C como entrada
while(1)
{
PORTD=PINC; //escribe en el puerto D los valores leídos en el
puerto C
_delay_ms(10); //retardo de 10ms
}
}
El acceso a los bits individuales de los
puertos es algo engorroso teniendo que hacer bastante uso de los
enmascaramientos pero podemos lidiar con esos problemas con la ayuda de las
librerías proporcionadas por Procyon AVRlib (la manera de obtenerlos y
situarlos en el lugar adecuado se mencionan en la anterior entrega titulada
WINAVR 0).
La nueva librería a utilizar es avrlibdefs.h y la incluiremos del
siguiente modo.
#include
<avrlib/avrlibdefs.h>
Las funciones disponibles para la
manipulación de bits de los puertos son:
bit_is_set(sfr, bit); //Retorna verdadero si el bit esta
a 1
bit_is_clear(sfr, bit); //Retorna verdadero si el bit es 0
cbi(reg,bit); //Pone a 0 el bit
sbi(reg,bit); //Pone a 1 el bit
Ejercicio 3.
Hacer que el bit 1 del puerto D muestre el
estado invertido del bit 5 del puerto C.
Solución.
Los puertos después del reset siempre
inician como entradas así que solo hacen falta definir los puertos de salida y
para no usar resistores externos utilizaremos los pull up internos del puerto
C.
#include <avr/io.h>
#include <avrlib/avrlibdefs.h>
#include <util/delay.h>
int main(void)
{
sbi(PORTC,5); //pull up activado en el bit 5 del puerto C
sbi(DDRD,1); //bit 1 del puerto D como salida
while(1)
{
if(bit_is_set(PINC,5))
{
cbi(PORTD,1);
}
else
{
sbi(PORTD,1);
}
_delay_ms(100);
}
}
Ejercicio 4.
Efectuar un contador ascendente descendente
visualizado en un display conectado al puerto B. Cuando el pin 0 del puerto A
esta a nivel bajo el contador es ascendente y de otro modo el contador es
descendente.
Solución.
Para generar los
dígitos en el display se hará uso de un decodificador implementado en forma de
vector.
#include <avr/io.h>
#include <avrlib/avrlibdefs.h>
#include <util/delay.h>
int main(void)
{
//decodificador para el display
unsigned char tabla[]={63,6,91,79,102,109,125,7,127,103};
unsigned char contador=0;
PORTD=0; //borra
el puerto D
DDRD=255; //puerto
D como salida
sbi(PORTA,0); //pullup
en el bit 0 del puerto D
while(1)
{
PORTD=tabla[contador];
_delay_ms(500);
if(bit_is_clear(PINA,0))
{
if(++contador==10) //primero incrementa contador y luego compara
{
contador=0;
}
}
else
{
if(--contador==255) //primero decrementa contador y luego compara
{
contador=9;
}
}
}
return 0;
}
Hasta la siguiente entrega.