' ************** Water_Pump_LCD.bas ************** ' This program runs on a PICAXE-20X2. It reads the user input water volume to pump ' and time between pump cycles from a pot and displays the status on an ' HD44780 compatible 16x2 LCD display.Timing comes from from a 1Hz input derived from ' the 60 Hz power line. Timing cycle runs contiuously, pumps water at the set time, ' resets the time count to zero and repeats. ' ***** Constants ***** symbol EnablePin = C.0 ' LCD Enable pin connected to C.0 symbol RegSelPin = C.1 ' LCD Register Select pin connected to C.1 symbol Setup = C.2 ' Set button used to input time and volume connected to C.2 symbol Test = C.3 ' Test button (configured as toggle on/off) connected to C.3 symbol Pump = C.4 ' Signal out to the pump circuit connected to C.4 symbol LED = C.5 ' LED indicating 1 Hz in is received and Picaxe is counting to C.5 symbol state = pinC.6 ' 1 Hz timing signal comes in on C.6 symbol Pot1 = C.7 ' Potentiometer for setting input values connected to C.7 ' ***** Variables ***** symbol index = b1 ' used as counter in For-Next loops symbol intgval= b2 ' used to hold each integer value sent to LCD symbol Time_Count = b3 ' used to hold time values input on the pot symbol rpt = b4 ' used for button repeat count symbol flag = b5 ' used for branching code during initial data inputs symbol timeout = b6 ' N/A used during testing only symbol h = b7 ' variable that tracks hours counted symbol m = b8 ' variable that tracks minutes counted symbol s = b9 ' variable that tracks seconds counted symbol hrs = b10 ' the time counter target hours value symbol mins = b11 ' the time counter target minutes value symbol secs = b12 ' the time counter target seconds value symbol x = b13 ' variable used for toggling pump on/off when test button is pressed symbol pulse = b14 ' variable used to track last state of incoming 1 Hz square wave symbol MSB = b15 ' used to store most significant bit of data fed to LCD symbol Tsecs = w18 ' variable used to hold mins + secs in secs symbol Vol = w19 ' used to hold desired water volume values input on the pot symbol VolMin = w20 ' time (in mins) to pump programmed volume based on 750 ml/min pump rating symbol VolSec = w21 ' time (in secs) to pump programmed volume based on 750 ml/min pump rating symbol char = w22 ' used for character to be sent to LCD symbol ValueX = w23 ' variable used to temporarily hold characters for display symbol pumptimeS = w24 ' calculated pump on time in secs derived from volume input symbol pumptimeM = w25 ' calculated pump on time in mins derived from volume input symbol y = w26 ' variable used temporarily for calculating pump on time ' ***** Directives ***** #com 3 ' specify download port #picaxe 20X2 ' specify processor #no_data ' save time downloading #terminal off ' disable terminal window ' ***** Main Program ***** dirsB = %11111111 ' set all portB pins as outputs dirsC = %00110011 ' set portC input/outputs ' ***** Initialize the LCD ***** pause 200 ' pause 200 mS for LCD initialize as per HD44780 specs char = 56 ' setup for 8-bits, 2 lines & 5X8 display gosub CmdLCD ' send instruction to LCD char = 12 ' display on, cursor off gosub CmdLCD ' send instruction to LCD char = 1 ' clear display, go home to line 1 of LCD display gosub CmdLCD ' send instruction to LCD wait 1 ' ***** Send intro text to line 1 of the LCD ***** for index = 0 to 15 lookup index, ("Water Pump Timer"), char ' read text characters in string gosub TxtLCD ' send text in the string to LCD next index Wait 2 char = 1 ' clear display,go home to line 1 of LCD display gosub CmdLCD ' send instruction to LCD for index = 0 to 15 lookup index, ("Programming mode"), char ' read text characters in string gosub TxtLCD ' send text in the string to LCD next index Wait 2 gosub Volume ' ***** Subroutines ***** Volume: ' sub to read in desired water volume to pump from pot char = 1 ' clear display, go home to line 1 of LCD display gosub CmdLCD ' send instruction to LCD for index = 0 to 15 lookup index, ("Enter Volume ml "), char ' read text characters in string gosub TxtLCD ' send text in the string to LCD next index do readadc C.7, Vol ' read ADC value on pin C.7 from pot in to Vol variable let Vol = Vol*10 max 2500 ' convert pot ADC value to allow for up to 2500 ml volume let VolSec = Vol*2/25 ' calculate time (in secs) to pump programmed volume based on 750 ml/min pump rating ' Note use 2/25 = 60/750 = 0.08. Because using 60/750 exceeds Word variable capacity char = 192 ' go to line 2 of LCD display gosub CmdLCD ' send instruction to LCD let ValueX = Vol ' put Vol into temp variable for manipulation gosub IntgOnly ' go to sub to display volume set by pot on to LCD char = 197 ' move LCD cursor right for spacing gosub CmdLCD ' send instruction to LCD for index = 0 to 1 lookup index, ("ml"), char ' read out "ml" text to LCD gosub TxtLCD ' send text to LCD next index let flag = 0 ' set flag to indicate program branch destination when Set button is pressed gosub Check_Set ' go check if Set button pressed yet loop ' loop & keep reading ADC value on pot until Set button is pressed Interval_Hours: ' sub to read in desired pump cycle time from pot in hours char = 1 ' clear display, go home to line 1 of LCD display gosub CmdLCD ' send instruction to LCD for index = 0 to 15 lookup index, ("Enter Time Hours"), char ' read text characters in string gosub TxtLCD ' send text in the string to LCD next index do readadc C.7, Time_Count ' read ADC value on pin C.7 from pot in to Time_Count variable let hrs = Time_Count/3 max 72 ' convert pot ADC value into hours from 0 to 72. Assume plant goes 3 days max without water. char = 192 ' go to line 2 of LCD display gosub CmdLCD ' send instruction to LCD let ValueX = hrs ' put hrs into temp variable for manipulation gosub IntgOnly ' go to sub to display hours set by pot on to LCD char = 197 ' move LCD cursor right for spacing gosub CmdLCD ' send instruction to LCD for index = 0 to 2 lookup index, ("hrs"), char ' read out "hrs" text to LCD gosub TxtLCD ' send text to LCD next index let flag = 1 ' set flag to indicate program branch destination when Set button is pressed gosub Check_Set ' go check if Set button pressed yet loop ' loop & keep reading ADC value on pot until Set button is pressed Interval_Mins: ' sub to read in desired pump cycle time from pot in minutes char = 1 ' clear display, go home to line 1 of LCD display gosub CmdLCD ' send instruction to LCD for index = 0 to 15 lookup index, ("Enter Time Mins "), char ' read text characters in string gosub TxtLCD ' send text in the string to LCD next index do readadc C.7, Time_Count ' read value on pin C.7 from pot in to Time_Count variable let mins = Time_Count/4 max 60 ' convert pot ADC value into mins from 0 to 60 char = 192 ' go to line 2 of LCD display gosub CmdLCD ' send instruction to LCD let ValueX = mins ' put mins into temp variable for manipulation gosub IntgOnly ' go to sub to display minutes set by pot on to LCD char = 197 ' move LCD cursor right for spacing gosub CmdLCD ' send instruction to LCD for index = 0 to 3 lookup index, ("mins"), char ' read out "mins" text to LCD gosub TxtLCD ' send text to LCD next index let flag = 2 ' set flag to indicate program branch destination when Set button is pressed gosub Check_Set ' go check if Set button pressed yet loop ' loop & keep reading ADC value on pot until Set button is pressed Check_Inputs: ' sub to check for zero inputs or time cycle too short for pump to dispense full volume let Tsecs = mins*60 ' convert cycle time mins to secs if Vol = 0 then gosub Error_Volume ' display error if volume set to zero if hrs = 0 and mins = 0 then gosub Error_Time ' display error if time set to zero if hrs = 0 and VolSec > Tsecs then gosub Error_Vol_Time ' display error if time to pump exceeds cycle time set +/- ~ 1% Display_Running: ' sub to display a message that the timer is running char = 1 ' clear display, go home to line 1 of LCD display gosub CmdLCD ' send instruction to LCD for index = 0 to 15 lookup index, ("Running Timer "), char ' read text characters in string gosub TxtLCD ' send text in the string to LCD next index Running: ' sub for counting incoming 1 Hz pulses do if state = 1 and pulse = 0 then let pulse = 1 high LED gosub CountTime endif ' if pin C.6 high and previous state was low then set pulse & LED high, go count if state = 0 and pulse = 1 then let pulse = 0 low LED endif ' if pin C.6 low and previous state was high then set pulse & LED low gosub Check_Test ' check if Test button pressed loop CountTime: ' sub that increments & counts secs, mins, hrs on each new incoming 1 Hz pulse inc s ' increment 1 second if s = 60 then inc m let s = 0 endif ' if secs = 60 then increment mins and reset secs to zero if m = 60 then inc h let m = 0 let s = 0 endif ' if mins = 60 then increment hrs and reset mins, secs to zero gosub Display ' go display current count if h = hrs and m = mins then let s = 0 let m = 0 let h = 0 gosub Dispense endif ' if time count = target time set by user, rest h,m,s to 0, go pump water if flag = 3 then gosub TimeCheck ' if flag = 3 then pump is on, so go check new elapsed time against programmed pump on time return Display: ' sub to display counter elapsed time char = 192 ' go to line 2 of LCD display gosub CmdLCD ' send instruction to LCD let ValueX = h ' put current h into a temp variable for manipulation gosub IntgTwoOnly ' go to sub to extract and display time digits char = 196 ' move LCD cursor right for spacing gosub CmdLCD ' send instruction to LCD let ValueX = m ' put current m into a temp variable for manipulation gosub IntgTwoOnly ' go to sub to extract and display time digits char = 200 ' move LCD cursor right for spacing gosub CmdLCD ' send instruction to LCD let ValueX = s ' put current s into a temp variable for manipulation gosub IntgTwoOnly ' go to sub to extract and display time digits TimeCheck: ' sub to check if pump on time is elapsed if pumptimeM = m and pumptimeS = s then Low Pump let flag =0 gosub Display_Running endif ' if current time count = pump time max then turn pump off return ' return to counting time Dispense: ' sub to turn on pump for required time based on the programmed volume gosub Display_Pumping ' go to sub that indictes pump is on and display target pump volume High Pump let flag = 3 ' turn on pump, set the flag indicating pump is on let pumptimeS = Vol*2 ' start to calculate the pump on time in secs based on volume let pumptimeS = pumptimeS/25 ' complete calculation of the pump on time in secs based on volume let pumptimeM = pumptimeS/60 ' calculate the pump on time in mins based on PumptimeS let y = pumptimeM*60 ' calculate the number of whole minutes of pump on time in seconds let pumptimeS = pumptimeS - y ' calculate the number of seconds of remaining pump on time after mins are counted return Display_Pumping: ' sub to display water is pumping and display target volume char = 1 ' clear display, go home to line 1 of LCD display gosub CmdLCD ' send instruction to LCD for index = 0 to 15 lookup index, ("Pumping "), char ' read text characters in string gosub TxtLCD ' send text in the string to LCD next index char = 136 ' move LCD cursor right for spacing gosub CmdLCD ' send instruction to LCD let ValueX = Vol ' put current Vol into a temp variable for manipulation gosub IntgOnly ' go to sub to display volume char = 141 ' move LCD cursor right for spacing gosub CmdLCD ' send instruction to LCD char = "m" ' send an "m" to display gosub TxtLCD ' send text to LCD char = 142 ' move LCD cursor right for spacing gosub CmdLCD ' send instruction to LCD char = "l" ' send an "l to display gosub TxtLCD ' send text to LCD return Test_Pump: ' sub to run pump when test button is pressed togglebit x, 0 ' toggle x between 0 and 1 when this sub is invoked if x = 1 then High Pump ' if x is toggled to a 1 turn pump on char = 1 ' clear display, go home to line 1 of LCD display gosub CmdLCD ' send instruction to LCD for index = 0 to 15 lookup index, ("Test Pumping "), char ' read text characters in string gosub TxtLCD ' send text in the string to LCD next index endif if x = 0 then Low Pump gosub Display_Running ' if x is toggled to 0, turn off pump return to displaying time count endif return Check_Set: ' sub to check if Set button is pressed button Setup, 1, 100,100, Rpt, 1, Send ' when Set button pressed, go to Send return Check_Test: ' sub to check if Test button pressed button Test, 1, 100,100, Rpt, 1, Test_Pump ' when Test button pressed, go to Test_Pump return Send: ' sub to branch depending on present program flag state if flag = 0 then goto Interval_Hours ' branch to Interval_Hours on flag = 0 if flag = 1 then goto Interval_Mins ' branch to Interval_Mins on flag = 1 if flag = 2 then goto Check_Inputs ' branch to Check_Inputs on flag = 2 Error_Volume: ' sub to indicate error due to volume input = 0 char = 1 ' clear display, go home to line 1 of LCD display gosub CmdLCD ' send instruction to LCD for index = 0 to 15 lookup index, ("Error Volume = 0"), char ' read text characters in string gosub TxtLCD ' send text in the string to LCD next index wait 2 ' pause 2 sec for display goto Volume ' return to Volume sub for new input Error_Time: ' sub to indicate error due to time input = 0 char = 1 ' clear display, go home to line 1 of LCD display gosub CmdLCD ' send instruction to LCD for index = 0 to 15 lookup index, ("Error Time = 0 "), char ' read text characters in string gosub TxtLCD ' send text in the string to LCD next index wait 2 ' pause 2 sec for display goto Interval_Hours ' return to Interval_Hours sub for new input Error_Vol_Time: ' sub to indicate error due to pump time > cycle time char = 1 ' clear display, go home to line 1 of LCD display gosub CmdLCD ' send instruction to LCD for index = 0 to 15 lookup index, ("Pump Time > Mins"), char ' read text characters in string gosub TxtLCD ' send text in the string to LCD next index wait 2 ' pause 2 sec for display goto Volume ' return to Volume sub for new input CmdLCD: low RegSelPin ' set up LCD for a command byte goto LoadLCD TxtLCD: ' set up LCD for text byte high RegSelPin LoadLCD: ' execute loading byte into LCD outpinsB = char ' load byte onto outpinsB pulsout EnablePin,1 ' load byte onto LCD return LoadIntgLCD: ' execute loading integer values onto LCD high RegSelPin ' set up LCD for text byte outpinsB = intgval ' load byte onto outpinsB pulsout EnablePin,1 ' execute loading byte into LCD return IntgOnly: ' sub to extract 1000's, 100's, 10's and 1's integers from ValueX data for index = 3 to 0 step -1 ' extract 1000's integer first then 100's then 10's then 1's let intgval = ValueX dig index ' use dig function to extract integers from MSB to LSB let MSB = ValueX dig 3 ' set dig = 3 to extract most significant bit (1000's), save for later use ' if index = 3 and intgval =0 then ' if 1000's are 0 then blank any leading "0" on display let intgval =%00100000 endif if index = 2 and MSB = 0 and intgval =0 then ' blank the 100's level "0's" only when 1000's are also "0" let intgval =%00100000 endif if intgval = 0 then let intgval =%00110000 ' Convert integers to LCD char codes else if intgval = 1 then let intgval =%00110001 else if intgval = 2 then let intgval =%00110010 else if intgval = 3 then let intgval =%00110011 else if intgval = 4 then let intgval =%00110100 else if intgval = 5 then let intgval =%00110101 else if intgval = 6 then let intgval =%00110110 else if intgval = 7 then let intgval =%00110111 else if intgval = 8 then let intgval =%00111000 else if intgval = 9 then let intgval =%00111001 endif gosub LoadIntgLCD ' execute loading integer value on LCD next index return IntgTwoOnly: ' extract 10's and 1's integers from ValueX data for index = 1 to 0 step -1 ' extract 10's integer first then 1's let intgval = ValueX dig index ' Use dig function to extract integers from MSB to LSB if intgval = 0 then let intgval =%00110000 ' Convert integers to LCD char codes else if intgval = 1 then let intgval =%00110001 else if intgval = 2 then let intgval =%00110010 else if intgval = 3 then let intgval =%00110011 else if intgval = 4 then let intgval =%00110100 else if intgval = 5 then let intgval =%00110101 else if intgval = 6 then let intgval =%00110110 else if intgval = 7 then let intgval =%00110111 else if intgval = 8 then let intgval =%00111000 else if intgval = 9 then let intgval =%00111001 endif gosub LoadIntgLCD ' execute loading integer value on LCD next index char = 194 ' move LCD cursor right for spacing gosub CmdLCD ' send command to LCD char = "h" ' send an "h" to display gosub TxtLCD ' send text to LCD char = 198 ' move LCD cursor right for spacing gosub CmdLCD ' send command to LCD char = "m" ' send an "m" to display gosub TxtLCD ' send text to LCD char = 202 ' move LCD cursor right for spacing gosub CmdLCD ' send command to LCD char = "s" ' send an "s" to display gosub TxtLCD ' send text to LCD return end