EJEMPLO 3 El manejo de los puertos como entrada y salida es la principal tarea en cualquier aplicación, pero en ocasiones es importante tener en cuenta los efectos de los pulsadores, cuando éstos cumplen una función de acuerdo a la cantidad de veces que son presionados. El tercer ejemplo consiste en un conmutador, es decir se enciende y se apaga un led mediante un mismo pulsador. Se conectan tres pulsadores, todos con las mismas funciones. Acá se ve el efecto que se hace para evitar el rebote de contactos, lo combatimos mediante software con retardos. Este rebote de contactos, como el pulsador tendrá dos funciones (encender y apagar), hace funcionar inadecuadamente al circuito si no se controla adecuadamente. Un código anti-rebote (llamando a una función de retardo de 20 milisegundos que el usuario implementa) es el siguiente: cambie: call in cpi brne
delay20m r16,pind r16,0 cambie
;retardo antirrebote ;leer puertoD ;comparar con cero, para asegurar que se soltó el pulsador ;si no se solto seguimos con el retardo
Acá tenemos el código del programa: ;-------------------------------------------------------------------------------; Programa: Led on/off con el mismo Pulsador On/Off, conmutación 3 puntos ; Version: 0.0 ; Autor: Lewin Lopez ; ; Dispositivo: ATmega16 Compilador: AVRASM2 ; Entorno IDE: AVR Studio4.15 Simulador: Proteus 7.5sp3 ; ; Notas: Este programa enciende un Led con un Pulsador, y lo apaga ; con el mismo pulsador, desde 3 puntos. ; ; Registros: r16 para almacenar la lectura del puertoD, ; r19 y r20 para el XOR, que cambia el estado del pin ; r17 y r18 para el retardo de 20ms antirrebote ; ; Conexiones: B1 -> Led ; D0 -> Pulsador1 ; D1 -> Pulsador2 ; D2 -> Pulsador3 ;-------------------------------------------------------------------------------;DIRECTIVAS EN ENSAMBLADOR .include "m16def.inc" ;ATmega16 ;reset-vector address $0000 .org $00 jmp inicio ;va a inicio ;PROGRAMA PRINCIPAL
inicio: ;Cargar el puntero de pila ;------------------------ldi r16,high(ramend) ;Configuracion de... out sph,r16 ldi r16,low(ramend) out spl,r16 ;...la pila: Stack: $045F=RAMEN $045F=RAMEND D ;Configuración de los puertos a utilizar ;--------------------------------------ser r16 ;r16 <- $FF out ddrb,r16 ;portB salida por 1 bit ldi r16,$F8 ;r16 <- $F8 out ddrd,r16 ;portD 3 entradas por 3LSB ;Valor Inicial ;------------ldi clr
r19,2
;cargar el valor para toggle r20
ciclo: in sbrc call sbrc call sbrc call jmp
r16,pind r16,0 cambie r16,1 cambie r16,2 cambie ciclo
cambie: call delay20m in r16,pind cpi r16,0 brne cambie eor r20,r19 out portb,r20 ret ; ============================= ; delay loop generator ; 80000 cycles: ; ----------------------------; delaying 79998 cycles: delay20m: ldi R17, $86 WGLOOP0: ldi R18, $C6 WGLOOP1: dec R18 brne WGLOOP1 dec R17 brne WGLOOP0 ; ----------------------------; delaying 2 cycles: nop nop ret ; =============================
;leer puertoD ;si el pin D0 es cero saltamos una instrucción ;cambiamos estado del pin ;si el pin D1 es cero saltamos una instrucción ;cambiamos estado del pin ;si el pin D2 es cero saltamos una instrucción ;cambiamos estado del pin ;bucle infinito
;retardo antirrebote ;leer puertoD ;comparar con cero, para asegurar que se solto el pulsador ;si no se solto seguimos con el retardo ;xor para cambio de estado una vez. ;salida al puertob ;retorno de subrutina
El esquema del circuito:
Apuntadores Los apuntadores trabajan a través de registros pares. Para el caso del apuntador Z, trabaja con los registro R30 y R31. Estos registros pueden trabajar conjuntamente o por separado a través de ZL (Z Lower) Lower) y ZH (Z Higher). En tal caso, ZL puede almacenar los bits del 0 al 7 de un número de 16 bits y ZH almacena los bits del 8 al 15. De igual manera el apuntador Y trabaja con los registros R28 y R29, mientras que el apuntador X lo hace con R26 y R27. Los apuntadores X, Y y Z tienen la flexibilidad de usar una dirección que se incremente o decremente automática automáticamente mente cada vez que realiza una operación de carga y almacenamiento de valores.
EJ:
Ld reg, apuntador+ Ld r20, X+
Ld reg, apuntador+ permite cargar el contenido de la localidad de la memoria. En el código anterior se carga el contenido de un apuntador X(R27-R26) en el registro r20, posteriormente suma 1 al apuntador.
EJ:
Ld reg, -apuntador Ld r20, -X
Ld reg, -apuntador decrementa uno al apuntador y posteriormente posteriorment e carga en un registro la localidad de la memoria alojada en el apuntador. En el ejemplo se resta uno al apuntador X y luego se carga el contenido del registro apuntado en r20.
EJ:
Ldd reg, apuntador+ number Ldd r17, Z+3
Carga la localidad de memoria del apuntador Y o Z en un registro y a continuación adiciona el número que se indica al apuntador. Esta instrucción no funciona para el apuntador X. Carga el valor del apuntador Z en r17 y posteriormente posterior mente incrementa la dirección de Z en 3 posiciones.
EJEMPLO 4 Es frecuente utilizador el apuntador para hacer búsqueda de datos y manejar tablas de datos. ;----------------------------------------------------------------; Programa: Busqueda con puntero ; Version: 0.0 ; Autor: Lewin Lopez ; ; Dispositivo: ATmega16 Compilador: AVRASM2 ; Entorno IDE: AVR Studio4.15 Simulador: Proteus 7.5sp3 ; ; Notas: Este programa hace un a busqueda de un dato 04 usando ; un registro apuntador Z para para el direccionamiento. Cuando encuentra ; el dato, muestra muestra por el puerto A el registro que contiene el dato. ; en todo momento momento se muestra por el el puerto B los datos que que guarda cada ; registro y se espera un segundo para continuar. ; ; Registros: r0-r12 -> Registros para almacenar datos. ; r16 -> registro temporal para pasar datos. ; r17 -> registro de busqueda. ; r30 -> registro apuntador. ; r22-r24 -> registros para retardo. ; ; Conexiones: Puerto A -> Displays BCD. ; Puerto B -> Displays DBCD. ;----------------------------------------------------------------;DIRECTIVAS EN ENSAMBLADOR .include "m16def.inc" ;ATmega16 .device ATMEGA16 ;reset-vector address $0000 .org $00 jmp inicio ;va al inicio con un RESET ;PROGRAMA PRINCIPAL inicio: ;Cargar el puntero de pila ;------------------------ldi r16,high(ramend) out sph,r16
;Configuracion de...
ldi r16,low(ramend) out spl,r16 ;...la pila: Stack: $045F=RAMEN $045F=RAMEND D ;Configuracion de los puertos a utilizar ser r16 out ddra, r16 out ddrb, r16
;Puerto A salida ;Puerto B salida
;Cargar los valores de datos para realizar búsqueda ldi r16, $01 mov r1,r16 ;Carga $01 en r1 ldi r16, $02 mov r2,r16 ;Carga $02 en r2 ldi r16, $03 mov r3,r16 ;Carga $03 en r3 ldi r16, $0F mov r4,r16 ;Carga $0F en r4 ldi r16, $05 mov r5,r16 ;Carga $05 en r5 ldi r16, $FF mov r6,r16 ;Carga $FF en r6 ldi r16, $A1 mov r7,r16 ;Carga $A1 en r7 ldi r16, $48 mov r8,r16 ;Carga $48 en r8 ldi r16, $F2 mov r9,r16 ;Carga $F2 en r9 ldi r16, $04 mov r10,r16 ;Carga $04 en r10 ldi r16, $05 mov r11,r16 ;Carga $05 en r11 ldi r16, $FF mov r12,r16 ;Carga $FF en r12 ;Valor Inicial del Apuntador Z (r31-r30) ldi r30, $00 ldi r30, $00 ;Etapa de búsqueda busca: ld R17, Z+ incrementa Z. cpi R17,$04 breq resultado out portb, r17 call tiempo jmp busca resultado: dec r30 conservar la direccion out porta, r30
; Carga en r17 el valor del registro apuntado por Z e ; Busca el valor $04 ; Si lo encuentra va a resultado ; si no lo encuentra, muestra en el puerto B el dato que hay, ; espera un tiempo ; y continua la busqueda
; si lo encuentra decrementa el puntero para ; del registro que contiene el dato ; y muestra el valo del registro por el puerto A
fin: jmp fin ; ============================= ; delay loop generator
; termina el programa y no hace más.
; 1000000 cycles: ; ----------------------------; delaying 999999 cycles: tiempo: ldi R22, $09 WGLOOP0: ldi R23, $BC WGLOOP1: ldi R24, $C4 WGLOOP2: dec R24 brne WGLOOP2 dec R23 brne WGLOOP1 dec R22 brne WGLOOP0 ----------------------------; delaying 1 cycle: nop ret ; =============================
En el ejemplo anterior se usa el apuntador Z para encontrar el registro que contiene el dato 04. Los registros 0 al 12 contienen una serie de valores predeterminados. El esquema del circuito:
EJEMPLO 5 El ejemplo 5 es una solución efectiva para el ejercicio de clase 5 para rotar un LED a través de pulsadores. Código del programa: ;----------------------------------------------------------------; Programa: Rotar un LED de acuerdo a 3 pulsadores ; Version: 0.0 ; Autor: Lewin Lopez ; ; Dispositivo: ATmega16 Compilador: AVRASM2 ; Entorno IDE: AVR Studio4.15 Simulador: Proteus 7.5sp3 ; ; Notas: Este programa hace rotar un LED conectado en el puerto C ; de acuerdo acuerdo al estado de 3 pulsadores. ; Pulsador 1: rota a la derecha. ; Pulsador 2: rota a la izquierda. ; Pulsador 3: detiene o pausa la rotación. ; ; Registros: r16 -> registro temporal para pasar datos. ; r17 -> registro para rotar ; r18 -> registro para leer los pulsadores ; r19 -> registro para activar rotaciones ; r22-r24 -> registros para retardo. ; ; Conexiones: A0 -> Pulsador 1 ; A1 -> Pulsador 2 ; A2 -> Pulsador 3 ; Puerto C -> LEDs. ;----------------------------------------------------------------;DIRECTIVAS EN ENSAMBLADOR .include "m16def.inc" ;ATmega16 .device ATMEGA16 ;reset-vector address $0000 .org $00 jmp inicio ;va al inicio con un RESET ;PROGRAMA PRINCIPAL inicio: ;Cargo el puntero de pila ;-----------------------ldi r16,high(ramend) ;Configuracion de... out sph,r16 ldi r16,low(ramend) out spl,r16 ;...la pila: Stack: $045F=RAMEND ;Configuro los puertos a usar ;y activo resistencias de pull-up necesarias ;---------------------------ldi r16,0b11111000 ;3 LSB de entrada solamente out ddra,r16 com r16 out porta,r16 ;activa 3 resistencias de pull-up ser r16 ;Todo el puerto C de salida out ddrc, r16
;Cargo el valor inicial para rotar ;------------------------------------------ldi r17,$01 ldi r19,$00 ;Evaluo el estado de los pulsadores ;---------------------------------ciclo: in r18, pina cpi r18, $06 breq rotaDer cpi r18, $05 breq rotaIzq cpi r18, $03 breq pausa cpi r19, $01 breq rotaDer cpi r19, $02 breq rotaIzq jmp ciclo
;valor de rotación ;Valor 00:no se ha presionado ningun pulsador
; Leo el estado de los pulsadores ; estado 00000110 (presionado solo A0) ; si se presiona el primer pulsador va a rotaDer ; estado 00000101 (presionado solo A1) ; si se presiona el segundo pulsador va a rotaIzq ; estado 00000011 (presionado solo A2) ; si se presiona va a pausa ; si antes se ha presionado A0 (R19=01) ; si antes se ha presionado A1 (R19=02)
rotaDer: clc ldi ror brne sec ror
r19,$01 r17
; borra el carry ; Rotacion a la derecha activada (ya se presiono A0) ; Roto a la derecha una vez
sigue r17
; activa el carry ; Roto a la derecha una vez
sigue: out call jmp
portc,r17 espera500ms ciclo
; muestro por el puerto el resultado de rotar ; espero medio segundo ; vuelvo a evaluar los pulsadores
rotaIzq: clc ldi out rol brne sec rol
r19,$02 portc,r17 r17
; borra el carry ; Rotacion a la izquierda activada (ya se presiono A1) ; muestro por el puerto C el valor del registro de rotacion ; Roto a la Izquierda una vez
dele r17
; activa el carry ; Roto a la Izquierda una vez
dele: call jmp
espera500ms ciclo
; espero medio segundo
ldi call jmp
r19,$00 espera500ms ciclo
; Rotacion desactivada ; espero medio segundo
pausa:
; ============================= ; Retardo de 500 ms ; 2000000 cycles: ; ----------------------------; delaying 1999998 cycles: espera500ms: ldi R22, $12 WGLOOP0: ldi R23, $BC WGLOOP1: ldi R24, $C4
WGLOOP2: dec R24 brne WGLOOP2 dec R23 brne WGLOOP1 dec R22 brne WGLOOP0 ; ----------------------------; delaying 2 cycles: nop nop ; ============================= ret
El esquemático del circuito es:
EJEMPLO 6 El ejemplo 6 es un programa para realizar un conteo ascendente/descendente de 0 a 9 periódico con incrementos cada segundo. El código del programa es: ;----------------------------------------------------------------; Programa: Contador 0 a 9 y 9 a 0 Infinito. ; Version: 0.0 ; Autor: Lewin Lopez ; ; Dispositivo: ATmega16 Compilador: AVRASM2 ; Entorno IDE: AVR Studio4.15 Simulador: Proteus 7.5sp3 ;
; Notas: Este programa hace un conteo de 0 a 9 con incrementos cada ; segundo usando un registro apuntador apuntador Z para el direccionamiento de datos ; para manejar el el display de 7 segmentos. segmentos. Una vez llega a 9, se devuelve a cero ; y vuelve a empezar. ; ; Registros: r5-r14 -> Registros para almacenar datos de displays. ; r16 -> registro temporal para pasar datos. ; r17 -> registro de carga de datos. ; r30 -> registro apuntador. ; r22-r24 -> registros para retardo. ; ; Conexiones: Puerto B -> Displas de 7 sgmentos de cátodo común. ;----------------------------------------------------------------;DIRECTIVAS EN ENSAMBLADOR .include "m16def.inc" ;ATmega16 .device ATMEGA16 ;reset-vector address $0000 .org $00 jmp inicio ;va al inicio con un RESET ;PROGRAMA PRINCIPAL inicio: ;Cargar el puntero de pila ;------------------------ldi r16,high(ramend) ;Configuracion de... out sph,r16 ldi r16,low(ramend) out spl,r16 ;...la pila: Stack: $045F=RAMEN $045F=RAMEND D ;Configuracion de los puertos a utilizar ;--------------------------------------ser r16 out ddrb, r16
;solo puerto b de salida.
;Cargar los valores de datos para mostrar los datos en el dis play ldi r16, $3F mov r5,r16 ldi r16, $06 mov r6,r16 ldi r16, $5B mov r7,r16 ldi r16, $4F mov r8,r16 ldi r16, $66 mov r9,r16 ldi r16, $6D mov r10,r16 ldi r16, $7D mov r11,r16 ldi r16, $07 mov r12,r16 ldi r16, $7F mov r13,r16 ldi r16, $67 mov r14,r16 ;Valor Inicial del apuntador cero:
ldi r30, $04 ;Inicio del conteo ascendente conteo: ld r17, Z+ cpi r30,$0F breq cero1 out portb,r17 call tiempo jmp conteo cero1: ldi r30, $0F ;Inicio conteo descendente conteo1: ld r17,-Z cpi r30, $04 breq cero out portb, r17 call tiempo jmp conteo1 tiempo: ; ============================= ; delay loop generator ; 4000000 cycles: ; ----------------------------; delaying 3999996 cycles: ldi R22, $24 WGLOOP0: ldi R23, $BC WGLOOP1: ldi R24, $C4 WGLOOP2: dec R24 brne WGLOOP2 dec R23 brne WGLOOP1 dec R22 brne WGLOOP0 ; ----------------------------; delaying 3 cycles: ldi R22, $01 WGLOOP3: dec R22 brne WGLOOP3 ; ----------------------------; delaying 1 cycle: nop RET ; =============================
El esquemático del circuito es:
EJERCICIO EN CLASE: a) Realizar el contador del ejercicio 6 utilizando apuntadores. b) Realizar un contador ascendente de 0 a 20 con RESET usando apuntadores. Debe tener un solo pulsador de incremento con antirebote por software, el conteo es ascendente con incrementos cada 2 segundos y cuando la cuenta llega a 20 se genera una señal que reinicia la cuenta.
NOTA: En caso de tener programas similares entre estudiantes, se solicitará sustentación individual y la nota será tomada de dicha sustentación sin tener en cuenta que el programa funcione o no.