November 22, 2024, 12:29:13 AM

News:

You can now use Vixen to program your Prop-1 and Prop-2 controllers!  Get started quickly and easily, without having to learn PBASIC.  Details in the Library forum.


Newbie real time clock

Started by Rover, December 19, 2007, 04:25:22 PM

Previous topic - Next topic

Rover

Hello All, I am a newbie - not often that I sound like an AA member

I recently purchased the prop2 starter kit (came in today), and in 10 minutes have the trainer doing its light pattern - ok, cool I'm a programmer in real life an this kit rocks

My background -
programming - very good to excellent (better be it pays the bills)
Electrical - AC or DC very good (ever own a boat?)
Electronics - if its a PC piece no problem - average to low on anything else

caution this might get verbose

My intended application for the unit was to use it to program/run  various outdoor (12 V) items that I have that are running off a wind turbine/solar cells - battery bank, other words 12V system . Some drawing amperages in the 5-15 range  (stream powered by bilge pump, lighting by halogen fogs) - all of this is currently controlled by a automotive wireless system with relays. I wanted to also use a microcontroller for on-off times of the various real time intervals.

I knew when I started into this that I would need an RTC --

Ok finally.. the question any examples on interfacing an RTC (remember Electronics (average to low))  - complete with electrical and pbasic flow

any input appreciated,

Rover

JonnyMac

While at Parallax I wrote a book of BS2 (core of the Prop-2) called StampWorks.  It has a chapter on using the DS1307 which is an I2C RTC with some extra RAM.  With a coin battery the DS1307 is good for 10 years without power.  The up-side of I2C is that it only takes two wires, and there are pull-ups on P12 - P15 that you could use -- the down-side is that you have to synthesize I2C comms and that chews up a bit of code space.

Here's a link to StampWorks:

-- http://www.parallax.com/Portals/0/Downloads/docs/books/sw/Web-SW-v2.1.pdf

You could also go with the DS1302; that takes an extra I/O pin but is lighter on code -- here's a link to an old Parallax App Note that will be helpful:

-- http://laspace.lsu.edu/aces/BalloonCourse/Programming/References/BalloonSat%20Documents/RTCappkit.pdf
Jon McPhalen
EFX-TEK Hollywood Office

Rover

Great that puts me on the track, thanks

JonnyMac

December 23, 2007, 02:29:46 PM #3 Last Edit: December 23, 2007, 05:14:26 PM by JonnyMac
You may find this program useful.  A user on the Parallax forums wanted to control digital outputs in real time with one second resolution and was getting time data from a DS1302.  This was my solution for the BS2 (Prop-2) based on my experiences with irrigation controllers when I worked for Toro. 

Note that this program simulates the RTC; just fold in your working RTC code and update the events table.


' =========================================================================
'
'   File...... Real_Time_Events.BS2
'   Purpose...
'   Author.... Jon Williams, EFX-TEK
'              Copyright (c) 2007 EFX-TEK
'   E-mail.... jwilliams@efx-tek.com
'   Started...
'   Updated...
'
'   {$STAMP BS2}
'   {$PBASIC 2.5}
'
' =========================================================================


' -----[ Program Description ]---------------------------------------------


' -----[ Revision History ]------------------------------------------------


' -----[ I/O Definitions ]-------------------------------------------------


' -----[ Constants ]-------------------------------------------------------

Yes             CON     1
No              CON     0


' -----[ Variables ]-------------------------------------------------------

match           VAR     Bit

secs            VAR     Byte                    ' RTC values
secs01          VAR     secs.NIB0
secs10          VAR     secs.NIB1
mns             VAR     Byte
mns01           VAR     mns.NIB0
mns10           VAR     mns.NIB1
hrs             VAR     Byte
hrs01           VAR     hrs.NIB0
hrs10           VAR     hrs.NIB1

oldSecs         VAR     Byte                    ' from last RTC scan

pntr            VAR     Word                    ' table pointer
tHrs            VAR     Byte                    ' read from table
tMins           VAR     Byte
tSecs           VAR     Byte
tEvent          VAR     Byte


' -----[ Initialization ]--------------------------------------------------

Reset:
  oldSecs = $99

  hrs = $05                                     ' preset for simulation
  mns = $58


' -----[ Program Code ]----------------------------------------------------

Main:
  DO
    GOSUB Get_Time                              ' get RTC values
    PAUSE 50
  LOOP UNTIL (secs <> oldSecs)                  ' loop until clock change
  oldSecs = secs                                ' save for next time
  GOSUB Scan_Events                             ' look for time in table

  DEBUG HOME, HEX2 hrs, ":", HEX2 mns, ":", HEX2 secs, CR

  IF match = Yes THEN                           ' match found
    DEBUG BIN8 tEvent                           ' do something with tEvent
  ENDIF

  GOTO Main


' -----[ Subroutines ]-----------------------------------------------------

Get_Time:
  ' replace this with RTC access

  ' simulate RTC increment (one second)
  ' -- values are in BCD (HEX2)

  secs01 = secs01 + 1
  IF secs01 = 10 THEN
    secs01 = 0
    secs10 = secs10 + 1
    IF secs10 = 6 THEN
      secs10 = 0
      mns01 = mns01 + 1
      IF mns01 = 10 THEN
        mns01 = 0
        mns10 = mns10 + 1
        IF mns10 = 6 THEN
          mns10 = 0
          hrs01 = hrs01 + 1
          IF hrs01 = 10 THEN
            hrs01 = 0
            hrs10 = hrs10 + 1
            IF hrs = $24 THEN
              hrs = $00
            ENDIF
          ENDIF
        ENDIF
      ENDIF
    ENDIF
  ENDIF
  RETURN

' -------------------------------------------------------------------------

Scan_Events:
  match = No                                    ' assume no match
  DO
    READ pntr, tHrs, tMins, tSecs, tEvent       ' read time, event outputs
    IF tHrs = hrs THEN                          ' check time for match
      IF tMins = mns THEN
        IF tSecs = secs THEN
          match = Yes                           ' set if time matches
          EXIT                                  ' stop scanning on match
        ENDIF
      ENDIF
    ENDIF
    pntr = pntr + 4                             ' point to next record
  LOOP UNTIL (tHrs = $99)                       ' stop loop if no match
  IF (tHrs = $99) THEN
    pntr = 0                                    ' reset if end of table
  ENDIF
  RETURN

' -------------------------------------------------------------------------


' -------------------------------------------------------------------------


' -------------------------------------------------------------------------


' -------------------------------------------------------------------------


' -----[ User Data ]-------------------------------------------------------

'                       +----------------------- hours   ($00 to $23)
'                       |    +------------------ minutes ($00 to $59)
'                       |    |    +------------- seconds ($00 to $59)
'                       |    |    |    +-------- event data
'                       |    |    |    |
Event1          DATA    $06, $00, $00, %00000001
Event2          DATA    $06, $00, $30, %00000010
Event3          DATA    $06, $01, $00, %00000100
Event4          DATA    $06, $15, $30, %00001000
Event5          DATA    $06, $30, $00, %00000000

EventsEnd       DATA    $99, $99, $99, %00000000
Jon McPhalen
EFX-TEK Hollywood Office

Rover

Ok I may possibly be an idiot... I picked up and RT from E-kits based on a DS1340-33 IC , which uses i2c .. and for the life of me don't have any idea on how to connect it
, please see http://gravitech.us/MicroResearch/I2C/I2C-RTC/I2C-RTC-Manual.pdf

honestly would not be upset if you did not reply...



JonnyMac

Let me once again recommend StampWorks -- chapter 32 shows how to synthesize I2C communications with the BS2.
Jon McPhalen
EFX-TEK Hollywood Office

livinlowe

Can you be more specific about what your not understanding? Sometimes just talking yourself through a problem will help yoursellf solving it.
Shawn
Scaring someone with a prop you built -- priceless!

Rover

Actually figured it out... needed to remove pins 1 and 2 from the ULN (thanks Jon), after that the routine that Jon wrote for the ds1307 worked as written after changing the pin assignments. The ds1307 and 1340 are virtually identical as far as addressing.

Rover

I'm posting my code .. absolutely no warranties - only things left to add are a voltage monitor and when it arrives the Parallax 912mHZ transceiver pair. Thanks for your help John. The code has been in testing on emulator LED array and doesn't seem to have an issue.

' =========================================================================
'
'   File....... PUMPETCV2.BS2
'   Purpose.... BS2 control of 12v waterfall/Stream with DS1340
'   Author..... Scott Barlow, Nobody
'   Comment.... Heavily copied and/or stolen and/or plagiarized and/or mangled from
'               Jon Williams circa 2004 DS1307.BS2 code. Good looking code is his
'               meandering/bloated code is mine
'   E-mail..... rover@rovr1.com
'   Started....
'   Updated.... 02 APR 2008
'
'   {$STAMP BS2}
'   {$PBASIC 2.5}
'
' =========================================================================


' -----[ Program Description ]---------------------------------------------
'
' Control routines for backyard stream/waterfall and LED lighting array
' PROP2 controller connected to 5 12 volt 30mA coil relays , contacts 10A, and a DS1340
' with battery backup

' -----[ Revision History ]------------------------------------------------
' -----[ I/O Definitions ]-------------------------------------------------

SDA             PIN     15                       ' I2C serial data line
SCL             PIN     14                       ' I2C serial clock line
Relay1          PIN     1                        ' Pump Relay
Relay2          PIN     2                        ' Water refill Solenoid
Relay3          PIN     3                        ' Led Lighting

' -----[ Constants ]-------------------------------------------------------

Ack             CON     0                       ' acknowledge bit
Nak             CON     1                       ' no ack bit
DS1340          CON     %1101 << 4

' -----[ Variables ]-------------------------------------------------------

slvAddr         VAR     Byte                    ' slave address
devNum          VAR     Nib                     ' device number (0 - 3)
addrLen         VAR     Nib                     ' 0, 1 or 2
devAddr         VAR     Word                    ' address in device

i2cData         VAR     Byte                    ' data to/from device
i2cWork         VAR     Byte                    ' work byte for TX routine
i2cAck          VAR     Bit                     ' Ack bit from device

idx             VAR     Nib
secs            VAR     Byte                    ' DS1307 time registers
mins            VAR     Byte
hrs             VAR     Byte
'day             VAR     Byte                    ' weekday
'date            VAR     Byte                    ' day in month, 1 - 31
'month           VAR     Byte
'year            VAR     Byte
control         VAR     Byte                    ' SQWV I/O control

currhour           VAR     Word                    'current hour
currmin            VAR     Word                    'current min
'Could reduce RAM room by reusing BYTE values, or only using 1 word var for current time in
' total minutes since midnight - but harder to follow

' -----[ EEPROM Data ]-----------------------------------------------------


' -----[ Initialization ]--------------------------------------------------

Reset:
  #IF ($stamp >= BS2P) #THEN
    #ERROR "Use I2COUT and I2CIN!"
  #ENDIF

  slvAddr = DS1340
  addrLen = 1

Setup:


' -----[ Program Code ]----------------------------------------------------

Main:

'--get clock every 30 seconds...since timing changes are hours apart

  DO
    GOSUB Get_Clock
    hrs = hrs & $3F
    currhour = (hrs.NIB1 * 10 + hrs.NIB0)
    currmin = (mins.NIB1 * 10 + mins.NIB0)

    '-TODO get voltage value of V+ for battery preservation

    GOSUB Check_Time_Period

    PAUSE 30000 '30 second delay until next loop

  LOOP
  END


' -----[ Subroutines ]-----------------------------------------------------
' ---- [Relay and Timing Related Subroutines]------------------------------
' Using Relays 1 throug 3 perform the following
' Based on Hour,Minutes
' Check_Time_Period - Run through if statements and perform approprate function
' Could probably have done this as Case select but would not be as easy to follow
' Morning_1  power relay 3 to turn on LEDs
' Morning_2  power relay 2 for ~3 minutes, power relay 1 to start pump
' Morning_3  Turn Off LEDs
' Evening_1  Tun on LEDs
' Evening_2  Turn off Pump
' Evening_3  Turn off LEDs

Check_Time_Period:  'Find out what period of the day we are
' The Following should work to allow system restarts and have
' the system discover what state it should be in
' as opposed to waiting for the next event, which might also be
' missed based on the 30 second loop timing if exact values used

'LEDs ON between 5:00 and 7:00
IF currhour >= 5 AND currhour < 7  THEN GOSUB Morning_1
'PUMP ON Between 6:30 and 21:00
IF ((currhour * 60) + currmin)  >= ((6 * 60) +  30) AND currhour < 21  THEN GOSUB Morning_2
'LEDs OFF Between 7:00 and 19:00
IF currhour >= 7 AND currhour < 19 THEN GOSUB Morning_3
'LEDs ON Bewteen 19:00 and 23:00
IF currhour >= 19 AND currhour < 23 THEN GOSUB Evening_1 'LEDs ON
'PUMP OFF 9 to midnight and midnight to 6:30
IF currhour >= 21 OR (currhour >= 0 AND ((currhour * 60) + currmin)  < ((6 * 60) +  30)) THEN GOSUB Evening_2
'LEDs OFF 11 to midnight and mindnight to 5:00
IF currhour >= 23 OR (currhour >= 0 AND currhour < 5) THEN GOSUB Evening_3

RETURN

Morning_1:
    ' check the current pin status for Relay3 - do nothing if ON
IF OUT3 = 0 THEN
   HIGH Relay3
   DEBUG HEX2 hrs, ":", HEX2 mins, ":", HEX2 secs ," - Morning1 LEDs ON", CR

ENDIF

RETURN

Morning_2:
          'if the pump is not on then replenish water and turn it on
IF OUT1 = 0 THEN
  DEBUG HEX2 hrs, ":", HEX2 mins, ":", HEX2 secs ," - Morning2 Turning WATER/PUMP ON", CR
  IF OUT2 = 0 THEN
  DEBUG HEX2 hrs, ":", HEX2 mins, ":", HEX2 secs ," - Morning2  WATER ON", CR
    HIGH Relay2   'turn on the water
    PAUSE 60000   'WAIT 3 minutes - 'I'd rather use SLEEP here but output interrupt every 2.3 seconds
                  'might recycle the relays
    PAUSE 60000
    PAUSE 60000
    GOSUB Get_Clock
    hrs = hrs & $3F
    LOW Relay2    'turn off the water
    DEBUG HEX2 hrs, ":", HEX2 mins, ":", HEX2 secs ," - Morning2  WATER OFF", CR
  ENDIF
    DEBUG HEX2 hrs, ":", HEX2 mins, ":", HEX2 secs ," - Morning2  PUMP ON", CR
    HIGH RELAY1   'turn on the pump
    ENDIF
RETURN

Morning_3:
IF OUT3 = 1 THEN
DEBUG HEX2 hrs, ":", HEX2 mins, ":", HEX2 secs ," - Morning3 LEDs OFF", CR
LOW Relay3 'Turn off LEDS
ENDIF
RETURN

Evening_1:
IF OUT3 = 0 THEN
DEBUG HEX2 hrs, ":", HEX2 mins, ":", HEX2 secs ," - Evening1 LEDs ON", CR
HIGH Relay3 'Turn on LEDs
ENDIF
RETURN

Evening_2:

IF OUT1= 1 THEN
LOW Relay1 'Turn Off pump
DEBUG HEX2 hrs, ":", HEX2 mins, ":", HEX2 secs ," - Evening2 PUMP OFF", CR
ENDIF
'Paranoid, redundant water turn off to be on the safe side
IF OUT2 = 1 THEN LOW Relay2
RETURN

Evening_3:
IF OUT3 = 1 THEN
LOW RELAY3 ' Turn off the LEDs
  DEBUG HEX2 hrs, ":", HEX2 mins, ":", HEX2 secs ," - Evening3 LEDs OFF", CR
ENDIF
RETURN


' -----[Clock Subroutines ]-----------------------------------------------------
' Do a block write to clock registers

Set_Clock:
  GOSUB I2C_Start                               ' send Start
  i2cWork = slvAddr & %11111110                 ' send slave ID (write)
  GOSUB I2C_TX_Byte
  i2cWork = 0                                   ' point at secs register
  GOSUB I2C_TX_Byte
  FOR idx = 0 TO 7                              ' write secs to control
    i2cWork = secs(idx)
    GOSUB I2C_TX_Byte
  NEXT
  GOSUB I2C_Stop
  RETURN


' Do a block read from clock registers

Get_Clock:
  GOSUB I2C_Start                               ' send Start
  i2cWork = slvAddr & %11111110                 ' send slave ID (write)
  GOSUB I2C_TX_Byte
  i2cWork = 0                                   ' point at secs register
  GOSUB I2C_TX_Byte
  GOSUB I2C_Start
  i2cWork = slvAddr | %00000001                 ' send slave ID (read)
  GOSUB I2C_TX_Byte
  FOR idx = 0 TO 6                              ' read secs to year
    GOSUB I2C_RX_Byte
    secs(idx) = i2cWork
  NEXT
  GOSUB I2C_RX_Byte_Nak                         ' read control
  control = i2cWork
  GOSUB I2C_Stop
  RETURN

' -----[ High Level I2C Subroutines]---------------------------------------

' Random location write
' -- pass device slave address in "slvAddr"
' -- pass address bytes (0, 1 or 2) in "addrLen"
' -- register address passed in "devAddr"
' -- data byte to be written is passed in "i2cData"

Write_Byte:
  GOSUB I2C_Start                               ' send Start
  i2cWork = slvAddr & %11111110                 ' send slave ID
  GOSUB I2C_TX_Byte
  IF (i2cAck = Nak) THEN Write_Byte             ' wait until not busy
  IF (addrLen > 0) THEN
    IF (addrLen = 2) THEN
      i2cWork = devAddr.BYTE1                   ' send word address (1)
      GOSUB I2C_TX_Byte
    ENDIF
    i2cWork = devAddr.BYTE0                     ' send word address (0)
    GOSUB I2C_TX_Byte
  ENDIF
  i2cWork = i2cData                             ' send data
  GOSUB I2C_TX_Byte
  GOSUB I2C_Stop
  RETURN


' Random location read
' -- pass device slave address in "slvAddr"
' -- pass address bytes (0, 1 or 2) in "addrLen"
' -- register address passed in "devAddr"
' -- data byte read is returned in "i2cData"

Read_Byte:
  GOSUB I2C_Start                               ' send Start
  IF (addrLen > 0) THEN
    i2cWork = slvAddr & %11111110               ' send slave ID (write)
    GOSUB I2C_TX_Byte
    IF (i2cAck = Nak) THEN Read_Byte            ' wait until not busy
    IF (addrLen = 2) THEN
      i2cWork = devAddr.BYTE1                   ' send word address (1)
      GOSUB I2C_TX_Byte
    ENDIF
    i2cWork = devAddr.BYTE0                     ' send word address (0)
    GOSUB I2C_TX_Byte
    GOSUB I2C_Start
  ENDIF
  i2cWork = slvAddr | %00000001                 ' send slave ID (read)
  GOSUB I2C_TX_Byte
  GOSUB I2C_RX_Byte_Nak
  GOSUB I2C_Stop
  i2cData = i2cWork
  RETURN


' -----[ Low Level I2C Subroutines]----------------------------------------

' *** Start Sequence ***

I2C_Start:                                      ' I2C start bit sequence
  INPUT SDA
  INPUT SCL
  LOW SDA

Clock_Hold:
  DO : LOOP UNTIL (SCL = 1)                     ' wait for clock release
  RETURN


' *** Transmit Byte ***

I2C_TX_Byte:
  SHIFTOUT SDA, SCL, MSBFIRST, [i2cWork\8]      ' send byte to device
  SHIFTIN SDA, SCL, MSBPRE, [i2cAck\1]          ' get acknowledge bit
  RETURN


' *** Receive Byte ***

I2C_RX_Byte_Nak:
  i2cAck = Nak                                  ' no Ack = high
  GOTO I2C_RX

I2C_RX_Byte:
  i2cAck = Ack                                  ' Ack = low

I2C_RX:
  SHIFTIN SDA, SCL, MSBPRE, [i2cWork\8]         ' get byte from device
  SHIFTOUT SDA, SCL, LSBFIRST, [i2cAck\1]       ' send ack or nak
  RETURN


' *** Stop Sequence ***

I2C_Stop:                                       ' I2C stop bit sequence
  LOW SDA
  INPUT SCL
  INPUT SDA
  RETURN