Wish Real Time Clock RTC_DS1307

atiaust

Active Member
Licensed User
Longtime User
Hi All,

Attached are the libraries for use with the RTC_DS1307 real time clock module for Arduino. This communicates via the I2C bus.

Have tried to write the C++ RunNative without much success.

Can someone assist.

Thanks
 

Attachments

  • rRTC.zip
    3.7 KB · Views: 459

inakigarm

Well-Known Member
Licensed User
Longtime User
Didn't have time to "clean" the code; this program Reads the B4R DS3231 RTC data (without library) displays on B4J logging console (selecting B4J serial connector on Board Selector) and writes Time to Arduino RTC from B4J

The "trickiest" part is to convert bcd to dec and viceversa

----- NEW CODE ------- 16-09-16

B4R Code
B4X:
#Region Project Attributes
    #AutoFlushLogs: True
    #CheckArrayBounds: True
    #StackBufferSize: 300
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'Public variables can be accessed from all modules.
    Public Serial1 As Serial
    Private astream As AsyncStreams
    Public wirevar As WireMaster 'I2C / TWI devices
    Private timer1 As Timer
    Private bc As ByteConverter

    Dim seconds,minutes, hours,dayonweek,day,month,year As Byte
    Dim bcd As Byte

    Private const RTC_ADDRESS As Byte= 0x68

      
End Sub

Private Sub AppStart

    Serial1.Initialize(115200)
    astream.Initialize(Serial1.Stream,"astream_NewData", "astream_Error")
    wirevar.Initialize 'I2C / TWI connection with DS3231 RTC Sensor
    Delay(100)

    Log("AppStart")
  
    'Set time (seconds,minutes,hours,dayOfWeek,dayOfMonth,month,year
    'setDS3231time(00,58,10,1,30,8,16)

    'Enable Timer to read Time on DS3231 RTC Sensor
    timer1.Initialize("timer1_Tick",1000)
    timer1.Enabled=True

End Sub

'Displays Time and Date in Log at Tick Event
Sub Timer1_Tick
  
    Dim breadtime(7) As Byte
    Dim DS3231value As Byte

    Dim Datetimevalues(16) As Byte
  
    breadtime=readDS3231time
  
    For i=0 To 6
        DS3231value=breadtime(i)
        Datetimevalues(2*i+1)=Bit.Get(DS3231value,7)*8+Bit.Get(DS3231value,6)*4+Bit.Get(DS3231value,5)*2+Bit.Get(DS3231value,4)*1
        Datetimevalues(2*i+2)=Bit.Get(DS3231value,3)*8+Bit.Get(DS3231value,2)*4+Bit.Get(DS3231value,1)*2+Bit.Get(DS3231value,0)*1
    Next
    'Log(hour-minute-second --- day-month-year)
    Log(Datetimevalues(5),Datetimevalues(6),"-",Datetimevalues(3),Datetimevalues(4),"-",Datetimevalues(1),Datetimevalues(2),"---",Datetimevalues(9),Datetimevalues(10),"/",Datetimevalues(11),Datetimevalues(12),"/",Datetimevalues(13),Datetimevalues(14))


End Sub



' Sets Time and Date (seconds,minutes,hours,dayOfWeek,dayOfMonth,month,year) data To DS3231
Sub setDS3231time(second As Byte, minute As Byte, hour As Byte, dayofweek As Byte,dayOfMonth As Byte, months As Byte, years As Byte)
  
    'First byte=0 --> Set Next input To start at the seconds register
    'Next bytes (in BCD): second,minutes, hours, dayOfWeek,dayOfMonth,month,year
    wirevar.WriteTo(RTC_ADDRESS,Array As Byte(0,decToBcd(second),decToBcd(minute),decToBcd(hour),decToBcd(dayofweek),decToBcd(dayOfMonth),decToBcd(month),decToBcd(year)))

End Sub

' Reads Time and Date data To DS3231
Sub readDS3231time As Byte()

    'set DS3231 register pointer To 00h
    wirevar.writeto(RTC_ADDRESS,Array As Byte(0)) 'set DS3231 register pointer To 00h

    ' request seven bytes of data from DS3231 starting from register 00h
    ' in BCD
    Dim Datetime1() As Byte=wirevar.RequestFrom(RTC_ADDRESS, 7)
  
    Return Datetime1

End Sub

'Sets data form astream buffer (in this case Serial, would be BLE, WIFI, etc..)
Sub astream_NewData (Buffer() As Byte)
   If Buffer.Length <> 7 Then
     Log("invalid data: Buffer Size not 7 --> ", Buffer.Length)
   Else
     hours = Buffer(0)
     minutes = Buffer(1)
     seconds = Buffer(2)
    dayonweek=Buffer(3)
    day = Buffer(4)
    month = Buffer(5)
    year = Buffer(6)

    Log("B4R: Received time data!")
    setDS3231time(seconds,minutes,hours,1,day,month,year)
   End If
End Sub

Sub astream_Error
    Log("error")
End Sub

' Convert normal decimal numbers To binary coded decimal
Sub decToBcd (val As Byte) As Byte

   Dim bcd As Byte
   Dim bcdUint As UInt
   Dim numdec,numord As UInt
   Dim bcduintmat(2) As UInt
   Dim b(),b1(),b2(),b4() As Byte

   If val>9 Then 'Convert to BCD

    b=NumberFormat(val,2,0) 'Byte to String

    'BCD=Dec number (4 bits High Nibble byte) + Ordinal number (4 bits Low Nibble Byte)
    b1=bc.SubString(b,0) 'Dec number
    b2=bc.SubString(b,1) 'Ordinal number

      b2(0)=b2(0)-48 'substract ASCII value corresponding to number 0
    b1(0)=b1(0)-48 'substract ASCII value corresponding to number 0

    'Need to translate Byte to Uint to XOR the 2 numbers to build BCD number
    numord=b2(0)
    numdec=Bit.ShiftLeft(b1(0),4)
  
    bcdUint=Bit.xor(numdec,numord)

    'Pass Uint result to Array of Bytes to apply ByteConverter UintstoBytes to obtain Bytes
    bcduintmat(0)=bcdUint
    b4=bc.UIntsToBytes(bcduintmat)
    bcd=b4(0)

  Else        'If val <=9, bcdnumber=number
      bcd=val
  End If
  'Log("bcd =" ,bcd)
  Return bcd

End Sub

' Convert binary coded decimal To normal decimal numbers
Sub BcdToDec (value As Byte) As Byte ()

    Dim bdec,bord,numbyte(2) As Byte

    'Get BCD from byte (value)
    'bdec= High Nibble, bord= Low Nibble

    bdec=Bit.Get(value,7)*8+Bit.Get(value,6)*4+Bit.Get(value,5)*2+Bit.Get(value,4)*1
    bord=Bit.Get(value,3)*8+Bit.Get(value,2)*4+Bit.Get(value,1)*2+Bit.Get(value,0)*1

    Log ("val ",value, "bdec ",bdec," bord =",bord)

    'Byte to Uint to XOR b1/b2 values (need to cast to UInt)
    numbyte(1)=bdec
    numbyte(0)=bord

    Log(numbyte(1),numbyte(0))
  
    Return numbyte

End Sub


B4J code
B4X:
#Region  Project Attributes
    #MainFormWidth: 800
    #MainFormHeight: 600
#End Region

'version 1.00
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form

    Private cmbPort As ComboBox
    Private btnOpen As Button
    Private btnSend As Button
    Private txtLogs As TextArea
    Private astream As AsyncStreams
    Private serial As Serial
    Private chkReset As CheckBox
    Private chkNow As CheckBox
    Private const BAUDRATE As Int = 115200
   
    Private txtMessagedate As TextField
    Private txtMessagetime As TextField

    Private valsec,valmin,valhour,valday,valmonth,valyear,getdayofweek As Byte

End Sub

Sub AppStart (Form1 As Form, Args() As String)

    MainForm = Form1
    MainForm.SetFormStyle("UNIFIED")
    MainForm.RootPane.LoadLayout("1") 'Load the layout file.
    MainForm.Show
   
    serial.Initialize("")
    cmbPort.Items.AddAll(serial.ListPorts)

    If cmbPort.Items.Size >0 Then cmbPort.SelectedIndex=0

End Sub

'Open Arduino Com
Sub btnOpen_Action
    If astream.IsInitialized Then
        astream.Close
        serial.Close
        btnOpen.Text = "Open"
        Return
    End If
    If cmbPort.SelectedIndex = -1 Then Return
    Try
        serial.Open(cmbPort.Items.Get(cmbPort.SelectedIndex))
        serial.SetParams(BAUDRATE, 8, 1, 0)

        astream.Initialize(serial.GetInputStream, serial.GetOutputStream, "astream")
   
        btnSend.Enabled = True
        btnOpen.Text = "Close"
        txtLogs.Text = "Connecting to Arduino through Port " & cmbPort.Value& " ..." & CRLF
   
    Catch
        Log(LastException)
        fx.Msgbox(MainForm, "Failed to open port", "")
    End Try

End Sub

'Try to Date and Time to Arduino
Sub btnSend_Action

    If CheckdatetimeisOk Then
        Send_Time (chkNow.Checked)
    Else
      txtLogs.Text= txtLogs.Text &CRLF & "Error malformed datetime, Check date and time entered: Try again"&CRLF
    End If

End Sub

'Clear Log
Sub btnClear_Action
    txtLogs.Text = ""
End Sub

'Check if Date&time formatsare HH/mm/ss and dd/MM/yy
Sub CheckdatetimeisOk As Boolean


    If txtMessagetime.Text.Length<>8 Or txtMessagedate.Text.Length<>8 Then  'Assure time and date have 10 digits
        txtLogs.Text="Malformed Time/date: Check if Time or Data has 8 character as HH/mm/ss or dd/MM/yy"
        Return False
    Else
        valhour=txtMessagetime.Text.SubString2(0,txtMessagetime.Text.IndexOf("/"))
        valmin=txtMessagetime.Text.SubString2(txtMessagetime.Text.IndexOf("/")+1,txtMessagetime.Text.LastIndexOf("/"))
        valsec=txtMessagetime.Text.SubString2(txtMessagetime.Text.LastIndexOf("/")+1,txtMessagetime.Text.Length)
   
        valday=txtMessagedate.Text.SubString2(0,txtMessagedate.Text.IndexOf("/"))
        valmonth=txtMessagedate.Text.SubString2(txtMessagedate.Text.IndexOf("/")+1,txtMessagedate.Text.LastIndexOf("/"))
        valyear=txtMessagedate.Text.SubString2(txtMessagedate.Text.LastIndexOf("/")+1,txtMessagedate.Text.Length)  'Extract 2000 from Year (ex:2016)
    End If
   

    If (valhour <24) And (valmin<61) And (valsec<61) And (valday<32) And (valmonth<13) And (valyear<100) Then
        Return True
    Else
        Return False
    End If

   
End Sub

'Build Date&time from DateTime (now) for HH/mm/ss and dd/MM/yy formats
Sub Parsedatetime (ticksnow As Long)

    Dim sectmp,minutetmp,hourtmp As String
    Dim daytmp,monthtmp,yeartmp As String
    sectmp=DateTime.GetSecond(ticksnow)
    minutetmp=DateTime.GetMinute(ticksnow)
    hourtmp=DateTime.GetHour(ticksnow)

    getdayofweek=DateTime.GetDayOfWeek(ticksnow)
    daytmp=DateTime.GetDayOfMonth(ticksnow)
    monthtmp=DateTime.GetMonth(ticksnow)
    yeartmp=(DateTime.GetYear(ticksnow)-2000)

    If sectmp <10 Then sectmp="0"& sectmp
    If minutetmp<10 Then minutetmp="0"&minutetmp
    If hourtmp<10 Then hourtmp="0"&hourtmp
    If daytmp<10 Then daytmp="0"&daytmp
    If monthtmp<10 Then monthtmp="0"&monthtmp
    If yeartmp<10 Then yeartmp="0"& yeartmp


    txtMessagetime.Text=hourtmp &"/"& minutetmp &"/"& sectmp
    txtMessagedate.text=daytmp&"/"& monthtmp &"/"& yeartmp

End Sub

'Send Date & Time to Arduino
Sub Send_Time (DateTimeisNow As Boolean)

    astream.Write(Array As Byte(valhour,valmin,valsec,getdayofweek,valday,valmonth,valyear))

End Sub

'Receive Date & Time from Arduino
Sub AStream_NewData (Buffer() As Byte)
    txtLogs.Text = txtLogs.Text & BytesToString(Buffer, 0, Buffer.Length, "utf8")
    txtLogs.SetSelection(txtLogs.Text.Length, txtLogs.Text.Length)
    Log(BytesToString(Buffer, 0, Buffer.Length, "utf8"))
End Sub

Sub AStream_Error
    Log("error")
End Sub

Sub AStream_Terminated
    Log("terminated")
End Sub

Sub MainForm_Closed
    serial.Close
End Sub

'Choose DateTime(now) as data to trasmit to Arduino
Sub chkNow_CheckedChange(Checked As Boolean)

    If Checked Then
        txtMessagedate.Enabled=False
        txtMessagetime.Enabled=False

        Dim now As Long=DateTime.Now
   
        Parsedatetime(now)            'Parse date and time to match HH/mm/ss and dd/MM/yy
    Else
   
        txtMessagedate.Enabled=True
        txtMessagetime.Enabled=True
    End If
End Sub
 

Attachments

  • B4J_Serial_Connector _RTC.zip
    5 KB · Views: 376
Last edited:

Erel

B4X founder
Staff member
Licensed User
Longtime User
Note that using JoinStrings inside a Log command is a mistake. It just wastes memory.
B4X:
Log(JoinStrings (Array As String(s1, s2))) 'not good
Log(s1, s2) 'good

I would also change the Timer sub to:
B4X:
Sub Timer1_Tick
 
  Dim breadtime(7) As Byte
  Dim b As Byte
  Dim bb(17) As Byte '0, 1, 2 are not used
  Dim bsec(2) As Byte
  Dim num As Byte
     bsec=BcdToDec(breadtime(i))
  For i=1 To 6
  bb(i + 2) = Bit.Get(b,7)*8+Bit.Get(b,6)*4+Bit.Get(b,5)*2+Bit.Get(b,4)*1
    bb(i + 3) = Bit.Get(b,3)*8+Bit.Get(b,2)*4+Bit.Get(b,1)*2+Bit.Get(b,0)*1
  Next
   
  Log(bsec(1),bsec(0),":",bb(3),bb(4),":",bb(1),bb(2))
 
End Sub

With that said, there are errors in the code as b is never set.
 
Last edited:

atiaust

Active Member
Licensed User
Longtime User
Thank you both for your replies.

This works for me but I was hoping I may have been able to use an inline C++ call to the library to get the time & date info.

Thanks again.
 

ingo.tw

Member
Licensed User
Longtime User
hi Erel: b is never set,run b4j time is error The following accessories,Can someone assist.

upload_2016-7-30_11-25-28.png
 
Top