PDA

View Full Version : Data from DS1307 (BCD) saved to ext memory and read back to display



flotulopex
- 18th July 2016, 23:07
Hi there,

I have setup a 16F690 reading a DS1307's time and date (I use RA2/INT interrupt to trigger the process every second), save this data to an external 24LC64 memory, read back what has just been written from the memory and display it.

If I bypass the I2CWRITE/I2CREAD commands, the DS1307 displays time correctly.

But, like in the code here under, after saving RTC's time to the memory, this is what I get after reading back the data from the external memory:
8269

Data from DT1307 is in BCD format and data conversion, that's where I think I'm wrong, is not my cup of tea :(

What am I missing?



'-------------------------------------------------------------------------------
' PIC 16F690 Fuses (MPASM)
@ __Config _FCMEN_OFF &_IESO_OFF &_CPD_OFF &_WDT_OFF &_HS_OSC &_BOR_OFF &_CP_OFF &_PWRTE_OFF &_MCLRE_OFF

'-------------------------------------------------------------------------------
' Registers 76543210
OPTION_REG = %10000000 'PORT A&B Pull-Ups disabled (look WPUA & WPUB) INTEDG rising edge on A2
ANSEL = %00000000 'Analog inputs Channels 0 to 7
ANSELH = %00000000 'Analog inputs Channels 8 to 11
ADCON0 = %00000000 'A/D Module is OFF
CM1CON0 = %00000000 'Comparator1 Module is OFF
CM2CON0 = %00000000 'Comparator2 Module is OFF
INTCON = %00010000 'INTerrupts CONtrol
TRISA = %00000100 'Set Input/Output (0 to 5)
PORTA = %00000000 'Ports High/Low (0 to 5)
TRISB = %00010000 'Set Input/Output (4 to 7)
PORTB = %00000000 'Ports High/Low (4 to 7)
TRISC = %00000000 'Set Input/Output (0 to 7)
PORTC = %00000000 'Ports High/Low (0 to 7)

'-------------------------------------------------------------------------------
' Defines
DEFINE OSC 4

'-------------------------------------------------------------------------------
' Variables
SQW VAR PORTA.2 'DS1307's 1Hz output
D_Out VAR PORTB.7 'serial data out for display
SCL VAR PORTC.0 'DS1307 clock line
SDA VAR PORTC.1 'DS1307 data line

DB0 VAR BYTE(8)
DB0(0) = 0 ' Seconds (00-59)
DB0(1) = 0 ' Minutes (00-59)
DB0(2) = 0 ' Hours (00-23)
DB0(3) = 0 ' Day (01-07; 1=Sunday, 2=Monday, ...)
DB0(4) = 0 ' Date (01-31)
DB0(5) = 0 ' Month (01-12)
DB0(6) = 0 ' Year (00-99)
DB0(7) = 0 ' Control (see datasheet)

D_Bps CON 16468 ' 9600 Driven Inverted None

'-------------------------------------------------------------------------------
' Initialize

'-------------------------------------------------------------------------------
' Program
ON INTERRUPT GOTO Read_DS1307

MAIN:
GOTO MAIN:
END

'-------------------------------------------------------------------------------
' Interrutp Service Routine
DISABLE
Read_DS1307: ' Read time Secs,Mins,Hours,Day,Date,Month,Year,Control
I2CREAD SDA,SCL,$D0,$00,[STR DB0\8] ' Read 8 bytes from DS1307

' Write to external memory
I2CWRITE SDA,SCL,$A0,$00,[DB0(2),DB0(1),DB0(0)]
PAUSE 10

'Read from external memory
I2CREAD SDA,SCL,$A0,$00,[DB0(2),DB0(1),DB0(0)]

SEROUT2 D_Out,D_Bps,[HEX2 DB0(2),":",HEX2 DB0(1),":",HEX2 DB0(0),13,10]

INTCON.1 = 0 'clear INTF interrupt flag
RESUME
ENABLE

Scampy
- 19th July 2016, 18:10
Hi Roger, I'm no expert, but maybe this can be of some use.

I have these variables to display the time on an LCD



TimeH var byte 'variable to store Hours
TimeM var byte 'variable to store Minutes
SS VAR Byte 'variable to store Seconds

RTCsec var byte 'RTC Seconds
RTCMin var byte 'RTC Minutes
RTCHour var byte 'RTC Hours


I then read the DS1307 and convert the BDC value into time as follows



I2CRead SDApin,SCLpin,$D0,$00,[RTCSec,RTCMin,RTCHour] ' read the RTC

timeH=(RTCHour>>4) 'convert the BCD format of the hours register and store in variable timeH
timeH=(timeH &$03)*10
timeH=timeH+(RTCHour&$0F)

timeM=(RTCMin>>4) 'convert the BCD format of the mins register and store in variable timeM
timeM=(timeM &$07)*10
timeM=timeM+(RTCMin&$0F)

ss=(RTCSec>>4) 'convert the BCD format of the sec register and store in variable ss
ss=(ss &$07)*10
ss=ss+(RTCSec&$0F)

LCDOut $FE,$C0+11,#TimeH DIG 1,#TimeH DIG 0,":",#TimeM DIG 1,#TimeM DIG 0 'display the current time on the LCD



Now maybe (I don't know as I've never written to an external e-prom) you can save the byte variables for TimeH, TimeM and SS with something like



I2Cwrite SDApin,SCLpin,$insert address of eeprom,[TimeH,TimeM,SS]


Like I said, I'm no expert, and may be sending you off on a tangent !!

Forgot to add, this is the routine to convert to BDC if required




CounterA=SetMN
Gosub ConvertBCD
RTCMin=CounterB

CounterA=SetHR
Gosub ConvertBCD
RTCHour=CounterB
I2Cwrite SDApin,SCLpin,$D0,$00,[RTCSec,RTCMin,RTCHour]


ConvertBCD:
CounterB=CounterA DIG 1 ' CounterA is the entry variable
CounterB=CounterB<<4 ' CounterB holds the converted BCD result on exit
CounterB=CounterB+CounterA DIG 0
Return


CounterA and CounterB are byte variables, as are setHR and setMN. I used these as the initial time to display on the LCD. For example I want to set the initial time to 12:00 I use 12 for setHR and 0 for setMN. If you need to convert from decimal to BDC before sending to the eepprom, then maybe this bit of code can help ??

richard
- 20th July 2016, 01:36
Malcom is nearly correct



I2Cwrite SDApin,SCLpin,$insert address of eeprom,[TimeH,TimeM,SS]

should be


I2Cwrite SDApin,SCLpin,$a0,eprom_location,[TimeH,TimeM,SS]

where :- for a 24lc64 8k bytes and 32 byte page size
1. eprom_location must be a word var
2. eprom_location must be < 8192
3. ( eprom_location//page_size ) < (32 -number_of_bytes to write ) ie don't try to write past a page boundary

ps can't see the need for bcd - bin - bcd conversions though

Scampy
- 20th July 2016, 19:08
Malcom is nearly correct


Hi Richard, nice to know I was almost there :)



ps can't see the need for bcd - bin - bcd conversions though

Roger stated that the RTC uses BDC format, which needs converting




Data from DT1307 is in BCD format and data conversion, that's where I think I'm wrong, is not my cup of tea :(



I presume that once you've converted the BDC format and stored them into variables as decimal values for hours and minutes you would then simply write those to the external memory, although they would need to be word variables, so would this be correct ?



I2Cwrite SDApin,SCLpin,$a0,eprom_location,[TimeH.lowbyte, TimeH.highbyte,TimeM.lowbyte, TimeM.highbyte,SS.lowbyte, SS.highbyte]


Assuming TimeH, TimeM and SS are all declared as word variables

flotulopex
- 20th July 2016, 19:44
...you would then simply write those to the external memory although they would need to be WORD variables...
I thought only the address variable must be WORD sized? :confused:
8270

flotulopex
- 20th July 2016, 21:28
Well,

I'm still making some mistake somewhere.

The display says now "55:55:55".

If I bypass the I2CWRITE and I2CREAD commands, everything is fine :frown:


'-------------------------------------------------------------------------------
' PIC 16F690 Fuses (MPASM)
@ __Config _FCMEN_OFF &_IESO_OFF &_CPD_OFF &_WDT_OFF &_HS_OSC &_BOR_OFF &_CP_OFF &_PWRTE_OFF &_MCLRE_OFF

'-------------------------------------------------------------------------------
' Registers 76543210
OPTION_REG = %10000000 'PORT A&B Pull-Ups disabled (look WPUA & WPUB) INTEDG rising edge on A2
'OSCCON = %01100000 'Internal RC set to 4Mhz - not to be used with XTal
ANSEL = %00000000 'Analog inputs Channels 0 to 7
ANSELH = %00000000 'Analog inputs Channels 8 to 11
ADCON0 = %00000000 'A/D Module is OFF
CM1CON0 = %00000000 'Comparator1 Module is OFF
CM2CON0 = %00000000 'Comparator2 Module is OFF
INTCON = %00010000 'INTerrupts CONtrol
TRISA = %00000100 'Set Input/Output (0 to 5)
PORTA = %00000000 'Ports High/Low (0 to 5)
TRISB = %00010000 'Set Input/Output (4 to 7)
PORTB = %00000000 'Ports High/Low (4 to 7)
TRISC = %00000000 'Set Input/Output (0 to 7)
PORTC = %00000000 'Ports High/Low (0 to 7)

'-------------------------------------------------------------------------------
' Defines
DEFINE OSC 4

'-------------------------------------------------------------------------------
' Variables
SQW VAR PORTA.2 ' RTC 1Hz output
D_Out VAR PORTB.7 ' serial data out
SCL VAR PORTC.0 ' RTC clock
SDA VAR PORTC.1 ' RTC data

RTC_Sec VAR BYTE ' Seconds (00-59)
RTC_Min VAR BYTE ' Minutes (00-59)
RTC_Hou VAR BYTE ' Hours (00-23)

D_Bps CON 16468 ' 9600 Driven Inverted None

'-------------------------------------------------------------------------------
' Initialize
PAUSE 1000 ' power-up serial-LCD
SEROUT2 D_Out,D_Bps,[27,"C",0] ' set serial-LCD cursor OFF
SEROUT2 D_Out,D_Bps,[27,"L",0] ' set serial-LCD backlight OFF

'-------------------------------------------------------------------------------
' Program
ON INTERRUPT GOTO Read_DS1307

MAIN:
GOTO MAIN:
END

'-------------------------------------------------------------------------------
' Interrutp Service Routine
DISABLE
Read_DS1307:
I2CREAD SDA,SCL,$D1,$00,[RTC_Sec,RTC_Min,RTC_Hou]

' Convert Hex coded to decimal
RTC_Sec = (RTC_Sec & $F)+((RTC_Sec >> 4)*10)
RTC_Min = (RTC_Min & $F)+((RTC_Min >> 4)*10)
RTC_Hou = (RTC_Hou & $F)+((RTC_Hou >> 4)*10)

' Write to external memory
I2CWRITE SDA,SCL,$A0,$00,[RTC_Sec,RTC_Min,RTC_Hou]
PAUSE 10

'Read from external memory
I2CREAD SDA,SCL,$A0,$00,[RTC_Sec,RTC_Min,RTC_Hou]

SEROUT2 D_Out,D_Bps,["Time: ",DEC2 RTC_Hou,":",DEC2 RTC_Min,":",DEC2 RTC_Sec,13,10]

INTCON.1 = 0
RESUME
ENABLE

pedja089
- 20th July 2016, 22:26
Address should be word or byte variable, not constant.


MemAdr var word
MemAdr =0
' Write to external memory
I2CWRITE SDA,SCL,$A0,MemAdr ,[RTC_Sec,RTC_Min,RTC_Hou]
PAUSE 10

'Read from external memory
I2CREAD SDA,SCL,$A0,MemAdr ,[RTC_Sec,RTC_Min,RTC_Hou]
EDIT:
Constant works for clock, as PBP send minimum 8 bits, but it wont work for EEPROM as it expecting 16bits.
I mention that in another topic.

Scampy
- 21st July 2016, 08:17
I have a project that sends values from 0 to 4096 to an 16 channel PWM led driver chip, and this is a sample line of code


I2CWRITE SDApin,SCLpin,i2cWriteAddress,i2cControl,[0,0,CH1_PWM.lowbyte,CH1_PWM.highbyte]


The reference to word variables I made was because your external eprom is expecting 16 bit values for the data, hence my reference to making your TimeH, TimeM and TimeS word variables, and trying the lowbyte / highbyte approach. - Like I mentioned in my first reply, I'm no expert, and this may be taking you off tangent, but then again, might be worth trying

flotulopex
- 21st July 2016, 09:24
Address should be word or byte variable, not constant.
Okay, I haven't declared the address as a variable at all.

So I'll give it a try a little later (I'm in the office right now).



...your external eeprom is expecting 16 bit values for the data.This is confusing me. I think the 24LC64 needs data in BYTE format as where it's addresses are in WORD format.

Dave
- 21st July 2016, 13:13
That is correct. The 24LC64 data is 8 bits wide per individual location. CH1_PWM.lowbyte,CH1_PWM.highbyte is the correct way to sequentially load data into the eeprom if the variable is a word.

flotulopex
- 21st July 2016, 14:53
It works!

I declared the EEPROM address as WORD, replaced the $00 in the I2CWRITE and I2CREAD commands and now the result is okay.

Thanks a lot for the help :smile:


'-------------------------------------------------------------------------------
' PIC 16F690 Fuses (MPASM)
@ __Config _FCMEN_OFF &_IESO_OFF &_CPD_OFF &_WDT_OFF &_HS_OSC &_BOR_OFF &_CP_OFF &_PWRTE_OFF &_MCLRE_OFF

'-------------------------------------------------------------------------------
' Registers 76543210
OPTION_REG = %10000000 'PORT A&B Pull-Ups disabled (look WPUA & WPUB) INTEDG rising edge on A2
'OSCCON = %01100000 'Internal RC set to 4Mhz - not to be used with XTal
ANSEL = %00000000 'Analog inputs Channels 0 to 7
ANSELH = %00000000 'Analog inputs Channels 8 to 11
ADCON0 = %00000000 'A/D Module is OFF
CM1CON0 = %00000000 'Comparator1 Module is OFF
CM2CON0 = %00000000 'Comparator2 Module is OFF
INTCON = %00010000 'INTerrupts CONtrol
TRISA = %00000100 'Set Input/Output (0 to 5)
PORTA = %00000000 'Ports High/Low (0 to 5)
TRISB = %00010000 'Set Input/Output (4 to 7)
PORTB = %00000000 'Ports High/Low (4 to 7)
TRISC = %00000000 'Set Input/Output (0 to 7)
PORTC = %00000000 'Ports High/Low (0 to 7)

'-------------------------------------------------------------------------------
' Defines
DEFINE OSC 4

'-------------------------------------------------------------------------------
' Variables
SQW VAR PORTA.2 ' RTC 1Hz output
D_Out VAR PORTB.7 ' serial data out
SCL VAR PORTC.0 ' RTC clock
SDA VAR PORTC.1 ' RTC data

RTC_Sec VAR BYTE ' Seconds (00-59)
RTC_Min VAR BYTE ' Minutes (00-59)
RTC_Hou VAR BYTE ' Hours (00-23)

Eep_Adr VAR WORD
Eep_Adr = $00

D_Bps CON 16468 ' 9600 Driven Inverted None

'-------------------------------------------------------------------------------
' Initialize
PAUSE 1000 ' power-up serial-LCD
SEROUT2 D_Out,D_Bps,[27,"C",0] ' set serial-LCD cursor OFF
SEROUT2 D_Out,D_Bps,[27,"L",0] ' set serial-LCD backlight OFF

'-------------------------------------------------------------------------------
' Program
ON INTERRUPT GOTO Read_DS1307

MAIN:
GOTO MAIN:
END

'-------------------------------------------------------------------------------
' Interrutp Service Routine
DISABLE
Read_DS1307:
I2CREAD SDA,SCL,$D1,$00,[RTC_Sec,RTC_Min,RTC_Hou]

SEROUT2 D_Out,D_Bps,["HEX: ",HEX2 RTC_Hou,":",HEX2 RTC_Min,":",HEX2 RTC_Sec,13,10]

' Convert Hex coded to decimal - can be usefull for external memory data storage (logging)
RTC_Sec = (RTC_Sec & $F)+((RTC_Sec >> 4)*10)
RTC_Min = (RTC_Min & $F)+((RTC_Min >> 4)*10)
RTC_Hou = (RTC_Hou & $F)+((RTC_Hou >> 4)*10)

' Write to external memory
I2CWRITE SDA,SCL,$A0,Eep_Adr,[RTC_Sec,RTC_Min,RTC_Hou]
PAUSE 10

'Read from external memory
I2CREAD SDA,SCL,$A0,Eep_Adr,[RTC_Sec,RTC_Min,RTC_Hou]

SEROUT2 D_Out,D_Bps,["DEC: ",DEC2 RTC_Hou,":",DEC2 RTC_Min,":",DEC2 RTC_Sec," "]

INTCON.1 = 0 'clear INTF interrupt flag
RESUME
ENABLE


Thank you Dave for explaining the WORD sized eeprom data.

Before I started this thread, I didn't know about "packed BDC (http://melabs.com/resources/articles/bcdnumbers.htm)". I think it can be interesting to reduce data size especially when, like in my current project, time data has to be stored in external memory.