Skip to content

Commit 1108dbb

Browse files
Updated to v2
1 parent 7351fb8 commit 1108dbb

29 files changed

+952
-214
lines changed

arduino-plant-watering.ino

+160-122
Original file line numberDiff line numberDiff line change
@@ -1,160 +1,198 @@
1-
#include "toggle_switch.h"
2-
#include "debounce.h"
1+
#include <avr/wdt.h>
2+
3+
#include <LiquidCrystal.h>
4+
#include <DS3232RTC.h> //http://github.com/JChristensen/DS3232RTC
5+
#include <Time.h> //http://www.arduino.cc/playground/Code/Time
6+
#include <Wire.h> //http://arduino.cc/en/Reference/Wire (included with Arduino IDE)
7+
8+
#include "config.h"
9+
#include "ds3232.h"
10+
#include "buttons.h"
11+
#include "lcd.h"
12+
#include "frames.h"
313
#include "busy_wait.h"
414

5-
#define BIT_IS_SET(x, n) ((x) & (1<<(n)))
6-
#define BIT_SET(x, n) ((x) |= (1<<(n)))
7-
#define BIT_UNSET(x, n) ((x) &= ~(1<<(n)))
8-
#define BIT_TOGGLE(x, n) ((x) ^= (1<<(n)))
15+
pump_t pump = {.state = PUMP_OFF, .state_start = 0, .count = 0};
916

10-
#define RELAY_BIT_POS 0
11-
#define TOGGLE_SWITCH_BIT_POS 1
12-
#define FLOAT_SWITCH_BIT_POS 2
17+
void setup() {
18+
uint8_t arrow[8] = {
19+
0b00000,
20+
0b00100,
21+
0b00010,
22+
0b11111,
23+
0b00010,
24+
0b00100,
25+
0b00000,
26+
0b00000
27+
};
28+
lcd.createChar(0, arrow);
29+
lcd.begin(COLS, ROWS);
30+
31+
lcd.print("WATER PUMPER 1.0");
32+
uint16_t _delay = 1000;
33+
uint16_t _char_delay = _delay / COLS;
34+
35+
uint8_t i, j = 0;
36+
for (j = 0; j < COLS; ++j) {
37+
if (j > 0) {
38+
busyWait(_char_delay);
39+
}
1340

14-
/* Input/Output pins */
15-
#define RELAY_PIN 4
16-
#define OFF_SWITCH 3
17-
#define FLOAT_SWITCH_PIN 2
41+
lcd.setCursor(0, 1);
42+
for (i = 0; i < j; ++i) {
43+
lcd.print('-');
44+
}
45+
lcd.write(byte(0));
46+
}
1847

19-
/* LEDs */
20-
#define OFF_SWITCH_LED_PIN 5
21-
#define FLOAT_SWITCH_LED_PIN 6
22-
#define PUMP_LED_PIN 7
48+
setSyncProvider(RTC.get);
49+
if (timeStatus() != timeSet) {
50+
lcd.print("Error: Invalid time status");
51+
}
2352

24-
/* watering schedule */
25-
#define TIME_BETWEEN_WATERING 10000
26-
#define WATER_TIME 5000
53+
delay(1000);
2754

28-
#define DEBUG 1
55+
/* configure our buttons, according to:
2956
30-
volatile uint8_t state_mask;
57+
[analog A0]
58+
|
59+
5v --> [1kΩ] -+--> [270Ω] +-> [390Ω] +
60+
| | |
61+
v v v
62+
[ btn ] [ btn ] [ btn ]
63+
| | |
64+
gnd <---------+-----------+----------+
65+
*/
66+
button_init(1000, 0);
67+
button_init(1000, 270);
68+
button_init(1000, 270 + 390);
3169

32-
volatile toggle_switch_t button;
33-
volatile toggle_switch_t float_switch;
34-
debounce_t button_debounce;
35-
debounce_t float_switch_debounce;
70+
readAlarm(ALARM_2, &alarm2_def);
3671

37-
unsigned long pump_state_msec;
72+
// clear alarm flags
73+
RTC.alarm(ALARM_1);
74+
RTC.alarm(ALARM_2);
3875

39-
void setup() {
40-
Serial.begin(9600);
41-
pinMode(RELAY_PIN, OUTPUT);
42-
pinMode(OFF_SWITCH_LED_PIN, OUTPUT);
43-
pinMode(PUMP_LED_PIN, OUTPUT);
44-
pinMode(FLOAT_SWITCH_LED_PIN, OUTPUT);
45-
46-
/* pullup the toggle switch to 10k internal resistor */
47-
pinMode(OFF_SWITCH, INPUT_PULLUP);
48-
/* pullup the float switch to 10k internal resistor */
49-
pinMode(FLOAT_SWITCH_PIN, INPUT_PULLUP);
50-
51-
/* because of INPUT_PULLUP, we need to take action when circuit goes from HIGH -> LOW or LOW -> HIGH */
52-
attachInterrupt(digitalPinToInterrupt(OFF_SWITCH), handleToggleButton, CHANGE);
53-
attachInterrupt(digitalPinToInterrupt(FLOAT_SWITCH_PIN), handleFloatSwitch, CHANGE);
54-
55-
debounce_init(&button_debounce);
56-
debounce_init(&float_switch_debounce);
57-
toggle_switch_init((toggle_switch_t*)&button, OFF_SWITCH, 1);
58-
toggle_switch_init((toggle_switch_t*)&float_switch, FLOAT_SWITCH_PIN);
59-
60-
pump_state_msec = 0;
61-
62-
/* if toggle switch is in ON position at startup ... */
63-
if (toggle_switch_on(&button)) {
64-
BIT_SET(state_mask, TOGGLE_SWITCH_BIT_POS);
65-
}
76+
RTC.squareWave(SQWAVE_NONE);
6677

67-
if (toggle_switch_on(&float_switch)) {
68-
BIT_SET(state_mask, FLOAT_SWITCH_BIT_POS);
69-
}
78+
current_time = now();
7079

71-
delay(1000);
72-
}
80+
RTC.setAlarm(ALM1_EVERY_SECOND, 0, 0, 0, 0); // every second
81+
//RTC.setAlarm(ALM2_MATCH_MINUTES, 0, 0, 0, 0); // every zero-th minute
82+
RTC.alarmInterrupt(ALARM_1, true);
83+
//RTC.alarmInterrupt(ALARM_2, true);
7384

74-
void handleToggleButton() {
75-
if (debounce_toggle_switch(&button, &button_debounce, 2)) {
76-
toggle_switch_read_state(&button);
85+
pinMode(RTC_INT_PIN, INPUT_PULLUP);
86+
attachInterrupt(digitalPinToInterrupt(RTC_INT_PIN), alarmChange, FALLING);
7787

78-
if (toggle_switch_on(&button)) {
79-
BIT_SET(state_mask, TOGGLE_SWITCH_BIT_POS);
80-
} else {
81-
BIT_UNSET(state_mask, TOGGLE_SWITCH_BIT_POS);
82-
}
88+
pinMode(FLOAT_SWITCH_INT_PIN, INPUT_PULLUP);
89+
attachInterrupt(digitalPinToInterrupt(FLOAT_SWITCH_INT_PIN), floatSwitchInterrupt, CHANGE);
90+
91+
pinMode(PUMP_PIN, OUTPUT);
92+
digitalWrite(PUMP_PIN, LOW);
93+
}
94+
95+
void pump_on() {
96+
if (digitalRead(FLOAT_SWITCH_INT_PIN) == FLOAT_SWITCH_OFF) {
97+
return;
8398
}
99+
100+
pump.state = PUMP_ON;
101+
pump.state_start = millis();
102+
pump.count++;
103+
digitalWrite(PUMP_PIN, HIGH);
104+
105+
/* configure watchdog to 1 second */
106+
watchdog_init(WDTO_1S);
84107
}
85108

86-
void handleFloatSwitch() {
87-
if (debounce_toggle_switch(&float_switch, &float_switch_debounce, 2)) {
88-
toggle_switch_read_state(&float_switch);
109+
void pump_off() {
110+
wdt_disable();
89111

90-
if (toggle_switch_on(&float_switch)) {
91-
BIT_SET(state_mask, FLOAT_SWITCH_BIT_POS);
92-
} else {
93-
BIT_UNSET(state_mask, FLOAT_SWITCH_BIT_POS);
94-
}
95-
}
112+
digitalWrite(PUMP_PIN, LOW);
113+
pump.state = PUMP_OFF;
114+
pump.state_start = millis();
96115
}
97116

98-
void loop() {
99-
writeStateMaskToLeds();
117+
uint16_t get_pump_count() {
118+
return pump.count;
119+
}
100120

101-
if (!BIT_IS_SET(state_mask, TOGGLE_SWITCH_BIT_POS) || !BIT_IS_SET(state_mask, FLOAT_SWITCH_BIT_POS)) {
102-
if (BIT_IS_SET(state_mask, RELAY_BIT_POS)) {
103-
digitalWrite(RELAY_PIN, LOW);
104-
pump_state_msec = 0;
105-
BIT_UNSET(state_mask, RELAY_BIT_POS);
106-
}
107-
return;
121+
/*
122+
RTC Alarm ISR
123+
*/
124+
void alarmChange() {
125+
alarmCalled = 1;
126+
}
127+
128+
/*
129+
Float switch ISR
130+
*/
131+
void floatSwitchInterrupt() {
132+
if (digitalRead(FLOAT_SWITCH_INT_PIN) == FLOAT_SWITCH_OFF && pump.state == PUMP_ON) {
133+
pump_off();
108134
}
135+
}
109136

110-
if (!BIT_IS_SET(state_mask, RELAY_BIT_POS)) {
111-
/* scheduler is active but pump is not running */
137+
void watchdog_init(uint8_t mask) {
138+
/* Clear the reset flag. */
139+
MCUSR &= ~(1 << WDRF);
112140

113-
if (pump_state_msec == 0 || ((millis() - pump_state_msec) > TIME_BETWEEN_WATERING)) {
114-
digitalWrite(RELAY_PIN, HIGH);
115-
pump_state_msec = millis();
116-
BIT_SET(state_mask, RELAY_BIT_POS);
117-
}
118-
return;
119-
}
141+
/* In order to change WDE or the prescaler, we need to
142+
* set WDCE (This will allow updates for 4 clock cycles).
143+
*/
144+
WDTCSR |= (1<<WDCE) | (1<<WDE);
120145

121-
/* scheduler is active and pump is running */
146+
/* set new watchdog timeout prescaler value */
147+
WDTCSR = mask;
122148

123-
if ((millis() - pump_state_msec) > WATER_TIME) {
124-
digitalWrite(RELAY_PIN, LOW);
125-
pump_state_msec = millis();
126-
BIT_UNSET(state_mask, RELAY_BIT_POS);
127-
}
149+
/* Enable the WD interrupt (note no reset). */
150+
WDTCSR |= _BV(WDIE);
128151
}
129152

130-
void turnLedOn(int pin) {
131-
if (digitalRead(pin) == LOW) {
132-
digitalWrite(pin, HIGH);
133-
}
153+
/*
154+
Watchdog ISR
155+
*/
156+
ISR(WDT_vect) {
157+
if ((millis() - pump.state_start) >= WATER_RUNTIME) {
158+
pump_off();
159+
}
134160
}
135161

136-
void turnLedOff(int pin) {
137-
if (digitalRead(pin) == HIGH) {
138-
digitalWrite(pin, LOW);
139-
}
140-
}
162+
void loop() {
163+
if (alarmCalled) {
164+
alarmCalled = 0;
165+
if (RTC.alarm(ALARM_1)) {
166+
handle_alarm1();
167+
}
141168

142-
void writeStateMaskToLeds() {
143-
if (BIT_IS_SET(state_mask, TOGGLE_SWITCH_BIT_POS)) {
144-
turnLedOn(OFF_SWITCH_LED_PIN);
145-
} else {
146-
turnLedOff(OFF_SWITCH_LED_PIN);
169+
if (RTC.alarm(ALARM_2) && is_alarm_active(ALARM_2)) {
170+
handle_alarm2();
171+
}
147172
}
148173

149-
if (BIT_IS_SET(state_mask, FLOAT_SWITCH_BIT_POS)) {
150-
turnLedOn(FLOAT_SWITCH_LED_PIN);
151-
} else {
152-
turnLedOff(FLOAT_SWITCH_LED_PIN);
174+
switch (get_active_frame()) {
175+
case FRAME_0:
176+
/* root frame */
177+
frame0();
178+
break;
179+
180+
case FRAME_1:
181+
/* menu frame */
182+
frame1();
183+
break;
184+
185+
case FRAME_2:
186+
/* menu option frame */
187+
frame2();
188+
break;
153189
}
154190

155-
if (BIT_IS_SET(state_mask, RELAY_BIT_POS)) {
156-
turnLedOn(PUMP_LED_PIN);
157-
} else {
158-
turnLedOff(PUMP_LED_PIN);
191+
set_prev_frame(get_active_frame());
192+
193+
if (get_next_frame() != -1) {
194+
set_active_frame(get_next_frame());
195+
set_next_frame(-1);
196+
set_last_draw();
159197
}
160198
}

0 commit comments

Comments
 (0)