in

Reloj digital parte 3 (de 3)

En la última entrega de esta serie de notas, en la que construimos un display gigante para utilizar como reloj o termómetro, encararemos la programación del microcontrolador que será el encargado de manejar todo el proyecto.Como adelantábamos en la segunda parte, el lenguaje de programación que utilizaremos será un dialecto del popular Basic, llamado Mikrobasic. Asumiremos que el lector tiene algún conocimiento básico de programación, pero igual intentaremos explicar cada parte de los programas que hemos preparado de ejemplo. Estos intentan ser una guía para que el lector cree sus propios programas y no un programa completo, ya que seria demasiado extenso para esta nota. Por supuesto, invitamos a aquellos que tengan dudas sobre algún punto en particular a darse una vuelta por el foro, donde intentaremos solucionar sus problemas.
Dicho todo esto, comencemos con la programación.Toda vez que una parte del código de un programa deba repetirse varias veces, conviene crear una función (o un procedimiento, según el caso) que lleve a cabo dicha tarea, de manera de no tener que repetir ese trozo de código varias veces en el programa, lo que hace mucho mas fácil el realizar posteriores cambios en el mismo.
En nuestro ejemplo utilizaremos dos funciones para representar información en el display. La primera de ellas se encarga de escribir un “0” o un “1” en el registro de desplazamiento que controla el encendido de los LEDs del display, y la segunda se apoya en la primera para escribir los bits correspondientes a un digito (0..9) en el display.
Mediante estas dos funciones podremos representar una hora o la temperatura en el display.
Para hacer más comprensible el código, podemos utilizar símbolos, que son simplemente un alias, un mecanismo que nos permite darle un nombre mas representativo a una puerto o a un pin del microcontrolador. Definiremos los siguientes:

Symbol clock = PORTB.1
Symbol data = PORTB.0
Symbol reset164 = PORTB.2
Symbol sino = PORTB.3

Cuando CLOCK pase de “0” a “1”, el valor presente en DATA ingresara en el registro de desplazamiento. Reset164 debe estar en “1” para que el registro se comporte normalmente, y lo pondremos a “0” cada vez que queramos limpiarlo, es decir, borrar todo su contenido y dejar sus salidas en “0”. Por ultimo, el símbolo que hemos llamado “sino” es el que enciende/apaga el display, ya que en ese pin del microcontrolador (el 3 del portB) hemos conectado todos los transistores que controlan los segmentos. Ante cualquier duda, conviene consultar los esquemas publicados en las notas anteriores.

Esta es la función completa, que analizaremos en detalle:

——————————————————–
sub function writedata (dim x as byte) as byte
‘Si DATA es 0, segmento encendido.
if x = 0 then
data = 1
else
data = 0
end if

delay_Us(2)
clock = 0
delay_Us(2)
clock = 1
delay_Us(2)

result = x
end sub
——————————————————–

La primera línea es la que define la función. Ahí podemos ver que el nombre que tendrá la misma será “writedata”, y que el argumento que recibe se guardara en la variable que hemos llamado “x”, cuyo tipo es “byte”, lo que significa que puede contener valores comprendidos entre 0 y 255 (00000000 a 11111111). La función devuelve como resultado también un byte, cuyo contenido es el mismo que el valor que se le paso.
La forma de utilizar la función es la siguiente:

Variable = writedata (valor)

Donde “variable” es una variable que habremos definido previamente como byte, para que pueda almacenar el dato que devuelve la función, y “valor” es el bit a escribir en el registro de desplazamiento, que puede ser “0” o “1”. Luego de ejecutada la función, “variable” tendrá el mismo valor que “valor”, en genera esto no sirve de nada, pero es bueno saberlo. Esto se debe a la línea que podemos ver dentro de la función, concretamente:

result = x

“result” es una variable interna de Mikrobasic que es la que contiene el valor final de la función. El hecho de que nosotros le asignemos el valor que contiene “x”, que es el parámetro que enviamos, es lo que explica el comportamiento expuesto.
El resto de la función se puede comprender fácilmente: al principio de la misma, el bloque:

——————————————————–
‘Si DATA es 0, segmento encendido.
if x = 0 then
data = 1
else
data = 0
end if
——————————————————–
se encarga de que “data” contenga el valor a escribir en el registro de desplazamiento. Es importante ver que cuando le pasamos “1”, para que el segmento correspondiente se encienda “data” deber ser “0”, debido a que las entradas de los 74LS164N que utilizamos están negadas (en caso de dudas, ver los artículos anteriores de la serie). Cuando necesitamos escribir un “0”, “data” valdrá “1”.
La instrucción delay_us(x) lo que hace es una demora de “x” microsegundos. Son necesarias para generar los pulsos de clock que envían efectivamente el contenido de “data” al registro de desplazamiento. Esto es lo que hace el último bloque de esta función:

——————————————————–
delay_Us(2)
clock = 0
delay_Us(2)
clock = 1
delay_Us(2)
——————————————————–

Esta función, a la que hemos llamado “writedigit” será invocada desde el programa principal cada vez que queramos escribir un digito. Para mostrar por ejemplo la hora, la llamaremos cuatro veces, una por cada digito que conforma la hora actual.
Vemos la función completa, y luego la analizaremos:

——————————————————–
sub function writedigit (dim x as byte) as byte
select case x
case 1
aux = writedata(0)
aux = writedata(0)
aux = writedata(0)
aux = writedata(1)
aux = writedata(0)
aux = writedata(1)
aux = writedata(0)
case 2
aux = writedata(0)
aux = writedata(1)
aux = writedata(1)
aux = writedata(0)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
case 3
aux = writedata(0)
aux = writedata(0)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
case 4
aux = writedata(1)
aux = writedata(0)
aux = writedata(0)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(0)
case 5
aux = writedata(1)
aux = writedata(0)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(0)
aux = writedata(1)
case 6
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(0)
aux = writedata(1)
case 7
aux = writedata(0)
aux = writedata(0)
aux = writedata(0)
aux = writedata(1)
aux = writedata(0)
aux = writedata(1)
aux = writedata(1)
case 8
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
case 9
aux = writedata(1)
aux = writedata(0)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
case 0
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(0)
aux = writedata(1)
aux = writedata(1)
end select
result = x
end sub
——————————————————–

Al igual que en el caso anterior, la primer línea de la función es la encargada de definir su nombre (“writedigit”), que tipo de dato va a recibir (byte), que variable lo vamos a almacenar (“x”) y que tipo de dato va a devolver la función (byte).
Usamos la estructura “select case”-“end select” para hacer diferentes tareas de acuerdo al valor recibido en “x”. Cada digito del “0” al “9” tiene su propio bloque de instrucciones dentro de la función, siendo cada uno simplemente una sucesión de llamadas a la función “writedata” que analizamos antes. Veamos por ejemplo como se escribe un “1” en el display:

——————————————————–
case 1
aux = writedata(0)
aux = writedata(0)
aux = writedata(0)
aux = writedata(1)
aux = writedata(0)
aux = writedata(1)
aux = writedata(0)
——————————————————–

Vemos que consta de siete llamadas a la function “writedata” con distintos valores. ¿De donde salen estos valores? Pues bien, es muy sencillo: cada digito esta formado por algunos segmentos encendidos, y otros apagados. El grafico del final de la página nos ilustra sobre cual es cada uno de los segmentos. Si vemos el bloque encargado de escribir un “1” y la figura mencionada, comprenderemos que las dos llamadas a la función “writedata” con valor “1” se encargan de encender el cuarto y sexto segmento, mientras los demás permaneces apagados.
Con los valores adecuados, podemos representar cualquier digito en el display, eso es justamente lo que hacen los demás bloques. Si es necesario, se pueden hacer bloques para otros signos, tales como “-“, “_”, “º”, etc.
La variable “aux” es una variable auxiliar, de tipo “byte”, que utilizamos solamente para llamar a la función que escribe el dato en el registro de desplazamiento.
La función “writedigit” termina con

result = x

lo que hace que la función contenga el valor que le pasamos para representar.

Como adelantáramos en las notas previas, para nuestro termómetro usaremos el sensor de temperatura Dallas DS18S20. Este sensor tiene un protocolo algo elaborado para comunicarse con el debido en parte a la posibilidad que brinde de conectar varios sobre un único hilo e ir interrogándolos individualmente, o de almacenar datos en su EEPROM interna. Ninguna de estas características se utiliza en este proyecto, pero el protocolo de comunicaciones debe ser respetado igualmente, por lo que deberemos cumplir los siguientes pasos:

– Se envía un comando de RESET, y uno para saltar la lectura de la ROM interna, seguido por una demora de al menos 120 microsegundos:

——————————————————–
Ow_Reset(portsensor, pinsensor) ‘ Envio un reset al sensor
Ow_Write(portsensor, pinsensor,$CC) ‘ Envio el comando $cc
Ow_Write(portsensor, pinsensor,$44) ‘ y luego $44
Delay_us(120) ‘ Espero 120 microsegundos
——————————————————–

– Una vez hecho eso, el sensor esta esperando nuestro siguiente comando. Enviamos nuevamente un RESET, y luego el comando para que comience la lectura y conversión de la temperatura:

——————————————————–
i = Ow_Reset(portsensor, pinsensor) ‘ Envio un reset al sensor
Ow_Write(portsensor, pinsensor,$CC) ‘ Envio el comando $cc
Ow_Write(portsensor, pinsensor,$BE) ‘ y luego $BE
——————————————————–

– Esperamos un segundo, y podemos leer el valor de la temperatura.

——————————————————–
Delay_ms(1000) ‘ Espero 1 segundo…
j1 = Ow_Read(portsensor, pinsensor) ‘ Leo primera parte del resultado
j2 = Ow_Read(portsensor, pinsensor) ‘ y la segunda parte.
——————————————————–

El resultado se encuentra en dos variables debido a que la precisión del sensor es mayor a los 8 bits de las variables tipo byte empleadas (j1 y j2). Esta parte del programa estará dentro del bucle principal, y se repetirá continuamente de manera que la temperatura se actualice cada mas o menos un segundo.

Juntando las partes explicadas, y agregando una pequeña sección para la configuración de los puertos del microcontrolador, tenemos el programa del termómetro listo. Con un par de modificaciones, es posible hacer el reloj, simplemente agregando un segundo por cada vuelta del bucle principal del programa, y representando la hora en el display con la función “writedigit”.

——————————————————–
program seg0002
‘———-SYMBOL————–
Symbol CLOCK = PORTB.1
Symbol data = PORTB.0
Symbol reset164 = PORTB.2
Symbol sino = PORTB.3
symbol portsensor = portb
symbol pinsensor = 5

‘———–DIM—————-
Dim i, j1, j2 As Byte
Dim aux As Word
dim text as char[4]

‘—-Rutinas, funciones y procedues——————
sub function writedata (dim x as byte) as byte
‘Si DATA es 0, segmento encendido.
if x = 0 then
data = 1
else
data = 0
end if

delay_Us(2)
clock = 0
delay_Us(2)
clock = 1
delay_Us(2)
result = x
end sub

‘Imprime un digito del 0 al 9
sub function writedigit (dim x as byte) as byte
select case x
case 1
aux = writedata(0)
aux = writedata(0)
aux = writedata(0)
aux = writedata(1)
aux = writedata(0)
aux = writedata(1)
aux = writedata(0)
case 2
aux = writedata(0)
aux = writedata(1)
aux = writedata(1)
aux = writedata(0)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
case 3
aux = writedata(0)
aux = writedata(0)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
case 4
aux = writedata(1)
aux = writedata(0)
aux = writedata(0)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(0)
case 5
aux = writedata(1)
aux = writedata(0)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(0)
aux = writedata(1)
case 6
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(0)
aux = writedata(1)
case 7
aux = writedata(0)
aux = writedata(0)
aux = writedata(0)
aux = writedata(1)
aux = writedata(0)
aux = writedata(1)
aux = writedata(1)
case 8
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
case 9
aux = writedata(1)
aux = writedata(0)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
case 0
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(1)
aux = writedata(0)
aux = writedata(1)
aux = writedata(1)
end select
result = 1
end sub

‘—Programa principal————
main:
cmcon = 7
porta=0

‘Configuro el portA:
TRISA.0 = 0 ‘Salida
TRISA.1 = 0 ‘Salida
TRISA.2 = 1 ‘Entrada H
TRISA.3 = 1 ‘Entrada M
TRISA.4 = 0 ‘Salida
TRISA.5 = 0 ‘Salida

‘Configuro el portB:
TRISB.0 = 0 ‘Salida (DATA)
TRISB.1 = 0 ‘Salida (CLOCK)
TRISB.2 = 0 ‘Salida (RESET)
TRISB.3 = 0 ‘Salida (SI/NO)
TRISB.4 = 1 ‘Entrada DS1820
TRISB.5 = 0 ‘Salida
TRISB.6 = 0 ‘Salida
TRISB.7 = 0 ‘Salida

reset164 = 1
sino = 0

clock = 0
data = 0

‘———PROGRAMA PRINCIPAL————
Delay_ms(500)
loop:
‘Leo la temperatura del sensor
Ow_Reset(portsensor, pinsensor) ‘ Envio un reset al sensor
Ow_Write(portsensor, pinsensor,$CC) ‘ Envio el comando $cc
Ow_Write(portsensor, pinsensor,$44) ‘ y luego $44
Delay_us(120) ‘ Espero 120 microsegundos
i = Ow_Reset(portsensor, pinsensor) ‘ Envio un reset al sensor
Ow_Write(portsensor, pinsensor,$CC) ‘ Envio el comando $cc
Ow_Write(portsensor, pinsensor,$BE) ‘ y luego $BE
Delay_ms(1000) ‘ Espero 1 segundo…
j1 = Ow_Read(portsensor, pinsensor) ‘ Leo primera parte del resultado
j2 = Ow_Read(portsensor, pinsensor) ‘ y la segunda parte.
j1 = j1 >> 1 ‘ Asumo temperatura >= 0C
ByteToStr(j1, text) ‘ Convierto j1 en texto

‘Escribo tres “0” para las salidas no conectadas:
for i =1 to 3
aux = writedata(0)
next i
aux = writedigit(text[0]-48)
aux = writedigit(text[1]-48)
aux = writedata(0) ‘”:” del centro apagados
aux = writedigit(text[2]-48)
aux = writedigit(text[3]-48)

Delay_ms(500) ‘Espero medio segundo y vuelvo a comenzar.
Goto loop
End.
——————————————————–

No hay mucho para explicar sobre el programa, ya que analizamos cada parte por separado anteriormente. La idea es que sirva como prototipo para que cada uno experimente con el, modificándolo a gusto para que muestre la hora, o la hora y la temperatura cada “x” segundos, etc.

La idea detrás de esta serie de notas es la experimentación, así que invitamos al lector a que emplee el foro para compartir su experiencia o para consultar si tiene alguna duda. Dentro de lo posible intentaremos ayudarlo a que lleve a buen puerto su proyecto.
El hardware propuesto es fácilmente modificable para crear displays de mayor tamaño agregando leds a cada segmento, o incluso haciendo segmentos que estén compuestos por mas de una fila de leds; o para hacer un display con mayor cantidad de dígitos para representar otro tipo de información. Los mas atrevidos pueden experimentar con displays que en lugar de usar dígitos de 7 segmentos empleen otro tipo de arreglo que permita mostrar, por ejemplo, caracteres y de esta manera crear un display alfanumérico.
Respecto del software, solo hemos dado una guía, por lo que el campo disponible para la experimentación es muy amplio.
¡Solo hay que animarse!

Reportar

¿Qué te pareció?

Escrito por Ariel Palazzesi

12 Comments

Leave a Reply
  1. para llevar a cabo este proyecto, tengo que tener algun circuito grabador de pic? de donde podría obtener dicho circuto? y con que soft se grabaría, me gustaría poder hacerlo. desde ya muchas gracias

  2. Existe algun proyecto por ahi para fabricar un cartel de texto pasante variable formado con diodos led? existe la forma de hacerlo? gracias por la información

  3. hola en este manual dice que la tercera placa sera la que controle la generación de los datos a mostrar, leer el sensor de temperatura, proveer un sistema para el ajuste de la hora y los minutos, etc. pero no he encontrado nada de eso y es la parte mas interesante pues deseo hacer un reloj que pueda medir temperatura gracias de antemano

  4. NECESITO UNA IDEA PARA HACER UN LETRERO DESPLAZANTE CON DIAPLAY MATRICIAL DE 7X5 PERO SIN USAR PICS SOLO MEMORIAS Y REGISTRO ALGO DISCRETO GRACIAS DE ANTEMANO

  5. quisiera que muestren el diagrama donde se encuentra el pic, ya que no esta en ningun lado y por favor la lista de los componentes que lleva. gracias

  6. hola alguien tiene el programa que se va ingresar en el pic, lo necesito porque estoy diseñando el proyecto y soy neofito en programacion de pic. gracias

  7. donde consigo el diagrama esquematico completo?? Estoy muy interesado en realizar este proyrcto… cuento con todos los componentes y software necesario… ayuda por favor

  8. No quiero ser abogado del diablo, pero la verdad, cuando vi el articulo me llamo la atención, y es una buena practica para novatos como yo. Pero no me entere de nada, primero no veo el esquema de micro. Segundo no entiendo el programa para nada. Ni se de donde ni como se saca el segundo para ser controlado. Y en cuanto a la explicación voy a suponer que soy muy torpe, porque no entiendo nada. Me resulta complejo, sus explicaciones creo yo estan hechas para expertos , porque no consigo saber nada. Y animo y agredezo sobre todo k hayan personas k aun sean capaces de compartir sus experiencias y sabidurias.

  9. hola me parece muy interesante tu proyecto estube leyendo pero no encontre el diagrama del pic ni la parte en como hacer para que el reloj funcione ni la parte en como puedo cambiar la hora al relojy que luego siga su curso, lo del registro de desplazamiento y como insertar numeros en el panel me quedo claro pero lo otro me tiene en duda, agredeceria la info 😀 gracias x tu tiempo 😀

  10. Hola, interesantisimo el proyecto, me encanta, pero como han dicho otros usuarios, no esta el esquema de la tercera placa, la de el PIC, agradeceria que la añadierais porfavor, me gusta mucho este proyecto,os felicito. Gracias.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Agatha Christie: Y No Quedó Ninguno

OneWebDay, el día de Internet