1#include <avr/sleep.h>
2#include <Arduino.h>
3#include <curveFitting.h>
4#include <hd44780.h>
5#include <hd44780ioClass/hd44780_pinIO.h>
6
7PROGMEM const bool debug = false;
8
9PROGMEM const int min_flow = 3;
10PROGMEM const int max_temp = 69;
11PROGMEM const int window = 23;
12PROGMEM const int pred_w = 6;
13PROGMEM const int order = 2;
14const uint8_t flowsensor = 2;
15const uint8_t t1_pin = A1;
16const uint8_t t2_pin = A2;
17
18
19const int rs = 8, en = 9, db4 = 4, db5 = 5, db6 = 6, db7 = 7;
20hd44780_pinIO lcd(rs, en, db4, db5, db6, db7);
21const int BACKLIGHT_PIN = 10;
22const int OFF = 0;
23const int ON = 1;
24
25#define SafeBLon() pinMode(BACKLIGHT_PIN, INPUT)
26
27void SafeBLoff() {
28 digitalWrite(BACKLIGHT_PIN, LOW);
29 delay(500);
30 pinMode(BACKLIGHT_PIN, OUTPUT);
31}
32
33
34#define PWM366 10
35#define PWM183 11
36#define PWM91 12
37#define PWM45 13
38#define PWM22 14
39#define PWM11 15
40
41
42#define PWM13 OCR4A
43
44
45double coeffs[3];
46double y[window];
47double x[window];
48
49byte adcsra_save = ADCSRA;
50byte prr0_save = 0x00;
51
52int t1 = 0;
53int t2 = 0;
54int t1t = 0;
55int t2t = 0;
56int t1sum = 0;
57int t2sum = 0;
58int t1avg = 0;
59int t2avg = 0;
60int t2last = 0;
61int last_zero = 0;
62double a = 0;
63double m = 0;
64double pred = 0;
65double pred0 = 0;
66unsigned int n = 0;
67unsigned long currentTime = 0;
68unsigned long cloopTime = 0;
69unsigned long lastPulse = 0;
70unsigned int seq = 0;
71volatile unsigned int count = 0;
72unsigned int liters = 0;
73String str = "";
74
75char format1[] = "F% 3d a% 4s m% 4s";
76char format2[] = "T% 3d P% 4s Q% 4s";
77
78
79void toLCD (const char* format, int a, double b, double c, int line) {
80 static char chr[16] = "";
81 static char outstr[6] = "";
82 static char outstr1[6] = "";
83
84 dtostrf(b, 3, 1, outstr);
85 dtostrf(c, 3, 1, outstr1);
86
87 lcd.setCursor(0, line);
88
89 sprintf(chr, format, a, outstr, outstr1);
90 lcd.print(chr);
91}
92
93void putLCD (char* format, int line) {
94 if (line == 0) {
95 format1[0] = format;
96 format2[0] = 'T';
97 } else {
98 format1[0] = 'F';
99 format2[0] = format;
100 }
101
102}
103template <class DATATYPE, unsigned char SIZE> class PushPop {
104 private:
105 const unsigned char m_Size = SIZE - 1;
106 DATATYPE m_Array[SIZE];
107 int m_Index;
108 public:
109 PushPop() {
110 m_Index = -1;
111 }
112 void Zero() {
113 m_Index = -1;
114 for (int i = 0; i < m_Size; i++) {
115 m_Array[i] = 210;
116 }
117 }
118 void Push(DATATYPE what) {
119 if (m_Index >= m_Size) {
120 Pop();
121 }
122 m_Index = min(m_Size, m_Index++);
123 m_Array[m_Index] = what;
124 }
125 DATATYPE Pop() {
126 for (int i = 0; i < m_Index; i++) {
127 m_Array[i] = m_Array[i + 1];
128 }
129 m_Index--;
130 return m_Array[m_Index];
131 }
132 DATATYPE Walk(int i) {
133 return m_Array[i];
134 }
135 DATATYPE Last() {
136 return m_Array[m_Index];
137 }
138 void printpp() {
139 for (int i = 0; i <= m_Index; i++) {
140 Serial.print(m_Array[i]);
141 Serial.print('\ ');
142 }
143 Serial.println();
144 }
145 DATATYPE avg(int n) {
146 DATATYPE sum = 0;
147 if (n == 0) {
148 n = m_Index;
149 }
150 int i;
151 for (i = m_Index - n ; i <= m_Index; i++) {
152 sum = sum + m_Array[i];
153 }
154 return sum / (n + 1);
155 }
156 void getmat(DATATYPE mat[]) {
157 for (int i = 0; i <= m_Index; i++) {
158 mat[i] = m_Array[i];
159 }
160 }
161 int getsize() {
162 return m_Index;
163 }
164
165 double slope(int n) {
166 if (n == 0) {
167 n = m_Index;
168 }
169 n = m_Index - n;
170 return ( m_Array[m_Index] - m_Array[n] ) / m_Index;
171 }
172};
173
174
175
176void pwm613configure()
177{
178
179 TCCR4A = 0;
180
181
182 TCCR4B = 0;
183
184
185 TCCR4C = 0;
186
187
188 TCCR4D = 0;
189
190 TCCR4E |= (1 << ENHC4);
191
192
193
194 PLLFRQ = (PLLFRQ & 0xCF) | 0x30;
195
196
197
198 OCR4C = 255;
199}
200
201
202
203void pwmSet13()
204{
205 if (TCCR4B == 0) {
206 TCCR4B = PWM91;
207 OCR4A = 255;
208 DDRC |= 1 << 7;
209 TCCR4A = 0x82;
210 }
211 delay(10);
212 if (debug) {
213 Serial.println("pwmset");
214 }
215}
216
217void pwmStop13()
218{
219 TCCR4B = 0;
220 digitalWrite(13, LOW);
221 delay(10);
222
223 if (liters < min_flow) {
224 seq = 0;
225 }
226}
227
228void flow() {
229 count++;
230}
231
232void wake() {
233 sleep_disable();
234 detachInterrupt(digitalPinToInterrupt(flowsensor));
235}
236
237int VtoC (int temp) {
238 double f = 1.81176e-10;
239 f = f * temp;
240 f = f - 5.03596e-7;
241 f = f * temp;
242 f = f + 0.0005340536;
243 f = f * temp;
244 f = f - 0.33203628;
245 f = f * temp;
246 f = f + 110.4503125;
247 if (f > 100 or f < 0 ) {
248 f = 0;
249 }
250 return (int(f));
251}
252
253
254PushPop<double, window> t2s;
255
256void setup() {
257 if (debug) {
258 Serial.begin(9600);
259 delay(3000);
260 Serial.println("Starting…");
261
262 }
263
264 analogReference((int)DEFAULT);
265
266 lcd.begin(16, 2);
267
268 lcd.clear();
269
270 pwm613configure();
271 pwmStop13();
272 pinMode(flowsensor, INPUT);
273 pinMode(t1_pin, INPUT);
274 pinMode(t2_pin, INPUT);
275
276 delay(3000);
277
278 lcd.setCursor(0, 0);
279 lcd.print("Starting...");
280
281 SafeBLon();
282
283 attachInterrupt(digitalPinToInterrupt(flowsensor), flow, RISING);
284 sei();
285 currentTime = millis();
286 cloopTime = currentTime;
287 lastPulse = currentTime;
288 t1sum = 0;
289 t2sum = 0;
290 n = 0;
291 t2last = 0;
292
293 for (int i = 0; i < window; i++) {
294 x[i] = i;
295 }
296
297}
298
299void loop() {
300
301new_cycle:
302 currentTime = millis();
303
304 yield();
305
306 delay(15);
307 t1 = analogRead(t1_pin);
308 t1 = 1.11 * t1 - 120.2;
309
310 delay(25);
311 t2 = analogRead(t2_pin);
312
313 t1sum = t1sum + t1;
314 t2sum = t2sum + t2;
315 n++;
316
317 t1avg = t1sum / n;
318 t2avg = t2sum / n;
319
320 t1t = VtoC(t1avg);
321 t2t = VtoC(t2avg);
322
323 if ((liters <= min_flow) or (t2t > max_temp)) {
324 if (debug) {
325 Serial.println("immediate stop");
326 }
327
328 pwmStop13();
329 }
330
331 if (currentTime >= (cloopTime + 500)) {
332
333
334
335 t2s.Push(t2t);
336
337 cloopTime = currentTime;
338
339
340 noInterrupts();
341 liters = count;
342 count = 0;
343 interrupts();
344
345
346
347 if (liters > min_flow) {
348 seq++;
349 lastPulse = currentTime;
350 last_zero = 0;
351 } else {
352 if (last_zero > 2) {
353 seq = 0;
354 }
355 last_zero++;
356 }
357 if (debug) {
358 str = "liters: " + String(liters) + " t1t: " + String(t1t) + " t2t: " + String(t2t) + " seq: " + String(seq) + " n: " + String(n);
359 Serial.println(str);
360 }
361
362 t1sum = 0;
363 t2sum = 0;
364 n = 0;
365
366 if ((liters <= min_flow) or (t2t > max_temp + 2) or (t1t >= 48)) {
367 if (debug) {
368 Serial.println("stop");
369 Serial.println("seq " + String(seq));
370 }
371 pwmStop13();
372 } else if (seq >= 5) {
373 t2s.getmat(y);
374 if (fitCurve(order, t2s.getsize(), x, y, sizeof(coeffs) / sizeof(double), coeffs) == 0 and !isnan(coeffs[0])) {
375 pred = (coeffs[0] * (window + pred_w) + coeffs[1]) * (window + pred_w) + coeffs[2];
376 pred0 = (coeffs[0] * (window + 1) + coeffs[1]) * (window + 1) + coeffs[2];
377 a = t2s.avg(10);
378 m = t2s.slope(4) * 2;
379
380
381 if (max(a, t2t) > (max_temp)) {
382 if (debug) {
383 Serial.println(" +Powering off");
384 }
385 putLCD ('M', 1);
386 pwmStop13();
387 } else if (min(a, t2t) < (max_temp - 12)) {
388 if (debug) {
389 Serial.println(" -Powering on");
390 }
391 putLCD ('m', 0);
392 pwmSet13();
393 } else if (m > 0.2) {
394 if (max(a, t2t) > (max_temp -10) and pred > (max_temp -5) and t2t < (pred0 + 1) and (pred0 + 1) < pred and pred > (a + 2)) {
395 if (debug) {
396 Serial.println(" Powering off");
397 }
398 putLCD ('.', 1);
399 pwmStop13();
400 } else if (min(a, t2t) < (max_temp -3) and pred < (max_temp -8) and t2t > pred0 and pred0 > (pred + 1) ) {
401 if (debug) {
402 Serial.println(" Powering on");
403 }
404 putLCD ('.', 0);
405 pwmSet13();
406 }
407 } else if (m <= -0.1) {
408 if (max(a, t2t) > (max_temp - 10) and pred > (max_temp -5) and t2t < (pred0 + 1) and (pred0 + 1) < pred) {
409 if (debug) {
410 Serial.println(" *Powering off");
411 }
412 putLCD (':', 1);
413 pwmStop13();
414 } else if (max(a, t2t) >= (max_temp -10) and t2t <= max_temp and pred < (max_temp -5) and a >= (pred + 6) and t2t > pred0 and pred0 > (pred + 1)) {
415 if (debug) {
416 Serial.println(" *Powering on");
417 }
418 putLCD (':', 0);
419 pwmSet13();
420 } else if ((t2t + 1) < a and t2t < max_temp and a >= (pred + 3) and t2t > pred0 and pred0 > (pred + 1)) {
421 if (debug) {
422 Serial.println(" *Powering on *");
423 }
424 putLCD ('-', 0);
425 pwmSet13();
426 }
427 } else {
428 if ((a <= t2t and t2t > (max_temp -4) and pred >= (a + 2) and pred0 < pred) or (t2t > (max_temp - 2))) {
429 if (debug) {
430 Serial.println(" **Powering off");
431 }
432 putLCD ('*', 1);
433 pwmStop13();
434 } else if (t2t <= (max_temp -4) and t2t < a and (pred + 2) < a and pred0 >= pred) {
435 if (debug) {
436 Serial.println(" **Powering on");
437 }
438 putLCD ('*', 0);
439 pwmSet13();
440 }
441 }
442 }
443 }
444
445 toLCD (format1, liters, a, m, 0);
446 toLCD (format2, t2t, pred, pred0, 1);
447
448 if ((currentTime >= (lastPulse + 300000)) and (liters < min_flow)) {
449sleepy:
450 if (debug) {
451 Serial.println("sleepy");
452 }
453 SafeBLoff();
454 delay(500);
455 noInterrupts();
456 detachInterrupt(digitalPinToInterrupt(flowsensor));
457 set_sleep_mode(SLEEP_MODE_PWR_DOWN);
458 sleep_enable();
459 attachInterrupt(digitalPinToInterrupt(flowsensor), wake, RISING);
460 interrupts();
461
462 adcsra_save = ADCSRA;
463 prr0_save = PRR0;
464
465 pwmStop13();
466
467 ADCSRA &= ~(1 << ADEN);
468 PRR0 = 0xFF;
469
470 sleep_mode();
471 sleep_disable();
472 PRR0 = 0x00;
473 ADCSRA |= (1 << ADEN);
474
475 ADCSRA = adcsra_save;
476 PRR0 = prr0_save;
477
478
479 noInterrupts();
480 attachInterrupt(digitalPinToInterrupt(flowsensor), flow, RISING);
481 interrupts();
482
483 currentTime = millis();
484 cloopTime = currentTime;
485 int times = 0;
486 count = 0;
487 liters = 0;
488 int i = 0;
489 t2s.Zero();
490
491 for (i = 0; i < 6; i++) {
492 while (currentTime < (cloopTime + 1000)) {
493 yield();
494 t2s.Push(VtoC(analogRead(t2_pin)));
495 delay(25);
496 currentTime = millis();
497 }
498 if (count > 0) {
499 noInterrupts();
500 liters = liters + count;
501 count = 0;
502 interrupts();
503 times = times + 1;
504 }
505 if ((liters > 50) and (times > 2)) {
506 break;
507 }
508 cloopTime = currentTime;
509 }
510
511 if ((times < 5) and (liters < 30)) {
512 goto sleepy;
513 }
514
515 seq = times;
516
517 currentTime = millis();
518 lastPulse = currentTime;
519
520 SafeBLon();
521 delay(100);
522 t1sum = 0;
523 t2sum = 0;
524 n = 0;
525
526 }
527 }
528}