'****************************[ Title ]**********************************
'* Name : I2C_DS1337.pbp *
'* Author : John R. Ellis *
'* Started : 11/20/2009 *
'* Version : 1.0 *
'* Compiler: PICBASIC PRO Compiler 2.60 from microEngineering Labs *
'* Notes : This code was designed/devloped on an EasyPic6 board. *
'* : *
'* Device : Options of 18F2550/4550 w/ serial COG 2x16 LCD *
'* Memory : 1846 bytes of Program Memory required *
'* Ref: : 1) Portions of this code are adapted from code written *
'* : by Tonigalea (see URL ref below), but modified to run on *
'* : an EasyPic6 with 18F4550 MCU and I2C controlled DS1337. *
'*
http://www.picbasic.co.uk/forum/show...hlight=DS1337*
'* : 2)
'************************************************* **********************
' -----------------------[ Program Description ]--------------------------
' This Program is for a PIC18F4550 and was tested in an EasyPic6 board. *
' Purpose: *
' 1) Initializes low power settings & enters SLEEP mode on power up. *
' 2) Monitors 1/min interrupt from external Real Time Clock *
' 3) Displays current time (HH:MM) on LCD and goes back to sleep. *
' 4) Puts Microcontroller back in Sleep State to await next *
' RTC interrupt. * *
'************************************************* ************************
'---------------------- 18F4550 Port/PIN Connections ]--------------------
'I/O pin connections to the 18F4550 MCU are as follows:
'PORTA.0 (02) RA0 not connected
'PORTA.1 (03) RA1 not connected
'PORTA.2 (04) RA2 not connected
'PORTA.3 (05) RA3 not provided on 18F4550
'PORTA.4 (06) RA4 not connected
'PORTA.5 (07) RA5 not connected
'PORTB.0 (21) Connected as I2C SDA output to DS1337
'PORTB.1 (22) Connected as I2C SCL output to DS1337
'PORTB.2 (23) Connected as INT2 interrupt from pin-7 (_INTA) of DS1337 RTC.
'PORTB.3 (24) Connected as input from pin-3 (SQW/_INTB) of DS1337 RTC.
'PORTB.4 (25) RB4 not connected
'PORTB.5 (26) RB5 not connected
'PORTB.6 (27) Connected as PGC for ICSP connection
'PORTB.7 (28) Connected as PGD for ICSP connection
'PORTC.0 (11) RC0 not connected.
'PORTC.1 (12) RC1 connected as an output to a Red LED for battery low.
'PORTC.2 (13) RC2 not connected
'PORTC.3 (14) not connected
'PORTC.4 (15) not connected.
'PORTC.5 (16) not connected.
'PORTC.6 (17) RC6 connected to pin-8 of DS1337 RTC as controllable power
'PORTC.7 (18) RC7 not connected
' -----[ Revision History ]-----------------------------------------------
' Version 1.0 Started on 11/20/2009
' -----[ Device Declaration ]---------------------------------------------
'************************************************* **********************
;--- if you un-comment these, you must comment the ones in the .inc file--
ASM ; 18F2550/4550, sith 8mhz crystal
__CONFIG _CONFIG1L, _PLLDIV_2_1L & _CPUDIV_OSC1_PLL2_1L & _USBDIV_2_1L
__CONFIG _CONFIG1H, _FOSC_HSPLL_HS_1H
__CONFIG _CONFIG2L, _PWRT_ON_2L & _BOR_OFF_2L & _VREGEN_ON_2L
__CONFIG _CONFIG2H, _WDT_ON_2H & _WDTPS_512_2H
__CONFIG _CONFIG3H, _PBADEN_OFF_3H ; PortB resets as digital
__CONFIG _CONFIG4L, _LVP_OFF_4L & _XINST_OFF_4L
ENDASM
' If 16F877 MCU used, use this config
'@ config XT_osc, wdt_off, pwrt_on, protect_off
' or
'@ _CONFIG _CONFIG1H,_OSCS_OFF_1H & _HS_OSC_1H
Include "Modedefs.Bas"
INCLUDE "DT_INTS-18.bas" ' Base Interrupt System
INCLUDE "ReEnterPBP-18.bas" ' Include if using PBP high priority interrupts
INCLUDE "ALLDIGITAL.pbp" ' Sets all registers for digital ops.
' User must make sure the AllDigital.pbp file
' is in same directory location as this source
' code before compiling.
'DEFINE SHOWDIGITAL 1 ' When uncommented will show analog settings
' in Assembler Results window.
' A/D & Comparators disabled for digital ops
' All of these statements should be commented out when using the
' INCLUDE "AllDigital.pbp" statement to set digital ops.
'ADCON1 = %00001111
'CMCON = 7
DEFINE OSC 48
' Initialize Hardware
' ===================
'Set registers
OSCCON.7 = 0 ' Clear IDLEN bit to allow SLEEP mode
' According to data sheet, must clear CONFIG2H.0 (WDTEN bit)
' in order to use WDTCON. Not clear from Data sheet how to reach
' WDTEN bit with with config fuses??
WDTCON.0 = 1 ' Set SWDTEN bit to turn on WDT
TRISA = 0 ' PORTA all outputs for LCD use
TRISB =%00001100 ' RB2 & RB3 set as RTC Alarm1 & Alarm2 inputs
TRISC = 0
TRISD = 0
TRISE = 0
'--------------[ Declare Variables, Aliases & Constants ]---------------
'************************************************* **********************
' Variables & Aliases for Pins other than RTC use
' ===============================================
ADINPUT VAR WORD ' Stores VP6 value as sampled by the A/D
b0 VAr Vdd.byte1 ' LSB of Vdd when right justified
b1 var Vdd.Byte0 ' MSB of Vdd when right justified
counter VAR WORD ' Index counter for day counter
day_count VAR WORD ' Stores daycounter value as of run time
dummy VAR Byte ' For read of on-interrupt port & clear mismatch
j VAR WORD ' Index for incrementing EEPROM address offset
LED_Red VAR PORTC.1 ' RC1 (Red LED) for low battery indicator
mo_range VAR WORD[31] ' Array for storing value for each day
Spare_1 VAR PORTB.7 ' PGD for ICSP & Spare I/O for normal ops
Spare_2 VAR PORTB.6 ' PGC for ICSP & Spare I/O for normal ops
time VAR WORD ' Stores day clock time in 24 hr format
Vdd VAR WORD ' Stores Vdd value as converted from ADINPUT
' Constants
'==========
Vthr CON 46 ' Threshold (3.3v) to trigger battery low voltage warning
' ...this is dictated by the drop-out and output voltage
' of the voltage regulator used in the power circuit.
'---------------SETUP FOR USING DS1337 Real Time Clock------------------
'************************************************* **********************
' Setup Hardware for uart
' =======================
DEFINE HSER_BAUD 115200
DEFINE HSER_RCSTA 90h
DEFINE HSER_TXSTA 24h
DEFINE HSER_CLROERR 1
' * NOTES for use with EasyPic6 development board:
'For use with COG 2x16 LCD:
' - Turn on Port Expander switches SW6.1, SW6.2, SW6.3, SW6.4 and SW6.5.
' - Turn on COG LCD 2x16 switches SW10.1, SW10.2, SW10.3, SW10.4, SW10.5 and SW10.6.
'For interface to DS1337 RTC:
' - To provide battery backup place a Shottky diode between + battery
' terminal and Vcc (pin-8) of the DS1337.
' - I2C communication lines should be connected to 4.7K pull-up resistors.
' - INTA & INTB lines should be connected to pull-up resistsors.
' - Turn off LEDs connected to I2C communication lines.
' Aliased Variables for CLock
' ===========================
Alarm1 VAR PORTB.2 ' Alarm1 input from DS1337 INTA (pin-3)
Alarm2 VAR PORTB.3 ' Alarm2 input from DS1337 INTB (pin-7)
SCL VAR PORTB.1 ' I2C clock pin
SDA VAR PORTB.0 ' I2C data pin
RTC CON %11010000 ' RTC device write address for I2C bus
' This is a list of allowable clock contrl settings, one which must be
' setup in the SetTimeAndDate subroutine as intended.
'contrl CON %00000000 ' Starts oscillar, sets the SQW/OUT to
' 1Hz pulse, no Alarm interrupt enabled.
' WORKS as intended!!
'contrl CON %00000001 ' Starts oscillator, sets the SQW/OUT to
' 1 HZ pulse, & enables INTA interrupt from
' A1F. WORKS as intended!!
'(see data sheet pg 10)
'contrl CON %00000010 ' Starts oscillator, sets the SQW/OUT to
' 1 HZ pulse, enables INTA interrupt from
' A2F. WORKS AS intended!!
'contrl CON %00000011 ' Starts the oscillator, sets the SQW/OUT
' to 1 Hz, enables INTA interrupt from A1F
' or from A2F. WORKS as intended!!
'contrl CON %000xx100 ' Starts oscillator, no interrupts enabled.
' WORKS as intended!!
'contrl CON %00000101 ' Starts oscillator, enables INTA interrupt
' from A1F, INTA/SQW off. INTA DOESN'T WORK!
'contrl CON %00000110 ' Starts oscillator, enables INTB interrupt
' from A2F. WORKS OK!
'contrl CON %00000111 ' Starts oscillator, enables INTA interrupt
' from A1F or INTB from A2F. WORKS OK!
' Both interrupts staggered 30 secs apart.
'contrl CON %00011111 ' Starts oscillator, enables INTA interrupt
' from A1F or INTB from A2F. WORKS OK!
'contrl CON %00011001 ' Sets RS1 & RS2,
' clears INTCN to enable INTA interrupt
' from A1F with 3.2768kHz on SQW output.
' SQW output WORKS OK but INTA doesn't!
'contrl CON %00011010 ' Sets RS1 & RS2,
' clears INTCN to enable INTA interrupt
' from A2F with 3.2768kHz on SQW. WORKS OK!
' RTC Address definitions
' ========================
SecReg CON $00 ' seconds address (00 - 59)
' MSB of SecReg must be set to a 0 to enable RTC
MinReg CON $01 ' minutes address (00 - 59)
HourReg CON $02 ' hours address (01 - 12) or (00 - 23)
DayReg CON $03 ' day address (1 - 7)
DateReg CON $04 ' date address (01 - 28/29, 30, 31)
MonthReg CON $05 ' month address (01 - 12)
YearReg CON $06 ' year address (00 - 99)
' Alarm 1 Address definitions
' ===========================
Alm1sec CON $07 ' Alarm 1 seconds address (00 - 59)
Alm1min CON $08 ' Alarm 1 minutes address (00 - 59)
Alm1hr CON $09 ' Alarm 1 hours address (01 - 12) or (00 - 23)
Alm1Day CON $0A ' Alarm 1 day address (1 - 7)
' Alarm 2 Address definitions
' ===========================
Alm2min CON $0B ' Alarm 2 minutes address (00 - 59)
Alm2hr CON $0C ' Alarm 2 hours address (01 - 12) or (00 - 23)
Alm2Day CON $0D ' Alarm 2 day address (1 - 7)
' Alias of Clock register addresses
' =================================
ContReg CON $0E ' CONTROL register address
StatusReg CON $0F ' STATUS register address
' Clock Variables
' ================
sec VAR BYTE ' seconds
MINs VAR BYTE ' minutes
hr VAR BYTE ' hours
day VAR BYTE ' day
date VAR BYTE ' date
mon VAR BYTE ' month
yr VAR BYTE ' year
' ALARM1 VARIABLES
' ================
A1sec VAR BYTE ' seconds
A1MINs VAR BYTE ' minutes
A1hr VAR BYTE ' hours
A1day VAR BYTE ' day
' ALARM2 VARIABLES
' ================
A2MINs VAR BYTE ' minutes
A2hr VAR BYTE ' hours
A2day VAR BYTE ' day
GoSub SetTimeAndDate ' Setup current time & alarm settings
'----------------------[ SETUP FOR INTERRUPTS ]-------------------------
'************************************************* **********************
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
;INT_Handler USB_Handler
INT_Handler INT2_INT, _Alarm, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM
@ INT_ENABLE INT2_INT ; enable external (INT) interrupts
INTCON.7 = 1 ' Set Global Interrupt Enable bit
INTCON2 = %00001000 ' Set INT2 for falling edge (Bit4-low)
' on RTC's interrupt.
INTCON3 = %10010000 ' Set INT2 high priority (Bit7-high), enable INT2
' (Bit4-high)
RTC_INT_FLG VAR INTCON3.1 'Alias for INT2 interrupt flag from RTC
'--------------------[ Begin Main Program Loop ]------------------------
'************************************************* **********************
Main:
' Place code here to put MCU and Ultrasonic srfdevice in SLEEP mode.
' Perform following steps to save power during Sleep mode
OSCCON.7 = 0 ' Clear IDLEN bit to allow SLEEP mode
' According to data sheet, must clear CONFIG2H.0 (WDTEN bit)
' in order to use WDTCON. Not clear from Data sheet how to do
' this with config fuses.
WDTCON.0 = 0 ' Clear SWDTEN bit to turn off WDT
' Make sure ADC and Comparators turned off..done previously by
' ALLDIGITAL include which sets ADCON1 = %00001111.
'TRISA = %00001000 ' Per JoeS to save power.
TRISA = %11111111 ' Set all PORTA pins as inputs during SLEEP.
'TRISB = %00000000 ' Per JoeS to save power
TRISB = %11111111 ' Set all PORTB pins as inputs during SLEEP.
'TRISC = %00001111 ' Per JoeS to save power
TRISC = %11111111 ' Set all PORTC pins as inputs during Sleep.
'PortA = %00000000 ' Per JoeS to save power
PortA = %11111111 ' Write Port A all High to clear mismatch
' & save power during SLEEP.
PortB = %11111111 ' Set all PORTB & PORTC pins High to
PortC = %11111111 ' save power in Sleep mode.
PORTE = %01111111 ' Disable all pull-ups during SLEEP (PORTE.7)
' and set all other bits to save power.
' Interrupt Settings
'INTCON = %10001000 ' Enable interrupts: GIE & RABIE but TMR0 disabled
'IOCA = %00001000 ' before SLEEP. Enable RA3 as RABIE on-change-INT
@ sleep
@ NOP ' @ NOP statement here makes no difference.
' Microcontroller is in Sleep State waiting for external interrupt.
GOTO Main ' Loop to Main to wait for next interrupt
End ' Safety measure to insure program stops if reaches here
'--------------------[ Begin Interrupt Handler ]------------------------
'************************************************* **********************
Alarm:
PAUSE 500 ' Delay to permit MCU oscillator to turn-on/stabilize
DEFINE WRITE_INT 1
DISABLE ' Disable interrupts during interrupt handler
'Initialize registers/ports upon Interrupt wakeup from Sleep during ISR.
OSCCON.7 = 0 ' Clear IDLEN bit to allow SLEEP mode
' According to data sheet, must clear CONFIG2H.0 (WDTEN bit)
' in order to use WDTCON. Not clear from Data sheet how to do
' this with config fuses.
WDTCON.0 = 1 ' Set SWDTEN bit to turn on WDT
TRISA = 0 ' SET PORTA all outputs for LCD use
TRISB =%00001100 ' SET RB2 & RB3 as RTC Alarm1 & Alarm2 inputs, all
' other PORTB pins as outpus
TRISC = 0 ' Set PORTC pins as outputs
TRISD = 0 ' Set PORTD pins as outputs
TRISE = 0 ' Set PORTE pins as outputs
PortA = %11111111 ' Set Port A all High to clear mismatch
' & save power.
PortB = %11111111 ' Set all PORTB & PORTC pins High to
PortC = %11111111 ' save power in Sleep mode.
HIGH PORTC.7 ' Turn on Test LED to indicate Alarm interrupt entered
PORTE.7 = 1 ' Enable all pull-ups during ops.
' A/D & Comparators were already disabled by ALLDIGITAL include
' Initialization of inputs/outputs
Alarm1 = 1 ' Init RB2 (INTA) @ High value as interrupt
' Process this Interrupt
IF RTC_INT_FLG = 1 THEN 'Verify the interrup is from RTC clock
' Interrupt was from RTC Alarm at midnight...Process the RTC alarm
' Display Time and ALARM1 settings on the LCD display 'No LCD during test
'GOSUB InitializeDisplay
'LCDOut L,Clr:Pause 50
'LCDOut L,Line1,"Time: ",HEX2 hr, ":", HEX2 MINs, ":", HEX2 sec
'PAUSE 500
'LCDOut L,Line2,"Alarm: ",HEX2 A2hr, ":", HEX2 A2MINs, ":", HEX2 $0
'PAUSE 500 ' Allow Time for user to view
'GOSUB DeInitializeDisplay
' Update day counter
READ 19,day_count ' Test if EEPROM data has been captured
' & erased and new monthly epoch started.
PAUSE 20
IF day_count = 0 Then ' If so then start new day counter epoch.
day_count = 1 ' Set day counter to 1st epoch day of 31.
j = 2 ' EEPROM address offset for range value.
ENDIF
WRITE 19,day_count 'Store day count in EEPROM address 19,20
PAUSE 20
counter = 0 ' Initialize range measurement counter.
mo_range[day_count] = 0
I2CREAD SDA, SCL, RTC, DateReg,[date] ' Read current date
PAUSE 20
' Store average as date-stamped value in EEPROM
WRITE (19+j),mo_range[day_count]' Store day's avg range in EEPROM
PAUSE 20
Write (21+j),date ' with date-stamp
PAUSE 20
day_count = day_count + 1 ' Increment the day counter
j = j + 4 ' Increment EEPROM address offset for range
' Reset Alarms for next day's interrupt
If Alarm1 = 0 Then ' Reset Alarm1 interrupt in DS1337
I2CWrite SDA, SCL, RTC, StatusReg,[$00] ' Clear STATUS register
Pause 20
ENDIF
ENDIF
LOW PORTC.7 ' Turn off LED indicated completed ISR
dummy = Alarm1 ' Clear mismatch condition
RTC_INT_FLG = 0 ' Clear MCU interrupt flag for next Alarm
' Resume Main Program
@ INT_RETURN
End ' Safety measure to insure program stops if reaches here
'------------------{ End of Interrupt Handler }-------------------------
' ----------------------[ START LIST OF SUBROUTINES ]-------------------
'************************************************* **********************
InitializeDisplay: ' Subroutine to initialize serial LCD
'=================
'--SETUP FOR USING 2x16 LCD THAT IS INSTALLED IN EASYPIC6-----
' LCD DEFINES FOR USING 2x16 LCD with PortA
'==========================================
' DEFINE LCD_DREG PORTA ' Use PORTA for LCD Data
'DEFINE LCD_DBIT 0 ' Use lower(4) 4 bits of PORTA
' PORTA.0 thru PORTA.3 connects to
' LCD DB4 thru LCD DB-7 respectively
'DEFINE LCD_RSREG PORTA ' PORTA for RegisterSelect (RS) bit
'DEFINE LCD_RSBIT 4 ' PORTA.4 pin for LCD's RS line
'DEFINE LCD_EREG PORTA ' PORTA for Enable (E) bit
'DEFINE LCD_EBIT 5 ' PORTA.5 pin for LCD's E line
'DEFINE LCD_BITS 4 ' Using 4-bit bus
'DEFINE LCD_LINES 2 ' Using 2 line Display
'DEFINE LCD_COMMANDUS 5000 ' Command Delay (uS)
'DEFINE LCD_DATAUS 200 ' Data Delay (uS)
' DEFINE LCD Control Constants
'=============================
L CON 254 ' Control Byte
Clr CON 1 ' Clear the display
Line1 CON 128 ' Point to beginning of line 1
Line2 CON 192 ' Point to beginning of line 2
'LCDOut L,CLR:Pause 50 ' Clear Display
'LCDOut L,Line1+2," RTC TEST " ' Display "RTC TEST" on 1st line
'Pause 500
'LCDOut L,Line2+2,"..Power On.. !!" ' Display "Power on" on 2nd line
'PAUSE 1000
Return
'DisplayTest: ' Subroutine to test LCD..Commented out till LCD installed
'===========
'LCDOut L,CLR:Pause 50 ' Clear Display
'LCDOut L,Line1+2," TEST " ' Display "TEST" on 1st line
'PAUSE 500
'LCDOut L,Line2+2,"..Power On.. !!" ' Display "Power on" on 2nd line
'Pause 1000
'RETURN
SetTimeAndDate: ' Subroutine to set current time, data and alarms
'==============
' Initialize clock variables to 0
yr=0:date =0:mon =0:day=0:hr=0:MINs=0:sec=0
A1sec=0:A1MINs=0:A1hr=0:A1Day=0
A2MINs=0:A2hr=0:A2day=0
' The BCD constants below set the RTC to: 14:00:00 on 12-05-2009
yr=$09
mon=$12
date=$05
day=$07
hr=$14
MINs=$00
sec=$00
'Define ALARM1 FOR 14:00:30 & to alarm when secs match (1/min).
' This requires A1M1=0 and A1M2=A1M3=A1M4=1
' (A1xxx + $80 or A1xxx + 128d sets bit 7 as A1Mx = 1)
A1hr = %10010100 '$14 + $80 = %100100100, for A1M3 = 1
'Bit6 must be 0 for 24 hour clock
A1MINs = %10000000 '$00 = %10000000, for A1M2 = 1
A1sec = %00110000 '$30 = %00110000, for A1M1 = 0
A1day = %10000111 '$07 + $80 = $10000111, for A1M4 = 1
'DY/_DT Bit6 = 0 for using Day of month alarm
'Define ALARM2 FOR 14:01:00 & to alarm once per minute (00 secs)
' This requires A2M2 = A2M3 = A2M4 = 1
' (A2xxx + $80 or A2xxx + 128d sets bit 7 as A2Mx = 1)
'A2hr = %10010100 '$14 + $80 = %10010100, for A2M3 = 1
'Bit6 must be 0 for 24 hour clock
'A2MINs = %10000001 '$01 + $80 = %10000001, for A2M2 = 1
'A2day = %10000111 '$07 + $80 = $10000111, for A2M4 = 1
'DY/_DT Bit6 = 0 for using Day of month alarm
'Set the main Time
I2CWrite SDA, SCL, RTC, SecReg,[sec,MINs,hr,day,date,mon,yr]
Pause 20
'Set the Alarm1 Time
I2CWrite SDA, SCL, RTC, Alm1sec,[A1sec,A1MINs,A1hr,A1day]
PAUSE 20
'Set the Alarm2 Time ' Commented out..Alarm2 not used in this appl.
'I2CWrite SDA, SCL, RTC, Alm2min,[A2MINs,A2hr,A2day]
'Pause 20
' Clear STATUS and set CONTROl registers
I2CWrite SDA, SCL, RTC, StatusReg,[$00] ' Clear STATUS register
PAUSE 20
I2CWrite SDA, SCL, RTC, ContReg,[%00000101]
' Starts the oscillator enables INTA
' interrupt from A1F. WORKS as intended!!
Pause 20
'Post setup test to see if Time set correctly by reading EEPROM stored time
I2CREAD SDA, SCL, RTC, SecReg,[sec,MINs,hr,day,date,mon,yr]
PAUSE 20
WRITE 19,sec 'Write time to EEPROM for check after post run test
I2CREAD SDA, SCL, RTC, MinReg,[MINs]
PAUSE 20
WRITE 21,MINs
I2CREAD SDA, SCL, RTC, HourReg,[hr]
PAUSE 20
WRITE 23,hr
Return
Move_Delay: ' Subroutine used during text moving on an LCD
'==========
' Function used for text moving
Pause 500 ' You can change the moving speed here
Return
' If the user program ends by getting to the last statement of the
' program at an END instruction, the MCU will SLEEP and await a wakeup.
END
Bookmarks