Story Transcript
LIST P=PIC16F84A #INCLUDE
; Pic a usar ; Lista de etiquetas de microchip
; Configuración opciones de hardware para la programación __CONFIG _CP_OFF & _PWRTE_ON & _WDT_OFF & _XT_OSC
; Valores de constantes: FRAC_INI
D'12'
SEGS_INI MINS_INI HORS_INI ADJMIN
D'196' D'196' D'232' D'9'
ADJHOR
D'34'
ADJDIA
D'6'
; Constante para inicio cuenta de fracciones de ; segundo ; Constante para inicio cuenta de segundos ; Constante para inicio cuenta de minutos ; Constante para inicio cuenta de horas ; Número de "frac_sec" que se necesita sumar cada ; minuto para ajustar el tiempo ; Número de "frac_sec" que se necesita restar cada ; hora para ajustar el tiempo ; Número de "frac_sec" que se necesita sumar cada ; 24 horas para ajustar el tiempo
;Ajustes: ; Un "frac_sec" es aproximadamente 1 / 244 s ; 1 MHz / 16 = 62.500 Hz ; 62.500 Hz / 256 = 244,140625 Hz ; T = 0,004096 s ; 0,004096 s * 244 = 0,999424 s; dif 1 segundo = -0,000576 s ; 1 "minuto" = 0,999424 s * 60 = 59,96544 s ; 60 s - 59,96544 s = 0,03456 s ; 0,03456 s / 0,004096 s = 8,4375 ; 1 "minutoadj" = 59,96544 s + (0,004096 s * 9) = 59,96544 s + 0,036864 s = 60,002304 s ; 1 "hora" = 60,002304 s * 60 = 3600,13824 s ; 3600 s - 3600,13824 s = -0,13824 s ; -0,13824 s / 0,004096 s = -33,75 s ; 1 "horaadj" = 3600,13824 s - (0,004096 s * 34) = ; = 3600,13824 s - 0,139264 s = 3599,998976 s ; 24 "horas" = 3599,998976 s * 24 = 86399,975424 s ; 86400 s - 86399,975424 s = 0,024576 s ; 0,024576 s / 0,004096 s = 6 ; 24 "horasadj" = 86399,975424 s + 0,004096 s * 6 = 86399,975424 s + 0,024576 s = 86400 s ; Activación de RB1-3 para las entradas de los pulsadores PULSADOR B'00001110' ; RB1, RB2 y RB3 ; Asignación de banderas. Los pulsadores activos proporcionan un "1" CHG H'03' ; Indica que se ha activado un pulsador o que es ; necesario actualizar los valores de la hora que tienen ; que mostrarse en los displays PSEG H'04' ; Pulsador A, modo segundero. PMIN H'05' ; Pulsador B, avance rápido minutos. PHOR H'06' ; Pulsador C, avance rápido horas. P_ON H'07' ; Un pulsador ha sido activado DSPOFF
B'11111111'
; Displays apagados
; Mapa de activación de segmentos para los displays (PORTB) ; a ; ========= ; | | ; f | | b ; | g | ; ========= ; | | ; e | | c ; | | ; ========= # p ; d ; gfedcbap CERO H'7E' ; 01111110 UNO H'0C' ; 00001100 DOS H'B6' ; 10110110 TRES H'9E' ; 10011110 CUATRO H'CC' ; 11001100 CINCO H'DA' ; 11011010 SEIS H'FA' ; 11111010 SIETE H'0E' ; 00001110 OCHO H'FE' ; 11111110 NUEVE H'DE' ; 11011110 SEGM_OFF equ H'00' ; Todos los segmentos apagados. Separador entre horas y minutos apagado (RB0).
; Posición de memoria de variables ; Las variables de tiempo comienzan con un número que permite contar y ajustar el tiempo ; Por ejemplo la variable "segundos" se inicia con 196 decimal, para que después de 60 ; incrementos de 1 segundo se produzca un 0 (196 + 60 = 256 -> 0) frac_sec H'0C' ; Fracciones de segundo (1/244) segundos H'0D' ; Segundos minutos H'0E' ; Minutos horas H'0F' ; Horas conta1 H'10' ; Variable 1 para bucle contador ; display H'11' ; Indicador de display que debe actualizarse digito1 H'12' ; Display unidad de minuto / unidad de segundo digito2 H'13' ; Display decena de minuto / decena de segundo digito3 H'14' ; Display unidad de hora digito4 H'15' ; Display decena de hora banderas H'16' ; Banderas; 3-CHG, 4-PSEG, 5-PMIN, 6-PHOR, 7-P_ON
___________ DISPLAY DECENA MIN / DECENA SEG -> RA,2 -|1 \__/ 18|DISPLAY UNIDAD MIN / UNIDAD SEG -> RA,3 -|2 17|NC -|3 16F84A 16|MCLR/ -|4 15|GND -|5 14|PUNTO dp -> RB,0 -|6 13|PUL A (SEG) / SEGMENTO a -> RB,1 -|7 12|PUL B (MIN) / SEGMENTO b -> RB,2 -|8 11|PUL C (HOR) / SEGMENTO c -> RB,3 -|9________10|-
RA,1 RA,0 XT XT Vcc RB,7 RB,6 RB,5 RB,4
-> ->
SEGMENTO SEGMENTO SEGMENTO SEGMENTO
g f e d
PORTA, control displays 7 segmentos de cátodo común PORTB, segmetos de los displays, led separadores, pulsadores como entrada El pulsador A (conectado a RB1) muestra el segundero en tanto permanezca presionado. El pulsador B (conectado a RB2) avanza rápidamente los minutos. El pulsador C (conectado a RB3) avanza rápidamente las horas.
Configurar puertos como salidas, blanquear display
INICIO
RB Pull Up desconectadas TMR0 en modo temporizador (se utilizan los pulsos de reloj internos, Fosc/4) Preescaler 1:16
Configuración OPTION: OPTION_REG = 10000011
Bits PORTA como salidas Bits PORTB como salidas Puerto A apaga los displays Con Puerto B todos los segmentos apagados. Separador entre horas y minutos encendido (RB0).
Configuración PUERTOS: TRISA = 0000 0000 TRISB = 0000 0000 PORTA = DSPOFF (1111 1111) PORTB = 0000 0001
Inicialización de variables: TMR0 = 1 display = 1111 1110 (decena de hora) digito1 = “CERO” digito2 = “CERO” digito3 = “CERO” digito4 = SEGM_OFF banderas = 0000 0000 Variables de tiempo: frac_sec = FRAC_INI (12d) segundos = SEGS_INI (196d) minutos = MINS_INI (196d) horas = HORS_INI (232d)
PRINCIPAL
Pag. 2
Pone 01h en TMR0 Inicia display seleccionando decena de hora Los valores para digito1, digito2, digito3 y digito4 permitirán que desde el primer momento aparezcan las 0:00 en el display.
PRINCIPAL
TMR0 cuenta libremente para no perder ciclos de reloj escribiendo valores
TMR0_LLENO
Incremento de TMR0
TMR0 se va incrementando líbremente con la señal de reloj a 1.000.000 MHz / 16 = 62.500 Hz
Se comprueba el bit Z de STATUS
NO TMR0=0
TMR0 se ha desbordado y se han contado 256 * 16 = 4096 ciclos de reloj, (4,096 ms) La frecuencia es: 62.500 Hz / 256 = 244,140625 Hz
SI
Se añade 1 a frac_sec frac_sec comienza por 12, hasta desbordarse cuenta 244
frac_sec = frac_sec + 1
NO
SI
frac_sec = 0
Se activa separador horas-minutos (RB0) Restaura la variable “frac_sec” para la próxima vuelta
RB0 = 1 frac_sec = FRAC_INI (12d)
Comprueba variables pulsadores
frac_sec = 0, se ha contado “1 segundo” (0,999424 s)
COMPROBAR_PUL El programa pasa por aquí cada 4,096 ms, esto es unas 244 veces por segundo
No hay pulsadores activados NO
Incrementar segundos, minutos y horas Ajustes cada minuto, hora y 1/2 dia “CHG” se pone a 1
SI
NO
INC_HORA
NO
Se comprueba el estado de “CHG” por si se ha activado algún pulsador o es necesario actualizar los valores de la hora que tienen que mostrarse en los displays Se actualiza hora, displays y pulsadores cada 4,096 ms (244 veces por segundo)
SI
CHG = 1
PSEG = 0
Se ha activado un pulsador pero no es PSEG, debe ser PMIN o PHOR SI
Si está pulsado PSEG, (Pul A) se mostrarán los segundos en el display
Pag. 7
COMPROBAR_CHG
P_ON = 1
Puesta en hora PMIN (Pul B) avanza los minutos PHOR (Pul C) avanza las horas
PONER_RELOJ
Pag. 6
COMPROBAR_SEG
Si no se han activado pulsadores ni ha cambiado la hora se salta a DISPLAY_PUL, que principalmente refresca uno de los displays cada vez que se accede a ella y escanea pulsadores. SI
digito2 = 0 digito3 = 0 digito4 = 0 digito1 = second – SEGS_INI (196d)
PSEG = 1
NO
Se mostrarán los segundos en el Se guardan la hora y los display de minutos minutos para su tratamiento Se guarda temporalmente el número de segundos en “digito1” Resto de variables “digit” a 0 digito3 se utiliza temporalmente para almacenar la hora, (Si la hora es 255, digito3 sería 255 – 232 = 23 digito1 se utiliza temporalmente para almacenar los minutos
Pag. 4
Pag. 5
Pag. 3
Se comprueba si se activo el pulsador de segundos (Pul A) para mostrar los segundos en el display
DISPLAY_PUL
DIV_DIGITOS
CONVER_COD_7S
Se borran los bits de flag para actualizar su estado Escanea pulsadores, si alguno está activado se pone a 1 la bandera que le corresponda así como “P_ON” y “CHG” Muestra los digitos correspondientes a los segundos o a los minutos y horas en el display que corresponda. Cada display se actualiza cada 244,14 Hz / 4 = 61,04 Hz.
OBTENER_H_M
digito3 = horas – HORS_INI (232d) digit 1 = minutos – MINS_INI (196d)
Divide los segundos o los minutos y las horas en digitos independientes, ejemplo, [14] lo pasa a [1]-[4]
Convierte cada digito (digito1, digito2, digito3 y digito4) en valores para los segmentos del display
Se borran los bits de flag para actualizar su estado Escanea pulsadores, si alguno está pulsado se pone a 1 el pulsador que le correspoda así como "P_ON" y "CHG" Muestra los digitos correspondientes a los segundos o a los minutos y horas en el display que corresponda.
DISPLAY_PUL
banderas = 0000 0000 PORTA = DSPOFF (1111 1111) w = SEGM_OFF XOR PORTB w = w AND B'11111110' PORTB = w XOR PORTB TRISB = PULSADOR (0000 1110)
Se borran los bits de flag para actualizar su estado Apagar los segmentos respetando separador horas-minutos (RB0) Se apagan los displays Se configuran los bits 1, 2 y 3 de PORTB como entrada Se almacena el estado de los pulsadores en var
COMPROBAR_PSEG
RB1 = 1
SI
w = SEGM_OFF XOR PORTB w = w AND B'11111110' PORTB = w XOR PORTB
CHG = 1 PSEG= 1 P_ON = 1
Este código copia los bits del literal SEGM_OFF que se quieran en PORTB, Se copiaran aquellos bits de SEGM_OFF cuya posición coincida con un 1 en la máscara que se utiliza con la función AND y se respetaran los valores de los bits PORTB que coincidan con un 0 en la máscara. En este caso SEGM_OFF = 00H y en la operación AND se utiliza B'11111110' con lo que en PORTB se respetará el valor de RB0 y se pondrán a cero el resto de bits.
NO
COMPROBAR_PMIN
RB2 = 1
SI
En nuestro caso se podría simplificarse el proceso, eliminando la primera XOR pero entonces no se podría trabajar con otros posibles valores de SEGM_OFF
CHG = 1 PMIN= 1 P_ON = 1
Ejemplos:
NO
Si PORTB es 1000 1110 w = SEGM_OFF XOR PORTB: 0000 0000 1000 1110 --------------1000 1110
COMPROBAR_PHOR
RB3 = 1
SI
CHG = 1 PHOR= 1 P_ON = 1
w = w AND B'11111110': 1000 1110 1111 1110 -------------1000 1110
NO
PORTB = w XOR PORTB 1000 1110 1000 1110 -------------0000 0000
ACTIVAR_SEGM Puerto B como salida
TRISB = 0000 0000
Se determina que display debe actualizarse, es decir, que dato debe presentarse en el puerto B y se establece el siguiente display Display es XXXX XXX0
SI
w = digito4
w = SEGM_OFF XOR PORTB: 0000 0000 1000 1111 --------------1000 1111
w = digito3
w = w AND B'11111110': 1000 1111 1111 1110 -------------1000 1110
w = digito2
PORTB = w XOR PORTB 1000 1110 1000 1111 -------------0000 0001
NO Display es XXXX XX0X
SI
Si PORTB es 1000 1111
NO Display es XXXX X0XX
SI
NO Display es XXXX 0XXX
SI
w = digito1
NO
Se entregar el valor de w en el puerto B respetando el valor de RB0
w = w XOR PORTB w = w AND B'11111110' PORTB = w XOR PORTB
Bit 7 de frac_sec = 0
NO
RB0 = 0
Se apagan los puntos de separación. Se activó en INICIO y se activa cada vez que frac_sec se hace 0.
SI
PORTA = display
Se habilita el display correspondiente Cada display se “enciende” con una cadencia de 244 Hz / 4 = 61 Hz
Rota display a siguiente posición
En la variable display se va desplazando un cero a la izquierda. Sólo se tendrán en cuenta los 4 bits menos significativos
PRINCIPAL
Pag. 2
Para rotar el display a la próxima posición se utiliza el siguiente código: rlf display,F ; Rota display 1 bit a la próxima posición bsf display,0 ; Asegura un 1 en la posición más baja de display (luego se hará 0 si es necesario) btfss display,4 ; Comprueba si el último display fué actualizado bcf display,0 ; Si lo fué, se vuelve a habilitar el primer display La variable display va cambiando: 1111 1101 1111 1011 1111 0111 1110 1110 1101 1101 1011 1011 0111 0111 1110 1110 Sólo valen los 4 bits menos significativos
DIV_DIGITOS
Divide los segundos o los minutos y las horas en digitos independientes, ejemplo, [14] lo pasa a [1]-[4]
digito4 = 0 digito2 = 0 conta1 = 2 FSR = digito1
Se ponen a cero las posiciones de las decenas para el caso de que no se incrementen Bucle para convertir cada número (segundos o minutos y horas) Dirección de digito1 en FSR para usar INDF La primera vez, FSR = digito1 (minutos o segundos) y la segunda vez FSR = digito3 (horas)
Se vuelve a comprobar si es necesario sumar uno a la decena cada vez que ésta se ha incrementado
Este LOOP se utiliza primero para los minutos o los segundos y después para las horas
INC_DECENAS LOOP
Averiguar cuantas “decenas” hay en el número. El número menos diez en cada bucle.
INDF = INDF - 10
Incf FSR,F Incf INDF,F Decf FSR,F
SI
CARRY = 1
Se comprueba "CARRY", que se pone a 1 si en la resta no se ha producido llevada Si C = 1 se añadirá 1 a la posición de las decenas
NO
INDF = 10 + INDF
Este LOOP se utiliza para las horas después de trabajar con los minutos o los segundos
C = 0, no se incrementan las decenas y se suma 10 para restaurar las unidades
LOOP2
FSR = digito3
PROX_NUM
Próximo número: Primero ha sido segundos o minutos y luego horas
conta1 = conta1 -1
NO
conta1 = 0 SI
CONVER_COD_7S
Pag. 5
El puntero apunta a la primera posición de las decenas Se añade 1 a las decenas Se restaura el valor de INDF para la próxima resta hasta que se termine
Convierte cada dígito a código 7 segmentos para los displays
CONVER_COD_7S
Coloca la dirección del primer digito (digito1) en FSR Prepara la variable conta1 para el bucle de los 4 displays
FSR = digito1 conta1 = 4
PROX_DIGITO
Obtener el valor de la variable "digito" actual
w = INDF
Pag. 8
LLamar a la rutina de conversión a código 7 segmentos
CODIGO_7S
Colocar en la variable "digito" actual el código 7 segmentos devuelto Incremente INDF para el próximo "digito" Se resta 1 a conta1
INDF = w FSR = FSR + 1 conta1 = conta1 - 1
NO
Permitir que conta1 de sólo 4 vueltas
conta1 = 0 SI
BORRAR_CERO
¿digito4 = “0”?
Si hay un cero en el display de las decenas de hora no se muestra (borrado de los ceros a la izquierda)
NO
SI digito4 = SEGM_OFF Si está pulsado PSEG no se muestra nada en el display de la posición de la unidad de hora. Contando con BORRAR_CERO, esto significa que sólo se mostrarán los segundos.
BORRAR_CERO_SEG
PSEG = 1 NO
DISPLAY_PUL
SI
digito3 = SEGM_OFF
Pag. 3
Puesta en hora de horas y minutos
PONER_RELOJ
Inicia los segundos cuando se pone el reloj en hora
segundos = SEGS_INI (196d)
PONER_MINUTOS Comprobar si se ha pulsado PMIN (Pulsador minutos) PMIN = 1
NO
SI
Avance rápido del tiempo cuando se ajustan minutos frac_sec = 175 Incrementar los minutos
frac_sec = 175d minutos = minutos + 1
minutos = 0
NO
SI
Iniciar minutos si al incrementar se han desbordado
minutos = MINS_INI
PONER_HORAS
Comprobar si se ha pulsado PHOR (Pulsador horas)
PHOR = 1
NO
SI
Avance rápido del tiempo cuando se ajustan horas frac_sec = 127d Incrementar las horas
frac_sec = 127d horas = horas + 1
NO horas = 0 SI
horas = HORS_INI (232d)
OBTENER_H_M
Pag. 2
Incrementar segundos, minutos y horas Ajustes cada minuto, hora y 24 horas
INC_HORA
CHG = 1
Se especifica que se ha producido un cambio
segundos = segundos + 1
Como ha pasado un segundo se incrementa “segundos”
segundos = 0
NO
SI
segundos = SEGS_INI (196d) frac_sec = frac_sec – ADJMIN (9d) minutos = minutos + 1
minutos = 0
Se ha desbordado "segundos" y se reestablece el valor inicial de “segundos” para la próxima vuelta Se resta 9 a “frac_sec” cada minuto para los ajustes de tiempo El minuto será 9 “frac_sec” más largo. Se añade 1 minuto
NO
SI
minutos = MINS_INI (196d) frac_sec = frac_sec + ADJHOR (34d) horas = horas + 1
horas = 0
Se reestablece el valor inicial de “minutos” para la próxima vuelta Se suma 34 “frac_sec” a cada hora para los ajustes de tiempo La hora será 34 “frac_sec” más corta Se añade 1 hora
NO
SI
horas = HORS_INI (232d) frac_sec = frac_sec – ADJDIA (6d)
COMPROBAR_CHG
Se reestablece el valor inicial de “horas” para la próxima vuelta Se resta 6 a “frac_sec” cada 24 horas para los ajustes de tiempo Cada 24 horas se añadirán 6 "frac_sec"
Pag. 2
SUBRUTINAS
CODIGO_7S
addwf retlw retlw retlw retlw retlw retlw retlw retlw retlw retlw
PCL,F CERO UNO DOS TRES CUATRO CINCO SEIS SIETE OCHO NUEVE
Devuelve el código 7 segmentos
Devuelve en el acumulador el valor de la constante CERO a NUEVE según el valor que se hubiese colocado en w