Hello!
I'm running an Arduino Pro Mini 3.3v/8MHz and I'm trying to get external interrupts to work with the watchdog timer. The purpose of the device is 1. to take temperature and humidity readings inside and outside of a bird nest box/burrow, with a timestamp, every 2 minutes and 2. to record the time of the bird(s) entering and exiting the nest, using two IR break beam sensors. If it isn't doing either of those, it goes to sleep. All data is written to an SD card, one file for climate, one for activity.
Currently, I have the climate readings working with the WDT. When I add and trigger the external interrupts for the IR sensors the program appears to hang.
I've been referencing Nick Gammon's power saving and interrupt posts, but my understanding of the interactions of external interrupts with the WDT is lacking. Specifically, I'm trying to merge Sketch I and Sketch J in this post.
I'd like each interrupt to wake the processor, record the sensor event and time stamp to variables, then go back to sleep, continuing the 8s WDT cycle it interrupted. Ideally, it would also write them to the SD card, but from everything I've read, I don't think that's something the ISR should do, even though I tested it and it worked, so I'm unsure. Any thoughts on writing to and SD card in an ISR?
I've searched many similar posts with similar issues, but the different formats or libraries in each makes it hard to make an apples-to-apples comparison. So I've made an account because I feel like I'm trying to push my head trough a brick wall. ![]()
Any other code tips are also appreciated!
// Libraries
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <SD.h>
#include <DS3231.h>
#include <Wire.h>
#include <ClosedCube_SHT31D.h>
#include <Arduino.h>
// Set Device ID - Maximum 3 characters
const String deviceID = "21A";
// Set the year - 2 characters
const String seasonYear = "25";
// SD Card Reader
const int chipSelect = 10;
File myFile;
String activityFileName, temperatureFileName;
//RTC Real Time Clock Module
DS3231 myRTC;
bool century = false;
bool h12Flag;
bool pmFlag;
// SHT30 Temp Sensor
ClosedCube_SHT31D sht3xd;
float temp1;
float hum1;
float temp2;
float hum2;
//status of break beam sensors
volatile int enStatus = 0;
volatile int enSecond = 0;
volatile int enMinute = 0;
volatile int exStatus = 0;
volatile int exSecond = 0;
volatile int exMinute = 0;
int sleepCount = 0; // Variable for sleep loop
// Watchdog Interrupt
ISR(WDT_vect){
wdt_disable();
}
void setup() {
Serial.begin(115200);
pinMode(2, INPUT_PULLUP); //Entrance side sensor
pinMode(3, INPUT_PULLUP); //Exit side Sensor
pinMode(8, OUTPUT); //Temp sensor 1 power
pinMode(9, OUTPUT); //Temp sensor 2 power
Wire.begin();
SD.begin(chipSelect);
sht3xd.begin(0x44);
Serial.print("Initializing SD card...");
if (!SD.begin(chipSelect)) {
Serial.println("initialization failed. Things to check:");
Serial.println("1. is a card inserted?");
Serial.println("2. is your wiring correct?");
Serial.println("3. did you change the chipSelect pin to match your shield or module?");
Serial.println("Note: press reset button on the board and reopen this Serial Monitor after fixing your issue!");
while (true);
}
Serial.println("initialization done.");
myRTC.setClockMode(false);
myRTC.setYear(25);
myRTC.setMonth(7);
myRTC.setDate(7);
myRTC.setHour(20);
myRTC.setMinute(5);
myRTC.setSecond(0);
//turn off 32kHz pin
byte temp_buffer = temp_buffer & 0b11110111;
writeControlByte(temp_buffer, 1);
//turn of the SQW signal
temp_buffer = 0b01111111;
writeControlByte(temp_buffer, 0);
// Sets device ID and season in file name
activityFileName = seasonYear + "ACT" + deviceID + ".txt";
temperatureFileName = seasonYear + "TMP" + deviceID + ".txt";
Serial.println("setup done");
}
void loop() {
Serial.println(enStatus); //trying to see if the interrupt runs
delay(500);
// only run if not awoken by the external interrupt, trying to preserve roughly 2 minute measuring intervals
if (enStatus == 0 && exStatus == 0){
clmateRecord(); // records external and internal temperature and humidity
sleepCount++;
}
activityRecord(); // records entering and exiting activity
ADCSRA = 0; // disable ADC
MCUSR = 0; // clear various "reset" flags
WDTCSR = bit (WDCE) | bit (WDE); // allow changes, disable reset
WDTCSR = bit (WDIE) | bit (WDP3) | bit (WDP0); // set interrupt mode and an interval
//wdt_reset(); // pat the dog :)
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
noInterrupts();
sleep_enable();
attachInterrupt (digitalPinToInterrupt(2), enDet, CHANGE);
attachInterrupt (digitalPinToInterrupt(3), exDet, CHANGE);
EIFR = bit (INTF0);
EIFR = bit (INTF1);
MCUCR = bit (BODS) | bit (BODSE); // turn off brown-out enable in software
MCUCR = bit (BODS);
interrupts();
sleep_cpu();
sleep_disable();
}
// Turn off RTC 32K and SQW
void writeControlByte(byte control, bool which) {
Wire.beginTransmission(0x68);
if (which) {
Wire.write(0x0f);
} else {
Wire.write(0x0e);
}
Wire.write(control);
Wire.endTransmission();
}
// Edge detect ISR to record activity
// Activity.txt format: ID, Sensor code (EN/EX), State after change, timestamp
//Enter Detect
void enDet (){
sleep_disable();
detachInterrupt (0);
if (enStatus == 0){
if (digitalRead(2) == LOW){
enStatus = -1;
enMinute = myRTC.getMinute();
enSecond = myRTC.getSecond();
}
if (digitalRead(2) == HIGH){
enStatus = 1;
enMinute = myRTC.getMinute();
enSecond = myRTC.getSecond();
}
}
}
//Exit Detect
void exDet (){
sleep_disable();
detachInterrupt (1);
if (exStatus == 0){
if (digitalRead(3) == LOW){
exStatus = -1;
exMinute = myRTC.getMinute();
exSecond = myRTC.getSecond();
}
if (digitalRead(3) == HIGH){
exStatus = 1;
exMinute = myRTC.getMinute();
exSecond = myRTC.getSecond();
}
}
}
void activityRecord(){
if (enStatus == -1){
myFile = SD.open(activityFileName, FILE_WRITE);
myFile.print(deviceID);
myFile.print(',');
myFile.print("EN,LOW,");
myFile.print(myRTC.getYear());
myFile.print('/');
myFile.print(myRTC.getMonth(century));
myFile.print('/');
myFile.print(myRTC.getDate());
myFile.print(' ');
myFile.print(myRTC.getHour(h12Flag, pmFlag));
myFile.print(':');
myFile.print(enMinute);
myFile.print(':');
myFile.print(enSecond);
myFile.println(',');
myFile.close();
enStatus = 0;
enMinute = 0;
enSecond = 0;
}
if (enStatus == 1){
myFile = SD.open(activityFileName, FILE_WRITE);
myFile.print(deviceID);
myFile.print(',');
myFile.print("EN,HIGH,");
myFile.print(myRTC.getYear());
myFile.print('/');
myFile.print(myRTC.getMonth(century));
myFile.print('/');
myFile.print(myRTC.getDate());
myFile.print(' ');
myFile.print(myRTC.getHour(h12Flag, pmFlag));
myFile.print(':');
myFile.print(enMinute);
myFile.print(':');
myFile.print(enSecond);
myFile.println(',');
myFile.close();
enStatus = 0;
enMinute = 0;
enSecond = 0;
}
if (exStatus == -1){
myFile = SD.open(activityFileName, FILE_WRITE);
myFile.print(deviceID);
myFile.print(',');
myFile.print("EX,LOW,");
myFile.print(myRTC.getYear());
myFile.print('/');
myFile.print(myRTC.getMonth(century));
myFile.print('/');
myFile.print(myRTC.getDate());
myFile.print(' ');
myFile.print(myRTC.getHour(h12Flag, pmFlag));
myFile.print(':');
myFile.print(exMinute);
myFile.print(':');
myFile.print(exSecond);
myFile.println(',');
myFile.close();
exStatus = 0;
exMinute = 0;
exSecond = 0;
}
if (exStatus == 1){
myFile = SD.open(activityFileName, FILE_WRITE);
myFile.print(deviceID);
myFile.print(',');
myFile.print("EX,HIGH,");
myFile.print(myRTC.getYear());
myFile.print('/');
myFile.print(myRTC.getMonth(century));
myFile.print('/');
myFile.print(myRTC.getDate());
myFile.print(' ');
myFile.print(myRTC.getHour(h12Flag, pmFlag));
myFile.print(':');
myFile.print(exMinute);
myFile.print(':');
myFile.print(exSecond);
myFile.println(',');
myFile.close();
exStatus = 0;
exMinute = 0;
exSecond = 0;
}
}
void clmateRecord(){
// set to 1 for debugging, normally 15
if (sleepCount == 1) {
digitalWrite(8, HIGH);
printResult1("Pooling Mode", sht3xd.readTempAndHumidity(SHT3XD_REPEATABILITY_HIGH, SHT3XD_MODE_POLLING, 50));
digitalWrite(8, LOW);
digitalWrite(9, HIGH);
printResult2("Pooling Mode", sht3xd.readTempAndHumidity(SHT3XD_REPEATABILITY_HIGH, SHT3XD_MODE_POLLING, 50));
digitalWrite(9, LOW);
// Temperature readings
// File name format YYTMP##x.txt: YY - season year, TMP - Temperature designation, IDx - Device ID, 2 numbers, 1 letter maximum
// YYTMPIDx.txt format: ID, Terperature 1, Humidity 1, Temperature 2, Humidity 2, Timestamp
myFile = SD.open(temperatureFileName, FILE_WRITE);
myFile.print(deviceID);
myFile.print(',');
myFile.print(temp1);
myFile.print(',');
myFile.print(hum1);
myFile.print(',');
myFile.print(temp2);
myFile.print(',');
myFile.print(hum2);
myFile.print(',');
myFile.print(myRTC.getYear());
myFile.print('/');
myFile.print(myRTC.getMonth(century));
myFile.print('/');
myFile.print(myRTC.getDate());
myFile.print(' ');
myFile.print(myRTC.getHour(h12Flag, pmFlag));
myFile.print(':');
myFile.print(myRTC.getMinute());
myFile.print(':');
myFile.print(myRTC.getSecond());
myFile.println(',');
myFile.close();
sleepCount = 0;
}
}
// Temp sensor readouts
void printResult1(String text, SHT31D result) {
if (result.error == SHT3XD_NO_ERROR) {
temp1 = result.t;
hum1 = result.rh;
}
}
void printResult2(String text, SHT31D result) {
if (result.error == SHT3XD_NO_ERROR) {
temp2 = result.t;
hum2 = result.rh;
}
}

