Ds3232 rtc

JSDL

Senior Member
Hi everyone, I've created a project using a Picaxe 28X2 and DS3231 RTC module interfaced to an LCD in 4-bit mode. Got everything working correctly. I used Picaxe VSM to simulate the circuit (using a DS1307 instead of DS3231 as VSM didn't have the DS3231), built the circuit, and all worked great with the help of some postings on the forum here. I wanted to implement the alarm function but since I was using the DS1307 in VSM, the RTC does not have alarm options. I then noticed VSM has the DS3232 in its library and after looking at the datasheet and seeing that it was pin compatible with the DS3231 and all the registers seemed to be at the same address, I substituted the DS1307 with DS3232 (in VSM only). Everything worked (time, date, etc) without a problem. The only glitch, however, is that the change between AM/PM is not updating. Once again, I looked at the datasheet and the time registers are at the exact same addresses ($02 for hour), so I cannot explain why the AM/PM bit is not being updated. Has anyone had any experience with this? Any suggestions would be appreciated.
 

bpowell

Senior Member
It would help if you posted your code.

Have you configured the 3232 to run in 12-hour mode (not 24-hour mode)?
 

JSDL

Senior Member
As stated, I have not changed anything other than swapping the chips. The RTC has been set to 12 hour mode. Some of the code is missing due to character limitation.

Code:
pause 100
setfreq m16
#picaxe 28x2


dirsB=%01011111
hi2csetup i2cmaster, %11010000, i2cslow, i2cbyte
SETINT %00000000, %00001000
hi2cout $0E, (%00000110)

pause 40

'###################Define Sysmbols for HD44780 pins

symbol LCD_ENABLE=c.7		'Enable pin on HD44780 LCD module
symbol LCD_RS=c.6		'Register Select pin on HD77480, HIGH=Data, LOW=Command
symbol TIME_SET_BUTTON=pinC.0
symbol ALARM_SET_BUTTON=pinA.2
symbol incbutton=pinc.1
symbol decbutton=pinc.5
symbol RTC_INT=pinc.3



symbol outbyte =b0
symbol counter = b1
symbol bcdnum = b2
symbol nibblecount=b3

'Time Variables
symbol seconds = b4
symbol mins = b5
symbol hour = b6
symbol day = b7
symbol date = b8
symbol month = b9
symbol year = b10
symbol temp = b11
symbol hour12=b24
symbol am_pm=b25
symbol bcdmax=b26
symbol bcdmin=b27
symbol work=b28
symbol ampm_bit=b29
symbol digit1=b30
symbol digit2=b31



'Set initial values for date and time
let seconds = $50
let mins = $59
let hour = %01110001
let day = $01
let date = $31
let month = $12
let year = $16




hi2cout 0, (seconds, mins, hour, day, date, month, year)
pause 10

eeprom 0,("Time: ")
eeprom 12,("Date: ")
eeprom 18, ("SET HOUR:")
eeprom 27, ("SET MINUTES:")
eeprom 39, ("SET SECONDS:")
eeprom 51, ("SET MONTH:")
eeprom 61, ("SET DAY:")
eeprom 69, ("SET YEAR:")
eeprom 78, ("SET AM/PM:")
eeprom 88, ("AM")
eeprom 90, ("PM")
eeprom 92, ("SET ALARM (HR):")

LOW LCD_ENABLE
LOW LCD_RS

'############Initialization sequence for HD44780 Module#############

for counter = 0 to 6
	lookup counter ,($33, $32, $28, $10, $01, $06, $0C), outbyte	
	gosub WRITE_LCD_INST
	pause 10
next counter


'#####################################################################



main:

if TIME_SET_BUTTON=1 then gosub SET_TIME
if ALARM_SET_BUTTON=1 then gosub SET_ALARM



DISPLAY_TIME:

hi2cin 0, (seconds, mins, hour, day, date, month, year)

hour12 = hour & $1F 
ampm_bit = hour & %00100000

if ampm_bit = 32 then
	low a.1
	high a.0
	else
	high a.1
	low a.0
end if


outbyte=$80
gosub WRITE_LCD_INST

for counter = 0 to 5
	read counter,outbyte
	gosub WRITE_LCD_DATA
next counter

outbyte=$C0
gosub WRITE_LCD_INST


for counter = 12 to 16
	read counter,outbyte
	gosub WRITE_LCD_DATA
next counter


bcdtoascii seconds, b12, b13
bcdtoascii mins, b14, b15
bcdtoascii hour12, b16, b17
bcdtoascii date, b18, b19
bcdtoascii month, b20, b21
bcdtoascii year, b22, b23


outbyte=$86	'Move cursor to Line 1 Position 6
gosub WRITE_LCD_INST

outbyte=b16
gosub write_lcd_data

outbyte=b17
gosub write_lcd_data

outbyte=":"
gosub write_lcd_data

outbyte=b14
gosub write_lcd_data

outbyte=b15
gosub write_lcd_data

outbyte=":"
gosub write_lcd_data

outbyte=b12
gosub write_lcd_data

outbyte=b13
gosub write_lcd_data

outbyte=$C6	'Move cursor to Line 2 Position 6
gosub WRITE_LCD_INST

outbyte=b20
gosub write_lcd_data

outbyte=b21
gosub write_lcd_data

outbyte="-"
gosub write_lcd_data

outbyte=b18
gosub write_lcd_data

outbyte=b19
gosub write_lcd_data

outbyte ="-"
gosub write_lcd_data

outbyte=b22
gosub write_lcd_data

outbyte=b23
gosub write_lcd_data

goto main

'############################################################################3

WRITE_LCD_INST:	'Write Commands to LCD

low LCD_RS
outbyte=outbyte * 256 | outbyte / 16

for nibblecount= 1 to 2
	'pinsB=outbyte / 16
	pinsB=outbyte
	pulsout LCD_ENABLE,1
	pause 4
	outbyte=outbyte / 16	'change to outbyte * 16 for Line 1 method
next nibblecount
return


WRITE_LCD_DATA:	'Write Data to LCD

high LCD_RS
outbyte=outbyte * 256 | outbyte / 16

for nibblecount= 1 to 2
	'pinsB=outbyte / 16
	pinsB=outbyte
	pulsout LCD_ENABLE,1
	pause 4
	outbyte=outbyte / 16	'change to outbyte * 16 for Line 1 method
next nibblecount
return

'#############################################################################################################
SET_TIME:

outbyte=$01			'Clear display
gosub write_lcd_inst

gosub SET_HOUR
gosub SET_MIN
gosub SET_SECONDS
gosub SET_MONTH
gosub SET_DATE
gosub SET_YEAR
gosub SET_AMPM
do while TIME_SET_BUTTON=1 loop
outbyte=$0C
gosub WRITE_LCD_INST
'goto main
'end
return


'#############################################################################################################


SET_HOUR:

do while TIME_SET_BUTTON=1 loop

for counter = 18 to 26		'Display "Set Hour"
	read counter,outbyte
	gosub WRITE_LCD_DATA
next counter





outbyte=$C0			'Move cursor to Line 2 Position 0
gosub WRITE_LCD_INST

outbyte=$0F			'Turn on blinking cursor
gosub write_lcd_inst

bcdtoascii hour12, digit1, digit2	'ADD THIS TO ALL TIME SUBS
outbyte=digit1
gosub write_lcd_data
outbyte=digit2
gosub write_lcd_data

bcdmax=$12:bcdmin=$01

do

outbyte=$C0			'Move cursor to Line 2 Position 0 ADD THIS TO ALL TIME SUBS
gosub WRITE_LCD_INST

if incbutton=1 then
	
	bcdnum=hour & $1F
	gosub bcdinc
	hour=hour &$E0 | bcdnum
	hi2cout 2, (hour)

hour12=bcdnum
bcdtoascii hour12, digit1, digit2
outbyte=digit1
gosub write_lcd_data
outbyte=digit2
gosub write_lcd_data

outbyte=$C0	'Move cursor to Line 2 Position 0
gosub WRITE_LCD_INST
		
do while incbutton=1 loop
endif

if decbutton=1 then
	
	bcdnum=hour & $1F
	gosub bcddec
	hour=hour &$E0 | bcdnum
	hi2cout 2, (hour)

hour12=bcdnum
bcdtoascii hour12, digit1, digit2
outbyte=digit1
gosub write_lcd_data
outbyte=digit2
gosub write_lcd_data

outbyte=$C0	'Move cursor to Line 2 Position 0
gosub WRITE_LCD_INST
		
do while decbutton=1 loop
endif


if TIME_SET_BUTTON=1 then exit
loop

return

'##############################################################################################################

SET_MIN:
do while TIME_SET_BUTTON=1 loop

outbyte=$01			'Clear display
gosub write_lcd_inst

for counter = 27 to 38		'Display "Set Minute"
	read counter,outbyte
	gosub WRITE_LCD_DATA
next counter


outbyte=$C0			'Move cursor to Line 2 Position 0
gosub WRITE_LCD_INST

outbyte=$0F			'Turn on blinking cursor
gosub write_lcd_inst

bcdtoascii mins, digit1, digit2	'ADD THIS TO ALL TIME SUBS
outbyte=digit1
gosub write_lcd_data
outbyte=digit2
gosub write_lcd_data


bcdmax=$59:bcdmin=$00

do

outbyte=$C0			'Move cursor to Line 2 Position 0 ADD THIS TO ALL TIME SUBS
gosub WRITE_LCD_INST



if incbutton=1 then
	
	bcdnum=mins
	gosub bcdinc

	mins=bcdnum

	hi2cout 1, (bcdnum)

bcdtoascii bcdnum, digit1, digit2
outbyte=digit1
gosub write_lcd_data
outbyte=digit2
gosub write_lcd_data

outbyte=$C0	'Move cursor to Line 2 Position 0
gosub WRITE_LCD_INST
		
do while incbutton=1 loop
endif

if decbutton=1 then
	
	bcdnum=mins
	gosub bcddec

	mins=bcdnum

	hi2cout 1, (bcdnum)

bcdtoascii bcdnum, digit1, digit2
outbyte=digit1
gosub write_lcd_data
outbyte=digit2
gosub write_lcd_data

outbyte=$C0	'Move cursor to Line 2 Position 0
gosub WRITE_LCD_INST
		
do while decbutton=1 loop
endif


if TIME_SET_BUTTON=1 then exit
loop

return

'################################################################################
SET_SECONDS:

do while TIME_SET_BUTTON=1 loop

outbyte=$01			'Clear display
gosub write_lcd_inst

for counter = 39 to 50		'Display "SET SECONDS"
	read counter,outbyte
	gosub WRITE_LCD_DATA
next counter


outbyte=$C0			'Move cursor to Line 2 Position 0
gosub WRITE_LCD_INST

outbyte=$0F			'Turn on blinking cursor
gosub write_lcd_inst

bcdtoascii seconds, digit1, digit2	'ADD THIS TO ALL TIME SUBS
outbyte=digit1
gosub write_lcd_data
outbyte=digit2
gosub write_lcd_data


bcdmax=$59:bcdmin=$00

do

outbyte=$C0			'Move cursor to Line 2 Position 0 ADD THIS TO ALL TIME SUBS
gosub WRITE_LCD_INST

if incbutton=1 then
	
	bcdnum=seconds
	gosub bcdinc

	seconds=bcdnum

	hi2cout 0, (bcdnum)

bcdtoascii bcdnum, digit1, digit2
outbyte=digit1
gosub write_lcd_data
outbyte=digit2
gosub write_lcd_data

outbyte=$C0	'Move cursor to Line 2 Position 0
gosub WRITE_LCD_INST
		
do while incbutton=1 loop
endif

if decbutton=1 then
	
	bcdnum=seconds
	gosub bcddec

	seconds=bcdnum

	hi2cout 0, (bcdnum)

bcdtoascii bcdnum, digit1, digit2
outbyte=digit1
gosub write_lcd_data
outbyte=digit2
gosub write_lcd_data

outbyte=$C0	'Move cursor to Line 2 Position 0
gosub WRITE_LCD_INST
		
do while decbutton=1 loop
endif


if TIME_SET_BUTTON=1 then exit
loop

return
 

JSDL

Senior Member
just noticed that when I set the hour to 12 (%01110010 instead of %01110001 ) in the code above, when the time switches over to 1, the date changes to Jan 1, 2017 and the AM/PM LED indicator switches accordingly to AM. Does this mean there is a bug in the VSM DS3232 part?
 

bpowell

Senior Member
Yeah, that doesn't sound right...according to the data-sheet, the day-of-week increments at midnight (which makes sense) not 1:00 PM!
 

hippy

Technical Support
Staff member
Does this mean there is a bug in the VSM DS3232 part?
There do seem to be bugs in the DS3232 VSM model when it comes to handling 12-hour mode. The bugs do not appear to be present in the DS1307 model.

Software and hardware bugs where a 12 hour clock only changes from AM to PM and vice-versa when going from 12:59:59 to 01:00:00 when it should change going from 11:59:59 to 12:00:00 is not as uncommon as one might hope, and this would seem to be a classic example of that. Unfortunately, in the DS32332 model case, it seems it does not trigger a date and day change until PM changes to AM.

Recommended practice is usually to stick with 24 hour mode and convert to and from 12-hour format when required, for display and time entry. That is less prone to bugs and should avoid any which may be present in software, hardware or simulated devices.
 

JSDL

Senior Member
Hi everyone, so I got this project working but something strange is happening now. I had the circuit bread boarded using 4 x AA batteries with a diode in series, and everything was working perfectly. Time set functions worked, alarm worked spot on when I set it. Now I have moved everything into a project box, using a 5V DC adapter (no regulator). The time works perfectly, but alarm works intermittently, but when I set it I know the interrupt occurs because I used a logic tester to test the state of C.2 and it goes LOW on the interrupt (alarm time set), but it does not trigger the serial MP3 player. When I manually connect C.2 low, then high again to simulate an interrupt, the MP3 player works and the sound is played. I'm almost certain this issue has to do with power, but cannot figure out what. Any ideas would be appreciated. Been working on this for hours. Thanks everyone for any input.
 

hippy

Technical Support
Staff member
If the setup is reliable when manually triggering C.2 but not reliable when the RTC is triggering C.2 that would be where I would look regardless of what a logic tester reported. Add something in the code which can show whether the interrupt is getting generated or not.

It could pretty much be anything, hardware or software. Maybe post details of both.

Perhaps avoid the issue entirely by handling alarm activation in software rather than relying on the RTC to generate an interrupt.
 

JSDL

Senior Member
Here is my interrupt routine:

Code:
Interrupt:

if pinC.2=0 then interrupt

sertxd ("Entered Interrupt Routine",cr,lf)	'used to debug if interrupt routine has executed

if ALARM_TOGGLE=1 then		'Alarm Toggle switch is in ON position
	serout MP3_Player_TX, t9600_16,($7E,$FF,$06,$0B,$00,$00,$00,$EF) 'Wake up MP3 player
	serout MP3_Player_TX, t9600_16,($7E,$FF,$06,$09,$00,$00,$02,$EF) 'Select MicroSD Storage
	serout MP3_Player_TX, t9600_16,($7E,$FF,$06,$0F,$00,$01,$02,$EF) 'Play track 2
end if

hi2cout $0E,(%00000100)			'reset Alarm 1 Interrupt on DS3231
setint %00000000, %00000100, C	're-initialize Picaxe Interrupt

return
as you can see I did a sertxd to output to the terminal when the interrupt occurs, and it always reaches the routine. On the hardware side, however, the MP3 player triggers sometimes, but not all the time. Like I mentioned, when manually bringing C.2 low, it works perfect. I can't figure out why.

circuit.jpg

The switch going to A.4 is an alarm toggle switch. In my actual setup, I have it tied high so it is always on.
 

hippy

Technical Support
Staff member
So does it always generate the "Entered Interrupt Routine" SERTXD when it should ?

If not the problem is likely in receiving the interrupt.

If it does then the problem is likely in triggering the MP3 player, or in the ALARM_TOGGLE handling. Perhaps some PAUSE after each SEROUT might help.
 

tmfkam

Senior Member
Here is my interrupt routine:

Code:
Interrupt:

if pinC.2=0 then interrupt

sertxd ("Entered Interrupt Routine",cr,lf)	'used to debug if interrupt routine has executed

if ALARM_TOGGLE=1 then		'Alarm Toggle switch is in ON position
	serout MP3_Player_TX, t9600_16,($7E,$FF,$06,$0B,$00,$00,$00,$EF) 'Wake up MP3 player
	serout MP3_Player_TX, t9600_16,($7E,$FF,$06,$09,$00,$00,$02,$EF) 'Select MicroSD Storage
	serout MP3_Player_TX, t9600_16,($7E,$FF,$06,$0F,$00,$01,$02,$EF) 'Play track 2
end if

hi2cout $0E,(%00000100)			'reset Alarm 1 Interrupt on DS3231
setint %00000000, %00000100, C	're-initialize Picaxe Interrupt

return
as you can see I did a sertxd to output to the terminal when the interrupt occurs, and it always reaches the routine. On the hardware side, however, the MP3 player triggers sometimes, but not all the time. Like I mentioned, when manually bringing C.2 low, it works perfect. I can't figure out why.

View attachment 20882

The switch going to A.4 is an alarm toggle switch. In my actual setup, I have it tied high so it is always on.
Those commands look as though they are for the DF_Player module (SPE035). Certain commands for this (in my experience at least) can take some considerable time to complete. One of those that seems to take the longest is selecting MicroSD storage, this can be as long as ten seconds before the device is ready. If there are a very large number of tracks, on a large MicroSD (I've got one running here with 6200+ tracks on a 64Gb card) potentially longer still. I've not tried the 'sleep' commands but I might expect them to take a few moments at least. In any case, I would be putting in a minimum of 250mS pause between each command, with at least 5 seconds following a request to change disks.

The DF_Player (SPE035) seems to automatically select MicroSD storage when it is powered up, if no MicroSD card is present it seems to automatically look for a USB storage device and use this if available. If both are present, it should be possible to switch between the two using the appropriate commands though this has occasionally (often for me!) failed to work as anticipated. If you can live with having only one device present at any one time, letting the DF_Player (SPE035) decide for itself which to use is the easiest and most reliable method by far.

Detecting whether a track has started is another potential problem. If you are only detecting whether the 'busy' pin has gone low it is best to have a significant pause following changing or starting a track playing back. The problem I've found is that tracks with higher numbers take longer to start, significantly so, if there are more than a few hundred tracks. Track 1 may take 500mS to load, Track 1000 may take seven seconds to load, Track 6000 may take fifteen seconds to load. This can lead to problems if you check the busy flag to test whether the current track has ended, if the track has not yet loaded it may look to have ended before it has begun. Sometimes the busy flag goes momentarily low (possibly when the DF_Player SPE035 checks to see if the track exists?) then goes high again during the 'loading' procedure, before going low when the track starts to play. I have had to develop a routine that tests the busy flag in a loop which checks to see that the busy flag has remained continuously low for at least 500mS with no high periods at all during that time, this has proved to be more reliable and flexible than just a single fixed delay which might have needed to be at least twenty seconds for upper tracks, yet might only need to be under half a second for lower tracks.
 
Top