clase teclado e interrupcion

12
INTERRUPCIONES Y MANEJO DE UN TECLADO Una interrupción es un evento especial, ya que "interrumpe" al microcontrolador de su ejecución en curso, podríamos mencionar como ejemplo el hecho de que el microcontrolador este ocupado ejecutando una secuencia de código para sumar multiplicar y hacer algunos procesos más de unos datos, una interrupción se genera y el microcontrolador es obligado a detener la ejecución de ese proceso que estaba haciendo y desviar su atención por un momento para ejecutar un código (subrutina) que se debe hacer por la presencia de la interrupción, posteriormente cuando se termine de ejecutar la rutina que se hace por la interrupción, el procesador del microcontrolador vuelve a ejecutar el proceso que antes estaba haciendo desde el lugar desde donde fue interrumpido. Las interrupciones tienen muchas ventajas, ya que se puede de cierta manera obtener una especie de "paralelismo" porque el micro puede ejecutar el código principal, y en momentos especiales por las interrupciones, ejecutar una parte de código como si todo sucediera a la misma vez y volver al programa principal. Pero a la vez se debe tener cuidado en su manejo, pues son un arma de doble filo si no son bien administradas, en caso de tener que usar muchas interrupciones, o al tener mucho código que ejecutar en la rutina de interrupción. El microcontrolador tiene varias fuentes de interrupción, algunas son: por conversión análoga a digital terminada, por escritura en la eeprom completada, por desborde de temporizadores, por recepción de datos en la uart, por transmisión de datos completada en la uart, interrupciones externas por pines del micro al detectar un flanco ya sea de bajada o subida, entre otras. En los micros AVR cada interrupción posee su propio vector de interrupción lo que hace más cómoda su ejecución y programación de la rutina correspondiente (ver tabla 11-1 del datasheet, adjunto en la siguiente página de este documento). Ahora se describen las configuraciones para utilizar la interrupción externa INT0, cabe mencionar que el micro ATMEGA16 posee dos fuentes de interrupción externa, estas son INT0 ya mencionada además de INT1, alojadas en los pines D2 y D3 del micro respectivamente. Usaremos la Interrupción INT0 en el pin D2, los registros involucrados para su configuración son: MCUCR – MCU Control Register GICR – General Interrupt Control Register GIFR – General Interrupt Flag Register

Upload: michael-martinez

Post on 03-Jul-2015

626 views

Category:

Documents


2 download

TRANSCRIPT

INTERRUPCIONES Y MANEJO DE UN TECLADO Una interrupción es un evento especial, ya que "interrumpe" al microcontrolador de su ejecución en curso, podríamos mencionar como ejemplo el hecho de que el microcontrolador este ocupado ejecutando una secuencia de código para sumar multiplicar y hacer algunos procesos más de unos datos, una interrupción se genera y el microcontrolador es obligado a detener la ejecución de ese proceso que estaba haciendo y desviar su atención por un momento para ejecutar un código (subrutina) que se debe hacer por la presencia de la interrupción, posteriormente cuando se termine de ejecutar la rutina que se hace por la interrupción, el procesador del microcontrolador vuelve a ejecutar el proceso que antes estaba haciendo desde el lugar desde donde fue interrumpido.

Las interrupciones tienen muchas ventajas, ya que se puede de cierta manera obtener una especie de "paralelismo" porque el micro puede ejecutar el código principal, y en momentos especiales por las interrupciones, ejecutar una parte de código como si todo sucediera a la misma vez y volver al programa principal. Pero a la vez se debe tener cuidado en su manejo, pues son un arma de doble filo si no son bien administradas, en caso de tener que usar muchas interrupciones, o al tener mucho código que ejecutar en la rutina de interrupción.

El microcontrolador tiene varias fuentes de interrupción, algunas son: por conversión análoga a digital terminada, por escritura en la eeprom completada, por desborde de temporizadores, por recepción de datos en la uart, por transmisión de datos completada en la uart, interrupciones externas por pines del micro al detectar un flanco ya sea de bajada o subida, entre otras.

En los micros AVR cada interrupción posee su propio vector de interrupción lo que hace más cómoda su ejecución y programación de la rutina correspondiente (ver tabla 11-1 del datasheet, adjunto en la siguiente página de este documento).

Ahora se describen las configuraciones para utilizar la interrupción externa INT0, cabe mencionar que el micro ATMEGA16 posee dos fuentes de interrupción externa, estas son INT0 ya mencionada además de INT1, alojadas en los pines D2 y D3 del micro respectivamente. Usaremos la Interrupción INT0 en el pin D2, los registros involucrados para su configuración son:

• MCUCR – MCU Control Register • GICR – General Interrupt Control Register • GIFR – General Interrupt Flag Register

Se muestra ahora el significado de los bits que intervienen en el manejo de la interrupción INTO (externa por el pin D2).

MCUCR – MCU Control Register

Bit 3, 2 – ISC11, ISC10: Interrupt Sense Control 1 Bit 1 and Bit 0: Se usan para la INT1. Bit 1, 0 – ISC01, ISC00: Interrupt Sense Control 0 Bit 1 and Bit 0: Se usan para la INT0, y responde a la siguiente tabla:

Que nos dice como se generará la interrupción, puede ser con un estado bajo en el pin (00), por cualquier cambio de estado (01), por flanco de bajada (10), o por flanco de subida (11).

GICR – General Interrupt Control Register

Bit 6 – INT0: External Interrupt Request 0 Enable: Mediante este bit puesto en 1 se activa la máscara de Interrupción Externa 0, esto quiere decir que activando el bit de interrupciones globales se podrá esperar por la interrupción configurada.

GIFR – General Interrupt Flag Register

Bit 6 – INTF0: External Interrupt Flag 0: Es la bandera de interrupción que se pone automáticamente en 1 cuando se ha producido la Interrupción Externa 0 y además las interrupciones globales están habilitadas, entonces el procesador saltará al vector de interrupción correspondiente. Se pondrá a 0 por hardware cuando la rutina de interrupción se ejecute. Ahora como ejemplo se muestra una forma de controlar la interrupción externa del micro por el pin D2 (INT0). Mediante 2 displays de 7 segmentos se visualiza un conteo ascendente de 0 a 99, conteo que será incrementado por la INT0. El manejo de los displays se hace por tabla de datos, o datos constantes en la memoria de programa, a la vez que accedo a la memoria RAM para almacenar los datos del conteo.

Código ;--------------------------------------------------------------------------------

; Programa: Contador 0-99 por interrupción

; Version: 0.0

;

; Dispositivo: ATmega16 Compilador: AVRASM2

; Entorno IDE: AVR Studio4.15 Simulador: Proteus 7.5sp3

;

; Notas: Este programa realiza un conteo ascendente de 0 a 99 mediante

; 2 Displays de 7 segmentos, y un pulsador que incrementa la cuenta

;

; Registros: r5 a r14 para la tabla que maneja los displays de 7 segmentos

; r16 para configuraciones, y despues con r15 manipula los datos de

; unidades y decenas de la tabla para el display.

; r30 y r21 para llevar la cuenta de las unidades y decenas.

; r22 es el registro bandera para saber si ocurre la interrupcion externa

; r30 y r31 (Z) para direccionamiento indirecto de las constantes

; en memoria de programa que se almacenan de los datos del display

; de 7 segmentos.

; r28 y r29 (Y), para copia de la dirección original de las constantes.

; r17 y r18 son para el retardo de 1ms.

;

; Conexiones: C0 -> Anodo Display 1

; C1 -> Anodo Display 2

; B0 -> Segmento a del Display

; B1 -> Segmento b del Display

; B3 -> Segmento c del Display

; B4 -> Segmento d del Display

; B5 -> Segmento e del Display

; B6 -> Segmento f del Display

; B7 -> Segmento g del Display

; D2 -> Pulsador

;--------------------------------------------------------------------------------

;DIRECTIVAS EN ENSAMBLADOR

.include "m16def.inc" ;ATmega16

.device ATMEGA16

;Constantes utilizadas

.def flag=r22

;reset-vector address $0000

.org $0000

jmp inicio ;va al inicio

;vector de interrupcion con la direccion de INT0

.org $02

jmp int_ext ;va a la interrupción externa

;Subrutina con instrucciones a realizar con INT0

int_ext:

ser flag ;ponemos flag (r22) a 255

reti ;retorno de rutina de interrupción, habilitando I del SREG

;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=RAMEND

;Confirugracion de los registros a usar

ser r16 ;r16 <- $FF

out ddrc,r16 ;portC todo de salida

out ddrb,r16 ;portB todo de salida

ldi r16,$fb ;r16 <- $fb

out ddrd,r16 ;portD salidas, excepto D2

;configuración de la Interrupción.

ldi r16,3 ;r16 <- 3

out mcucr,r16 ;configuramos nivel bajo para INT1, y flanco de subida para

INT0

ldi r16,$40 ;r16 <- $40

out gicr,r16 ;activamos la INT0 solamente

clr r16 ;r16 <- 0

out gifr,r16 ;limpiarmos flags de interrupcion INTF0 e INTF1 e INTF2

;Cargar los valores de datos para mostrar los datos en el display de ánodo común

;Puerto: B7 B6 B5 B4 B3 B2 B1

B0

;Segmentos: g f e d c X b a

ldi r16, $80 ; 1 0 0 0 0 0 0 0

mov r5,r16 ;Cero en R5

ldi r16, $F1 ; 1 1 1 1 0 0 0 1

mov r6,r16 ;Uno en R6

ldi r16, $48 ; 0 1 0 0 1 0 0 0

mov r7,r16 ;Dos en R7

ldi r16, $60 ; 0 1 1 0 0 0 0 0

mov r8,r16 ;Tres en R8

ldi r16, $31 ; 0 0 1 1 0 0 0 1

mov r9,r16 ;Cuatro en R9

ldi r16, $22 ; 0 0 1 0 0 0 1 0

mov r10,r16 ;Cinco en R10

ldi r16, $02 ; 0 0 0 0 0 0 1 0

mov r11,r16 ;Seis en R11

ldi r16, $B0 ; 1 0 1 1 0 0 0 0

mov r12,r16 ;Siete en R12

ldi r16, $00 ; 0 0 0 0 0 0 0 0

mov r13,r16 ;Ocho en R13

ldi r16, $20 ; 0 0 1 0 0 0 0 0

mov r14,r16 ;Nueve en R14

;inicializacion de registros importantes

clr flag ;bandera para identificar interrupción puesta a 0

ldi r20,$00 ;registro para unidades

ldi r21,$00 ;registro para decenas

ldi r30,$05 ;apuntador Z a R5 que contiene el cero

sei ;se habilitan las interrupciones globales

;ciclo de mostrar en el display

ciclo:

cpi flag,255 ;preguntamos si flag es 255

breq incremento ;si es 255, la interrupción ocurrió, saltamos a incrementar

multi:

call multiplexar ;vamos a visualizar los datos en los displays multiplexados

jmp ciclo ;ciclo infinito

;rutina de incremento hasta 99

incremento:

call multiplexar ;mostramos datos, hasta que se suelte el pulsador

sbic pind,2 ;pin D2 esta todavía siendo pulsado?

jmp incremento ;si, está pulsado, volvemos a mostrar el valor actual del conteo, sino se

salta instrucción

inc r20 ;incrementamos el valor de r20 que contiene el valor de unidades

cpi r20,10 ;r20<10?

brmi salir ;si es menor, salimos, sino...

clr r20 ;r20 <- 0, unidades a cero

inc r21 ;incrementamos r21 que contiene el valor de decenas

cpi r21,10 ;r21<10?

brmi salir ;si es menor, salimos, sino...

clr r21 ;r21 <- 0,decenas a cero

salir:

clr flag ;ponemos flag a 0

jmp multi ;volvemos a multiplexar, con los nuevos datos

multiplexar:

cbi portc,0 ;apagamos ambos

cbi portc,1 ;displays

mov r28,r30 ;copiamos la dirección donde estan

mov r29,r31 ;los datos del display

add r30,r20 ;se suma el valor de unidades, para desplazarse en la tabla

ld r16,Z ;r16 <- (Z)

mov r30,r28 ;r30 <- r28

add r30,r21 ;se suma el valor de decenas, para desplazarse en la tabla

ld r15,Z ;r17 <- (Z)

mov r30,r28 ;r30 <- r28

out portb,r16 ;se muestra en el display de unidades, el valor correspondiente

sbi portc,0 ;enciende el display correspondiente

;call unseg

call delay1m ;tiempo de retardo para que sea visible al ojo

cbi portc,0 ;se apaga el display encendido anteriormente

out portb,r15 ;se muestra en el display de decenas, el valor correspondiente

sbi portc,1 ;enciende el display correspondiente

;call unseg

call delay1m ;tiempo de retardo para que sea visible al ojo

cbi portc,1 ;se apaga el display encendido anteriormente

ret

; =============================

; delay loop generator

; 4000 cycles:

; -----------------------------

; delaying 3999 cycles:

delay1m:

ldi R17, $1F

WGLOOP00: ldi R18, $2A

WGLOOP11: dec R18

brne WGLOOP11

dec R17

brne WGLOOP00

; -----------------------------

; delaying 1 cycle:

nop

ret

; =============================

; =============================

;Subrutina de 1seg

; 4000000 cycles:

; -----------------------------

; delaying 3999996 cycles:

unseg: ldi R17, $24

WGLOOP03: ldi R18, $BC

WGLOOP04: ldi R19, $C4

WGLOOP05: dec R19

brne WGLOOP05

dec R18

brne WGLOOP04

dec R17

brne WGLOOP03

; -----------------------------

; delaying 3 cycles:

ldi R17, $01

WGLOOP06: dec R17

brne WGLOOP06

; -----------------------------

; delaying 1 cycle:

ret

; =============================

Esquema de conexiones:

Programa para uso de teclado de matriz de 4x4

Ahora, un programa que lee una tecla presionada en un teclado 4x4. Una buena manera de ahorrar líneas de entrada al micro es, en lugar de dedicar una línea exclusiva por cada tecla utilizada, emplear un teclado matricial. El teclado matricial se caracteriza por estar cada una de las teclas conectada a dos líneas (una columna y una fila) que la identifican. De este modo el número de teclas que pueden conectarse es el producto de filas por el de columnas.

La técnica de programación requiere tanto de entradas como de salidas. Las filas están conectadas a las patillas de salida y las columnas a las de entrada.

Se comienza el testeo colocando a ‘0’ la primera columna, y a ‘1’ las restantes. Si la tecla pulsada estuviese en la fila ‘1’, ésta colocaría en su línea un ‘0’ lógico. Bastará con hacer un muestreo de las filas, buscando el 0, para saber la tecla exacta que fue pulsada en la matriz de teclas.

Si no es pulsada ninguna tecla en una fila, las entradas se encuentran en estado flotante, razón por la que son necesarias las resistencias de polarización internas, que mantienen las entradas a nivel alto.

También pueden usarse resistencias externas, e incluso llevarlas a tierra. En tal caso, lo que se busca es un UNO en las líneas de entrada.

Las instrucciones que son útiles para saber cuando se presiona la tecla son:

sbic pinb,5

Brinca la siguiente instrucción si el bit 5 del puerto B está en CERO.

Si fuera sbis, brinca la siguiente instrucción si el bit 5 del puerto B está en UNO.

El programa es:

;----------------------------------------

;

; Autor: MigSantiago

; Adaptación ATMEGA16 por Lewin Lopez

;

; Notas: Este programa realiza un barrido por filas

; en el puerto B donde se encuentra conectado un teclado

; matricial 4x4. En el puerto D se muestra el valor de la

; tecla de acuerdo a la tabla siguiente:

;

; pb4 pb5 pb6 pb7

; | | | |

; pb0 -> 0 1 2 3

; pb1 -> 4 5 6 7

; pb2 -> 8 9 a b

; pb3 -> c d e f

;

; Registros: r16 -> registro temporal para pasar datos.

; r17 -> registro de mostrar tecla presionada

; r18 -> registro para contar el barrido

; r19 -> registro para contar la fila actual

;

; Conexiones: Puerto B -> Teclado

; pb0, pb1, pb2, pb3 Salidas matriz

; pb4, pb5, pb6, pb7 Entradas matriz

; Puerto D -> Salida Hexadecimal de tecla presionada

; pd4 -> salida estado tecla presionada (E)

;----------------------------------------

.include "m16def.inc"

.device ATMEGA16

.org 0000

jmp inicio

inicio:

;Cargar el puntero de pila

LDI R16, HIGH(RAMEND)

OUT SPH, R16

LDI R16, LOW(RAMEND)

OUT SPL, R16

;Configuracion de puertos

SER R16 ;FF

OUT DDRD,R16 ;PtoD Salida

LDI R16,$0F ;00001111

OUT DDRB,R16 ;PtoB 4sal 4ent

;Inicializacion de puertos y activacion de pull-up

CLR R16

OUT PORTD,R16 ;borra PtoD

OUT PORTB,r16 ;borra PtoB y desactiva pull-up internas

reinicio:

;Programa Principal

clr r16

clr r17 ;Registro mandado a ptoD

clr r18 ;registro del contador de barrido

clr r19 ;indicador de línea actual de barrido

linea1:

ldi r16,$01

out portb,r16 ;rb0=1 línea 1 activa

rjmp barrido ;va a checar presión de tecla

linea2:

inc r19

inc r18 ;en subrutina barrido, la primer línea

;no hace incremento, por eso se

;incrementa aquí

ldi r16,$02

out portb,r16 ;rb1=1 línea 2 activa

rjmp barrido

linea3:

inc r19 ;incrementa indicador de línea

inc r18

ldi r16,$04

out portb,r16 ;rb2=1 línea 3 activa

rjmp barrido

linea4:

inc r19 ;incrementa indicador de línea

inc r18

ldi r16,$08

out portb,r16 ;rb3=1 línea 4 activa

rjmp barrido

nopresion:

clr r16 ;pon E y LEDS a cero

out portd,r16 ;no hubo presión

rjmp reinicio

barrido:

sbic pinb,4 ;si rb4=0 no hay presión

rjmp presion

inc r18 ;siguiente tecla

sbic pinb,5

rjmp presion

inc r18 ;siguiente tecla

sbic pinb,6

rjmp presion

inc r18 ;siguiente tecla

sbic pinb,7

rjmp presion

rjmp quelinea ;no hubo presión en X línea

presion:

mov r17,r18 ;r17=r18

out portd,r17 ;saca tecla y E por portd

sbi portd,4 ;pd4=1 es decir E=1

rjmp reinicio ;que ya no haga barrido

quelinea:

cpi r19,$00 ;determina en que línea de barrido va

breq linea2 ;va a línea 2

cpi r19,$01

breq linea3

cpi r19,$02

breq linea4

cpi r19,$03

breq nopresion ;se va a limpiar ptod

;-----------------------------

Al final lo que hace el programa es determinar si se presionó una tecla. Si se presionó, enciende la salida E (pd4) y saca la tecla por pd0, pd1, pd2, pd3. Si se presionara el CERO sólo encendería E y pd0, pd1, pd2, pd3 estarían apagadas. Si se presionara la tecla F encendería E y todas las demás: 1111 = 15 = F. El esquema de conexiones es:

Declaración de variables

No uso la declaración de variables para los registros del AVR, pero les explico unas directivas para usarlas:

Si quieres definir pines:

.equ RxD =0; En este caso el pin 0 se llama RxD

.equ TxD =1; En este caso el pin 1 se llama TxD

Si quieres renombrar registros:

.def contbit =R16

.def temporal =R17

Y se usan normalmente:

cbi PORTD,TxD; el pin 1 se pone a cero

ldi contbit,$aa; Carga el R16 con AA

EJERCICIO EN CLASE 9.

a) Realizar un programa que permita identificar la tecla presionada en el teclado, pero muestre su salida por el puerto C, conecte el teclado al puerto D y utilice resistencias internas de pull-up.

b) Realizar un programa que utilice la interrupción externa INT1 para detectar un pulsador que cuando se presiona incrementa la letra que se visualiza en un LCD. El programa debe funcionar hasta mostrar la letra ‘z’.