1. /* 2. * SG6auto.c 3. * Copyright (c) Will White 11/11/17 4. * Appalachian State University Honors Thesis Project 5. * 6. * Control sequence for an AVR Atmega328p microcontroller to automate a small scale 7. * snowmaking system. Interfaces with two solid state relays to control an air compresso r 8. * and pressure washer, a solenoid valve, and a state indicator LED. Reads from a DHT22 9. * temperature and humidity sensor and an Adafruit flow sensor. 10. * The MIT License (MIT) 11. * 12. * Permission is hereby granted, free of charge, to any person obtaining a copy 13. * of this software and associated documentation files (the "Software"), to deal 14. * in the Software without restriction, including without limitation the rights 15. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16. * copies of the Software, and to permit persons to whom the Software is 17. * furnished to do so, subject to the following conditions: 18. * 19. * The above copyright notice and this permission notice shall be included in 20. * all copies or substantial portions of the Software. 21. * 22. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28. * THE SOFTWARE. 29. */ 30. 31. 32. #include 33. #include 34. #include "DHT.h" 35. #include "DHT.c" 36. #include "flowSensor.h" 37. #include "flowSensor.c" 38. #include "Serial.h" 39. #include "Serial.c" 40. 41. #define ON_WETBULB 27 // degrees farenheit 42. #define TOO_HOT 100 43. #define COLD 20 44. #define FLOW_READ_PIN 3 45. #define DHT_READ_PIN 2 46. #define OUT_PORT PORTB 47. #define WATER_PIN 2 48. #define PUMP_PIN 1 49. #define AIR_PIN 0 50. #define ON 1 51. #define OFF 0 52. #define LED_PIN 3 53. 54. uint8_t systemOn; 55. uint8_t coldFlag; 56. uint8_t waterInFlag; 57. uint8_t pumpOn; 58. uint8_t airOn; 59. uint8_t waterOn; 60. uint32_t timeOn; 61. uint32_t timeOff; 62. 63. int temps[] = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 64. 38, 39, 40}; 65. int hums[] = {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 66. 100}; 67. int wbTable[21][19] = {{14,14,14,15,15,15,16,16,16,17,17,18,18,18,19,19,19,20,20}, 68. {14,15,15,16,16,16,17,17,17,18,18,18,19,19,19,20,20,21,21} , 69. {15,16,16,16,17,17,17,18,18,19,19,19,20,20,20,21,21,22,22} , 70. {16,16,17,17,18,18,18,19,19,19,20,20,21,21,21,22,22,22,23} , 71. {17,17,18,18,18,19,19,20,20,20,21,21,22,22,22,23,23,23,24} , 72. {18,18,18,19,19,20,20,20,21,21,22,22,22,23,23,24,24,24,25} , 73. {18,19,19,20,20,20,21,21,22,22,23,23,23,24,24,25,25,25,26} , 74. {19,19,20,20,21,21,22,22,23,23,23,24,24,25,25,26,26,26,27} , 75. {20,20,21,21,22,22,23,23,23,24,24,25,25,26,26,27,27,27,28} , 76. {20,21,21,22,22,23,23,24,24,25,25,26,26,27,27,28,28,28,29} , 77. {21,22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29,29,30} , 78. {22,22,23,23,24,25,25,26,26,27,27,28,28,29,29,29,30,30,31} , 79. {23,23,24,24,25,25,26,26,27,27,28,28,29,29,30,30,31,31,32} , 80. {23,24,24,25,26,26,27,27,28,28,29,29,30,30,31,31,32,32,33} , 81. {24,25,25,26,26,27,27,28,29,29,30,30,31,31,32,32,33,33,34} , 82. {25,25,26,27,27,28,28,29,29,30,31,31,32,32,33,33,34,34,35} , 83. {25,26,27,27,27,28,29,29,30,30,31,31,32,32,33,33,34,34,35} , 84. {26,27,27,28,29,29,30,31,31,32,32,33,34,34,35,35,36,36,37} , 85. {27,27,28,29,29,30,30,31,31,32,33,33,34,35,35,36,36,37,38} , 86. {27,28,29,30,30,31,32,32,33,34,35,36,36,37,37,38,38,39,39} , 87. {28,29,30,31,31,32,32,33,34,34,35,36,36,37,38,38,39,39,40} 88. }; 89. 90. uint8_t turnOn(void); 91. void turnOff(uint8_t error); 92. int getWB(int T, int H); 93. void turnWaterOn(void); 94. 95. int main(){ 96. 97. char output[30]; 98. int temperature, humidity; 99. float wetbulbTemp, gallonsPerMinute; 100. uint8_t successfulStartup; 101. 102. /* Initialization sequences */ 103. dht_init(DHT_READ_PIN); 104. flowSensorInit(FLOW_READ_PIN); 105. USART_init(); 106. systemOn = 0; 107. 108. /* Control loop */ 109. while (1) { 110. 111. /* check inputs */ 112. temperature = (int) readTemp(1); 113. _delay_ms(2050); // delay to give sensor time to send new reading 114. humidity = (int) readHumidity(); 115. wetbulbTemp = (float) getWB(temperature, humidity); 116. gallonsPerMinute = getFlowrate(); 117. 118. /* check reading every minute if system is off */ 119. if (systemOn == 0) 120. _delay_ms(60000); 121. 122. /* turn system off if it's not cold enough */ 123. if (systemOn == 1 && coldFlag == 0) 124. turnOff(0); 125. 126. /* turn system on if it's cold enough */ 127. else if (systemOn == 0 && coldFlag == 1) 128. successfulStartup = turnOn(); 129. 130. g */ /* turn water on at marginal temperatures to prevent system from freezin 131. else if (wetbulbTemp <= 28 && coldFlag == 0 && systemOn == 0) 132. turnWaterOn(); 133. 134. /* turn system off if water shuts off for any reason */ 135. else if (systemOn == 1 && getFlowrate() < 0.3) 136. turnOff(1); 137. 138. /* otherwise stay put */ 139. 140. /* used as indicator */ 141. if (systemOn == 1) 142. OUT_PORT |= 1 << LED_PIN; 143. else 144. OUT_PORT &= ~(1 << LED_PIN); 145. 146. _delay_ms(2000); 147. 148. /* debug sequences 149. if (systemOn == 1) USART_putstring("ON "); 150. if (systemOn == 0) USART_putstring("OFF "); 151. if (isFlowing()) USART_putstring("FLOWING\n"); 152. if (!isFlowing()) USART_putstring("NOT FLOWING\n"); 153. ftoa(wetbulbTemp, output, 3); 154. USART_putstring(output); 155. ftoa((float) temperature, output, 3); 156. USART_send(' '); 157. USART_putstring(output); 158. ftoa((float) humidity, output, 3); 159. USART_send(' '); 160. USART_putstring(output); 161. USART_send('\n'); 162. */ 163. 164. } 165. return 0; 166. } 167. 168. /* 169. * Turn on Sequence, returns 1 if successful, 0 if failure 170. */ 171. uint8_t turnOn(void) { 172. 173. int count; 174. 175. systemOn = 1; // will get turned off if water doesn't flow 176. timeOn = 0; // measures the time the system is on 177. USART_putstring("Turning on\n"); 178. 179. /* turn compressor on */ 180. DDRB = 0xFF; 181. OUT_PORT |= 1 << AIR_PIN; 182. 183. /* turn water on (solenoid valve) */ 184. OUT_PORT |= 1 << WATER_PIN; 185. 186. /* wait for water reading 187. water flow should be 1.6gpm during normal operation */ 188. while (getFlowrate() < 0.3) { 189. USART_putstring("Waiting for water\n"); 190. if (count++ >= 60) { // wait for one minute for water to turn on 191. turnOff(0); 192. ERROR(2); // unsuccessful startup error 193. return 0; 194. } 195. } 196. //USART_putstring("Turning Pump On\n"); 197. 198. /* turn pump on */ 199. OUT_PORT |= 1 << PUMP_PIN; 200. 201. return 1; 202. 203. } 204. 205. /* 206. * turn off sequence 207. */ 208. void turnOff(uint8_t error) { 209. 210. USART_putstring("Turning off\n"); 211. systemOn = 0; 212. 213. // turn pump off 214. OUT_PORT &= ~(1 << PUMP_PIN); 215. _delay_ms(10000); 216. 217. // turn air off 218. OUT_PORT &= ~(1 << AIR_PIN); 219. _delay_ms(10000); 220. 221. // turn water off 222. OUT_PORT &= ~(1 << WATER_PIN); 223. 224. // go into error mode if water stops flowing 225. if (error == 1) 226. ERROR(3); 227. } 228. 229. /* 230. * For use in marginal temps to prevent freezing 231. */ 232. void turnWaterOn(void) { 233. PORTB |= 0x04; 234. waterOn = 1; 235. } 236. 237. /* 238. * Uses wbTable to determine the wet bulb temperature given the 239. * temperature and humidity 240. */ 241. int getWB(int T, int H) { 242. 243. int tin, hin, wb; 244. 245. // ensure proper bounds 246. if (T > 40) wb = TOO_HOT; 247. else if (T < 20) wb = COLD; 248. else { 249. if (H < 10) H = 10; 250. if (H > 100) H = 100; // should never happen 251. 252. for (tin = 0; tin < 21; tin++) // find temperature index in wbTable 253. if (temps[tin] == T) break; 254. 255. for (hin = 0; hin < 18; hin++) { // find humidity index in wbTable 256. if (hums[hin] <= H && hums[hin+1] >= H) break; 257. 258. } 259. wb = wbTable[tin][hin]; 260. } 261. if (wb <= ON_WETBULB) 262. coldFlag = 1; 263. else 264. coldFlag = 0; 265. return wb; 266. } 267. 268. /* 269. * Error routines 270. * 1 blink for DHT read error 271. * 2 blinks for unsuccessful startup error 272. * 3 blinks for water flow interruption error 273. * Must reset to exit 274. */ 275. void ERROR(uint8_t mode) { 276. 277. uint16_t length; 278. DDRB = 0xFF; 279. 280. if (mode == 1) { // DHT read error, blink once 281. while (1) { 282. OUT_PORT &= ~(1 << LED_PIN); 283. _delay_ms(1000); 284. OUT_PORT |= (1 << LED_PIN); 285. _delay_ms(1000); 286. } 287. 288. } else if (mode == 2) { // unsuccessful startup error, blink twice 289. while (1) { 290. OUT_PORT |= 1 << LED_PIN; 291. _delay_ms(333); 292. OUT_PORT &= ~(1 << LED_PIN); 293. _delay_ms(333); 294. OUT_PORT |= 1 << LED_PIN; 295. _delay_ms(333); 296. OUT_PORT &= ~(1 << LED_PIN); 297. _delay_ms(1000); 298. } 299. 300. 301. } else if (mode == 3) { // water flow interruption, blink three times 302. while (1) { 303. OUT_PORT |= 1 << LED_PIN; 304. _delay_ms(200); 305. OUT_PORT &= ~(1 << LED_PIN); 306. _delay_ms(200); 307. OUT_PORT |= 1 << LED_PIN; 308. _delay_ms(200); 309. OUT_PORT &= ~(1 << LED_PIN); 310. _delay_ms(200); 311. OUT_PORT |= 1 << LED_PIN; 312. _delay_ms(200); 313. OUT_PORT &= ~(1 << LED_PIN); 314. _delay_ms(1000); 315. } 316. 317. } 318. 319. } 320. 321.