Code:
' PIC 16f886 (28 pin)
' Connections:
' --------------------
' LCD:
'
' PORTB.2 ' LCD RS bit
' PORTB.3 ' LCD Enable Bit
' PORTB.4 ' LCD Data
' PORTB.5 ' LCD Data
' PORTB.6 ' LCD Data
' PORTB.7 ' LCD Data
' PORTC.1 ' LCD Backlight (20mA)
' PORTC.2 ' LCD Power Vdd +5V ~1.5mA
' ------------------------
' ' Buttons:
' PORTC.3 ' Enter / Confirm / Run Up / increase
' PORTC.4 ' Forward
' PORTC.5 ' Back
' PORTC.6 ' Down / decrease
' PORTC.7 ' Up / increase
' ----------------------------
' ' Solar Charge Control:
' PORTC.0 ' To depletion mode MOSFET in series with Solar panel & Battery pack
' -----------------------------
' ' Solar Energy Detect:
' PORTA.2 ' ADC or Input to determine if Solar panel is producting power
' -----------------------------
' ' Battery Level:
' PORTA.3 ' ADC Monitor battery level (state of charge / Charging)
' ---------------------------
' ' Oscillator:
' PORTA.6 ' 4 MHZ Xtal
' PORTA.7 ' 4 MHZ Xtal
' -----------------------------------
' ' Temperature Sensor
' PORTA.5 ' DS1821 Digital temperature sensor
' --------------------------------
'
' EEPROM Locations
' 0 = Alarm temperature set (trip) point
' 1 = Battery level for compare to current batt level to determine charging or not
' 2 = Daily High temperature
' 3 = Daily Low temperature
'
'
'
' CONSTANTS
sol_con con 500 ' Set point where Solar array has enough sun to set flag "sun_up"
'
' Define LCD pins
DEFINE LCD_DREG PORTB ' Sets LCD Data Port to Port-B instead of default Port A
DEFINE LCD_DBIT 4 ' Sets for use of PortB bits 4 thru 7 for the data
DEFINE LCD_RSREG PORTB ' Sets RS (Register Select) to Port B instead of default PortA.4
DEFINE LCD_RSBIT 2 ' Sets RS (Register Select) to bit 2 of port B (PORTB.2)
' ' Enable stays at the default PORTB.3
' Define oscillator
'
define OSC 4 ' Define Oscillator as 4 MHZ
'
' Define Variables
'
btn_up var PORTC.7 ' Momentary SPST push buttons for setting system options
btn_dwn var PORTC.6 ' Momentary SPST push buttons for setting system options
btn_back var PORTC.5 ' Momentary SPST push buttons for setting system options
btn_nxt var PORTC.4 ' Momentary SPST push buttons for setting system options
btn_entr var PORTC.3 ' Momentary SPST push buttons for setting system options
'
sun_lvl var word ' Holds solar energy level info from ADC 2
sun_up var bit ' Storage for sun is shining flag
sun_toggle var bit ' Toggle bit used for resetting daily Hi and Lo Temperatures
toggle_drag var bit ' Qualifier bit to drag toggle bit low with sun_up going low
batt_lvl var word ' Holds battery level info from ADC 3
batt_mem var byte ' Battery level written to memory after subtracting ~450 (indicates 0-100%)
batt_comp var bit ' Storage for flag when batt_lvl compared to batt_mem
charge var bit ' Storage for battery charging or discharging flag for LCD
chg_y_n var byte ' Holds charactor for LCD to display "Y" if charging "N" if not
solar_fet var PORTC.0 ' Solar array control ON / OFF (Depletion mode MOSFET)
'
lcd_lite var PORTC.1 ' LCD Backlight ON / OFF (~20 mA)
lcd_pwr var PORTC.2 ' LCD power down ON / OFF
'
tx_pwr var PORTA.0 ' Transmitter board power (5V into 3V reg.)
tx_alrm var PORTA.1 ' Transmitter - send alarm for low temperature condition
tx_tst var PORTA.4 ' Transmit / receive loop test
tx_confm var PORTB.0 ' Confirmation from receiver that transmitted data was received
tx_g_ng var bit ' Storage for transmit/receive go, no-go flag from tx_confm cycle
'
lcd_info var byte ' Index for which LCD Info to display on line two, 1-4...
' ' ...1=batt_lvl, 2=batt_chrg, 3=tx_g_ng, 4=alrm_set
m var byte ' Storage for mainloop counter
b var byte ' Storage for button set loop counter
counter1 var byte ' Storage for longer period counter 1
counter2 var byte ' Storage for longer period counter 2
'
' DS1821 digital temperature sensor
command var byte ' Storage for command
i var byte ' Storage for loop counter
temp var BYTE ' Storage for temperature
DQ var PORTA.5 ' Alias DS1821 data pin
DQ_DIR var TRISA.5 ' Alias DS1821 data direction pin
'
alrm_set var byte ' Store set point for alarm to trip at
day_hi var byte ' Storage for Daily High temperature EEPROM loc. 2
day_lo var byte ' Storage for Daily Low temperature EEPROM loc. 3
' Define ACD settings
DEFINE ADC_BITS 10 ' 10 bit A/D Conversion
DEFINE ADC_CLOCK 3 ' Set clock source (rc = 3)
ANSELH = 0 ' Set AN8 thru AN13 Off
ANSEL = %00001100 ' Set pins A.2 & A.3 (AN2, AN3) to analog input, the rest to digital
'ADCON0
ADCON1 = %10000000 ' Set up A/D converter - Right Just., VDD REF.
'
' Set Ports input/output
TRISA = %11101100 ' Set port A I/O
TRISB = %00000001 ' Set port B I/O
TRISC = %11111000 ' Set port C I/O
'SSPCON = 0 ' turn off serial comm
'Define ADC_SAMPLEUS 50 ' Set sampling time in uS (For different chip not needed)
'CM1CON0 = 0 ' Comparators off (Set to zero by default, not needed)
'CM2CON0 = 0 ' Comparators off (Set to zero by default, not needed)
'
'
'
' ALL Settings done by me TO HERE 04/02/2013
' Test parameters. These will be replaced by actual inputs..............
input PORTB.1
tx_g_ng = PORTB.1
lcd_info = 0
' End Test Parameters
' START-UP
high lcd_pwr ' Turn on the LCD display
pause 2000 ' Wait 1 sec for LCD to start up
low tx_pwr ' Turn off the transmitter. A loop will turn it on when needed
low tx_alrm ' Turn off alarm to ensure no accidental activation
low tx_tst ' Turn off Transmitter test pin, loop activates it when needed
write 1, 0 ' Put a zero in EEPROM location 1, clear Battery level in memory (batt_mem)
batt_mem = 0 ' Clear batt_mem - Set to 0
batt_comp = 0 ' Set battery compare flag to 0
read 0, alrm_set ' Get the alarm set temperature from memory
gosub get_temp ' Get current temperature
high solar_fet ' Turn on solar array to charge batteries
sun_lvl = 0 ' Set sun level reading to 0 to prevent false indication of charging
b = 0
' End Start-up
' Mainloop
mainloop:
Lcdout $fe, 1, " Main Loop" 'Display sign-on message
pause 1000
'm = 0
For m = 1 to 250 ' For Next loop generates X second delay while checking buttons
gosub check_button ' Check to see if a button has been pressed
pause 10 ' pause 10 milliseconds
next m ' Repeat loop 250 times
'
lcd_info = lcd_info + 1 ' Increment LCD info VAR, lcd_info count determines what info is displayed on the LCD
Lcdout $fe, 1, "LCD Info ", dec (lcd_info)
pause 1000
' if lcd_info = 3 then goto alarm_ck ' Check for am Alarm condition (temperature below the set point)
If lcd_info >= 6 then ' Reset LCD info VAR to 0 when count reaches 6
lcd_info = 0 ' Reset LCD info VAR to 0 when count reaches 6
counter1 = counter1 + 1 ' Longer period counter, used for longer delays in program (Hi Lo temp reset, Sleep?)
' if counter1 >= 5 then ' X cycles throught 250 counter above...
' gosub tx_test '
counter1 = 0 ' Reset counter 1 after GOSUB
'counter2 = 0 ' reset counter 2
' endif
gosub get_temp ' Get curent temperature
endif
'
' Go and display LCD infor based on lcd_info count
branchl lcd_info,[lcd_batt,lcd_chrg,lcd_tx,lcd_alrm_set,lcd_day_hi,lcd_day_lo]
'
get_temp:
Gosub init1821 ' Init the DS1821
command = $EE ' Start temperature conversion. Changed from 44h to EEh for DS1821
Gosub write1821
Pause 1000 ' Wait 1 second for conversion to complete
Gosub init1821 ' Do another init
command = $AA ' Read the temperature.
Gosub write1821
Gosub read1821
' Display the decimal temperature
' Lcdout $fe, 1, dec (temp >> 1),".",dec(temp.0 * 5)," degrees C" ' This line was the original code, replacement right below
' Convert to Degrees Fahrenheit
temp = temp * 9/5 + 32 ' Degree C to Degrees F ONLY work for positive Degrees C temps (32 F and above).
return
' Initialize DS1821 and check for presence
init1821:
Low DQ ' Set the data pin low to init
Pauseus 500 ' Wait > 480us
DQ_DIR = 1 ' Release data pin (set to input for high)
Pauseus 100 ' Wait > 60us
If DQ = 1 Then
Lcdout $fe, 1, "DS1821 not Found"
Pause 500
Goto mainloop ' Try again
Endif
Pauseus 400 ' Wait for end of presence pulse
Return
' Write "command" byte to the DS1821
write1821:
For i = 1 to 8 ' 8 bits to a byte
If command.0 = 0 Then
Gosub write0 ' Write a 0 bit
Else
Gosub write1 ' Write a 1 bit
Endif
command = command >> 1 ' Shift to next bit
Next i
Return
' Write a 0 bit to the DS1821
write0:
Low DQ
Pauseus 60 ' Low for > 60us for 0
DQ_DIR = 1 ' Release data pin (set to input for high)
Return
' Write a 1 bit to the DS1821
write1:
Low DQ ' Low for < 15us for 1
@ nop ' Delay 1us at 4MHz
DQ_DIR = 1 ' Release data pin (set to input for high)
Pauseus 60 ' Use up rest of time slot
Return
' Read temperature from the DS1821
read1821:
For i = 1 to 8 ' 16 bits to a word. * Changed to 8 for DS1821 Byte
temp = temp >> 1 ' Shift down bits
Gosub readbit ' Get the bit to the top of temp
Next i
Return
' Read a bit from the DS1821
readbit:
temp.7 = 1 ' Preset read bit to 1. Was temp.15 chgd to .7
Low DQ ' Start the time slot
@ nop ' Delay 1us at 4MHz
DQ_DIR = 1 ' Release data pin (set to input for high)
If DQ = 0 Then
temp.7 = 0 ' Set bit to 0. Was temp.15 chgd to .7
Endif
Pauseus 60 ' Wait out rest of time slot
Return
'
'
check_button:
if btn_up = 0 OR btn_dwn = 0 OR btn_back = 0 _ ' If any button is pressed
OR btn_nxt = 0 OR btn_entr = 0 then ' Go to button loop
High lcd_lite ' Turn on the LCD Backlight
goto button_loop
endif
return
' ADC
adc_loop: ' Get readings form the Analog to digital converters
'
ADCIN 2, sun_lvl ' Get ADC value from ADC 2, the solar array
if sun_lvl > sol_con then ' If the ADC reading is high enough...
sun_up = 1 ' ... consider the sun to be up (day time).
else
sun_up = 0 ' If ADC reading not high enough, the sun is considered down (night)
endif
ADCIN 3, batt_lvl ' Get ADC value from ADC channel 3
batt_lvl = (batt_lvl - 450) ' Remove bottom 4.4 volts or so from battery reading
if batt_lvl > 575 then batt_lvl = 0 ' Limit high battery level reading, too high = 0 (error)
return
' Battery - compare ADC volts to volts in EEPROM (memory) location 1
batt_mem_comp:
read 1, batt_mem
if batt_lvl >= batt_mem and _ ' If battery level is increasing or staying the...
batt_comp = 0 then batt_comp = 1 ' ...same set batt_comp 1 to indicate charging
if batt_lvl > batt_mem then write 1, batt_lvl ' As battery is charging write the new higher voltage to memory
if batt_lvl < (batt_mem - 15) then batt_comp = 0 ' If battery voltage falls (by about 0.2), Battery not charging...
' ... this gives a buffer for passing clouds etc.
' Check if battery charging (increasing or steady volts)
charge_ck_loop:
'
if sun_up = 1 and batt_comp = 1 then charge = 1 ' If sun is up and batt volts increasing then charging
if sun_up = 0 and batt_comp = 1 then charge = 0 ' If sun is not up, no charging
if sun_up = 1 and batt_comp = 0 then charge = 0 ' If battery volts aren't going up, no charging
if sun_up = 0 and batt_comp = 0 then charge = 0 ' No sun, no volts, No charge.
' Daily reset of batt_mem
reset_batt_mem:
'
if sun_up = 0 and batt_comp = 0 then write 1, 0 ' Write a 0 to EEPROM loc. 1 when
' sun goes down and batt discharging
return
'Compare, set, reset, & read from EEPROM daily Hi & Lo temperatures
'
compare_hi_lo:
if sun_up = 1 then toggle_drag = 1 ' When the sun comes up set toggle drag to 1
if sun_up = 0 and toggle_drag = 1 then sun_toggle = 0 ' If the sun is down set toggle drag to 0
if sun_toggle = 0 then ' If sun toggle is a 0 then reset daily hi & lo temperatures by...
write 2, temp ' Write the current temperature to EEPROM locatio 2 (Hi temp)
write 3, temp ' Write the current temperature to EEPROM locatio 3 (Lo temp)
sun_toggle = 1 ' Set suntoggle bit to 1
toggle_drag = 0 ' Set toggle drag to 0
endif
if temp > day_hi THEN write 2, temp ' If current temperature is greater than hi temp in...
' ...memory then write the new higher temperature
if temp < day_lo THEN write 3, temp ' If current temperature is less than lo temp in...
' ...memory then write the new lower temperature
read 2, day_hi ' Read the hi temperature into the variable day_hi
read 3, day_lo ' Read the lo temperature into the variable day_lo
Return
' LCD Display Information cycle
lcd_batt: '$DF hex for degree symbol
gosub adc_loop ' Get battery and Solar levels
Lcdout $fe, 1, " Temp is ", dec (temp), $DF, "F" ' Display current temperature
Lcdout $fe, $C0, "Battery At ", DEC (batt_lvl), "%" ' Display battery fullness %age
goto mainloop
lcd_chrg:
gosub batt_mem_comp ' Run battery voltage comparison loop if voltage...
' ... is increasing charge = 1
if charge = 1 then
chg_y_n = $59 ' 59 is Hex for "Y" if charging ($ indicates Hex)
Else
chg_y_n = $4E ' 4E is Hex for "N" if not charging
endif
Lcdout $fe, 1, " Temp is ", dec (temp), $DF, "F" ' Display current temperature
Lcdout $fe, $C0, "Charging?(Y/N) ", (chg_y_n) ' Display "Y" if charging & "N" if not
goto mainloop
lcd_tx:
if tx_g_ng = 1 then ' Check to see if the Tx/RX test passed
Lcdout $fe, 1, " Temp is ", dec (temp), $DF, "F" ' Display current temperature
Lcdout $fe, $C0, "Tx/Rx Test: PASS" ' Display that test passed
else
Lcdout $fe, 1, " Temp is ", dec (temp), $DF, "F" ' Display current temperature
Lcdout $fe, $C0, "Tx/Rx Test FAIL!" ' Display that test failed
PAUSE 1000 ' ... and pause for 5 sec to bring attention
endif
goto mainloop
lcd_alrm_set:
Lcdout $FE, 1, " Temp is ", dec (temp), $DF, "F" ' Display current temperature
Lcdout $FE, $C0, "Alrm Tmp Set ", DEC (alrm_set),$DF ' Display what the alarm is set...
goto mainloop ' ...to go off at
lcd_day_hi:
gosub compare_hi_lo
Lcdout $FE, 1, " Temp is ", dec (temp), $DF, "F" ' Display current temperature
Lcdout $FE, $C0, "Daily Hi ", DEC (day_hi), $DF, "F" ' Display the daily hi temperature
goto mainloop
lcd_day_lo:
Lcdout $FE, 1, " Temp is ", dec (temp), $DF, "F" ' Display current temperature
Lcdout $FE, $C0, "Daily Lo ", DEC (day_lo), $DF, "F" ' Display the daily lo temperature
goto mainloop
'
' What gets done when a button is pressed...
button_loop:
if btn_up = 1 and btn_dwn = 1 and btn_back = 1 _ ' If no buttons are pressed go to mainloop...
and btn_nxt = 1 and btn_entr = 1 then
goto mainloop
endif
button_set_loop:
if btn_up = 0 then up ' If the up button is pressed go to the Up loop
if btn_dwn = 0 then down ' If the down button is pressed go to the Down loop
if btn_back = 0 then back ' If the back button is pressed go to the Back loop
if btn_nxt = 0 then forward ' If the next button is pressed go to the Next loop
if btn_entr = 0 then ' If the enter button is pressed go to the Enter loop
goto enter
else
goto button_loop ' If no buttons are pressed run the button loop again...
endif ' ... which takes you to the main loop.
up:
while btn_up = 0 ' While the Up button is pressed do this loop...
pause 33 ' pause 33 milliseconds to debounce switch
alrm_set = alrm_set + 1 ' increase alarm set point by one degree F
pause 300 ' pause for 300 milliseconds
lcdout $FE, 1, dec (alrm_set) ' Display the alarm set point as it's changed
wend ' Repeat, increasing it 1 degree F every ~1/3...
' ... second until the switch is released
goto button_loop
down:
while btn_dwn = 0
pause 50
alrm_set = alrm_set - 1
pause 300
lcdout $FE, 1, dec (alrm_set)
wend
goto button_loop
back:
while btn_back = 0
pause 50
alrm_set = alrm_set - 1
pause 300
lcdout $FE, 1, dec (alrm_set)
wend
goto button_loop
forward:
while btn_nxt = 0
pause 50
alrm_set = alrm_set + 1
pause 300
lcdout $FE, 1, dec (alrm_set)
wend
goto button_loop
enter: ' Enter button loop
while btn_entr = 0 ' While the button is pressed...
pause 50 ' pause 0.05 seconds
wend ' Do this loop until button is released
write 0, alrm_set ' Write the new setting to memory location zero
lcdout $FE, 1, dec (alrm_set), " Has Been Set" ' Disp[lay what has been set
pause 3000 ' Leave that displayed for 3 seconds
goto mainloop ' go back to normal operation (main loop)
tx_test:
lcdout $FE, 1, " Transmit Test" ' Display that a tx test is being performed
LCDOUT $FE, $C0, " In Progress"
high tx_pwr ' Turn on the transmitter
pause 1000 ' Wait 1 seconds for the transmitter to stabilize
high tx_tst ' Output a high to the chosen data pin for the test
pause 1500 ' wait 1.5 sec for the signal to tbe received and confirmation sent back
if tx_confm = 1 then ' Check for confirmation from the receiver
tx_g_ng = 1 ' Set the Tx go/no go bit to 1 if confirmation was received...
else
tx_g_ng = 0 ' ...Otherwise set it to 0
endif
low tx_pwr ' Turn off the tranxmitter
low tx_tst ' set the transmit test pin back to low
IF tx_g_ng = 1 Then ' Display the result of the test...
lcdout $FE, 1, " Transmit Test"
LCDOUT $FE, $C0, " PASS"
pause 1500
Else
lcdout $FE, 1, " Transmit Test"
LCDOUT $FE, $C0, " FAIL"
pause 3000
endif
return
' Check for alarm condition (Low Temperature) and activate alarm as required
'
alarm_ck:
if temp <= alrm_set then ' Compare current temp to set temp, run loop if alarm
high tx_pwr ' Turn on transmitter
high lcd_pwr ' Turn on LCD
pause 2000 ' Wait for LCD to initialize
for i = 1 to 10 ' Run loop 10 times
high tx_alrm ' Alarm pin on Txmitter high
low lcd_lite ' turn off LCD backlight
LCDOUT $FE, 1, "**** ALARM! ****" ' Display alarm message
LCDOUT $FE, $C0, "TEMPERATURE LOW!" ' Display alarm message
gosub check_button ' Check for button press
pause 1500 ' Pause for 1.5 sec
low tx_alrm ' Turn off alarm pin o Txmitter
high lcd_lite ' Turn on LCD backlight
LCDOUT $FE, 1, "TEMPERATURE LOW!" ' Display alarm message
LCDOUT $FE, $C0, "**** ALARM! ****" ' Display alarm message
gosub check_button ' Check for button press
pause 1500 ' Pause for 1.5 sec
next i ' Repete loop
'gosub compare_hi_lo ' Reset
gosub get_temp ' Get gurrent temperature
endif
if temp > alrm_set then ' If current temp is back above set temp...
low tx_alrm ' Turn off the Alarm pin on Txmitter
low tx_pwr ' Turn off Txmitter power
low lcd_lite ' Turn off LCD Backlight after alarm or shortly after a button press
goto mainloop ' Go back to normal operation (main loop)
else
goto alarm_ck ' If temp is low go to alarm loop again.
endif
end
'''''' CODE Size Check """""""""""""""""
' SOLAR cut-off ' Mind where this is put (after the math on batt_lvl for display)
if batt_lvl >= 110 then ' If battery level 110% or more turn off solar array
Low solar_fet ' Puts ground (0 volts) on MOSFET gate
else
high solar_fet ' Puts +5 volts on MOSFET gate
endif
' SOLAR Powered cycle 'Goes in main loop
if sun_lvl >= 200 then
gosub run_day
else
gosub run_nite
endif
run_day:
' constant runnng loop with LCD display, backlite w/ good battery, tx tests
return
if batt_lvl >= 100 then
high lcd_lite
'Run loop
endif
run_nite:
' sleep cycle loop implemented, low power mode
return
' NIGHT Sleep mode
low lcd_pwr
low lcd_lite
'TRISA = %11101100 ' Set port A I/O Ok, No change
TRISB = %11111111 ' Set port B I/O was %00000001 for LCD out & tx_confm in
TRISC = %11111010 ' Set port C I/O was %11111000 buttons,
' ' C.2 LCD pwr, C.1 LCD Lite, C.0 sol-FET
ANSEL = 0 ' Turn off ADCs
'
FLAGS = 0 ' So LCD will reinitalize on wake-up
Sleep 60
ANSEL = %00001100 ' Reset(AN2, AN3) on
TRISB = %00000001 ' Set port B I/O
TRISC = %11111000 ' Set port C I/O
end
Bookmarks