
ECE595 Hydroponics water balancing system (Project 2)
Dependencies: mbed phread TextLCD
main.cpp@0:e628a132c5fa, 2020-05-06 (annotated)
- Committer:
- thecreid1
- Date:
- Wed May 06 14:58:48 2020 +0000
- Revision:
- 0:e628a132c5fa
Project 2 Firmware;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
thecreid1 | 0:e628a132c5fa | 1 | /** ECE595 Project 2: IoT Hydroponics |
thecreid1 | 0:e628a132c5fa | 2 | ** ##Complete Firmware## |
thecreid1 | 0:e628a132c5fa | 3 | **/ |
thecreid1 | 0:e628a132c5fa | 4 | /* mbed Microcontroller Library |
thecreid1 | 0:e628a132c5fa | 5 | * Copyright (c) 2018 ARM Limited |
thecreid1 | 0:e628a132c5fa | 6 | * SPDX-License-Identifier: Apache-2.0 |
thecreid1 | 0:e628a132c5fa | 7 | */ |
thecreid1 | 0:e628a132c5fa | 8 | |
thecreid1 | 0:e628a132c5fa | 9 | #include "mbed.h" |
thecreid1 | 0:e628a132c5fa | 10 | #include "phread.h" |
thecreid1 | 0:e628a132c5fa | 11 | #include "PwmOut.h" |
thecreid1 | 0:e628a132c5fa | 12 | #include "TextLCD.h" |
thecreid1 | 0:e628a132c5fa | 13 | #include <string> |
thecreid1 | 0:e628a132c5fa | 14 | #include <sstream> |
thecreid1 | 0:e628a132c5fa | 15 | #include <iomanip> |
thecreid1 | 0:e628a132c5fa | 16 | |
thecreid1 | 0:e628a132c5fa | 17 | Serial HC06(PTC15, PTC14); //Create serial object for the HC06 to be read from/written to |
thecreid1 | 0:e628a132c5fa | 18 | Serial pc(USBTX,USBRX); //Create serial object for the COM port to interface with a terminal application |
thecreid1 | 0:e628a132c5fa | 19 | Ticker timeKeep; //Create the time keeping interrupt. More information below in its definition |
thecreid1 | 0:e628a132c5fa | 20 | |
thecreid1 | 0:e628a132c5fa | 21 | //** Servo Initialization |
thecreid1 | 0:e628a132c5fa | 22 | PwmOut smoto(PTA1); |
thecreid1 | 0:e628a132c5fa | 23 | DigitalOut led1(LED1); |
thecreid1 | 0:e628a132c5fa | 24 | DigitalOut phPump1(D0); |
thecreid1 | 0:e628a132c5fa | 25 | DigitalOut phPump2(D1); |
thecreid1 | 0:e628a132c5fa | 26 | PHread sensor(A0); |
thecreid1 | 0:e628a132c5fa | 27 | //Serial pc(USBTX, USBRX); |
thecreid1 | 0:e628a132c5fa | 28 | |
thecreid1 | 0:e628a132c5fa | 29 | //** LCD pin intialization |
thecreid1 | 0:e628a132c5fa | 30 | TextLCD lcd(PTC12, PTC4, PTD0, PTD2, PTD3, PTD1); // rs, e, d4-d7 |
thecreid1 | 0:e628a132c5fa | 31 | |
thecreid1 | 0:e628a132c5fa | 32 | |
thecreid1 | 0:e628a132c5fa | 33 | //** Global ints to keep/track time |
thecreid1 | 0:e628a132c5fa | 34 | int cthours = 0; //Current time integers |
thecreid1 | 0:e628a132c5fa | 35 | int ctminutes = 0; //These are incremented using a ticker component to keep |
thecreid1 | 0:e628a132c5fa | 36 | int ctseconds = 0; //real time. |
thecreid1 | 0:e628a132c5fa | 37 | |
thecreid1 | 0:e628a132c5fa | 38 | float phMeas = 7.0; |
thecreid1 | 0:e628a132c5fa | 39 | int gallon_cnt = 5; //User set: gallons currently in the tank //tohours |
thecreid1 | 0:e628a132c5fa | 40 | |
thecreid1 | 0:e628a132c5fa | 41 | int min_cnt = 0; //Integer tracking the amount of time the pump is running |
thecreid1 | 0:e628a132c5fa | 42 | |
thecreid1 | 0:e628a132c5fa | 43 | char buffer[10]; //buffer for the serial comms between BT module and board, sent from mobile app to BT |
thecreid1 | 0:e628a132c5fa | 44 | char *initarray[3]; //array for inital storage of timer info |
thecreid1 | 0:e628a132c5fa | 45 | |
thecreid1 | 0:e628a132c5fa | 46 | //** Delimiter section for parsing data |
thecreid1 | 0:e628a132c5fa | 47 | char sdelim[] = " "; //seperation delimiter |
thecreid1 | 0:e628a132c5fa | 48 | char cdelim[] = "c"; //current time command |
thecreid1 | 0:e628a132c5fa | 49 | char gdelim[] = "g"; //Gallon Measurement Sent from the App |
thecreid1 | 0:e628a132c5fa | 50 | |
thecreid1 | 0:e628a132c5fa | 51 | bool pumpIt = false; |
thecreid1 | 0:e628a132c5fa | 52 | |
thecreid1 | 0:e628a132c5fa | 53 | std::string phOut; |
thecreid1 | 0:e628a132c5fa | 54 | std::string timeOut; |
thecreid1 | 0:e628a132c5fa | 55 | |
thecreid1 | 0:e628a132c5fa | 56 | std::stringstream phStream; |
thecreid1 | 0:e628a132c5fa | 57 | std::stringstream timeStream; |
thecreid1 | 0:e628a132c5fa | 58 | |
thecreid1 | 0:e628a132c5fa | 59 | //** prereference functions |
thecreid1 | 0:e628a132c5fa | 60 | void timekeep(void); |
thecreid1 | 0:e628a132c5fa | 61 | void hcRxCallback(void); |
thecreid1 | 0:e628a132c5fa | 62 | float ph_measurement(void); |
thecreid1 | 0:e628a132c5fa | 63 | void pumpOn(void); |
thecreid1 | 0:e628a132c5fa | 64 | void pumpOff(void); |
thecreid1 | 0:e628a132c5fa | 65 | void printTime(void); |
thecreid1 | 0:e628a132c5fa | 66 | |
thecreid1 | 0:e628a132c5fa | 67 | //** main function |
thecreid1 | 0:e628a132c5fa | 68 | int main() |
thecreid1 | 0:e628a132c5fa | 69 | { |
thecreid1 | 0:e628a132c5fa | 70 | //*Baud rate init |
thecreid1 | 0:e628a132c5fa | 71 | HC06.baud(9600); |
thecreid1 | 0:e628a132c5fa | 72 | pc.baud(9600); |
thecreid1 | 0:e628a132c5fa | 73 | |
thecreid1 | 0:e628a132c5fa | 74 | //*interupt init |
thecreid1 | 0:e628a132c5fa | 75 | timeKeep.attach(&timekeep, 0.999); |
thecreid1 | 0:e628a132c5fa | 76 | HC06.attach(&hcRxCallback, Serial::RxIrq); |
thecreid1 | 0:e628a132c5fa | 77 | |
thecreid1 | 0:e628a132c5fa | 78 | //*infinite loop |
thecreid1 | 0:e628a132c5fa | 79 | while(1) { |
thecreid1 | 0:e628a132c5fa | 80 | if(pumpIt){ //if pump has not been run this hour |
thecreid1 | 0:e628a132c5fa | 81 | if(phMeas > 7.5){ //run either pump for a second if needed |
thecreid1 | 0:e628a132c5fa | 82 | phPump1.write(1); |
thecreid1 | 0:e628a132c5fa | 83 | wait(1); |
thecreid1 | 0:e628a132c5fa | 84 | phPump1 = 0; |
thecreid1 | 0:e628a132c5fa | 85 | } |
thecreid1 | 0:e628a132c5fa | 86 | else if(phMeas < 6.5){ |
thecreid1 | 0:e628a132c5fa | 87 | phPump2 = 1; |
thecreid1 | 0:e628a132c5fa | 88 | wait(1); |
thecreid1 | 0:e628a132c5fa | 89 | phPump2 = 0; |
thecreid1 | 0:e628a132c5fa | 90 | } |
thecreid1 | 0:e628a132c5fa | 91 | else{} |
thecreid1 | 0:e628a132c5fa | 92 | pumpIt = false; //stop pumps from running for another hour |
thecreid1 | 0:e628a132c5fa | 93 | } |
thecreid1 | 0:e628a132c5fa | 94 | } |
thecreid1 | 0:e628a132c5fa | 95 | } |
thecreid1 | 0:e628a132c5fa | 96 | |
thecreid1 | 0:e628a132c5fa | 97 | //** Timekeeping function. This function is triggered every 0.999 seconds as an interrupt |
thecreid1 | 0:e628a132c5fa | 98 | void timekeep() |
thecreid1 | 0:e628a132c5fa | 99 | { |
thecreid1 | 0:e628a132c5fa | 100 | |
thecreid1 | 0:e628a132c5fa | 101 | ctseconds += 1; //Increment the seconds and compare to 60 |
thecreid1 | 0:e628a132c5fa | 102 | if (ctseconds >= 60) { |
thecreid1 | 0:e628a132c5fa | 103 | ctminutes += 1; |
thecreid1 | 0:e628a132c5fa | 104 | ctseconds = 0; |
thecreid1 | 0:e628a132c5fa | 105 | |
thecreid1 | 0:e628a132c5fa | 106 | if(min_cnt == 1) //if the minute counter was just reset, turn on the pump |
thecreid1 | 0:e628a132c5fa | 107 | pumpOn(); |
thecreid1 | 0:e628a132c5fa | 108 | else if(min_cnt == 16){ //after 15 minutes, turn the pump off |
thecreid1 | 0:e628a132c5fa | 109 | pumpOff(); |
thecreid1 | 0:e628a132c5fa | 110 | min_cnt = 0; //stop minute counter |
thecreid1 | 0:e628a132c5fa | 111 | } |
thecreid1 | 0:e628a132c5fa | 112 | else{}; //empty else loop |
thecreid1 | 0:e628a132c5fa | 113 | |
thecreid1 | 0:e628a132c5fa | 114 | if(min_cnt % 2){ //on odd minutes, run this code |
thecreid1 | 0:e628a132c5fa | 115 | phMeas = ph_measurement(); //read and set measurements |
thecreid1 | 0:e628a132c5fa | 116 | printTime(); //set time |
thecreid1 | 0:e628a132c5fa | 117 | lcd.printf("%s\n%s", phOut, timeOut); //send ph and time to LCD |
thecreid1 | 0:e628a132c5fa | 118 | } |
thecreid1 | 0:e628a132c5fa | 119 | |
thecreid1 | 0:e628a132c5fa | 120 | |
thecreid1 | 0:e628a132c5fa | 121 | if(min_cnt){ //if minute count is not 0, increment |
thecreid1 | 0:e628a132c5fa | 122 | min_cnt++; |
thecreid1 | 0:e628a132c5fa | 123 | } |
thecreid1 | 0:e628a132c5fa | 124 | } |
thecreid1 | 0:e628a132c5fa | 125 | if (ctminutes >= 60) { //compare minutes to 60 |
thecreid1 | 0:e628a132c5fa | 126 | cthours += 1; |
thecreid1 | 0:e628a132c5fa | 127 | ctminutes = 0; |
thecreid1 | 0:e628a132c5fa | 128 | min_cnt = 1; //reset the minute counter |
thecreid1 | 0:e628a132c5fa | 129 | pumpIt = true; //reset the boolean allowing the pumps to run |
thecreid1 | 0:e628a132c5fa | 130 | } |
thecreid1 | 0:e628a132c5fa | 131 | if (cthours >= 24) { //compare hours to 24 |
thecreid1 | 0:e628a132c5fa | 132 | cthours = 0; |
thecreid1 | 0:e628a132c5fa | 133 | } |
thecreid1 | 0:e628a132c5fa | 134 | |
thecreid1 | 0:e628a132c5fa | 135 | pc.printf("time: %d : %d : %d\n\n",cthours,ctminutes,ctseconds); |
thecreid1 | 0:e628a132c5fa | 136 | return; |
thecreid1 | 0:e628a132c5fa | 137 | } |
thecreid1 | 0:e628a132c5fa | 138 | |
thecreid1 | 0:e628a132c5fa | 139 | /* This the RX_IRQ. There are global variables altered within this function, |
thecreid1 | 0:e628a132c5fa | 140 | ** therefore disabling IRQ will allow this to operate without any interruption |
thecreid1 | 0:e628a132c5fa | 141 | ** ***Note*** this function will not exit and print unless the buffer has read |
thecreid1 | 0:e628a132c5fa | 142 | ** into it 8 bits of data. |
thecreid1 | 0:e628a132c5fa | 143 | **/ |
thecreid1 | 0:e628a132c5fa | 144 | void hcRxCallback() |
thecreid1 | 0:e628a132c5fa | 145 | { |
thecreid1 | 0:e628a132c5fa | 146 | __disable_irq(); |
thecreid1 | 0:e628a132c5fa | 147 | HC06.gets(buffer, 8); |
thecreid1 | 0:e628a132c5fa | 148 | pc.printf("recieved: %s\n",buffer); |
thecreid1 | 0:e628a132c5fa | 149 | |
thecreid1 | 0:e628a132c5fa | 150 | //*String Concatenation |
thecreid1 | 0:e628a132c5fa | 151 | int i = 0; |
thecreid1 | 0:e628a132c5fa | 152 | char *p = strtok(buffer, sdelim); //Delimiter to parse the string into tokens |
thecreid1 | 0:e628a132c5fa | 153 | while(p != NULL) { //loops while there is data to be read |
thecreid1 | 0:e628a132c5fa | 154 | initarray[i++] = p; //Saves the value of P into the next slot of initarray |
thecreid1 | 0:e628a132c5fa | 155 | p = strtok(NULL, sdelim); //rinse and repeat |
thecreid1 | 0:e628a132c5fa | 156 | } |
thecreid1 | 0:e628a132c5fa | 157 | /** For debug purposes, this will print the array elements for the |
thecreid1 | 0:e628a132c5fa | 158 | ** user to review. |
thecreid1 | 0:e628a132c5fa | 159 | **/ |
thecreid1 | 0:e628a132c5fa | 160 | for(i = 0; i<3; i++) { |
thecreid1 | 0:e628a132c5fa | 161 | pc.printf("%s\n",initarray[i]); |
thecreid1 | 0:e628a132c5fa | 162 | } |
thecreid1 | 0:e628a132c5fa | 163 | //*String sorting |
thecreid1 | 0:e628a132c5fa | 164 | if (!strcmp(initarray[0], cdelim)) { //Compare the command character to the 'c' command |
thecreid1 | 0:e628a132c5fa | 165 | cthours = atoi(initarray[1]); |
thecreid1 | 0:e628a132c5fa | 166 | ctminutes = atoi(initarray[2]); |
thecreid1 | 0:e628a132c5fa | 167 | pc.printf("new time: %d %d\n\n",cthours,ctminutes); |
thecreid1 | 0:e628a132c5fa | 168 | } |
thecreid1 | 0:e628a132c5fa | 169 | if (!strcmp(initarray[0], gdelim)) { //Compare the command character to the 'g' command |
thecreid1 | 0:e628a132c5fa | 170 | gallon_cnt = atoi(initarray[1]); |
thecreid1 | 0:e628a132c5fa | 171 | pc.printf("Current Gallon Amount: %d\n\n",gallon_cnt); |
thecreid1 | 0:e628a132c5fa | 172 | } |
thecreid1 | 0:e628a132c5fa | 173 | |
thecreid1 | 0:e628a132c5fa | 174 | __enable_irq(); |
thecreid1 | 0:e628a132c5fa | 175 | return; |
thecreid1 | 0:e628a132c5fa | 176 | } |
thecreid1 | 0:e628a132c5fa | 177 | |
thecreid1 | 0:e628a132c5fa | 178 | //** Time Condition Begin, EveryHOur on the Hour, cycle a water pump for 15 min |
thecreid1 | 0:e628a132c5fa | 179 | //** and add ph up and/or ph downt to the mixture for desired ph level |
thecreid1 | 0:e628a132c5fa | 180 | float ph_measurement() |
thecreid1 | 0:e628a132c5fa | 181 | { |
thecreid1 | 0:e628a132c5fa | 182 | float phMeasurement; |
thecreid1 | 0:e628a132c5fa | 183 | //Check ph |
thecreid1 | 0:e628a132c5fa | 184 | phMeasurement = sensor.get_pH(); |
thecreid1 | 0:e628a132c5fa | 185 | phStream << "pH : " << std::fixed << std::setprecision(2) << phMeasurement; |
thecreid1 | 0:e628a132c5fa | 186 | phOut = phStream.str(); |
thecreid1 | 0:e628a132c5fa | 187 | return phMeasurement; |
thecreid1 | 0:e628a132c5fa | 188 | } |
thecreid1 | 0:e628a132c5fa | 189 | |
thecreid1 | 0:e628a132c5fa | 190 | void printTime() |
thecreid1 | 0:e628a132c5fa | 191 | { |
thecreid1 | 0:e628a132c5fa | 192 | std::stringstream sHours; |
thecreid1 | 0:e628a132c5fa | 193 | std::stringstream sMinutes; |
thecreid1 | 0:e628a132c5fa | 194 | |
thecreid1 | 0:e628a132c5fa | 195 | if(cthours == 24) |
thecreid1 | 0:e628a132c5fa | 196 | sHours << "00"; |
thecreid1 | 0:e628a132c5fa | 197 | else if(cthours < 10) |
thecreid1 | 0:e628a132c5fa | 198 | sHours << "0" << cthours; |
thecreid1 | 0:e628a132c5fa | 199 | else |
thecreid1 | 0:e628a132c5fa | 200 | sHours << cthours; |
thecreid1 | 0:e628a132c5fa | 201 | |
thecreid1 | 0:e628a132c5fa | 202 | if(ctminutes == 60) |
thecreid1 | 0:e628a132c5fa | 203 | sMinutes << "00"; |
thecreid1 | 0:e628a132c5fa | 204 | else if(ctminutes < 10) |
thecreid1 | 0:e628a132c5fa | 205 | sMinutes << "0" << ctminutes; |
thecreid1 | 0:e628a132c5fa | 206 | else |
thecreid1 | 0:e628a132c5fa | 207 | sMinutes << ctminutes; |
thecreid1 | 0:e628a132c5fa | 208 | |
thecreid1 | 0:e628a132c5fa | 209 | timeStream << "Time : " << sHours.str() << ":" << sMinutes.str(); |
thecreid1 | 0:e628a132c5fa | 210 | timeOut = timeStream.str(); |
thecreid1 | 0:e628a132c5fa | 211 | } |
thecreid1 | 0:e628a132c5fa | 212 | |
thecreid1 | 0:e628a132c5fa | 213 | void pumpOn() |
thecreid1 | 0:e628a132c5fa | 214 | { |
thecreid1 | 0:e628a132c5fa | 215 | smoto.pulsewidth_ms(2.0f); |
thecreid1 | 0:e628a132c5fa | 216 | } |
thecreid1 | 0:e628a132c5fa | 217 | |
thecreid1 | 0:e628a132c5fa | 218 | void pumpOff() |
thecreid1 | 0:e628a132c5fa | 219 | { |
thecreid1 | 0:e628a132c5fa | 220 | smoto.pulsewidth_ms(0.0f); |
thecreid1 | 0:e628a132c5fa | 221 | } |
thecreid1 | 0:e628a132c5fa | 222 |