Follow along with the video below to see how to install our site as a web app on your home screen.
Nota: This feature currently requires accessing the site using the built-in Safari browser.
************************************
;
; ===================================================================
; Del libro "MICROCONTROLADOR PIC16F84. DESARROLLO DE PROYECTOS"
; E. Palacios, F. Remiro y L. López. [URL="http://www.pic16f84a.com"]www.pic16f84a.com[/URL]
; Editorial Ra-Ma. [URL="http://www.ra-ma.es"]www.ra-ma.es[/URL]
; ===================================================================
;
; Programa para un reloj digital en tiempo real con puesta en hora. Visualiza los datos del
; reloj en formato: "Día Mes Año" (Primera línea)
; "Día_de_la_Semana Horas:Minutos:Segundos", (Segunda línea)
; (por ejemplo " 7 Diciemb. 2004" (Primera línea).
; "Martes 8:47:39" (Segunda línea).
;
; La actualización del reloj se consigue leyendo el chip DS1307, que es un reloj y
; calendario en tiempo real compatible con bus I2C.
;
; El DS1307 se configura para que genere una señal cuadrada de un 1 Hz por su pin SQW/OUT.
; Esta señal se aplica al pin de interrupción INT del PIC16F84A de manera que genera una
; interrupción cada segundo, que es cuando realiza la lectura del DS1307 y la visualiza.
;
; La "PuestaEnHora" se logra mediante dos pulsadores: "MODO" e "INCREMENTAR".
; Su modo de operación es:
; 1º Pulsa MODO, los "Años" se ponen intermitente y se ajustan mediante el
; pulsador INCREMENTAR.
; 2º Pulsa MODO y pasa a ajustar los "Meses" de forma similar.
; 3º Se va pulsando MODO secuencialmente para ajustar del modo anteriormente
; explicado los días del mes, los días de la semana, las horas y los minutos.
; 4º Pulsa MODO y se acabó la "PuestaEnHora", pasando a visualización normal.
;
; Cuando se ajusta una variable de tiempo, ésta debe aparecer en intermitencia.
;
; Los pulsadores MODO e INCREMENTAR se conectan a líneas del Puerto B y su
; funcionamiento se basa en interrupción por cambio en la línea del Puerto B:
;
; ZONA DE DATOS **********************************************************************
LIST P=16F84A
INCLUDE <P16F84A.INC>
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
CBLOCK 0x0C
Auxiliar ; Registro auxiliar.
Intermitencia ; Para lograr la intermitencia. Si es 0, apaga en intermitencia.
FlagsAjuste ; Guarda los flags para establecer los
ENDC ; ajustes de día, mes, año, hora, etc.
#DEFINE ModoPulsador PORTB,7 ; Los pulsadores se conectan a estos
#DEFINE IncrementarPulsador PORTB,6 ; pines del Puerto B.
#DEFINE OndaCuadrada_DS1307 PORTB,0 ; La onda cuadrada al pin RBO/INT.
#DEFINE F_AjusteAnho FlagsAjuste,5 ; Flags para los diferentes modos de
#DEFINE F_AjusteMes FlagsAjuste,4 ; ajustes.
#DEFINE F_AjusteDia FlagsAjuste,3
#DEFINE F_AjusteDiaSemana FlagsAjuste,2
#DEFINE F_AjusteHora FlagsAjuste,1
#DEFINE F_AjusteMinuto FlagsAjuste,0
; ZONA DE CÓDIGOS ********************************************************************
ORG 0
goto Inicio
ORG 4
goto ServicioInterrupcion
Mensajes
addwf PCL,F
MensajeLunes
DT "Lunes ", 0x00
MensajeMartes
DT "Martes ", 0x00
MensajeMiercoles
DT "Mierc. ", 0x00
MensajeJueves
DT "Jueves ", 0x00
MensajeViernes
DT "Viernes ", 0x00
MensajeSabado
DT "Sabado ", 0x00
MensajeDomingo
DT "Domingo ", 0x00
;
MensajeEnero
DT " Enero ", 0x00
MensajeFebrero
DT " Febrero", 0x00
MensajeMarzo
DT " Marzo ", 0x00
MensajeAbril
DT " Abril ", 0x00
MensajeMayo
DT " Mayo ", 0x00
MensajeJunio
DT " Junio ", 0x00
MensajeJulio
DT " Julio ", 0x00
MensajeAgosto
DT " Agosto ", 0x00
MensajeSeptiembre
DT "Septiem.", 0x00
MensajeOctubre
DT "Octubre ", 0x00
MensajeNoviembre
DT "Noviemb.", 0x00
MensajeDiciembre
DT "Diciemb.", 0x00
MensajeBlanco
DT " ", 0x00 ; Ocho espacios en blanco.
;
DiasSemana
addwf PCL,F
nop ; No hay día 0 de la semana. Empiezan en
retlw MensajeLunes ; el día 1 de la semana (Lunes).
retlw MensajeMartes ; Día 2 de la semana.
retlw MensajeMiercoles ; Día 3 de la semana.
retlw MensajeJueves ; Día 4 de la semana.
retlw MensajeViernes ; Día 5 de la semana.
retlw MensajeSabado ; Día 6 de la semana.
retlw MensajeDomingo ; Día 7 de la semana.
Meses
addwf PCL,F
nop ; No hay mes 0x00.
retlw MensajeEnero ; Empiezan en el mes 1 (Enero).
retlw MensajeFebrero ; Mes 0x02
retlw MensajeMarzo ; Mes 0x03
retlw MensajeAbril ; Mes 0x04
retlw MensajeMayo ; Mes 0x05
retlw MensajeJunio ; Mes 0x06
retlw MensajeJulio ; Mes 0x07
retlw MensajeAgosto ; Mes 0x08
retlw MensajeSeptiembre ; Mes 0x09
nop ; (Como el DS1307 trabaja en BCD,
nop ; estos meses se rellenan con
nop ; "nop").
nop
nop
nop
retlw MensajeOctubre ; Mes 0x10
retlw MensajeNoviembre ; Mes 0x11
retlw MensajeDiciembre ; Mes 0x12
FinTablas
; Estas tablas y mensajes se sitúan al principio del programa con el propósito que no
; supere la posición 0FFh de memoria ROM de programa. De todas formas, en caso que así
; fuera se visualizaría el siguiente mensaje de error en el proceso de ensamblado:
;
IF (FinTablas > 0xFF)
ERROR "Atención: La tabla ha superado el tamaño de la página de los"
MESSG "primeros 256 bytes de memoria ROM. NO funcionará correctamente."
ENDIF
; Instrucciones de inicialización. ------------------------------------------------------
;
Inicio
call LCD_Inicializa
bsf STATUS,RP0 ; Acceso banco 1.
bcf OPTION_REG,NOT_RBPU ; Se activan las resistencias de Pull-Up del Puerto B.
bsf ModoPulsador ; Los pulsadores se configuran como entrada.
bsf IncrementarPulsador
bsf OndaCuadrada_DS1307
bcf OPTION_REG,INTEDG ; Interrupción INT activa por flanco de bajada.
bcf STATUS,RP0 ; Acceso banco 0.
clrf FlagsAjuste ; Inicializa todos los flags de la puesta en hora.
call DS1307_Inicializa ; Configura la señal cuadrada que genera el
; DS1307 en su pin SQW/OUT a 1 Hz.
;
; Ahora lee el bit 7 de los segundos para saber el estado anterior del reloj antes del
; reset. Este bit es el CH (Control Halt) y permite poner en marcha (CH=0) o parar el
; reloj (CH=1). Tras la lectura pueden ocurrir dos casos:
; - Si CH está a 0 quiere decir que anteriormente el reloj ya se ha puesto en hora alguna
; vez y está en modo "respaldo". Es decir, ha fallado la alimentación y el DS1307 se está
; alimentando por la batería conectada al pin "VBAT", aunque el reloj no se visualice en
; la pantalla. Por tanto, no debe inicializarse porque se corrompería el contenido del
; DS1307 que ya está en marcha.
; - Si CH está a 1, quiere decir que estaba parado y es la primera vez que se pone en hora.
;
call DS1307_Lee ; Lee los segundos en el DS1307 y comprueba el
btfss Segundo,7 ; valor del bit CH. Si es "1" salta toda la
goto AntesConBateria ; inicialización de los registros y la puesta
; en hora inicial.
call DS1307_CargaInicial ; Realiza la carga inicial a 1 Enero de 2004.
movlw b'10011000' ; Las interrupciones se deben habilitar después
movwf INTCON ; de la carga inicial del DS1307.
call PuestaEnHoraReset ; Puesta en hora por primera vez.
goto Principal
AntesConBateria
movlw b'10011000' ; Habilita las interrupciones INT, RBI y la
movwf INTCON ; general GIE.
; La sección "Principal" de mantenimiento. Pasa al modo reposo y sólo espera las
; interrupciones procedentes de la línea "SQW/OUT" del DS1307 que se producen cada
; segundo en funcionamiento normal y cada 500 ms cuando esté en la "PuestaEnHora".
Principal
sleep
goto Principal
; Subrutina "ServicioInterrupcion" ------------------------------------------------------
;
; Detecta qué ha producido la interrupción y ejecuta la subrutina de atención correspondiente.
ServicioInterrupcion
btfsc INTCON,INTF ; Si es una interrupción procedente de la onda
call Reloj ; cuadrada del DS1307 actualiza la visualización.
btfss INTCON,RBIF ; Si es una interrupción RBI lee los pulsadores.
goto FinInterrupcion
btfss ModoPulsador ; ¿Está presionado el pulsador de "MODO"?
call PuestaEnHora ; Sí, pasa a poner en hora.
btfss IncrementarPulsador ; ¿Pulsado "INCREMENTAR"?
call Incrementar ; Sí, pasa a incrementar el registro de tiempo
FinInterrupcion ; correspondiente.
bcf INTCON,RBIF ; Limpia los flags de reconocimiento de la
bcf INTCON,INTF ; interrupción.
retfie
; Subrutina "Reloj" ---------------------------------------------------------------------
;
; Esta subrutina actualiza los registros Anho, Mes, Dia, DiaSemana, Hora, Minuto y
; Segundo leyendo el DS1307 a través del bus I2C. Se ejecuta debido a la petición de
; interrupción de la señal cuadrada de 1 Hz, que procede del pin "SQW/OUT" del DS1307 y
; se ha conectado al pin RB0/INT del PIC16F84A.
;
; Esta interrupción ocurre cada segundo si está en visualización normal y cada 500 ms si
; está en puesta en hora con el objetivo de conseguir la intermitencia.
;
; Si no está en puesta en hora está en funcionamiento normal, por tanto se limita a leer
; el DS1307 y a visualizar la hora.
;
Reloj
movf FlagsAjuste,F ; Si no está en puesta en hora se limita a
btfsc STATUS,Z ; leer el DS1307.
goto Leer_DS1307
; Si está en algún modo de ajuste debe interrumpir cada 500 ms para lograr la intermitencia
; alternando la interrupción por flanco de subida o de bajada. Esto lo consigue mediante la
; operación XOR del flag INTEDG con un "1", lo cual invierte este bit cada vez que ejecuta
; la instrucción y por tanto conmuta entre flanco ascendente y descendente.
bsf STATUS,RP0 ; Acceso banco 1.
movlw b'01000000' ; El bit INTEDG está en el lugar 6 del registro.
xorwf OPTION_REG,F
bcf STATUS,RP0 ; Acceso banco 0.
; Además complementa el registro Intermitencia para que se produzca la intermitencia
; cada 500 milisegundos cuando está en la puesta en hora.
comf Intermitencia,F
goto ActualizaReloj ; Visualiza el reloj y sale.
Leer_DS1307
; No está en ningún modo de ajuste, sino en funcionamiento normal de reloj y pasa a leer los
; registros del reloj-calendario DS1307 a través del bus I2C. Los registros del DS1307 ya
; trabajan en formato BCD, por tanto no hay que hacer ningún tipo de conversión al leerlos.
call DS1307_Lee
ActualizaReloj ; Estas dos instrucciones se pueden
; call VisualizaReloj ; obviar, ya que a continuación efectivamente
; return ; ejecuta la subrutina VisualizaReloj y
; retorna.
; Subrutina "VisualizaReloj" ------------------------------------------------------------
;
; Visualiza el reloj en formato "Dia Mes Año" (Primera Línea)
; "Día_de_la_Semana Horas:Minutos:Segundos", (Segunda Línea)
; Por ejemplo " 7 Diciemb. 2004" (Primera Linea).
; "Martes 8:47:39" (Segunda Línea).
; La variable ajustada debe aparecer en intermitencia. Esto se logra con ayuda de
; cualquier bit del registro Intermitencia que conmuta cada 500 ms en la subrutina Reloj.
;
VisualizaReloj
call LCD_Linea1 ; Se sitúa en la primera línea.
btfss F_AjusteDia ; ¿Está en la puesta en hora?
goto EnciendeDia ; No. Pasa a visualización normal.
btfss Intermitencia,0 ; Sí. Pasa a intermitencia si procede.
goto ApagaDia ; Apaga en la intermitencia.
EnciendeDia
movf Dia,W ; Lo visualiza. El DS1307 ya lo da en BCD.
call LCD_Byte ; Visualiza rechazando cero de las decenas.
goto VisualizaMes
ApagaDia
call LCD_DosEspaciosBlancos ; Visualiza dos espacios en blanco.
;
VisualizaMes
call LCD_UnEspacioBlanco ; Visualiza un espacio en blanco.
btfss F_AjusteMes ; ¿Está en la puesta en hora?
goto EnciendeMes ; No. Visualización normal.
btfss Intermitencia,0 ; Sí. Intermitencia si procede.
goto ApagaMes ; Apaga en la intermitencia.
EnciendeMes
movf Mes,W ; Lo visualiza.
call EscribeMes
goto VisualizaAnho
ApagaMes
movlw MensajeBlanco
call LCD_Mensaje ; Visualiza varios espacios en blanco.
;
VisualizaAnho
btfss F_AjusteAnho ; ¿Está en la puesta en hora?
goto EnciendeAnho ; No. Visualización normal.
btfss Intermitencia,0 ; Sí. Intermitencia si procede.
goto ApagaAnho ; Apaga en la intermitencia.
EnciendeAnho
call LCD_UnEspacioBlanco ; Visualiza un espacio en blanco.
movlw 0x20 ; Visualiza el "20xx", del año "dos mil ...".
call LCD_Byte
movf Anho,W
call LCD_ByteCompleto
goto VisualizaDiaSemana
ApagaAnho
movlw MensajeBlanco
call LCD_Mensaje ; Visualiza varios espacios en blanco.
;
VisualizaDiaSemana
call LCD_Linea2 ; Se sitúa en la segunda línea.
btfss F_AjusteDiaSemana ; ¿Está en la puesta en hora?
goto EnciendeDiaSemana ; No. Visualización normal.
btfss Intermitencia,0 ; Sí. Intermitencia si procede.
goto ApagaDiaSemana ; Apaga en la intermitencia.
EnciendeDiaSemana
movf DiaSemana,W ; Lo visualiza.
call EscribeDiaSemana
goto VisualizaHoras
ApagaDiaSemana
movlw MensajeBlanco
call LCD_Mensaje ; Visualiza varios espacios en blanco.
;
VisualizaHoras
btfss F_AjusteHora ; ¿Está en la puesta en hora?
goto EnciendeHoras ; No. Visualización normal.
btfss Intermitencia,0 ; Sí. Intermitencia si procede.
goto ApagaHoras ; Apaga las horas en la intermitencia.
EnciendeHoras
movf Hora,W ; Va a visualizar las horas.
call LCD_Byte ; Visualiza rechazando cero de las decenas.
goto VisualizaMinutos
ApagaHoras
call LCD_DosEspaciosBlancos ; Visualiza dos espacios en blanco.
;
VisualizaMinutos
movlw ':' ; Envía ":" para separar datos.
call LCD_Caracter
btfss F_AjusteMinuto ; ¿Está en la puesta en hora?.
goto EnciendeMinutos
btfss Intermitencia,0
goto ApagaMinutos
EnciendeMinutos
movf Minuto,W ; Visualiza minutos.
call LCD_ByteCompleto
goto VisualizaSegundos
ApagaMinutos
call LCD_DosEspaciosBlancos ; Visualiza dos espacios en blanco.
;
VisualizaSegundos
movlw ':' ; Envía ":" para separar datos.
call LCD_Caracter
movf Segundo,W ; Visualiza segundos.
call LCD_ByteCompleto
return
;
; Subrutina "EscribeDiaSemana" ----------------------------------------------------------
;
; Escribe el día de la semana en la posición actual de la pantalla, utilizando la tabla
; "DiaSemana". Supone que el Lunes es el día 1 y el Domingo el 7.
; En el registro W se le introduce el día de la semana numérico y en la pantalla aparece el
; día de la semana en letras. Así por ejemplo si (W)=0x02 en la pantalla aparecerá "Martes".
;
; Primero comprueba que no ha superado el valor máximo para evitar problemas de saltos
; erráticos con la llamada "call DiasSemana", en caso de una lectura defectuosa de este
; dato por parte del DS1307.
;
EscribeDiaSemana
sublw 0x07 ; ¿Ha superado su valor máximo?
btfsc STATUS,C
goto Llamada_a_DiasSemana
movlw 0x01 ; Lo inicializa si ha superado su valor máximo.
movwf DiaSemana
Llamada_a_DiasSemana
movf DiaSemana,W
call DiasSemana
call LCD_Mensaje
return
; Subrutina "EscribeMes" ----------------------------------------------------------------
;
; Escribe el mes del año en la posición actual de la pantalla, utilizando la tabla "Meses".
;
; Primero comprueba que no ha superado el valor máximo para evitar problemas de saltos
; errático con la llamada "call Meses", en caso de una lectura defectuosa de este dato
; por parte del DS1307.
;
; El DS1307 trabaja en BCD y la tabla en binario natural. Esto es un problema que se
; soluciona con una correcta distribución de la tabla "Meses".
;
EscribeMes
sublw 0x12 ; ¿Ha superado su valor máximo? (Observad que
btfsc STATUS,C ; trabaja en BCD).
goto Llamada_a_Meses
movlw 0x01 ; Lo inicializa si ha superado su valor máximo.
movwf Mes
Llamada_a_Meses
movf Mes,W ; Retorna el resultado en el registro W.
call Meses
call LCD_Mensaje
return
; Subrutina "PuestaEnHora" --------------------------------------------------------------
;
; Subrutina de atención a la interrupción producida por el pulsador MODO que pone en hora
; el reloj. Cada vez que pulsa se desplaza el "1" a través del registro FlagsAjuste,
; pasando a ajustar secuencialmente: años, meses, días, días de la semana, horas y minutos.
;
; Para comprender el funcionamiento de esta subrutina hay que saber que el registro
; FlagsModos contiene 5 flags que permite diferenciar cada uno de los ajustes de registros
; de tiempo:
; - "F_AjusteAnho": bit 5 de FlagsAjuste, para ajustar los años.
; - "F_AjusteMes": bit 4 de FlagsAjuste, para ajustar los meses.
; - "F_AjusteDia": bit 3 de FlagsAjuste, para ajustar los días del mes.
; - "F_AjusteDiaSemana": bit 2 de FlagsAjuste, para ajustar los días de la semana.
; - "F_AjusteHora": bit 1 de FlagsAjuste, para ajustar las horas.
; - "F_AjusteMinuto": bit 0 de FlagsAjuste, para ajustar los minutos.
;
; Así pues el contenido del registro FlagAjuste identifica los siguientes ajustes:
; - (FlagsAjuste)=b'00100000'. Está ajustando el registro Anho (Años).
; - (FlagsAjuste)=b'00010000'. Está ajustando el registro Mes.
; - (FlagsAjuste)=b'00001000'. Está ajustando el registro Dia.
; - (FlagsAjuste)=b'00000100'. Está ajustando el registro DiaSemana (Lunes, Martes, etc).
; - (FlagsAjuste)=b'00000010'. Está ajustando el registro Hora.
; - (FlagsAjuste)=b'00000001'. Está ajustando el registro Minuto.
; - (FlagsAjuste)=b'00000000'. Está en visualización normal del reloj en tiempo real.
;
; Pueden ocurrir tres casos:
; - Que pulse "MODO" estando en modo de visualización normal identificado porque
; (FlagsAjuste)=b'0000000'. En este caso debe activar el flag F_AjusteAnho, es decir,
; carga (FlagsAjuste)=b'00100000', ya que el flag F_AjusteAnho es el bit 5 del registro
; FlagsAjuste.
; - Que pulse "MODO" estando ya en la puesta en hora, en cuyo caso debe pasar al
; ajuste del siguiente registro de tiempo. Ésto lo hace mediante un desplazamiento
; a derechas. Así por ejemplo, si antes estaba ajustando los meses, es decir:
; (FlagsAjuste)=b'00010000', pasará a (FlagsAjuste)=b'00001000' que se identifica
; como ajuste de los días del mes.
; - Que pulse "MODO" estando en el último ajuste correspondiente a los minutos,
; (FlagsAjuste)=b'00000001', pasará a (FlagsAjuste)=b'00000000', indicando que la
; puesta en hora ha terminado y pasa a visualización normal del reloj en tiempo real.
;
PuestaEnHora
call Retardo_20ms ; Espera a que se estabilicen niveles de tensión.
btfsc ModoPulsador ; Si es un rebote sale fuera.
goto FinPuestaEnHora
PuestaEnHoraReset ; Al pulsar "MODO" se apaga la variable de
clrf Intermitencia ; tiempo que se va a ajustar.
btfsc F_AjusteMinuto ; Si antes estaba en ajuste de minutos es que
goto FuncionamientoNormal ; ha terminado. Graba datos en el DS1307 y sale.
movf FlagsAjuste,F ; Si antes estaba en funcionamiento normal ahora
btfss STATUS,Z ; pasa a ajustar el año.
goto AjustaSiguiente ; Sino pasa a ajustar la variable de tiempo siguiente.
bsf F_AjusteAnho ; Pasa a ajustar el año.
clrf Segundo ; Inicializa contador de segundos.
goto FinPuestaEnHora
AjustaSiguiente ; Desplaza un uno a la derecha del registro
bcf STATUS,C ; FlagsAjuste para ajustar secuencialmente cada
rrf FlagsAjuste,F ; uno de los registros de tiempo: año, mes, día,
goto FinPuestaEnHora ; día de la semana, hora y minuto.
;
; Lo siguiente se ejecuta si ya ha acabado el ajuste de la hora, es decir, pasa a
; funcionamiento normal. En este caso hay que realizar tres operaciones:
; - Fijar la interrupción INT solo por flanco de bajada.
; - Inicializar a cero todos los flags de ajuste contenidos en (FlagsAjuste).
; - Escribir el DS1307 con los datos de las variables de tiempo contenidas en la
; memoría RAM del microcontrolador.
;
FuncionamientoNormal
bsf STATUS,RP0 ; Acceso banco 1.
bcf OPTION_REG,INTEDG ; Interrupción INT activa por flanco de bajada.
bcf STATUS,RP0 ; Acceso banco 0.
clrf FlagsAjuste ; Inicializa los flags de ajuste.
call DS1307_Escribe ; Graba los datos en el DS1307.
FinPuestaEnHora
call VisualizaReloj ; Visualiza los datos del reloj digital.
btfss ModoPulsador ; Ahora espera deje de pulsar.
goto FinPuestaEnHora
return
; Subrutina "Incrementar" ---------------------------------------------------------------
;
; Subrutina de atención a la interrupción por cambio de la línea RB6 al cual se ha
; conectado el pulsador "INCREMENTAR".
;
; Incrementa según corresponda una sola de las siguientes variables: (Anho), (Mes),
; (Dia), (DiaSemana), (Hora) o (Minuto).
Incrementar
call Retardo_20ms ; Espera a que se estabilice el nivel de tensión.
btfsc IncrementarPulsador ; Si es un rebote sale fuera.
goto FinIncrementar
btfsc F_AjusteAnho
call IncrementaAnhos
btfsc F_AjusteMes
call IncrementaMeses
btfsc F_AjusteDia
call IncrementaDias
btfsc F_AjusteDiaSemana
call IncrementaDiasSemana
btfsc F_AjusteHora
call IncrementaHoras
btfsc F_AjusteMinuto
call IncrementaMinutos
movlw b'11111111'
movwf Intermitencia ; Visualiza siempre mientras incrementa.
call VisualizaReloj ; Visualiza mientras espera que deje
call Retardo_200ms ; de pulsar.
btfss IncrementarPulsador ; Mientras permanezca pulsado
goto Incrementar ; incrementará el dígito.
FinIncrementar
return
; Subrutina "IncrementaMinutos" ---------------------------------------------------------
;
; Incrementa el valor de la variable Minutos. Si supera los 0x59, lo resetea.
; Este incremento se debe realizar en BCD para ello utiliza la subrutina AjusteBCD.
IncrementaMinutos
incf Minuto,F ; Incrementa los minutos.
movf Minuto,W ; Lo pasa a BCD.
call AjusteBCD
movwf Minuto ; Lo guarda.
sublw 0x59 ; ¿Ha superado su valor máximo?
btfss STATUS,C
clrf Minuto ; Lo inicializa si ha superado su valor máximo.
return
; Subrutina "IncrementaHoras" -----------------------------------------------------------
;
IncrementaHoras
incf Hora,F ; Incrementa las Horas.
movf Hora,W ; Ahora hace el ajuste BCD.
call AjusteBCD
movwf Hora ; Lo guarda.
sublw 0x23 ; ¿Ha superado su valor máximo?
btfss STATUS,C
clrf Hora ; Lo inicializa si ha superado su valor máximo.
return
; Subrutina "IncrementaDiasSemana" ------------------------------------------------------
;
IncrementaDiasSemana
incf DiaSemana,F
movf DiaSemana,W
sublw .7 ; ¿Ha superado su valor máximo?
btfsc STATUS,C
goto FinIncrementaDiasSemana
movlw .1 ; Lo inicializa si ha superado su valor máximo.
movwf DiaSemana
FinIncrementaDiasSemana
return
; Subrutina "IncrementaDias" ------------------------------------------------------------
;
IncrementaDias
incf Dia,F ; Incrementa.
movf Dia,W ; Ahora hace el ajuste BCD.
call AjusteBCD
movwf Dia ; Lo guarda.
sublw 0x31 ; ¿Ha superado su valor máximo?
btfsc STATUS,C
goto FinIncrementaDias
movlw .1 ; Lo inicializa si ha superado su valor máximo.
movwf Dia
FinIncrementaDias
return
; Subrutina "IncrementaMeses" -----------------------------------------------------------
;
IncrementaMeses
incf Mes,F ; Incrementa.
movf Mes,W
call AjusteBCD ; Ajusta a BCD.
movwf Mes ; Lo guarda.
sublw 0x12 ; ¿Ha superado su valor máximo?
btfsc STATUS,C
goto FinIncrementaMeses
movlw .1 ; Lo inicializa si ha superado su valor máximo.
movwf Mes
FinIncrementaMeses
return
; Subrutina "IncrementaAnhos" ------------------------------------------------------------
;
; Incrementa el valor de la variable (Anhos). Cuando llega a 0x30 (BCD), lo resetea.
; Es decir, llega hasta el año 2030, que se ha considerado suficientemente alto.
; Este incremento se debe realizar en BCD para ello utiliza la subrutina AjusteBCD.
;
IncrementaAnhos
incf Anho,F ; Incrementa.
movf Anho,W ; Ahora hace el ajuste BCD.
call AjusteBCD
movwf Anho ; Lo guarda.
sublw 0x30 ; ¿Ha superado su valor máximo?.
btfss STATUS,C ; Si no llega a su máximo sale.
clrf Anho ; Lo inicializa si ha superado su valor máximo.
return
; Subrutina "AjusteBCD" -----------------------------------------------------------------
;
; Esta subrutina pasa a BCD el dato de entrada. Para ello detecta si las unidades superan
; el valor "9", en cuyo caso le suman 6 para pasarlo a BCD. Por ejemplo, si previamente
; (Minuto)=0x19, al incrementarle resulta (Minuto)=0x1A que no es un código válido BCD, si se
; le suma 6 resulta (Minuto)=0x1A+0x06=0x20 que es un código válido BCD.
;
; Entrada: En (W) el código a convertir
; Salida: En (W) el código convertido en BCD.
;
AjusteBCD
movwf Auxiliar ; Guarda el valor del número a convertir.
andlw b'00001111' ; Se queda con su parte baja.
sublw .9 ; Comprueba si pasa de nueve.
btfsc STATUS,C
goto NoSuperaNueve
movlw .6 ; Sí lo ha superado, por tanto le suma 6.
addwf Auxiliar,F
NoSuperaNueve
movf Auxiliar,W ; Retorna el resultado en el registro (W).
return
INCLUDE <BUS_I2C.INC> ; Subrutinas de control del bus I2C.
INCLUDE <DS1307.INC> ; Subrutinas de control del DS1307.
INCLUDE <RETARDOS.INC>
INCLUDE <LCD_4BIT.INC>
INCLUDE <LCD_MENS.INC>
END
; ===================================================================
; Del libro "MICROCONTROLADOR PIC16F84. DESARROLLO DE PROYECTOS"
; E. Palacios, F. Remiro y L. López. [URL="http://www.pic16f84a.com"]www.pic16f84a.com[/URL]
; Editorial Ra-Ma. [URL="http://www.ra-ma.es"]www.ra-ma.es[/URL]
; ===================================================================
;******************************** Librería DS1307.INC ***********************************
;
; ===================================================================
; Del libro "MICROCONTROLADOR PIC16F84. DESARROLLO DE PROYECTOS"
; E. Palacios, F. Remiro y L. López. [URL="http://www.pic16f84a.com"]www.pic16f84a.com[/URL]
; Editorial Ra-Ma. [URL="http://www.ra-ma.es"]www.ra-ma.es[/URL]
; ===================================================================
;
; Estas subrutinas permiten realizar las tareas de manejo del reloj-calendario DS1307
; Este dispositivo transmite la información vía serie a través de un bus I2C.
;
; ZONA DE DATOS **********************************************************************
CBLOCK
Anho ; Guarda el año.
Mes ; Guarda el mes.
Dia ; Guarda el día.
DiaSemana ; Guarda el día de la semana: lunes, etc.
Hora ; Guarda las horas.
Minuto ; Guarda los minutos.
Segundo ; Guarda los segundos.
ENDC
DS1307_DIR_ESCRITURA EQU 0xD0 ; Dirección del DS1307.
DS1307_DIR_LECTURA EQU 0xD1
; Subrutina "DS1307_Inicializa" ---------------------------------------------------------
;
; Configura la señal cuadrada que genera el DS1307 en su pin SQW/OUT a 1 Hz.
DS1307_Inicializa
call I2C_EnviaStart ; Envía condición de Start.
movlw DS1307_DIR_ESCRITURA ; Indica al DS1307 que el byte a escribir,
call I2C_EnviaByte ; está en la posición 07h, que corresponde
movlw 0x07 ; al control de la señal cuadrada.
call I2C_EnviaByte
movlw b'00010000' ; Escribe en el registro de control para
call I2C_EnviaByte ; configurar onda cuadrada del DS1307 a 1 Hz.
call I2C_EnviaStop ; Termina de enviar datos.
return
; Subrutina "DS1307_Lee" ----------------------------------------------------------------
;
; Se leen las variables de tiempo del DS1307 y se guardan en los registros correspondientes.
;
DS1307_Lee
bcf I2C_UltimoByteLeer
call I2C_EnviaStart ; Envía condición de Start.
movlw DS1307_DIR_ESCRITURA ; Indica al DS1307 que el primer byte
call I2C_EnviaByte ; a leer está en la posición 00H, que corresponde
movlw 0x00 ; a los segundos.
call I2C_EnviaByte
call I2C_EnviaStop ; Envía condición de Stop.
; Ahora va a leer el DS1307.
call I2C_EnviaStart ; Envía condición de Start.
movlw DS1307_DIR_LECTURA
call I2C_EnviaByte
call I2C_LeeByte ; Lee los segundos.
movwf Segundo ; Lo carga en el registro correspondiente.
call I2C_LeeByte ; Lee el resto de los registros utilizando
movwf Minuto ; el mismo procedimiento.
call I2C_LeeByte
movwf Hora
call I2C_LeeByte
movwf DiaSemana
call I2C_LeeByte
movwf Dia
call I2C_LeeByte
movwf Mes
bsf I2C_UltimoByteLeer ; Para terminar.
call I2C_LeeByte
movwf Anho
call I2C_EnviaStop ; Acaba de leer.
return
; Subrutina "DS1307_CargaInicial" -------------------------------------------------------
;
; Realiza una carga inicial en los registros internos del reloj-calendario DS1307 a fecha
; Lunes, 1 de Enero de 2004 a las 0:00:00.
;
DS1307_CargaInicial
movlw .1 ; Inicializa todos los datos del reloj: Año, mes,
movwf Dia ; día, día de la semana, hora, minuto y segundo.
movwf Mes
movwf DiaSemana
movlw .4
movwf Anho ; Inicializa en el año 2004.
clrf Hora
clrf Minuto
clrf Segundo ; Después lo graba en el DS1307 para
; call DS1307_Escribe ; ponerlo en marcha.
; return
;
; Subrutina "DS1307_Escribe" ----------------------------------------------------------------
;
; Carga los datos de los registros Anho, Mes, etc., dentro del DS1307.
DS1307_Escribe
call I2C_EnviaStart ; Envía condición de Start.
movlw DS1307_DIR_ESCRITURA ; Indica al DS1307 que el primer byte a escribir
call I2C_EnviaByte ; está en la posición 00h que corresponde
movlw 0x00 ; a los segundos.
call I2C_EnviaByte
movf Segundo,W ; Pasa los segundos de la memoria del PIC16F84A
call I2C_EnviaByte ; al DS1307.
movf Minuto,W ; Y se repite el proceso para el resto.
call I2C_EnviaByte
movf Hora,W
call I2C_EnviaByte
movf DiaSemana,W
call I2C_EnviaByte
movf Dia,W
call I2C_EnviaByte
movf Mes,W
call I2C_EnviaByte
movf Anho,W
call I2C_EnviaByte
call I2C_EnviaStop ; Termina de enviar datos.
return
; ===================================================================
; Del libro "MICROCONTROLADOR PIC16F84. DESARROLLO DE PROYECTOS"
; E. Palacios, F. Remiro y L. López. [URL="http://www.pic16f84a.com"]www.pic16f84a.com[/URL]
; Editorial Ra-Ma. [URL="http://www.ra-ma.es"]www.ra-ma.es[/URL]
; ===================================================================