Code:
'STATUS: Compiles & assembles OK with CPU @ 8 MHz.
' Sets date/time/Alarm1 OK.
' Displays initialized date/time continuously (if LCD installed).
' On change interrupts from clock _INTA OK
' Logs time stamps for 1st interrupt into EEPROM.
' However no more _INTA interrupts are recognized and a voltmeter
' reveals the MCU pin connected to _INTA stays low thereafter with no
' more RBC_INT recognition.
'< FL_PIC16F886 >' ' First valid PIC found within the first 200 lines will
' highlight AND set device.
'***********************************************************************
' -----------------------[ Program Description ]----------------------------------------
' PICBASIC PRO program to set RTC & demo operation of a LCD/4-bit mode *
' 1) Initializes 2x16 or 2x8 LCD display with EasyPic6. *
' 2) Initializes DS1337 Real-time-clock & sets time/date/Alarm1. *
' (user must adjust code in SetTimeDate subroutine for desired *
' startup time/date/Alarm1 settings) *
' 3) This code sets Alarm1 to go off every minute..adjust as needed. *
' 4) Alarm1 is used as RBC_INT interrupt by MCU. *
' 5) Also displays date/time on LCD every second. *
' *
'*************************************************************************
'-----------------[ 16F886 Port/PIN Connections ]------------------
'I/O pin connections to the 16F886 MCU are as follows:
'PORTA.0 (02) output to LCD D4 & also multiplexed as input from LM34.
'PORTA.1 (03) output to LCD D5.
'PORTA.2 (04) output to LCD D6 & also mulitplexed as Vref+ input.
'PORTA.3 (05) output to LCD D7.
'PORTA.4 (06) output to LCD RS.
'PORTA.5 (07) ouput to LCD E.
'PORTB.0 (21) output as I2C SDA to DS1337.
'PORTB.1 (22) output as I2C SCL to DS1337.
'PORTB.2 (23) input as interrupt on change from pin-3 (_INTA) of DS1337 RTC.
' Also senses pushbutton for manual interrupt for RangeFinder.
'PORTB.3 (24) input from SQW/_INTB pin-7 of DS1337 RTC.
'PORTB.4 (25) set as A/D Channel 11 for analog input from LM34 output
'PORTB.5 (26) unconnected
'PORTB.6 (27) connected as PGC for ICSP connection.
'PORTB.7 (28) connected as PGD for ICSP connection.
'PORTC.0 (11) output RC0 to control external power to SRF02 & LM34.
'PORTC.1 (12) output RC1 to MSEL on WiFi Module
'PORTC.2 (13) output RC2 to LCD R/W or to _RES_PD on WiFi module
'PORTC.3 (14) reserved to connect as Vbus to 470 pf capacitor for USB
'PORTC.4 (15) output RC4 to a Red LED for low voltage warning.
'PORTC.5 (16) output RC5 to Green LED for routine entry indicator.
'PORTC.6 (17) output as TX to WiFi module RXD.
'PORTC.7 (18) output as RX to WiFi module TXD.
'--------------[ Define EEPROM usage ]-----------------------------------
'09 = day_cnt ' Most recent day_cnt
'10 = J ' Index for counting interrupts received
'11 = hr ' Hour time from RTC after setting RTC
'12 = MINs ' Minutes time from RTC after setting RTC
'13 = sec ' Seconds time from RTC after setting RTC
'14 = A1hr ' Alarm1 hour time from RTC after setting RTC
'15 = A1MINs ' Alarm1 minutes time from RTC after setting RTC
'16+J = hr ' Log Hour
'17+J = MINs ' Log Minutes
'18+J + sec ' Log Seconds
'240 = ID(0) ' LSB of device ID
'241 = ID(1) ' MSB of device ID
'242 = mon ' Month when clock was set
'243 = date ' Date when clock was set
'244 = yr ' Year when clock was set
'INCLUDE "CodeSize.pbp" 'FOR TEST ONLY
DEFINE Measure 1
;@ StartSize(LOOKUP) 'FOR TEST ONLY
Pause 10 ' This statement is placed at beginning of code for ICD use
'Disable Debug
' Set configuration fuses for the MCU
' To use standard config include file, comment out below statement
@ __config _CONFIG1, _HS_OSC & _WDT_OFF & _MCLRE_OFF & _LVP_OFF & _CP_OFF
'--------------[ Define Hardware / Set Registers ]------------------------
DEFINE OSC 8 ' MCU uses external 8 MHz crystal
DEFINE I2C_SLOW 1 ' Set i2c to the standard speed
DEFINE I2C_HOLD 1 ' Enable recieving i2c device to pause communication
Include "Modedefs.Bas" ' Mode definitions for Debug,Serin/out,
' Shiftin/out, Xin/out.
INCLUDE "ALLDIGITAL.pbp" ' Sets all registers for digital ops.
' User must make sure AllDigital.pbp file
' is in same or higher directory location as
' this source code before compiling.
'DEFINE SHOWDIGITAL 1 ' When uncommented will show analog settings
' in Assembler Results window.
INCLUDE "DT_INTS-14.bas" ' Base Interrupt System
INCLUDE "ReEnterPBP.bas" ' Include if using PBP high priority interrupts
' Allows re-entry to PBP from a High Priority
' ASM interrupt. Must have DT_INTS-14.bas
' loaded first.
TRISA = 0 ' Set all PortA initally to outputs for LCD use
TRISC = %10000000 ' Set PortC to all outputs except PortC.7 which is
' reserved as RX input.
' PortC.1 is output for MSEL to WiFi module
' PortC.2 is used for the LCD R/W connection when
' LCD present..otherwise as _RES_PD to Wifi Module.
' PortC.4 is output to LED_RED
'****************** SETUP PORTB for RBC_INT Interupt *************
'--- Setup Interrupts ----------------------------------------------------
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler RBC_INT, _Alarm, PBP, yes
; INT_Handler HLVD_INT, _VoltLow, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM
' Per DT, DT_INTS already takes care of setting INTCON register
' but this code doesn't work unles below registers also set as indicated:
IOCB.2= 1 ' ENABLE IOC INERRUPT ON PORTB.2 (RB2) for Alarm1
TRISB = %00010100 ' RB2 set as input from RTC Alarm1
' PORTB.2 is also an interrupt from manual switch GND
' PORTB.4 is set for input as A/D Channel 11
WPUB = 0 ' DISABLE all PortB pull-ups
CM1CON0 = 0 ' DISABLE COMPARATORS
CM2CON0 = 0 ' DISABLE COMPARATORS
'--- Variables & Aliases -------------------------------------------------
CNT VAR BYTE ' Counter for timing
CNT = 0
day_cnt VAR BYTE
D_LAY VAR BYTE ' Stores delay value
dummy VAR BYTE ' dummy variable for resetting PortB mismatch
ADR VAR BYTE[9] ' Array stores IP address
deviceID1 VAR BYTE ' Serial # of MCU (MSB)
deviceID2 VAR BYTE ' Serial # of MCU (LSB)
ext_pwr VAR PortC.0 ' MCU Controlled external power to SRF02 & LM34
I VAR Byte ' Index for loop counters
ID VAR BYTE[8] ' Array for storing device ID parameters
J VAR BYTE ' Index to EEPROM address for logging
LCD_Flag VAR Bit ' Flag when set indicates LCD is installed/used
LED_RED VAR PortC.4 ' Red LED
LED_GRN VAR PortC.5 ' Green LED used to indicate Routine entries
logflag VAR BYTE ' Flag used in ISR to indicate to log time stamp
LowVolt VAR BIT ' Flag that is set when MCU power source is low volt
MSEL VAR PORTC.1 ' iChip Mode Select
_RES_PD VAR PORTC.2 ' iCHIP RESET/Power-Down
OK VAR BYTE ' Captures K in I/OK FTP return messages for testing
SCL VAR PORTB.1 ' I2C clock pin
SDA VAR PORTB.0 ' I2C data pin
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 op
temp VAR WORD ' Stores measured temperature
TX VAR PORTC.6 ' Serial interface to iWiFI module
RX VAR PORTC.7
VDD VAR WORD ' Used in low voltage detection algorithm
wsave VAR BYTE $70 SYSTEM ' Required per DT post 108282
CLEAR ' Clear all RAM (sets all VAR declarations to zero)
'ENABLE DEBUG
'--- Initialize ----------------------------------------------------------
' User must set FLAGS for current configuration
'LowVolt = 0 ' Initalize low voltage Flag
LCD_Flag = 0 ' Clear if LCD un-installed; set otherwise
'--- Read MCU Serial Number is stored in 4 ea device ID Locations
' at memory locations Addresses $2000 to $2003 but can't be read at run time
deviceID1 = ID(0) ' MSB of MCU Device Serial Number
deviceID2 = ID(1) ' LSB of MCU Device Serial Number
WRITE 240, ID(0) ' Write fixed values to EEPROM for test
WRITE 241, ID(1)
'--- Initialize epoch indexes at time of powerup/reset
day_cnt = 0
WRITE 6, day_cnt ' Store new epoch initialized day_count
'*******************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
' 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
RTCdevice CON $D0 ' Device write address = %11010000 for RTC
' This is a list of allowable clock contrl settings, one which
' must be setup in the SetTimeAndDate subroutine for intended use.
'(see data sheet pgs 9-10 for explanation)
'contrl CON %00000000 ' Starts oscillar, sets the SQW/OUT to
' 1Hz pulse, no Alarm interrupts 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!!
'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 %000xx101 ' Starts oscillator, enables INTA interrupt
' from A1F, INTB/SQW off. WORKS OK!
'contrl CON %000xx110 ' Starts oscillator, enables INTB interrupt
' from A2F. WORKS OK!
'contrl CON %000xx111 ' Starts oscillator, enables INTA interrupt
' from A1F or INTB from A2F. WORKS OK!
' Both interrupts staggered 30 secs apart.
'contrl CON %00011111 ' Starts oscillator, sets RS1 & RS2,
' enables INTA interrupt from A1F
' or A2F starts 32.768khz on SQW output.
' WORKS OK!
'contrl CON %00011001 ' Starts oscillator, sets RS1 & RS2,
' clears INTCN to enable INTA interrupt
' from A1F with 32.768kHz on SQW output.
' SQW output WORKS OK but INTA doesn't!
'contrl CON %00011010 ' Starts oscillator, sets RS1 & RS2,
' clears INTCN to enable INTA interrupt
' from A2F with 32.768kHz on SQW. WORKS OK!
' RTC Address definitions
SecReg CON $00 ' seconds address (00 - 59)
' Must set MSB of SecReg to a 0 to enable RTC
MinReg CON $01 ' minutes address (00 - 59)
HrReg 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)
MonReg 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..not used in this application
'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 of week (Sunday = 7)
date VAR BYTE ' date in month
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..not used in this application
'A2MINs VAR BYTE ' minutes
'A2hr VAR BYTE ' hours
'A2day VAR BYTE ' day
GOTO JumpPoint ' Jump over all subroutines so they don't execute on powerup
' ----------------------[ START SUBROUTINES ]--------------------------
InitializeDisplay: ' Subroutine to initialize 2X16 or 2x8 LCD display
'==========
'--SETUP FOR USING 2x16 or 2x8 LCD INSTALLED on PROTOBOARD IN EASYPIC6--
' LCD DEFINES FOR USING 2x16 LCD with PortA in EASYPIC6
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 connect 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_RWREG PORTC ' LCD read/write port
DEFINE LCD_RWBIT 2 ' LCD read/write bit
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 1500' Command Delay (uS)
DEFINE LCD_DATAUS 44 ' Data Delay (uS)
' DEFINE LCD Control Constants
Line1 CON 128 ' Point to beginning of line 1 ($80)
Line2 CON 192 ' Point to beginning of line 2 ($C0)
' Test the LCD during initialization
'IF LCD_Flag = 1 THEN ' Uncomment FOR TESTING ONLY
'LCDOUT $fe,1:FLAGS=0:PAUSE 250 ' Clear Display
'LCDOUT $fe,Line1,"LCD TEST" ' Display on 1st line
'LCDOUT $fe,Line2,"POWER ON" ' Display on 2nd line
'PAUSE 2000
'ENDIF
Return
SetTimeAndDate: ' Subroutine to set current time, date and alarms
'==========
' Blink LED_GRN 2X times to indicate entered SetTimeAndDate
FOR I = 0 TO 1
TOGGLE LED_GRN
Pause 500
Toggle LED_GRN
PAUSE 500
Next
' Initialize the display & clock
Pause 100 ' Wait for LCD to startup after power on
' 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: 18:22:00 on 10-06-2011
hr=$18
MINs=$22
sec=$00
day=$05
mon=$10
date=$06
yr=$11
' Per MAXIM TechSupport, proper sequencing requires setting
' INTCN = 1, & A2IE=A1IE=0 in controle register before setting alarms.
I2CWRITE SDA, SCL, RTCdevice, ContReg,[%00000100]
PAUSE 10
'Define ALARM1 FOR 18:21:00 & to alarm 1/min
' For 1/min requires A1M1=0 and A1M2=A1M3=A1M4=1
' For 1/hr requires A1M1=A1M2=0 and A1M3=A1M4=1
' (A1xxx + $80 or A1xxx + 128d sets bit 7 as A1Mx = 1)
A1hr = %10011000 '$18 + $80 = %10011000, for A1M3 = 1
'Bit6 must be 0 for 24 hour clock
A1MINs = %10100001 '$23 = %10100011, for A1M2 = 1
A1sec = %00000000 '$00 = %00000000, for A1M1 = 0
A1day = %10000101 '$05 + $80 = %10000101, for A1M4 = 1
'DY/_DT Bit6 = 0 for using Day of month alarm
'Define ALARM2 FOR 12:01:00 & to alarm once per minute (00 secs)
'Disabled in this application
' This requires A2M2 = A2M3 = A2M4 = 1
' (A2xxx + $80 or A2xxx + 128d sets bit 7 as A2Mx = 1)
'A2hr = $12 + $80 '$12 + $80 = %10010010, for A2M3 = 1
'Bit6 must be 0 for 24 hour clock
'A2MINs = $01 + $80 '$01 + $80 = %10000001, for A2M2 = 1
'A2day = $07 + $80 '$07 + $80 = $10000111, for A2M4 = 1
'DY/_DT Bit6 = 0 for using Day of month alarm
' Per MAXIM TechSupport, reset control register for desired Alarm
' after setting alarms.
I2CWrite SDA, SCL, RTCdevice, ContReg,[%00000101]
PAUSE 10
'Set the main Time
I2CWrite SDA, SCL, RTCdevice, SecReg,[sec,MINs,hr,day,date,mon,yr]
PAUSE 10
'Set the Alarm1 Time
I2CWrite SDA, SCL, RTCdevice, Alm1sec,[A1sec,A1MINs,A1hr,A1day]
PAUSE 10
'Set the Alarm2 Time ' Alarm2 disabled for this application
'I2CWrite SDA, SCL, RTCdevice, Alm2min,[A2MINs,A2hr,A2day]
'PAUSE 10
'IF LCD_Flag = 1 THEN ' Uncomment FOR TESTING ONLY
'Test to see if Time set correctly by displaying on LCD
'I2CREAD SDA, SCL, RTCdevice, SecReg,[sec,MINs,hr,day,date,mon,yr]
'LCDOut $fe,1 ' Clear Display
'LCDOUT $fe,Line1,"SetTime"
'LCDOUT $FE,LINE2,hex2 hr,":",hex2 MINs,":",hex2 sec
'PAUSE 3000 ' Delay so user can view display
'Test if Alarm1 set correctly by displaying stored Alarm1 time
'I2CREAD SDA,SCL,RTCdevice,Alm1sec,[A1sec,A1MINs,A1hr,A1day]
'LCDOut $fe,1 ' Clear Display
'LCDOUT $fe,Line1,"SetAlm1"
'LCDOut $FE,line2,hex2 A1hr,":",hex2 A1MINs,":",hex2 A1sec
'PAUSE 3000 ' Delay so user can view display
'ENDIF
' Clear STATUS and set CONTROL registers
I2CWrite SDA, SCL, RTCdevice, StatusReg,[$00]
PAUSE 10
I2CWrite SDA, SCL, RTCdevice, ContReg,[%00000101]
' Starts oscillator, no interrupts enabled.
' WORKS as intended!!
Pause 10
RETURN
ISR:
' Put code here for actions to take due to RTC Alarm1 interrupt
IF logflag = 1 THEN 'RTC interrupt has occured..start ISR
'LOW LED_GRN
' Blink the RED LED 1 sec 3x
FOR I = 0 TO 2
TOGGLE LED_RED
PAUSE 1000
TOGGLE LED_RED
PAUSE 1000
NEXT
PAUSE 1000
IF J > 220 THEN ' If logging space is full start over with logging
J = 0 ' Reset logging index to start of logging space
' Logging space covers time stamps for 220 interrupts
ENDIF
' Read current time/date..display if LCD installed
'DISABLE ' Disable PortB interrupts during I2C bus use
I2CREAD SDA, SCL, RTCdevice, SecReg,[sec,MINs,hr,day,date,mon,yr]
'ENABLE
PAUSE 20
'IF LCD_Flag = 1 THEN ' Uncomment FOR TESTING ONLY
'LCDOUT $fe,1 ' Clear Display
'LCDOUT $FE,LINE2,hex2 hr,":",hex2 MINs,":",hex2 sec
'PAUSE 1000
'ENDIF
'Put code here to log time of interrupt
WRITE 16+J, hr ' Log timestamp for Alarm1 to EEPROM
WRITE 17+J, MINs
WRITE 18+J, sec
WRITE 19+J, logflag
J = J+4
'LOW LED_RED
logflag = 0 ' Reset logflag
ENDIF
RETURN
' ----------------------[ END OF SUBROUTINES ]--------------------------
JumpPoint:
'Setup for starting Main Program
IF LCD_Flag = 1 Then GOSUB InitializeDisplay ' Initialize LCD before
' starting mainloop
GOSUB SetTimeAndDate ' Set RTC time/date before starting mainloop
'IF LCD_Flag = 1 THEN ' This code block FOR TESTING ONLY
'LCDOut $fe,1' Clear Display
'LCDOUT $fe,Line1,"Entered"
'LCDOUT $fe,Line2,"JumpPoint"
'Pause 2000
'ENDIF
'Initialize epoch indexes at time of powerup/reset
day_cnt = date
WRITE 6, day_cnt ' Store new epoch initialized day_count
Pause 20
J = 0 ' Initialize EEPROM logging index
' Log program start date/time/Alarm1
WRITE 7,mon
WRITE 8,date
WRITE 9,yr
WRITE 11,hr
WRITE 12,MINs
WRITE 13,sec
WRITE 14,A1hr
WRITE 15,A1MINs
'Initialize LEDs to off before mainloop
LOW LED_GRN
LOW LED_RED
logflag = 0 ' Clear logflag before mainloop
' Enable the interrupts that are to be active during main loop.
@ INT_ENABLE RBC_INT ; enable RBC interrupts
;@ INT_ENABLE LVD_INT ; enable LVD interrupt
'--------------------[ Begin Main Program Loop ]-------------------------
;@ StartSize(MainLoop) ; FOR TEST ONLY
mainloop:
' Blink Green LED 1x at start of mainloop...Uncomment FOR TEST ONLY
TOGGLE LED_GRN
PAUSE 250
TOGGLE LED_GRN
PAUSE 2000
'Check to see if Alarm1 Interrupt occured and service if it did
DISABLE 'Disable PortB interrupts during ISR routine
GOSUB ISR
ENABLE
' Display current Date/Time if LCD installed
IF LCD_Flag = 1 THEN
LCDOUT $fe,1 ' Clear Display
LCDOUT $fe,Line1,HEX2 mon,"/",HEX2 date,"/", HEX2 yr
LCDOUT $FE,Line2,HEX2 hr,":",HEX2 MINs,":",HEX2 sec
PAUSE 250
ENDIF
WRITE 255,9 'Test if executing to this location
GOTO mainloop
;@ EndSize(MainLoop) ; Uncomment FOR TEST ONLY
'--------------------[ Begin Interrupt Handlers ]------------------------
Alarm:
' Blink Red LED 3x at start of Alarm interrupt...Uncomment FOR TEST ONLY
FOR I = 0 TO 2
TOGGLE LED_RED
PAUSE 250
Toggle LED_RED
PAUSE 250
NEXT
PAUSE 2000
logflag = 1 ' Set flag to log this RB2 interrupt in mainloop
dummy = PORTB ' Read PortB to eliminate mismatch on interrupt
' Resume Main Program where Interrupt happened
@ INT_RETURN
'------------------{ End of Interrupt Handlers }-------------------------
END ' Safety measure to insure program stops if reaches here
Bookmarks