Skip to content

PICAXE Clock Exercise: I2C communications with selective display updating

The Revolution Education folks have done a nice job of building the microcontroller interface library into their boot loader to make the PICAXE. The I2C communications provide an example. This is the core of the code needed to pull time from a DS1307 clock chip via I2C and put it on a display at a configurable position.

The clock has 57 bytes of battery backed SRAM. The first 8 are clock data and the remaining 57 bytes are RAM (08h – 3Fh) which are used here for display configuration data starting at byte 10.

First up is to define the positions and raw clock data as variables in the register bank:

; LCD display positions else don't display if out of range
Symbol tpos = b6        ; hh:mm
Symbol spos = b7        ; :ss
Symbol apos = b8        ; am pm
Symbol zpos = b9        ; UTC, PST, etc
Symbol dpos = b10        ; mo/da/yr
Symbol mpos = b11        ; Jan, Feb ... or mo/
Symbol wpos = b12        ; MON
Symbol tz = b13            ; time zone (-UTC offset) index to Table_TZ
; w7 b:14:b15 reserved

; clock raw data
Symbol sc = b16        ; data read to these registers is compared to
Symbol mn = b17        ; a scratchpad copy from previous clock read
Symbol hr = b18        ; this allows selective display updating and
Symbol wd = b19        ; clock data reading based on what changes
Symbol da = b20
Symbol mo = b21
Symbol yr = b22

Next is to define pointers to the scratchpad where the previous data read is stored. This allows comparing the current clock data to what has been displayed in order to determine what needs updating.

; scratchpad 1024 bytes -- ptr, @ptr or get/put
Symbol clock_data = 31        ; seconds, bit 7 = 0 to enable oscillator
Symbol clock_data_min = 32
Symbol clock_data_hr = 33    ; bit 6 = AM/PM, bit 5 is ten hour
Symbol clock_data_dow = 34    ; day of week low 3 bits
Symbol clock_data_dom = 35    ; bits 6,7 = 0
Symbol clock_data_mo = 36    ; bits 5,6,7=0
Symbol clock_data_yr = 37    ; -2000
Symbol clock_data_control = 38    ; %00010000 enable output at 1Hz

In order to be able to display month, day, and time zone abbreviations, tables are set up with indices to the start of each table.

; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
; TABLE 0-255 (program space) compiler written program space read only
; data. See readtable, tablecopy
Symbol Table_ID = 0
Symbol Table_DOW = 20        ; indices to table data
Symbol Table_months = 42
Symbol Table_TZ = 80
    TABLE Table_ID, ("DS1307 Test by K1CD")
    TABLE Table_DOW, ("SUNMONTUEWEDTHUFRISAT")
    TABLE Table_months, ("JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC")
    TABLE Table_TZ, ("U123AECMP")

In the clock data registers, byte 0 (seconds) bit 7 is clock halt bit. This must be 0 for the clock to run. Byte 2 (hour) bit 6 set for 12 hour mode where bit 5 set for p.m. Bit 6 low uses bit 5 for hours 20-23. To initialize the I2C communications, the microcontroller needs to know that the PICAXE controls the bus, the clock clock address (from its spec sheet), the fact that the clock uses a 100 KHz I2c link with 8 MHz PICAXE, and that clock memory is byte addressed. Other initialization tasks include clearing the scratchpad data to assure a fresh clock data read and clearing the display.

init_clock:
    hi2csetup i2cmaster, %11010000, i2cslow_8, i2cbyte

; pull clock options from clock static RAM
    hi2cin 10, (tpos, spos, apos, zpos, dpos, mpos, wpos, tz)

; fall through to reset clock and refresh with new clock read

reset_clock_display:
    For i = clock_data to clock_data_yr
        put i, $FF     ; fill buffer to assure all data read,
    Next i              ; formatted, and put in display buffer
    Gosub LCD_Reset     ; clear display

; fall through to read_clock to read and display the current clock data

Read time and date and format for display. The first 8 bytes in clock are BCD time values with hour having am.pm flag. The routine uses b0 and the defined registers. Clock display data updated to LCD position as indicated. The BCD clock data with a few flags thrown in (e.g. hours) needs a great deal of care if using a time value in tests or calculations. For values <10, BCD and binary are the same but >9 means the high order nibble is another digit (like in hexadecimal notation).

Note that the calls to the LCD set position and display characters are omitted in this code to emphasise the clock data processing.

read_clock:
; Seconds
    hi2cin 0,(sc)
    get clock_data, b0
    If b0 = sc Then
        Return  ; no time change, leave as is
    EndIf
    put clock_data, sc      ; update time buffer
    If spos < $FF Then
        BCDtoASCII sc, i, j     ; seconds (CH assumed not set)
        b0 = spos
 ; [[ position LCD to b0 and then display i and j ]]
        Sertxd("sec @",#b0,"=",i,j,cr,lf)
    EndIf

This pattern of reads, comparison to scratchpad values, scratchpad updating, and display if position is valid is repeated for the other clock values. For Hours, it is necessary to parse out the 12 or 24 hour mode bit and the am/pm bit.

; Hours
    hi2cin 2,(hr)
    get clock_data_hr, b0
    If b0 = hr Then
        Return
    EndIf
    put clock_data_hr, hr
    b0 = hr         ; easier to check bits
    If bit6 = 1 Then    ; 12 hour mode
        morning = bit5  ; mainly used for DST testing
        If bit5 = 1 Then
            i = "p"
            bit5 = 0
        Else
            i = "a"
        EndIf
        bit6 = 0        ; clear bit for BCD conversion
        hr = b0         ; am/pm bits cleaned saved
    ;   If apos < $FF Then ; print am or pm
    ;   EndIf
    ; Else          ; 24 hour mode
    ;   If hr < 12 Then
    ;       morning = 0
    ;   Else
    ;       morning = 1
    ;   EndIf
    EndIf

The morning flag is used for daylight savings time checks. Calculating day of week and checking for daylight savings time adjustments are on the agenda. As the magic DST hour is this weekend, it is a good time to check the tests for whether the clock should be adjusted. As always, there are complications to consider. One of them is that the VCC lead to my LCD display broke, and something else got messed up so I had to spend time figuring out how to fix those problems so I could run tests to get the major bugs fixed.

For this sample, though, go through the code and look for the I2C communications commands hi2csetup, hi2cin, and hi2cout. Look at how the BCD routines built into the PICAXE are used. Here, they are mainly to get display values but in some places, binary values are needed for calculation.

Don’t worry, the whole thing will get posted to the TCL software library before long.

Post a Comment

You must be logged in to post a comment.