Template
261 lines
6.0 KiB
Arduino
261 lines
6.0 KiB
Arduino
// https://gist.github.com/jdneo/43be30d85080b175cb5aed3500d3f989
|
|
|
|
// Timer Interrupt example for Adafruit Feather M0.
|
|
// Callback function can be written in TC3_Handler().
|
|
|
|
// better comments with TC5
|
|
// https://gist.github.com/nonsintetic/ad13e70f164801325f5f552f84306d6f
|
|
|
|
// Handlers declared here
|
|
// https://github.com/arduino/ArduinoCore-samd/blob/master/cores/arduino/cortex_handlers.c
|
|
// (void*) TC3_Handler, /* 18 Basic Timer Counter 0 */
|
|
// void TC3_Handler (void) __attribute__ ((weak, alias("Dummy_Handler")));
|
|
// to be defined by user
|
|
|
|
|
|
// VUSB -> Hdr-1
|
|
// D12 -> Hdr-2
|
|
// Hdr-3
|
|
// D11 <- Hdr-4
|
|
// Hdr-5
|
|
// GND -> Hdr-6
|
|
|
|
#define DEBUG false
|
|
|
|
#define DEBUGSTATE(s) {\
|
|
Serial.println(); \
|
|
Serial.print("S"); \
|
|
Serial.println(s); \
|
|
Serial.println(); \
|
|
}
|
|
|
|
#define LED_PIN 13
|
|
|
|
#define PUMP_PIN 12
|
|
#define PUMP_ON digitalWrite(PUMP_PIN,LOW)
|
|
#define PUMP_OFF digitalWrite(PUMP_PIN,HIGH)
|
|
|
|
#define FLOW_PIN 11 // this is INT0
|
|
#define FLOWING digitalRead(FLOW_PIN)==LOW
|
|
#define NOTFLOWING digitalRead(FLOW_PIN)==HIGH
|
|
|
|
// 2/3 = 66% duty cycle
|
|
#define PUMP_RUN_TIME 1200 // ticks. run for 2min = 120sec after flowstarted
|
|
#define PUMP_OFF_TIME 600 // ticks. keep off 1min = 60sec before re-enabling
|
|
|
|
#define FLOW_THLD 20 // ticks @ RATE 2 seconds
|
|
|
|
#define RATE 10 // Hz == 100mS ticks
|
|
|
|
// declare Timer1_ISR functions
|
|
void startTimer(int frequencyHz);
|
|
void setTimerFrequency(int frequencyHz);
|
|
void TC3_Handler();
|
|
|
|
bool isLEDOn = false;
|
|
bool notRun = true;
|
|
|
|
|
|
/*
|
|
* ticks are each 100mS so uint is 6553.5 seconds = 109.2 min
|
|
* ticktime 32 bit 0.1sec rollover is 13 years
|
|
* 16 bits would be 109 minutes
|
|
* make all timers unsigned long to avoid comparison wrap around
|
|
*/
|
|
|
|
unsigned long totalflow = 0;
|
|
|
|
unsigned long flowstarted = 0;
|
|
unsigned long flowstopped = 0;
|
|
unsigned long pumpstarted = 0;
|
|
unsigned long pumpstopped = 0;
|
|
|
|
|
|
boolean flow = false;
|
|
boolean pumpOn = false;
|
|
boolean pumpRan = false;
|
|
boolean pumpEnabled = true;
|
|
|
|
// FSM
|
|
enum FSM {S0,S1,S2,S3};
|
|
|
|
FSM state=S0;
|
|
|
|
volatile boolean intflag1 = false; // external interrupt (event)
|
|
volatile unsigned long ticktime = 0;
|
|
volatile unsigned int ticknum = 0;
|
|
|
|
|
|
|
|
// external pin interrupt handler
|
|
void flowstate() {
|
|
if (!intflag1) {
|
|
intflag1 = true;
|
|
}
|
|
}
|
|
|
|
// called from TC3 ISR...
|
|
void Tick(void) {
|
|
ticknum++;
|
|
ticktime++;
|
|
} // end Tick
|
|
|
|
void toggleLED(){
|
|
digitalWrite(LED_PIN, isLEDOn);
|
|
isLEDOn = !isLEDOn;
|
|
}
|
|
|
|
void setup() {
|
|
pinMode(LED_PIN, OUTPUT);
|
|
pinMode(PUMP_PIN, OUTPUT);
|
|
pinMode(FLOW_PIN, INPUT_PULLUP);
|
|
attachInterrupt(FLOW_PIN, flowstate, FALLING);
|
|
startTimer(RATE);
|
|
|
|
if (DEBUG) {
|
|
//Initialize serial and wait for port to open:
|
|
Serial.begin(9600);
|
|
while (!Serial) {
|
|
; // wait for serial port to connect. Needed for native USB port only
|
|
}
|
|
}
|
|
} // end setup()
|
|
|
|
|
|
/*
|
|
* S0: wait for flow threshold before turning pump on
|
|
* S1: wait for pump off
|
|
* S2: wait for flow to stop
|
|
* S3: wait for hysteresis time before cycling again
|
|
*
|
|
* When the pump stops and there is still flow (demand), don't restart the pump until flow stops + offtime
|
|
* This avoids cycling the pump during a shower.
|
|
*/
|
|
|
|
// loop() is called repeatedly
|
|
void loop () {
|
|
|
|
switch (state){
|
|
case S0:
|
|
if (flow && pumpEnabled) {
|
|
state = S1;
|
|
if (DEBUG) DEBUGSTATE(state)
|
|
if (DEBUG) Serial.print("pump start @ ");
|
|
if (DEBUG) Serial.println(ticktime);
|
|
pumpOn = true;
|
|
pumpEnabled = false;
|
|
pumpstarted = ticktime;
|
|
}
|
|
break;
|
|
case S1:
|
|
if (!pumpOn) {
|
|
state = S2;
|
|
if (DEBUG) DEBUGSTATE(state)
|
|
}
|
|
break;
|
|
case S2:
|
|
if (!flow) { // wait for flow to stop; don't need to keep pumping!
|
|
state = S3;
|
|
if (DEBUG) DEBUGSTATE(state)
|
|
//totalflow = Tflow;
|
|
}
|
|
break;
|
|
case S3:
|
|
// post totalflow via MQTT
|
|
if (pumpEnabled) { // limit duty cycle
|
|
state = S0;
|
|
if (DEBUG) DEBUGSTATE(state)
|
|
}
|
|
break;
|
|
} // FSM
|
|
|
|
|
|
|
|
// record flowstart time
|
|
if (intflag1 && (flowstarted == 0)) {
|
|
flowstarted = ticktime; // only set flowstarted time once!
|
|
}
|
|
|
|
|
|
// process interrupt (after setting flowstart time)
|
|
if (intflag1) {
|
|
if (ticktime > flowstarted + FLOW_THLD) { // delay to avoid bounces generating more interrupts
|
|
if (FLOWING) {
|
|
flow = true; // set flow state 2000mS after interrupt IF still flowing
|
|
} else { // flow didn't last longer than the threshold!
|
|
flow = false;
|
|
flowstarted = 0; // reset
|
|
}
|
|
intflag1 = false; // clear interrupt.
|
|
if (DEBUG) Serial.println("flow interrupt");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// record flowstop time
|
|
if ((flow == true) && (NOTFLOWING) && (flowstopped == 0)) {
|
|
flowstopped = ticktime; // only set flowstopped time once!
|
|
if (DEBUG) Serial.println("flow stop");
|
|
}
|
|
|
|
// flow stop
|
|
if ((flow == true) && (flowstopped > 0)){
|
|
if (ticktime > flowstopped + 20){ // flow state changes 2 sec after flowstopped
|
|
flow = false;
|
|
flowstopped = 0;
|
|
}
|
|
}
|
|
|
|
// pump stop
|
|
if (pumpOn){ // pump run time
|
|
if (ticktime > (pumpstarted + PUMP_RUN_TIME)) {
|
|
if (DEBUG) Serial.print("pump stop @ ");
|
|
if (DEBUG) Serial.println(ticktime);
|
|
if (DEBUG) Serial.println(pumpstarted);
|
|
pumpOn = false;
|
|
flowstarted = 0;
|
|
pumpstarted = 0;
|
|
pumpstopped = ticktime;
|
|
}
|
|
}
|
|
|
|
// pump enable
|
|
if (pumpstopped > 0){
|
|
if (ticktime > (pumpstopped + PUMP_OFF_TIME)) {
|
|
pumpEnabled = true;
|
|
pumpstopped = 0;
|
|
}
|
|
}
|
|
|
|
// motor control
|
|
if (pumpOn) {
|
|
PUMP_ON;
|
|
} else {
|
|
PUMP_OFF;
|
|
}
|
|
|
|
|
|
// 1 Hz debug events
|
|
if (ticknum >= 10) { // 1 sec
|
|
ticknum = 0;
|
|
toggleLED();
|
|
//Serial.println(ticktime);
|
|
if (DEBUG) {
|
|
Serial.print(state);
|
|
Serial.print(" ");
|
|
Serial.print(intflag1);
|
|
Serial.print(flow);
|
|
Serial.print("\t");
|
|
Serial.print(flowstarted);
|
|
Serial.print("\t");
|
|
Serial.print(flowstopped);
|
|
Serial.print("\t");
|
|
Serial.print(pumpEnabled);
|
|
Serial.print(pumpOn);
|
|
Serial.println();
|
|
}
|
|
}
|
|
|
|
} // end loop()
|