¿Cómo multiplexar una matriz de leds?


Vamos a empezar con un nuevo tutorial, esta vez con un cómo sobre multiplexación, cómo multiplexar una matriz de leds.

Si se quisiera controlar una sola columna de una matriz de 5x7 leds se necesitaría un puerto completo de un pic, 7 pines para controlar las filas y 1 para controlar la columna, eso significa que para controlar todos los leds de la matriz se necesitarían 4 puertos de 8 bits, demasiado para un microcontrolador, sobre todo para un 16F628a.

Para reducir el número de pines requeridos las cinco columnas de la matriz son multiplexadas, esto significa que solamente se necesitarán siete pines, uno por cada fila de la matriz, y cinco para habilitar cada una de las columnas.

Usando un pic 16F628a se puede utilizar el puerto B para controlar las filas y el puerto A para las columnas. La técnica de multiplexación consiste en mostrar una columna a la vez, mientras eso se haga lo suficientemente rápido parecerá que todas las columnas estan encendidas a la vez y no se verá ningún parpadeo, por esa misma razón la base de tiempo para la multiplexación es muy importante por lo que se utiliza la interrupción del timer 2 para esa tarea.

La multiplexación es muy sencilla y se ejecuta dentro de la rutina de interrupción del timer 2, se realiza más o menos de la siguiente manera:

  • Espera interrupción
  • Se deshabilitan las columnas
  • Se escribe en el puerto B el valor de las filas
  • Se habilita la primer columna
  • Espera interrupción
  • Se deshabilitan las columnas
  • Se escribe en el puerto B el valor de las filas
  • Se habilita la siguiente columna
  • Espera interrupción
  • ...
Así se repite hasta llegar a la quinta columna, entonces la ejecución de la multiplexación vuelve al principio y se vuelve a repetir.

El programa de ejemplo muestra en conteo descendente los números del 9 al 0. La multiplexación se lleva a cabo en la rutina de interrupción del timer 2. El programa principal lo que hace es leer un número almacenado en una variable (un registro de memoria) y decodificarlo para ser desplegado en la matriz, como la matriz es de 5 columnas para decodificar el número se necesitan 5 registros donde se guardaran los valores de las filas de cada columna.

Esquemático de circuito para multiplexar una matriz de leds
El diagrama del circuito de ejemplo es el siguiente:

A continuación pueden ver el video de este ejemplo:


Descargar código: Multiplexar una matriz de 5x8 leds

Este tutorial está basado en el tutorial How to multiplex a matrix of LED's.


Teclado Matricial 4x3.


Esta rutina es una adaptación de la rutina original del Teclado Matricial 4x4 hecha por petición popular (ok, un solo comentario, pero alguien lo pidió). La lógica del manejo del teclado matricial 4x3 es la misma que para el teclado 4x4, el nibble bajo del puerto B se configura como salida y el nibble alto como entrada. Se recorre un cero por el nibble bajo y se va incrementando un puntero que es el que nos ayuda a saber exactamente que tecla se presionó.

Como este teclado cuenta con solo 12 teclas, el puntero llegará hasta 12 y si no se presionó ninguna tecla para entonces la rutina que explora el teclado volverá a empezar. En realidad la lógica es la misma que para el teclado matricial de 16 teclas, así que si desean leer la explicación completa lo pueden hacer en la página del teclado matricial 4x4.

Este es el diagrama de conexión del teclado en un pic 16f628a.

Esquema electrónico de teclado matricial para PIC

Descargar el código: Teclado Matricial 4×3.

Con esto vuelvo después de unos meses, espero no tardarme tanto para volver a actualizar el blog. Como siempre sus comentarios son bien recibidos y se aceptan sugerencias para futuros tutoriales.

Temporizador Timer 2 en los microcontroladores PIC.


El Timer 2 es un temporizador de 8 bits que tiene la particularidad de tener un preescalador y un post-escalador. Además este módulo cuenta con un registro de periodo PR2 que marca el valor máximo que puede alcanzar la cuenta del registro TMR2. A diferencia de los otros temporizadores, el temporizador Timer 2 no incrementa su cuenta hasta llegar a 0xFF y después al desborde sino que incrementa su cuenta desde 0x00 con cada ciclo de instrucción hasta que el valor del registro TMR2 coincide con el del registro PR2 y después, en el siguiente ciclo reinicia la cuenta desde 0x00.

Este módulo cuenta con un preescalador y un post-escalador. El preescalador tiene la misma función que en los otros dos timers y sirve
como divisor de frecuencia antes de cada incremento. El post-escalador funciona como un divisor de frecuencia después de cada coincidencia
entre los registros TMR2 y PR2. Si el post-escalador es 1:1 la bandera de interrupción TMR2IF se habilitará en cada coincidencia entre TMR2 y PR2, en cambio si por ejemplo el post-escalador es 1:16, la interrupción se presentará cada 16 coincidencias.

Este temporizador, al igual que el Timer 1, puede habilitarse y deshabilitarse mediante el bit TMR2ON.

El preescalador se selecciona con los bits T2CKPS1:T2CKPS0 y el post-escalador con los bits T0UTPS3:TOUTPS0 de la siguiente manera:
Preescalador        Post-escalador
 00 = 1:1            0000 = 1:1
 01 = 1:4            0001 = 1:2
 1x = 1:16           0010 = 1:3
     .
     .
     .
       1111 = 1:16
Carga y Temporización

La temporización del Timer 2 está dada por la siguiente expresión:

TempTMR2 = [Preescaler*(PR2+1)*Postscaler]*Tinstr

Donde
Preescaler = Valor del preescalador
PR2 = Valor cargado al registro PR2
Postscaler = Valor del post-escalador
Tinstr = 4/frecuencia de oscilación
TempTMR2 = Temporización dada en segundos

La temporización máxima que puede alcanzar el Timer 2 es la misma que alcanza el Timer 0. Utilizando el oscilador interno del pic 16f628 la temporización máxima sería de 65536uS. Si se desea otra temporización se puede lograr cargando el valor necesario al registro PR2.

PR2 = [([TempTMR2/(4/fosc)])/(Preescaler*Postscaler)]-1

Veamos el mismo ejemplo de los temporizadores anteriores, ahora aplicado al Timer 2: Se desea complementar el valor del puerto B cada
50ms. Se estará revisando que se haya cumplido el tiempo de la temporizacion checando la bandera TMR2IF. Utilizando la expresión de la
precarga y utilizando el preescalador y el post-escalador más grande (16) obtenemos el valor quer que necesitamos cargar al registro PR2 para obtener una temporizacion de 50mS.

PR2 = [([50mS/(4/4Mhz)])/(16*16)]-1 = 194.31

Ya que no podemos cargar numeros fraccionarios el valor del registro PR2 necesario es 194. El código del programa sería el siguiente:
INICIO
 bsf     STATUS,RP0
 clrf    TRISB
 bcf     STATUS,RP0
 movlw   b'01111010'
 movwf   T2CON
 clrf    PORTB
 bcf     PIR1,TMR2IF
PRECARGA
 bcf     T2CON,TMR2ON
 bsf     STATUS,RP0
 movlw   .194
 movwf   PR2
 bcf     STATUS,RP0
 bsf     T2CON,TMR2ON
ESPERA
 btfss   PIR1,TMR2IF
 goto    ESPERA
 bcf     PIR1,TMR2IF
 comf    PORTB,f
 goto    PRECARGA
Descargar código: Ejemplo del temporizador Timer 2


Temporizador Timer 1 en los microcontroladores PIC.


El Timer 1 es un módulo temporizador/contador de 16 bits, que consiste en dos registros de 8 bits (TMR1H y TMR1L) que son de lectura y escritura. Este módulo incrementa su cuenta desde 0x000 hasta 0xFFFF y al desbordarse vuelve a 0x0000. Al presentarse el desborde la bandera de interrupción TMR1IF se pone a 1 y, si está habilitada, la interrupción se presenta.

Este módulo al igual que el Timer 0 puede funcionar en modo temporizador y en modo contador. En modo temporizador el par de registros TMR1 se incrementa en cada ciclo de instrucción, este modo se selecciona poniendo a 0 el bit TMR1CS del registro T1CON. En modo contador el par de registros TMR1 se incrementa en cada flanco ascendente de una señal de reloj externa, este modo se selecciona poniendo a 1 el bit TMR1CS del registro T1CON.

El preescalador del Timer 1 tiene un valor máximo de 8 y se selecciona con los bits T1CKPS1:T1CKPS0 de la siguiente manera:
00 = 1:1
 01 = 1:2
 10 = 1:4
 11 = 1:8
A diferencia del Timer 0, el Timer 1 tiene la posibilidad de activar o detener la cuenta mediante el bit TMR1ON del registro T1CON.

Carga y Temporización

En modo temporizador el Timer 1 incrementa su cuenta en cada ciclo de instrucción. La temporización que se puede obtener con este módulo se obtiene de la siguiente relación:

TempTMR1 = [(65536 - precarga)*PS]*Tinstr

Donde:
precarga = Valor que se le asigna al par de registros TMR1 al comenzar la temporización
PS = Valor del preescalador
Tinstr = 4/frecuencia de oscilación
TempTMR1 = Temporización dada en segundos

La temporización máxima utilizando el oscilador interno del pic 16f628 y el valor más grande de preescalador es:

TempTMR1.Max = [(65536 - 0)*8]*1uS = 524288uS

De modo que la temporización máxima que se puede tener con este temporizador, utilizando el oscilador interno de 4Mhz del pic 16f628,
es de 524.288mS. Con la misma frecuencia de oscilación el Timer 0 solamente podia lograr una temporización de 65.538mS así que con el
Timer 1 se logran temporizaciones de mayor duración. Si se desea obtener una temporización distinta solo se debe escribir en el par de registros TMR1 el valor de la precarga necesaria para la temporización deseada.

precarga = -[([Temporizacion/(4/fosc)])/PS]+65536

Veamos el mismo ejemplo que el del temporizador Timer 0 ahora aplicado al Timer 1: Se desea complementar el valor del puerto B cada 50mS. Se estará revisando que se haya cumplido el tiempo de la temporización checando la bandera TMR1IF. Utilizando la expresión de la precarga y utilizando el preescalador más grande (8) obtenemos el valor que necesitamos cargar al par de registros TMR1 para obtener una temporización de 50mS.

precarga = -[([50mS/(4/fosc)])/8]+65536 = 59286 = 0xE796

Así que para obtener una temporización de 50mS mediante el Timer 1 se debe cargar 0xE7 al registro TMR1h y 0x96 al registro TMR1L. El código del programa sería el siguiente:
INICIO
    bsf     STATUS,RP0
    clrf    TRISB
    bcf     STATUS,RP0
    movlw   b'00110000'
    movwf   T1CON
    clrf    PORTB
    bcf     PIR1,TMR1IF
PRECARGA
    bcf     T1CON,TMR1ON
    movlw   0xE7
    movwf   TMR1H
    movlw   0x96
    movwf   TMR1L
    bsf     T1CON,TMR1ON
ESPERA
    btfss   PIR1,TMR1IF
    goto    ESPERA
    bcf     PIR1,TMR1IF
    comf    PORTB,f
    goto    PRECARGA
La configuración del Timer 1 se realiza mediante las líneas “movlw b’01100000′” y “movwf T1CON“. Mediante estas lineas se configura el timer en modo temporizador (TMR1CS = 0) y se selecciona el preescalador máximo (T1CKPS1:T1CKPS0 = 11). Una vez configurado el timer 1 se limpia el puerto B y la bandera TMR1IF del registro PIR1. Posteriormente se realiza la precarga cargando un 0xE7 al registro TMR1H y un 0x96 al registro TMR1L. Nótese que antes de realizar la carga se detuvo el timer poniendo a 0 el bit TMR1ON, esto se hace para evitar errores al momento de cargar el valor a los registros TMR1, después de realizar la carga se enciende el timer poniendo a 1 el bit TMR1ON y en ese momento la temporización comienza.

Para saber si la temporización terminó se está revisando continuamente la bandera TMR1IF. Mientras esta sea 0 la temporización aún no habrá terminado, cuando la bandera es 1 entonces la temporización finalizó, entonces se borra la bandera TMR1IF, se complementa el puerto B y se vuelve a realizar la precarga. De este modo el programa está complementado el puerto B cada 50mS.

Descargar código: Ejemplo del temporizador Timer 1


El temporizador Timer 0 en los microcontroladores PIC.


El Timer 0 es un modulo temporizador/contador de 8 bits que cuenta con un preescalador programable también de 8 bits. Puede funcionar como temporizador o como contador. En modo temporizador el valor del registro TMR0 se incrementa con cada ciclo de instrucción (o cada X ciclos dependiendo del preescalador). En modo contador el valor del registro TMR0 se incrementa en cada flanco (ascendente o descendente) del pin RA4/T0CKI. En ambos casos al desbordarse (pasar de 0xFF a 0x0) el registro TMR0 la bandera de interrupción del timer 0 (bit T0IF del registro INTCON) se pone a 1.

El modo temporizador se selecciona poniendo a cero el bit T0CS del registro OPTION. Poniendo a uno ese bit el modulo trabaja en modo
contador
, en este modo de operación además se debe seleccionar si el incremento se producirá en cada filo ascendente o descendente, al poner a cero el bit T0SE del registro OPTION se selecciona el filo ascendente.

El preescalador es compartido por el Timer 0 y por el Watchdog. Se asigna a un módulo o a otro mediante el bit PSA del registro OPTION. Poniendo el bit a 1 el preescalador se asigna al Watchdog y poniendolo a 0 el preescalador se asigna al Timer 0. El valor del preescalador se selecciona con los bits PS2:PS0 de la siguiente manera:
PS2:P20    TMR0    WDT
  000      1:2     1:1
  001      1:4     1:2
  010      1:8     1:4
  011      1:16    1:8
  100      1:32    1:16
  101      1:64    1:32
  110      1:128   1:64
  111      1:256   1:128
Carga y temporización

En modo temporizador el Timer 0 incrementa su cuenta en cada ciclo de instrucción. Este modo sirve para generar temporizaciones y bases de tiempo de la misma forma que los retardos por software, sin embargo las temporizaciones con el Timer 0 pueden ser más exactas y además se cuenta con la ventaja de que el módulo puede trabajar mediante interrupciones así que el programa puede ejecutar otras isntrucciones mientras se realiza la temporización.

La temporización que se puede obtener con este módulo se obtiene de la siguiente relación:

Temporización = [(256 - precarga)*PS+2]*Tinstruccion

Donde:
precarga = Valor que se le asigna al registro TMR0 al comenzar la temporización
PS = Preescalador. Si esta asignado al watchdog tomará el valor de 1
Tinstrucción = 4/frecuencia de oscilación
y la temporización está dada en segundos.

La temporización máxima utilizando el oscilador interno del pic 16f628 es:

Temp.max. = [(256 - 0)*256+2]*1uS = 65528uS

De modo que la temporizacion máxima que se puede tener con el es solamente de 65.538mS. Si se desea obtener una temporizacion distinta solo se debe escribir en el registro TMR0 el valor de la precarga necesaria.

precarga = -[([Temporizacion/(4/fosc)]-2)/PS]+256

Donde, de nuevo, la temporización está dada en segundos.

Veamos un ejemplo de aplicación: Se desea complementar el valor del puerto B cada 50mS. Se estará revisando que se haya cumplido el tiempo de la temporización checando la bandera T0IF. Utilizando la expresión de la precarga y utilizando el preescalador más grande (256) obtenemos el valor que necesitamos cargar al registro TMR0 para obtener una temporización de 50mS.

precarga = -[([50mS/(4/4Mhz)]-2)/256]+256 = 60.69 ≈ 60

Ya que no podemos cargar numeros fraccionarios el valor de precarga necesario es 60. Teniendo entonces el valor de la precarga el código del programa sería el siguiente:
INICIO
    bsf     STATUS,RP0
    clrf    TRISB
    movlw   b'00000111'
    movwf   OPTION_REG
    bcf     STATUS,RP0
    clrf    PORTB
    bcf     INTCON,T0IF
PRECARGA
    movlw   .60
    movwf   TMR0
ESPERA
    btfss   INTCON,T0IF
    goto    ESPERA
    bcf     INTCON,T0IF
    comf    PORTB,f
    goto    PRECARGA
La configuración del Timer 0 se realiza mediante las líneas "movlw b'00000111'" y "movwf OPTION_REG". Mediante estas lineas se configura el timer en modo temporizador (T0CS = 0), el preescalador se asigna al timer 0 (PSA = 0) y se selecciona el preescalador máximo (PS2:PS0 = 111). Una vez configurado el timer 0 se limpia el puerto B y la bandera T0IF. Posteriormente se realiza la precarga cargando un 60 al registro TMR0 y en ese momento la temporización comienza.

Para saber si la temporización terminó se está revisando la bandera T0IF. Mientras esta sea 0 la temporización aún no habrá terminado, cuando la bandera es 1 entonces la temporización finalizó, se borra la bandera, se complementa el puerto B y se vuelve a realizar la precarga. De este modo el programa está complementado el puerto B cada 50mS.

Descargar código: Ejemplo del temporizador Timer 0