- #1
thegreengineer
- 54
- 3
Good evening people, I was planing to make a programmable clock using a PIC16F877A microcontroller, a LM016 LCD display and a DS3232 RTC module. The DS3231 RTC module communicates with the PIC via I2C bus. At first I built some subroutines for controlling I2C communication: the commands have names in Spanish yet I explain what they do:
I built the circuit in Proteus to test if the I2C communication works fine. For this purpose I just built the DS3231 part.
If I upload a hex file with no i2c instructions the RTC starts counting from TIME at 00:00:00 and DATE at 00/00/00. Now let's suppose when I start the simulation I want the TIME to display at 00:10:00. For this what do I have to do? Well it's obvious that I need to write into the DS3232. So the first thing I do is initialializing the I2C comunication by calling the i2c_inicializa function at the very first. After that I send the start condition with the i2c_inicio command. Then I have to send the adress of the slave plus the R/W bit for declaring if I want to read or write. Since DS3232 has an address of B'1101000' and I want to write in the DS3232 I send the byte B'11010000' with the i2c_envia_dato command (by previously loading the B'11010000' value into the W register). The I send the address, so I check the DS3232 datasheet and I find that the MINUTES register is in address 01H of the adress map, so I send the value B'00000001' with the i2c_envia_dato command. Then I'm at the MINUTES register so if I want a "10" at the minutes register then I send (in BCD) B'00010000' with the i2c_envia_dato command. Finally to end the communication I call the i2c_parada for the stop condition. The source code is this:
After that I compile (build) and there are no errors, however when loading the code in PROTEUS the simulation still starts at time 00:00:00. And I don't know where my mistake is, I already checked the datasheet of the RTC module, still don't know. I would appreciate your answers. Thanks.
Code:
i2c_inicializa ;This subroutine is for initiating the I2C module
bcf STATUS,RP1
bsf STATUS,RP0
bsf TRISC,TRISC3
bsf TRISC,TRISC4
movlw B'10000000'
movwf SSPSTAT
bcf STATUS,RP0
movlw B'00101000'
movwf SSPCON
bsf STATUS,RP0
movlw B'00000000'
movwf SSPCON2
movlw D'9'
movwf SSPADD
return
i2c_espera ;This is just an idle subroutine for producing a delay time between commands
call retardo_2ms
return
i2c_inicio ;Start condition
bcf STATUS,RP1
bsf STATUS,RP0
call i2c_espera
bsf SSPCON2,SEN
return
i2c_reinicio ;Restarting condition
bcf STATUS,RP1
bsf STATUS,RP0
call i2c_espera
bsf SSPCON2,RSEN
return
i2c_parada ;Stop condition
bcf STATUS,RP1
bsf STATUS,RP0
call i2c_espera
bsf SSPCON2,PEN
return
i2c_envia_dato ;Write data into slave device
bcf STATUS,RP1
bcf STATUS,RP0
call i2c_espera
movwf SSPBUF
return
i2c_recibe_dato ;Reading data from slave
bcf STATUS,RP1
bsf STATUS,RP0
call i2c_espera
bsf SSPCON2,RCEN
call i2c_espera
bsf SSPCON2,ACKDT
bsf SSPCON2,ACKEN
bcf STATUS,RP1
bcf STATUS,RP0
movf SSPBUF,0
return
I built the circuit in Proteus to test if the I2C communication works fine. For this purpose I just built the DS3231 part.
If I upload a hex file with no i2c instructions the RTC starts counting from TIME at 00:00:00 and DATE at 00/00/00. Now let's suppose when I start the simulation I want the TIME to display at 00:10:00. For this what do I have to do? Well it's obvious that I need to write into the DS3232. So the first thing I do is initialializing the I2C comunication by calling the i2c_inicializa function at the very first. After that I send the start condition with the i2c_inicio command. Then I have to send the adress of the slave plus the R/W bit for declaring if I want to read or write. Since DS3232 has an address of B'1101000' and I want to write in the DS3232 I send the byte B'11010000' with the i2c_envia_dato command (by previously loading the B'11010000' value into the W register). The I send the address, so I check the DS3232 datasheet and I find that the MINUTES register is in address 01H of the adress map, so I send the value B'00000001' with the i2c_envia_dato command. Then I'm at the MINUTES register so if I want a "10" at the minutes register then I send (in BCD) B'00010000' with the i2c_envia_dato command. Finally to end the communication I call the i2c_parada for the stop condition. The source code is this:
Code:
;RELOJ PROGRAMABLE CON ALARMA ELABORADO CON PIC16F877A
;AUTOR: MARCO AURELIO VILLARREAL DEL VALLE
;MATRICULA: 1639019
;CLASE DE MICROCONTROLADORES
__CONFIG _FOSC_HS & _WDTE_OFF & _PWRTE_OFF & _BOREN_OFF & _LVP_OFF & _CPD_OFF & _WRT_OFF & _CP_OFF
LIST P=16F877A
#INCLUDE <P16F877A.INC>
;Iniciando en el banco 0
ORG 0x00
CBLOCK 0x26
CONT_PAL
ENDC
bcf STATUS,RP1
bsf STATUS,RP0
clrf TRISB
clrf TRISC
clrf TRISD
bcf STATUS,RP0
call i2c_inicializa
call i2c_inicio
movlw B'11010000'
call i2c_envia_dato
movlw B'00000001'
call i2c_envia_dato
movlw B'00010000'
call i2c_envia_dato
call i2c_parada
principal
goto principal
#INCLUDE <retardos.INC>
#INCLUDE <i2c.INC>
#INCLUDE <lcd.INC>
END