Code:
' -----------------------[ Program Description ]--------------------------
' PICBASIC PRO program for Ultrasonic measurement & USB ops *
' 1) Initializes 2x16 LCD display with EasyPic6. *
' 2) Initializes DS1337 Real-time-clock. *
' 3) Takes range measurement from SRF02 Ultrasonic sensor upon *
' programmed interrupt time from DS1337 RTC & displays results *
' on 2x16 display. *
' 4) Also displays time/date at time of measurment. *
' 5) Also logs date-stamped measurement in EEPROM *
' 6) When USB connection is detected, transfers log data to host PC *
' & receives time/date corrections when sent from PC host. *
' *
'*************************************************************************
' -----------------------[ Revision History ]-----------------------------
' Version 1.0 Started on 03/22/10
' Version 1.5 Fully functional TX mode completed (06/01/10)
' Version 1.5.1 Having difficulty with SLEEP mode operation
'-----------------18F2550/4550 Port/PIN Connections ]--------------------
'I/O pin connections to the 18F4550 MCU are as follows:
'PORTA.0 (02) connected to LCD D4.
'PORTA.1 (03) connected to LCD D5.
'PORTA.2 (04) connected to LCD D6.
'PORTA.3 (05) connected to LCD D7.
'PORTA.4 (06) connected to LCD RS.
'PORTA.5 (07) connected to LCD E.
'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-3 (_INTA) of DS1337 RTC.
' Also senses pushbutton for manual range measurement.
'PORTB.3 (24) connected as input from SQW/_INTB pin-7 of DS1337 RTC.
'PORTB.4 (25) RB4 connected to Green LED to indicate USB connected & power on.
'PORTB.5 (26) RB5 not connected...used during test as mainloop heartbeat LED
'PORTB.6 (27) connected as PGC for ICSP connection.
'PORTB.7 (28) connected as PGD for ICSP connection.
'PORTC.0 (11) RC0 connected to control external power to Ultrasonic sensors.
'PORTC.1 (12) RC1 connected as an output to a Red LED for battery low.
'PORTC.2 (13) RC2 connected to LCD R/W.
'PORTC.3 (14) RC3/Vbus connected to 470 pf capacitor for USB
'PORTC.4 (15) normally connected as USB D-.
'PORTC.5 (16) normally connected as USB D+.
'PORTC.6 (17) normally connected as RS232 TX.
'PORTC.7 (18) normally connected as RS232 RX.
'INCLUDE "CodeSize.pbp" 'FOR TEST ONLY
DEFINE Measure 1
Pause 10 ' This statement is placed at beginning of code for ICD use
;-- if you un-comment these, you must comment the ones in the .inc file --
ASM ; 18F2550/4550, 8mhz crystal
__CONFIG _CONFIG1L, _PLLDIV_2_1L & _CPUDIV_OSC4_PLL6_1L & _USBDIV_2_1L
__CONFIG _CONFIG1H, _FOSC_HSPLL_HS_1H
__CONFIG _CONFIG2L, _PWRT_ON_2L & _BOR_OFF_2L & _VREGEN_ON_2L
__CONFIG _CONFIG2H, _WDT_OFF_2H & _WDTPS_512_2H
__CONFIG _CONFIG3H, _PBADEN_OFF_3H
__CONFIG _CONFIG4L, _LVP_OFF_4L & _XINST_OFF_4L
ENDASM
'--------------[ Define Hardware / Set Registers ]------------------------
DEFINE OSC 16 ' CPU oscillator set at 16 MHz for compiler read
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.
'DEFINE SHOWDIGITAL 1 ' When uncommented will show analog settings
' in Assembler Results window.
INCLUDE "DT_INTS-18.bas" ' Base Interrupt System
INCLUDE "ReEnterPBP-18.bas" ' Include if using PBP high priority interrupts
TRISA = 0 ' PortA output connections are used for LCD interface
TRISB = %00001100 ' RB2 & RB3 set as RTC Alarm1 & Alarm2 inputs
' PORTB.2 is also an input from switch grounding
' PortB.5 is used for a mainloop Heartbeat LED output
TRISC.2 = 0 ' PortC.2 is used for the LCD R/W connection
CLEAR
;--- Setup Interrupts ----------------------------------------------------
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler USB_ACTV_INT, _ACTVIFhandler, ASM, no ; first in list
INT_Handler USB_Handler
INT_Handler INT2_INT, _Range, PBP, yes
INT_Handler HLVD_INT, _LowVolt, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
endasm
' Per DT, DT_INTS already takes care of setting INTCON and RCON registers
' but this doesn't work unles INTCON2 set per below:
INTCON2 = %10000000 ' Set INT2 for falling edge (Bit4-low)
' on RTC's interrupt.
' Disable all PortB pull-ups (Bit7-high)
RTC_INT_FLG VAR INTCON3.1 'INT2 interrupt flag from RTC..DT_INTS handles
;--- Setup USB -----------------------------------------------------------
INCLUDE "DT_HID260.pbp"
DEFINE USB_VENDORID 6017
DEFINE USB_PRODUCTID 2000
DEFINE USB_VERSION 1
DEFINE USB_VENDORNAME "LodeStar Assoc. Inc."
DEFINE USB_PRODUCTNAME "FillMonitor"
DEFINE USB_SERIAL "002"
DEFINE USB_INSIZE 16 ; IN report is PIC to PC (8,16,32,64)
DEFINE USB_OUTSIZE 16 ; OUT report is PC to PIC
DEFINE USB_POLLIN 10 ; Polling times in mS, MIN=1 MAX=10
DEFINE USB_POLLOUT 10
; --- Each USB status LED is optional, comment them if not used ----------
; -- They can be assigned to any pin, and no further action is required --
DEFINE USB_LEDPOLARITY 1 ; LED ON State [0 or 1] (default = 1)
DEFINE USB_PLUGGEDLED PORTB,4 ; LED indicates if USB is connected
;DEFINE USB_TXLED PORTB,6 ; " " data being sent to PC
;DEFINE USB_RXLED PORTB,5 ; " " data being received from PC
'--- Variables & Aliases -------------------------------------------------
BATTLOW VAR BIT ' Flag that is set when battery is low
corHr VAR BYTE ' Corrected Hr from PC
corMINs VAR BYTE ' Corrected MINs from PC
corSecs VAR BYTE ' Corrected Secs from PC
corMon VAR BYTE ' Corrected month (Mon) from PC
corDate VAR Byte ' Corrected Date in Month from PC
corYr VAR BYTe ' Corrected Yr from PC
corA1hr VAR Byte ' Corrected Alarm1 hour from PC
corA1MINs VAR byte ' Corrected Alarm1 minutes from PC
corA1sec VAR byte ' Corrected Alarm1 seconds from PC
day_cnt VAR BYTE ' Counter for day number during monthly epoch
deviceID1 VAR BYTE ' Serial # of MCU (MSB)
deviceID2 VAR BYTE ' Serial # of MCU (LSB)
empty VAR BYTE ' Used as variable when empty buffer needed
stamp VAR Byte ' Stored Date stamp of measurment
ext_pwr VAR PORTC.0 ' Alias to control power to Ultrasonic sensors
I VAR Byte ' Index for loop counters
ID VAR BYTE(8) ' DeviceID array
J VAR BYTE ' EEPROM address index for storing measurements
LED_RED VAr PortC.1 ' Red LED used to indicate battery is low
LED_GRN VAR PortB.4 ' Green LED used to indicate Routine entries
LCD_Flag VAR Bit ' Flag when set indicates LCD is installed/used
ReportID VAR Byte ' Report ID for USB message
ResetClk VAR BIT ' Reset flag if set resets microcontroller clock
rng0 VAR w0.Byte0 ' LSB of range measurement when right justified
rng1 VAR w0.byte1 ' MSB of range measurement when right justified
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
X VAR WORD ' Used as a loop index during Main for USB
w0 var word ' W0 is the word value of the range measurement
' Constants
'==========
RTCdevice CON $D0 ' Device write address = %11010000 for DS1337 RTC
srfdevice CON $E0 ' Device address for SRF02 ultrasonic RangeFinder
;--- Initialize ----------------------------------------------------------
' Set FLAGS for current configuration
BATTLOW = 1 ' Test Low Battery Flag = 0
LCD_Flag = 1 ' Set for LCD installed/used; cleared otherwise
PR2 = 249 ' 0-1000 duty range
T2CON = %00000101 ' TMR2 on, prescaler 1:4
TRISB = 0
' Read MCU Serial Number from device ID Locations
TBLPTRU=$20 ' Address $200000
TBLPTRH=$00
TBLPTRL=$00
For i = 0 To 7
@ TBLRD*+ ; Get value and increment the address
ID(i) = TABLAT ; Store the byte as ID(i)
Next
deviceID1 = ID(0) ' MSB of MCU Device Serial Number
deviceID2 = ID(1) ' LSB of MCU Device Serial Number
deviceID1 = 0
deviceID2 = 2
WRITE 240, ID(0) ' Write fixed values to EEPROM
WRITE 241, ID(1)
'Initialize epoch indexes at time of powerup/reset
day_cnt = 0
WRITE 9, day_cnt ' Store new epoch initialized day_count
Pause 10
J = 16 ' Initialize EEPROM logging index @ start address
WRITE 10,J ' Store new epoch initialized J index
Pause 10
'Initialize LEDs to off
LOW LED_GRN
LOW LED_RED
'*******************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..previously set
'SDA VAR PORTB.0 ' I2C data pin..previously sset
'RTCdevice CON %11010000 ' RTC device write address..already set
' 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 LCD display
'=================
' Blink LED_GRN 3X to indicate entered IntializeDisplay
For i = 0 to 2
HIGH LED_GRN
Pause 500
LOW LED_GRN
PAUSE 500
Next
'-----SETUP FOR USING 2x16 LCD THAT IS INSTALLED 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
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
Return
SetTimeAndDate: ' Subroutine to set current time, date and alarms
'==============
' Blink LED_GRN 2X times to indicate entered SetTimeAndDate
For i = 0 to 1
HIGH LED_GRN
Pause 500
LOW LED_GRN
PAUSE 500
Next
HIGH ext_pwr ' Temporarily turn on power to SRF02 for I2C bus use
PAUSE 70 ' Delay to let I2C bus stabilize after SRF02 turn on
' Initialize the display & clock
' 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: 08:15:00 on 06-23-2010
hr=$08
MINs=$15
sec=$00
day=$03
mon=$06
date=$23
yr=$10
' Per MAXIM TechSupport, proper sequencing requires setting
' INTCN = 1, & A2IE=A1IE=0 before setting alarms.
I2CWrite SDA, SCL, RTCdevice, ContReg,[%00000101]
PAUSE 10
'Define ALARM1 FOR 08:16:00 & to alarm when secs match (1/min).
' This requires A1M1=0 and A1M2=A1M3=A1M4=1
' ($80+$A1xxx or 128d+A1xxx sets bit 7 as A1Mx = 1)
A1hr = %10001000 '$80+$08 = $88 = %10001000 = 136d, for A1M3 = 1
'Bit6 must be 0 for 24 hour clock
A1MINs = %10010110 '$80+$16 = $96 = %10010110 = 150d, for A1M2 = 1
A1sec = $00 '$00 = %00000000, for A1M1 = 0
A1day = %10000011 '$80+$03 = $83 = %10000011 = 131d, 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)
'Disabled in this application
' This requires A2M2 = A2M3 = A2M4 = 1
' (A2xxx + $80 or A2xxx + 128d sets bit 7 as A2Mx = 1)
'A2hr = $14 + $80 '$14 + $80 = %10010100, 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
' Write date/time setting to EEPROM
WRITE 242, Mon
WRITE 243, Date
WRITE 244, Yr
WRITE 245, hr
WRITE 246, MINs
Write 247, sec
'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 ' This code block 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 2000 ' 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 2000 ' 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
LOW ext_pwr ' Turn off power to the SRF02 at end of I2C use.
' This statement will distort the I2C bus & ext_pwr must be set
' HIGH again before any attempts are made to use the I2C bus.
Return
DisplayDateTime ' Subroutine to display date/time on LCD
'==============
LCDOut $fe,1 ' Clear Display
HIGH ext_pwr ' Temporarily turn on SRF02 power for I2C bus use
PAUSE 70 ' Delay to let I2C bus stabilize after SRF02 turn on
I2CREAD SDA, SCL, RTCdevice, SecReg,[sec,MINs,hr,day,date,mon,yr]
LCDOUT $fe,Line1,Hex2 mon,"/",hex2 date,"/", hex2 yr
LCDOUT $fe,Line2,hex2 hr,":",hex2 MINs,":",hex2 sec
LOW ext_pwr ' Turn off power to SRF02 until I2C bus is needed
Pause 2000
Return
' ----------------------[ END OF SUBROUTINES ]--------------------------
JumpPoint:
' This block FOR TEST ONLY...comment out for ops.
rng0 = 8 ' Initializes for data set
date = 0
For X = 16 To 220 Step 3 ' Write 45 ea 3 byte data sets to EEPROM
' Max EEPROM index is $DC or dec 220
date = date +1
rng0 = rng0+1
rng1 = 0
WRITE x, date ' Log Day of month date-stamp
WRITE x+1, rng0 ' Log LSB of range for day's measurement
WRITE X+2, rng1 ' Log MSB of range for day's measurement
NEXT
'Setup for starting Main Program
' Initialize LCD if installed before starting main loop?
IF LCD_Flag = 1 Then GOSUB InitializeDisplay
GOSUB SetTimeAndDate ' Set RTC time/date before starting mainloop
' Also turns SRF02 power off to save battery
' until I2C bus is needed again.
IF LCD_Flag = 1 Then ' This code block FOR TESTING ONLY
' Comment out for ops.
LCDOut $fe,1' Clear Display
LCDOUT $fe,Line1,"Entered"
LCDOUT $fe,Line2,"JumpPoint"
' Display Date/Time on LCD
GOSUB DisplayDateTime
ENDIF
' Enable the interrupts that are to be active during main loop.
@ INT_ENABLE INT2_INT ; enable external (INT) interrupts
'--------------------[ Begin Main Program Loop ]-------------------------
Main:
GOSUB DisplayDateTime
' Store current date/time in EEPROM
WRITE 242, Mon
WRITE 243, Date
WRITE 244, Yr
WRITE 245, hr
WRITE 246, MINs
Write 247, sec
' BufferOut (PIC to PC) Data Structure
' BufferOut(0) = 0, must always be zero as valid Report ID
' BufferOut(1) = DeviceID1 or MSB of Device Serial Number
' BufferOut(2) = DeviceID2 or LSB of Device Serial Number
' BufferOut(3) = mon
' BufferOut(4) = date
' BufferOut(5) = yr
' BufferOut(6) = hr (Pic hours time)
' BufferOut(7) = MINs (Pic minutes time)
' BufferOut(8) = sec (Pic seconds time)
' BufferOut(9) = stamp
' BufferOut(10) = rng0
' BufferOut(11) = rng1
' BufferOut(12) = BATTLOW (Low Battery Flag)
' BufferOut(13) = n/a ..0
' BufferOut(14) = n/a ..0
' BufferOut(15) = n/a ..0
' BufferOut(15) must be zero for sending data buffers (1) thru (14)
' ...else must send a text string with Buffer(15) = 1
@ ON_USBRX_GOSUB _HandleRX
IF J > 222 THEN ' If reached maximum EEPROM usage location...
J = 16 ' ..reset pointer to start of range data
Endif
READ j, stamp ' Read date stamp of measurment
READ J+1, rng0 ' Read range measurement from EEPROM
READ J+2, rng1
Pause 10
J = J + 3
' Send Data to PC
' Send device ID to PC
' Send current Date/Time to PC
' Send each EEPROM stored range measurement to PC
' Send current BATTLOW indicator to PC
ARRAYWRITE USBTXBuffer,[0,deviceID1,deviceID2,mon,date,yr, _
hr,MINs,sec,A1hr,A1mins,A1sec,BATTLOW,stamp,0,0]
GOSUB SendIfReady
' Place code here to put MCU and Ultrasonic Ranger in SLEEP mode.
' while waiting for clock or USB interrupt to wakeup from SLEEP mode.
' If USB is un-plugged, put MCU in deep sleep to save power.
' If the USB is still Plugged, no sense putting PIC to sleep because it
' will just wake up again in 1ms or less.
' The ACTVIE enable bit is already enabled by DT_HID.
' You don't need to do anything with it before going to sleep.
IF !Plugged THEN ' Go into deep sleep
UCON.1 = 1 ' Set the SUSPEND bit on the USB module
ENDIF
' NOTE: All of above code works fine and the USB_Handler and INT2_INT interrupts
' work as intended. However, as soon as the below @ SLEEP & @ NOP
' statements are un-commented, the unit does go into sleep mode, but
' then plugging in the USB will not wake it up.
' Nor does the INT2_INT interrupt continue to work....so MCU just stays
' in SLEEP mode until powerup/reset.
;@ SLEEP
;@ NOP
' Microcontroller is in Sleep State awaiting next interrupt from RTC or USB
GOTO Main
;@ EndSize(MainLoop) ; FOR TEST ONLY
;--- Send Data if Plugged and ready, otherwise discard -------------------
SendIfReady:
IF Plugged AND TX_READY THEN DoUSBOut
RETURN
;--- Wait till Ready to send or until unplugged --------------------------
WaitToSend:
WHILE Plugged and !TX_READY : WEND
IF TX_READY THEN GOSUB DoUSBOut
RETURN
;---- Receive incoming data...PORTB LEDS & corrected time/date -----------
HandleRX:
;@ INT_DISABLE INT2_INT ; disable external (INT) interrupts
IF LCD_Flag = 1 Then ' This code block for testing only
LCDOut $fe,1' Clear Display
LCDOUT $fe,Line1,"Entered"
LCDOUT $fe,Line2,"HandleRX"
Pause 1000 ' Delay for user to view LCD
ENDIF
' BufferIn (PC to PIC) Structure
'BufferIn(0) = ReportID => always 0
'BufferIn(1) is sent by PC as PORTB settings but used as a Flag
'ResetClk = BufferIn(1) ' PORTB is Reset flag..if set restarts MCU clock
'corHr = BufferIn(2) ' Corrected Hr setting from PC
'corMINs = BufferIn(3) ' Corrected MINs setting from PC
'corSecs = BufferIn(4) ' Corrected Secs setting from PC
'corMon = BufferIn(5) ' Corrected Mon setting from PC
'corDate = BufferIn(6) ' Corrected Date from PC
'corYr = BufferIn(7) ' Corrected Yr from PC
'corA1hr = BufferIn(8) ' Corrected Alarm1 hour from PC
'corA1MINs = BufferIn(9)' Corrected Alarm1 minutes from PC
'corA1sec = BufferIn(10)' Corrected Alarm1 seconds from PC
' Receive ResetClk and corrected FMReset flag/time/date from PC
ARRAYREAD USBRXBuffer,[ReportID,ResetClk,corHr,corMINs,corSecs,corMon, _
corDate,corYr,corA1hr,corA1MINs,corA1sec,empty,empty,empty,empty,empty]
IF ReportID = 0 Then ' Check for valid RX report
IF ResetClk = 1 Then ' Check if time correction sent
' Convert Decimal -> Hex coded time data
mon = (corMon DIG 1) * $10 + (corMon DIG 0)
date = (corDate DIG 1) * $10 + (corDate DIG 0)
yr = (corYr DIG 1) * $10 + (corYr DIG 0)
hr = (corHR DIG 1) * $10 + (corHR DIG 0)
MINs = (corMINs DIG 1) * $10 + (corMINs DIG 0)
sec = (corSecs DIG 1) * $10 + (corSecs DIG 0)
A1hr = A1hr + $80 ' Set Alarm1 to interrupt every 24 hours
A1hr = (corA1hr DIG 1) * $10 + (corA1hr DIG 0)
A1MINs = (corA1MINs DIG 1) * $10 + (corA1MINs DIG 0)
A1sec = (corA1sec DIG 1) * $10 + (corA1sec DIG 0)
Write 224,ResetClk ' Record Reset flag state in EEPROM
WRITE 225,mon ' Update PIC date/time from PC corrections
WRITE 226,date
WRITE 227,yr
WRITE 228,hr
Write 229,MINs
Write 230,sec
WRITE 231,empty
'Set the corrected time/date
I2CWrite SDA, SCL, RTCdevice, SecReg,[sec,MINs,hr,day, _
date,mon,yr]
PAUSE 10
'Set the Alarm1 Time (1 x every 24 hours)
I2CWrite SDA, SCL, RTCdevice, Alm1sec,[A1sec,A1MINs,A1hr]
PAUSE 10
LCDOut $fe,1' Clear Display
LCDOUT $fe,Line1,"SetAlm1"
LCDOut $FE,line2,hex2 A1hr,":",hex2 A1MINs,":",hex2 A1sec
PAUSE 2000 ' Delay so user can view display
ENDIF
Endif
' Read back time setting for verification
I2CREAD SDA, SCL, RTCdevice, SecReg,[sec,MINs,hr,day,date,mon,yr]
LOW ext_pwr ' Turn off power to the SRF02 at end of display.
' This statement will distort the I2C bus and ext_pwr
' must be set HIGH again before any attempts are made to
' use the I2C bus.
' Send RTC corrected time to PC as verification of corrections
ARRAYWRITE USBTXBuffer,[0,deviceID1,deviceID2,mon,date,yr, _
hr,MINs,sec,A1hr,A1Mins,A1sec,BATTLOW,stamp,0,0]
'hr,MINs,sec,A1hr,A1MIns,A1sec,BATTLOW,stamp,rng0,0]
GOSUB SendIfReady
' If ResetClk = 1, put code here to reset EEPROM memory index to J=16
' and POR of MCU for new logging epoch .
;@ INT_ENABLE INT2_INT ;re-enable external (INT) interrupts
return
'---------------------[ACTVIF - interrupt handler]------------------------
ACTVIFhandler:
IF UCON.1 THEN UCON.1 = 0 ' Clear the SUSPEND bit to wakeup USB module
@ INT_RETURN
'--------------------[ Range - interrupt handler ]------------------------
Range:
Enable Debug
IF LCD_Flag = 1 Then ' This code block FOR TESTING ONLY
LCDOut $fe,1' Clear Display
LCDOUT $fe,Line1,"Entered"
LCDOUT $fe,Line2,"Range:"
ENDIF
' Reset registers from SLEEP power save state to operational state
TRISA = 0 ' PortA output connections are used for LCD interface
TRISB = %00001100 ' RB2 & RB3 set as RTC Alarm1 (Alm1) & Alarm2 inputs
' PORTB.2 is an Alm1 interrupt or SW1 grounding input
' PORTB.4 is used during test as a Green LED heartbeat
' and as a USB connected indicator during ops
TRISC.1 = 0 ' PORTC.1 used during test as a RED LED output
TRISC.2 = 0 ' PortC.2 is used for the LCD R/W connection
ADCON1= %11111111 ' Set PortA to Digital I/O after SLEEP mode.
' Blink LED_GRN 1X to indicate entered Range ISR
HIGH LED_GRN
Pause 500
LOW LED_GRN
PAUSE 500
' Test for low battery condition that causes Vdd to go below 3.3 vdc
' Setup registers for HLVD module to support low voltage interrupt
' Step 1-Disable the module by clearing HLVDCON.4
HLVDCON.4 = 0 ' Implement Step 1
' Step2 HLVD3:HLVDL0=1000 'Set the trip point at Vdd=3.39 vdc
' Step3 HLVDCON.7=0 'Set VDIRMAG=0 to detect low voltage transition
' Step4 HLVDCON.4=1 'Enable the HLVD module
HLVDCON = %00011000 'Implements Steps 2-4
' Clear the HLVDIF interrupt flag (PIR2<2>)
PIR2.2 = 0
' Setup the interrupt and an ISR in your code and enable the interrupt
' where you want to test for low voltage
@ INT_ENABLE HLVD_INT ; enable HLVD interrupt
' If low voltage exists a HLVD interrupt will take place here and
' the ISR will blink the low voltage warning LED 5x.
HIGH ext_pwr ' Temporarily turn on power to SRF02 for I2C bus use
PAUSE 70 ' Delay to let I2C bus stabilize after SRF02 turn on
'DEFINE WRITE_USED 1 'Required if only writing WORD variables in v2.6
' Update day counter and address offset for day's measurements
READ 9,day_cnt ' Test if EEPROM data has been captured
' & cleared by PC & new monthly epoch
' started.
day_cnt = day_cnt + 1 ' Increment day counter
Write 9,day_cnt 'Update contents of day_count memory address
Pause 10
If J >= $DF Then ' Max logging EEPROM memory address is 223
J = 16 ' If allocated EEPROM already used, start over
ENDIF
' Make SRF02 Range Measurement
I2CWRITE SDA,SCL,$E0,0,[80]' Request start of ranging in inches
pause 100 ' Wait for ranging to finish
I2CREAD SDA,SCL,$E0,2,[rng1,rng0] ' Get ranging results
WRITE 240,Word w0 ' Write range to EEPROM
' Display time & range measurement on LCD display in inches
IF LCD_Flag = 1 Then ' This code block for testing only
LCDOut $FE,1:FLAGS=0:Pause 250 ' Clear Display
I2CREAD SDA, SCL, RTCdevice, SecReg,[sec,MINs,hr,day,date,mon,yr]
LCDOUT $fe,1
LCDOUT $fe,Line1,Hex2 mon,"/",hex2 date,"/",hex2 yr
LCDOUT $fe,Line2,hex2 hr,":",hex2 MINs,":",hex2 sec
Pause 200 ' Allow Time for user to view
LCDOUT $FE,1
LCDOut $FE,Line1,"Range:" ' Display on 1st line
LCDOut $FE,Line2,#w0," in." ' Display on 2nd line
ENDIF
PAUSE 3000 ' Allow Time for user to view
' Clear STATUS register & Alarm flags..ready for next interrupt
I2CWrite SDA, SCL, rtcdevice, StatusReg,[$00]
LOW ext_pwr ' Turn off power to the SRF02 at end of display.
' This statement will distort the I2C bus and ext_pwr
' must be set HIGH again before any attempts are made to
' use the I2C bus.
' Store range as date-stamped value in EEPROM
WRITE J+1,WORD w0 'Store day's range in EEPROM
PAUSE 10
Write J,date ' with day of month date-stamp
PAUSE 10
' Step pointer to next logging address in EEPROM
J = J + 3
WRITE 10,J 'Update contents of J index EEPROM memory address
Pause 10
PAUSE 470 ' Delay to permit I2C bus to stabilize after SRF02 off
@ INT_DISABLE HLVD_INT
Disable debug
' Resume Main Program
@ INT_RETURN
LowVolt:
BATTLOW = 1 ' Set low battery warning flag
' Blink LED_RED 5X to indicate Low Battery voltage detected
For i = 0 to 4
HIGH LED_RED
Pause 500
LOW LED_RED
PAUSE 500
Next
' Resume Main Program
@ INT_RETURN
End ' Safety measure to insure program stops if reaches here
Bookmarks