Greenhouse part 2- detecting state and adding more sensors

Part 2

Here I will add a state detecting button and integrate some other sensors.

State change

I mentioned in my last post that I wanted to add a button to start and stop the program. Right now, the program starts running immediately when it receives power. That's good for starting, but I would rather it start with a button push and stop with one, so I can safetly remove the SD card without corrupting data. To do this, I need to add a button that can detect state changes.

First test

For my initial test, I modified the code from the state-change-detection tutorial from Programming Electronics so that it changes an LED from on to off with every button push and resets the state tracking variable.

// constants
const int buttonPin = 14;
const int ledPin = 15;

// changing variables
int buttonCounter = 0;
int buttonState =0;
int lastButton = 0;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
  Serial.println("setup done, starting!");
}

void loop() {
  buttonState = digitalRead(buttonPin);
  if(buttonState != lastButton){
    if (buttonState == HIGH){
    buttonCounter++;
    Serial.println("on!");
    Serial.print("number of button pushes is ");
    Serial.println(buttonCounter);
    } else {
    Serial.println("off");
}
  delay(50);
}
lastButton = buttonState;

if (buttonCounter % 2 == 0){
  digitalWrite(ledPin, HIGH);
  buttonCounter = 0;
  // put your main code here, to run repeatedly:
} else {
  digitalWrite(ledPin, LOW);

}
}

And my testing circuit diagram looks like so

state_change_test_bb.png

Figure 1: State change test. Note LED polarity is wrong in this fritzing.

This works great, but it is a lot of code to do a relatively simple thing. It also polls the button state from within the loop, which can slow down larger programs or it wont detect the change immediately. A better solution would be to wrap the state change function in an interrupt.

Wrapping the on-off in an interrupt

The first step will be to shorten the previous code and wrap it in an interrupt function that checks and alters a global variable to track state.
I will set this variable to 0 at the beginning of the program's normal routine, this way whenever it is plugged in it is automatically set to off and has to be manually started.

#include "Arduino.h"

// constants
const int interruptPin = 14;
const int ledPin = 15;

// changing variables
volatile int buttonCounter = 0;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  Serial.println("setup done, starting!");
  attachInterrupt(digitalPinToInterrupt(interruptPin), button, RISING);
}

void loop() {
  Serial.println("no interrupt");
  delay(1000);
}

void button(){
  buttonCounter++;
  Serial.println("interrupt called");
  if  (buttonCounter % 2 == 0){
    Serial.println("high loop");
    digitalWrite(ledPin, HIGH);
    buttonCounter = 0;
}else{
    digitalWrite(ledPin, LOW);
    Serial.println("low loop!");
}
}

That is much simpler and easier than I thought. I will probably improve the interrupt state checker as I go. The problem with this is that the debounce on the button is not great as it is a cheap button, so I used these instructions to control for the cheap hardware and only activate on a real push to control this.

#include "Arduino.h"

// constants
const int interruptPin = 14;
const int ledPin = 15;

// changing variables
long lastDebounceTime = 0;
long debounceDelay = 50; 
volatile int buttonCounter = 0;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  Serial.println("setup done, starting!");
  attachInterrupt(digitalPinToInterrupt(interruptPin), button, RISING);
}

void loop() {
  Serial.println("no interrupt");
  delay(1000);
}

void button(){
  if ((millis() - lastDebounceTime) > debounceDelay){
  lastDebounceTime = millis();
  buttonCounter++;
  Serial.println("interrupt called");
  if  (buttonCounter % 2 == 0){
    Serial.println("high loop");
    digitalWrite(ledPin, HIGH);
    buttonCounter = 0;
}else{
    digitalWrite(ledPin, LOW);
    Serial.println("low loop!");
}
}
}

The serial statements were useful for debugging, but I will remove them in the final project.

TODO More explanation on what debounce is, why we need to account for it and what exactly this code does.

that is all I had time for this weekend. Next weekend I will control the temperature logger with the button and start adding my other sensors.

Controlling the temperature logger with a button

Coming soon

Adding the soil moisture and water level sensors

Coming soon

adding the water pump

Coming soon