El programita que sirve para probar el reloj:
'************************* PIC Entrenadora BASIC (PicEBasic)******************************
'NOMBRE: 16F88_LCD_RTC
'VERSION: 1.0
'MICRO: PIC16f88A
'FECHA/AUTOR: 12/06 - By COS, PSI v7.41
'Descripcion: muestra en el display la fecha y la hora.
'Para transferir la hora al reloj dejar pulsada la tecla S1
'***************************************************************************************************
Define CONFIG = 0x2f50 'Configuración bits (Fuses)
Define CONFIG2 = 0x3ffc 'Configuración bits (Fuses)
Define CLOCK_FREQUENCY = 8 'Clock en Mhz
'Define SIMULATION_WAITMS_VALUE = 1 'Activar para simulación
'-------------------------------------Puertos del LCD---------------------------------------------
Define LCD_BITS = 4 'indicamos que el bus de datos del lcd sera de 4bit
Define LCD_DREG = PORTA 'el bus de datos sera el puerto A
Define LCD_DBIT = 0 'el bus de datos seran los 4 bit menos significativos del puerto A
Define LCD_RSREG = PORTB 'el bit de control RS sera del puerto B
Define LCD_RSBIT = 7 'se usara el RB7 como RS
Define LCD_EREG = PORTB 'el bit de control E sera del puerto B
Define LCD_EBIT = 6 'se usara el RB6 como E
'Define LCD_RWREG = PORTA 'el bit de control RW sera del puerto A
'Define LCD_RWBIT = 5 'se usara el RA5 como RW
Define LCD_COMMANDUS = 2000 'Tiempo de espera despues de ejecutar un comand del lcd en uSeg.
Define LCD_DATAUS = 50 'Tiempo de espera despues de enviar un dato al LCD en uSeg.
Define LCD_INITMS = 50 'Tiempo de espera despues de inicializar el Display, solo se ejecuta una vez en mSeg.
'Asignacion de I/O y valores de inicio de las salidas
ANSEL = %00000000 'Los pin I/O digitales
CMCON = 0x07 'Comparador a off
OSCCON = 0x7e 'Set intrc To 8mhz, se usara reloj interno a 8Mhz
TRISA = 0x00 'Puerto A como salidas
TRISB = 0x00 'Puerto B como salidas
TRISA.4 = 1 'Como entrada (RA4, adc)
TRISA.6 = 1 'Como entrada (RA6, tecla S1)
TRISA.5 = 1 'Como entrada (RA5, tecla S2)
PORTB.3 = 1 'Luz lcd a on (RB3)
PORTA.7 = 1 'Led amarillo a off
PORTB.0 = 1 'Led verde a off
'------------------------------------------------------------------------
Lcdinit 'Inicializa el lcd sin cursor
WaitMs 1000 'Espera 1Seg
Lcdout "16f88LCD_RTC/I2C" 'Escribe en el lcd
Lcdcmdout LcdLine2Home 'Selecciona la linea dos como proxima para escritura
Lcdout "Pruebas con I2C" 'Escribe en el lcd
WaitMs 3000 'Espera 3Seg
Lcdcmdout LcdClear
'Puerto I2C ---------------------------------------------------------
Symbol sda = PORTB.1 'Asignamos nombre al pin que hara de sda del puerto i2c
Symbol scl = PORTB.4 'Asignamos nombre al pin que hara de SCL del puerto I2C
'Variables Generales -------------------------------------------
Dim aux_4h As Byte 'Contendra el nibble alto del dato leido por el I2C
Dim aux_4l As Byte 'Contendra el nibble bajo del dato leido por el I2C
Dim i As Byte 'Variable indice
Dim reg(7) As Byte 'Contendra los valores finales de fecha y hora en el sistema decimal
'Inicializacion del reloj -------------------------------------------
'Aqui escribimos los valores para cargar al RTC ------
If RA6 = 0 Then 'Si la tecla S1 esta pulsada pasaremos los datos al reloj
I2CWrite sda, scl, 0xd0, 0, 0x00 'Segundos, escrito en hex, porque coincide en este caso con BCD del RTC
I2CWrite sda, scl, 0xd0, 1, 0x59 'Minutos
I2CWrite sda, scl, 0xd0, 2, 0x23 'Horas
I2CWrite sda, scl, 0xd0, 3, 0x01 'Dia de la semana
I2CWrite sda, scl, 0xd0, 4, 0x31 'Dia del mes
I2CWrite sda, scl, 0xd0, 5, 0x12 'Mes
I2CWrite sda, scl, 0xd0, 6, 0x06 'Año
I2CWrite sda, scl, 0xd0, 7, 0x10 'Salida a 1hz
Endif
'Bucle principal -----------------------------------------------------
main:
Gosub print_lcd 'Actualiza la hora
WaitMs 100 'Pausa de 100mSeg.
Goto main
End
'**************************************Subrutinas**********************************************
print_lcd: 'Lee la hora del RTC, la pasa a decimal y la envia al lcd
i = 0
While i <= 6 'Se repite el codigo comprendido entre while y wend, mientras i sea menor o igual a 6
I2CRead sda, scl, 0xd0, i, reg(i) 'Lectura de la direccion de memoria indicada del RTC, formato BCD
aux_4l = reg(i) And %00001111 'Eliminamos los bit de configuracion del RTC y dejamos solo el nibble bajo
If i = 0 Then aux_4h = reg(i) And %01110000 'Segundos, borrado de bit configuracion y almacena nibble alto
If i = 1 Then aux_4h = reg(i) And %11110000 'Minutos, almacena nibble alto
If i = 2 Then aux_4h = reg(i) And %10110000 'Horas, borrado de bit configuracion y almacena nibble alto
If i = 3 Then aux_4h = reg(i) And %11110000 'Dia_semana, almacena nibble alto
If i = 4 Then aux_4h = reg(i) And %11110000 'Dia_mes, almacena nibble alto
If i = 5 Then aux_4h = reg(i) And %11110000 'Mes, almacena el nibble alto
If i = 6 Then aux_4h = reg(i) And %11110000 'Año, almacena el nibble alto
aux_4h = ShiftRight(aux_4h, 4) 'Convierte el nibble alto en bajo
reg(i) = (aux_4h * 10) + aux_4l 'Fusiona los nibbles alto y bajo en una sola variable en formato decimal
i = i + 1 'Incrementa la variable indice con cada repeticion del bucle While/Wend
Wend 'Fin del bucle y salta a While
Lcdcmdout LcdLine1Home 'Cursor del lcd a la izquierda en la linea 1
If reg(2) < 10 Then Lcdout "0" 'Si horas es inferior a 10 escribe el cero delante
Lcdout #reg(2), ":" 'Escribe la hora y el separador
If reg(1) < 10 Then Lcdout "0" 'Si minutos es inferior a 10 escribe el cero delante
Lcdout #reg(1), ":" 'Escribe los minutos y el separador
If reg(0) < 10 Then Lcdout "0" 'Si segundos es inferior a 10 escribe el cerodelante
Lcdout #reg(0) 'Escribe los segundos
Lcdcmdout LcdLine2Home 'Cursor del lcd a la izquierda en la linea 2
If reg(3) = 1 Then Lcdout "Dom" 'Asigna el literal al dia de la semana
If reg(3) = 2 Then Lcdout "Lun"
If reg(3) = 3 Then Lcdout "Mar"
If reg(3) = 4 Then Lcdout "Mie"
If reg(3) = 5 Then Lcdout "Jue"
If reg(3) = 6 Then Lcdout "Vie"
If reg(3) = 7 Then Lcdout "Sab"
Lcdout "/" 'Escribe separador
If reg(4) < 10 Then Lcdout "0" 'Si dia del mes es inferior a 10 escribe cero
Lcdout #reg(4), "/" 'Escribe el dia del mes y el separador
If reg(5) < 10 Then Lcdout "0" 'Si mes es inferior a 10 escribe cero
Lcdout #reg(5), "/20" 'Escribe el mes, separador y los dos primeros digitos del año de 4 digitos
If reg(6) < 10 Then Lcdout "0" 'Si año es inferior a 10 escribe primero el cero
Lcdout #reg(6) 'Escribe el año
Return
PD: Recuerdo que los registros del RTC DS1307 se programan y se leen en BCD.
PD: 03/06/08
I2CWrite sda, scl, 0xd0, x, x
I2CRead sda, scl, 0xd1, x, x
0xd0 = %11010000 => Seleccion del chip DS1307 y modo escritura
0xd1 = %11010001 => Seleccion del chip DS1307 y modo lectura
%1101000x (direccion de seleccion del chip %1101000) siendo "x" el bit indicador de Write/Read. Este bit menos significativo lo controla directamente la funcion I2CWrite y I2CRead, por lo que su valor
es indiferente, la funcion I2CWrite lo pondra a valor "0" de forma automatica y al ser compilada tambien I2CRead lo colocara a 1.