SapFlow Probe
A low-cost HRM probe for measuring a tree's water consumption
schedule.h File Reference
#include <OPEnS_RTC.h>
#include <LowPower.h>
#include "pinout.h"
#include "measure.h"
#include "debug.h"

Go to the source code of this file.

Functions

void alarmISR (void)
 Interrupt handler for RTC alarm. More...
 
void feather_sleep (void)
 Maximizes power savings during sleep. More...
 
void sleep_cycle (int interval=5)
 Sleep function for periodic sleeping. More...
 
int schedule (struct pt *pt=&sched_thd)
 Controls general measurement schedule. More...
 

Variables

static struct pt sched_thd
 Protothread control structure for measure()
 
static RTC_DS3231 rtc_ds
 Instance of our real-time clock.
 
static bool sleep
 Global flag to prep for sleep.
 

Function Documentation

◆ alarmISR()

void alarmISR ( void  )

Interrupt handler for RTC alarm.

Called when the feather wakes up from sleep. Disables the RTC interrupt.

Definition at line 5 of file schedule.cpp.

5  {
6  // Reset the alarm.
7  rtc_ds.armAlarm(1, false);
8 
9  // Disable this interrupt
10  detachInterrupt(digitalPinToInterrupt(ALARM_PIN));
11 }

◆ feather_sleep()

void feather_sleep ( void  )

Maximizes power savings during sleep.

Steps for going to sleep:

  1. Attach interrupt to RTC pin
  2. Disconnect from the SD card
  3. Disconnect from Serial and USB
  4. Turn off power rails and status LED
  5. Begin deep sleep

Steps for waking up:

  1. Attach USB and Serial
  2. Turn on power rails and status LED
  3. Open SD card

Definition at line 13 of file schedule.cpp.

13  {MARK();
14  // Wait for the alarm to clear
15  while(!digitalRead(ALARM_PIN)){
16  pinMode(ALARM_PIN, INPUT_PULLUP);
17  Serial.print("Waiting on alarm pin...");
18  delay(10);
19  }MARK();
20  // Disable SPI to save power
21  pinMode(SPI_SCK, INPUT);
22  pinMode(SPI_MOSI, INPUT);
23  pinMode(SD_CS, INPUT);
24  // Turn off power rails
25  digitalWrite(EN_3v3, HIGH);
26  digitalWrite(EN_5v, LOW);
27  digitalWrite(STATUS_LED, LOW);MARK();
28  Serial.println("Sleeping");
30 #if 1
31  // Prep for sleep
32  Serial.end();
33  USBDevice.detach();
34  // Low-level so we can wake from sleep
35  // We have to call this twice - maybe a synchronization issue?
36  attachInterrupt(digitalPinToInterrupt(ALARM_PIN), alarmISR, LOW);
37  attachInterrupt(digitalPinToInterrupt(ALARM_PIN), alarmISR, LOW);
38  // Sleep
39  LowPower.standby();
40 
41  // Prep to resume
42  USBDevice.attach();
43  Serial.begin(115200);
44 #else
45  // Pretend to sleep, so the serial terminal doesn't exit
46  // This draws a lot of power, so don't do this in production
47  while(digitalRead(ALARM_PIN));
48 #endif
49  // Resume the watchdog
53  MARK();
54  // Enable the power rails
55  digitalWrite(STATUS_LED, HIGH);
56  digitalWrite(EN_3v3, LOW);
57  digitalWrite(EN_5v, HIGH);
58  // Start the SD card again
59  pinMode(SPI_SCK, OUTPUT);
60  pinMode(SPI_MOSI, OUTPUT);
61  pinMode(SD_CS, OUTPUT);MARK();
62  sd.begin(SD_CS, SD_SCK_MHZ(1));MARK();
63 }

◆ schedule()

int schedule ( struct pt *  pt = &sched_thd)

Controls general measurement schedule.

This is the schedule:

  1. Measure temperature of tree (before heat is applied)
  2. Apply heat pulse
  3. Wait for the peak of the heat to reach the upper and lower probes.
  4. Measure the sap flow
  5. Sleep until next measurement cycle
    Parameters
    ptA pointer to the protothread control structure. The default parameter is correct. Don't forget to initialize the control structure in setup().
    Returns
    the status of the protothread (Waiting, yeilded, exited, or ended)

Definition at line 81 of file schedule.cpp.

82 {
83  PT_BEGIN(pt);
84  Serial.print("Initializing schedule thread... ");
85  // RTC Timer settings here
86  if (! rtc_ds.begin()) {
87  Serial.println("Couldn't find RTC");
88  }
89  // If this is a new RTC, set the time
90  if (rtc_ds.lostPower()) {
91  Serial.println("RTC lost power, lets set the time!");
92  // Set the RTC to the date & time this sketch was compiled
93  rtc_ds.adjust(DateTime(F(__DATE__), F(__TIME__)));
94  }
95  Serial.println("Done");
96  // This is the main schedule for the program
97  while (1)
98  {
99  Serial.print("Awoke at ");MARK();
100  Serial.println(rtc_ds.now().text());MARK();
101  PT_WAIT_THREAD(pt, baseline());MARK(); //<Measure the baseline temp
102  digitalWrite(HEATER, HIGH);MARK(); //< Turn on the heater
103  Serial.print("Heater On at ");MARK();
104  Serial.println(rtc_ds.now().text());MARK();
105  PT_TIMER_DELAY(pt,6000);MARK(); //< Heater is on for 6 seconds
106  digitalWrite(HEATER, LOW);MARK(); //< Turn off the heater
107  Serial.print("Heater Off at ");MARK();
108  Serial.println(rtc_ds.now().text());MARK();
109  PT_TIMER_DELAY(pt,100);MARK(); //< Wait for heat to propagate
110  Serial.println("Temperature probably reached plateau");MARK();
111  PT_WAIT_THREAD(pt, delta());MARK(); //<Calculate the sapflow
112  Serial.println("Finished logging");MARK();
113  sleep_cycle(5); MARK(); //<Sleep until the next multiple of 5 minutes
114  sleep = false;
115  }
116  PT_END(pt);
117 }

◆ sleep_cycle()

void sleep_cycle ( int  interval = 5)

Sleep function for periodic sleeping.

Sleep until the time is a round multiple of the minute inteval. Produces unexpected bevahior for non-factors of 60 (7, 8, 9, 11, etc). For example, if it's 5:39 and you select an interval of 15, the microcontroller will wake up at 5:45, since 3*15 = 45. This function internally calls feather_sleep() to handle prep and resume from sleeping

Parameters
intervalThe increment to sleep for.

Definition at line 67 of file schedule.cpp.

67  {MARK();
68  Serial.print("Sleeping until nearest multiple of ");
69  Serial.print(interval);
70  Serial.println(" minutes");MARK();
71  DateTime t = rtc_ds.now();MARK();
72  t = t + TimeSpan( interval * 60 );MARK();
73  uint8_t minutes = interval*(t.minute()/interval);MARK();
74  rtc_ds.setAlarm(ALM2_MATCH_MINUTES, minutes, 0, 0);MARK();
75  Serial.print("Alarm set to ");MARK();
76  t = rtc_ds.getAlarm(2);MARK();
77  Serial.println(t.text());MARK();
78  feather_sleep();MARK();
79 }
EN_5v
@ EN_5v
Control pin for 5v Power rail. Output, Active-high.
Definition: pinout.h:13
STATUS_LED
@ STATUS_LED
Built-in LED on feather. Active-high.
Definition: pinout.h:17
sleep_cycle
void sleep_cycle(int interval)
Sleep function for periodic sleeping.
Definition: schedule.cpp:67
EN_3v3
@ EN_3v3
Control pin for 3.3V power rail. Output, Active-low.
Definition: pinout.h:12
rtc_ds
static RTC_DS3231 rtc_ds
Instance of our real-time clock.
Definition: schedule.h:11
SPI_MOSI
@ SPI_MOSI
SPI data pin. Output.
Definition: pinout.h:21
alarmISR
void alarmISR()
Interrupt handler for RTC alarm.
Definition: schedule.cpp:5
feather_sleep
void feather_sleep(void)
Maximizes power savings during sleep.
Definition: schedule.cpp:13
FunctionMarker::print
void print(void)
Prints the most recently recorded value.
Definition: debug.cpp:42
FunctionMarker::resume
void resume(void)
Re-enable the watchdog. You should do this right after waking from sleep.
Definition: debug.cpp:37
baseline
int baseline(struct pt *pt)
Calculates baseline temperature.
Definition: measure.cpp:65
FunctionMarker::pause
void pause(void)
Pause the watchdog. You'll want to do this before sleeping.
Definition: debug.cpp:33
sd
static SdFat sd
File system object.
Definition: sd_log.h:14
HEATER
@ HEATER
Control pin for heater switch. Output, Active-high.
Definition: pinout.h:15
MARK
#define MARK()
This macro records the line number and function name.
Definition: debug.h:72
halt_location
static class FunctionMarker halt_location
Singleton of our debug class.
Definition: debug.h:64
delta
int delta(struct pt *pt)
Calculates temperature delta and sapflow.
Definition: measure.cpp:91
FunctionMarker::read
bool read(void)
Read the recorded value from flash.
Definition: debug.cpp:58
sleep
static bool sleep
Global flag to prep for sleep.
Definition: schedule.h:13
SPI_SCK
@ SPI_SCK
SPI clock pin. Output.
Definition: pinout.h:20
ALARM_PIN
@ ALARM_PIN
Interrupt pin from RTC. Pull-up, Active-low.
Definition: pinout.h:16
SD_CS
@ SD_CS
SPI chip select for SD card. Output, Active-low.
Definition: pinout.h:14