2

I have been working on this program for a simple controller. I have a prototype all wired up and working however the momentary push button is not very reliable. Sometimes it reads and other times it ignors it.

Here is my code.

/*
 * Valve Purge Control/heater control
 */
#include <math.h>

int feedValve = 12;                              // feed valve is connected to pin 12
int returnValve = 11;                            // return valve is connected to pin 11
int heater = 10;                               // heater is connected to pin 10
//int loopValves = 9                             // loop valves are connected to pin 9
//int pump = 8                                   // pump is connected to pin 8
int button = 2;                                  // button is connected to pin 2

int val;                                         // variable for reading the pin status
int val2;                                        // variable for reading the delayed/debounced status
int buttonState;                                 // variable to hold the button state

int buttonMode = 0;                               // Is valve on or off?

void setup() {
  pinMode(feedValve, OUTPUT);                    // Set the Feed Valve pin as output
  pinMode(returnValve, OUTPUT);                  // Set the Return Valve pin as output
  pinMode(heater, OUTPUT);                       // Set the Heater Valve pin as output
  //pinMode(loopValves, OUTPUT);                 // Set the Loop Valves pin as output
  //pinMode(pump, OUTPUT):                       // Set Pump pin as output
  pinMode(button, INPUT);                        // Set the switch pin as input
  Serial.begin(9600);                            // Set up serial communication at 9600bps
  buttonState = digitalRead(button);             // read the initial state
}

double Thermister(int RawADC) {
  double Temp;
  Temp = log(((10240000/RawADC) - 10000));
  Temp = 1 / (0.001129148 + (0.000234125 * Temp) + (0.0000000876741 * Temp * Temp * Temp));
  Temp = Temp - 273.15;           // Convert Kelvin to Celcius
  Temp = (Temp * 1.8) + 32.0;    // Convert to F
  return Temp;
}

void loop(){
  val = digitalRead(button);                     // read input value and store it in val
  delay(10);
  val2 = digitalRead(button);                    // read the input again to check for bounces
  if (val == val2) {                             // make sure we got 2 consistant readings!
    if (val != buttonState) {                    // the button state has changed!
      if (val == LOW) {                          // check if the button is pressed
        if (buttonMode == 0) {                   // is the button off?
           buttonMode = 1;                       // turn buttonMode to 1
          } else {
            if (buttonMode == 1){
            buttonMode = 0;                      // turn buttonMode to 0
          }
        }
      }  
     buttonState = val;
    }
    if (buttonMode == 1) {
      double Temp = Thermister(analogRead(0));   // read Thermistor
      //Serial.println(Temp);
      if (Temp > 90){
        digitalWrite(feedValve, HIGH);           // turn on feed valve
        delay(5000);                             
        digitalWrite(returnValve, HIGH);         // turn on return valve
      }
      if (Temp < 100)digitalWrite(heater, HIGH);      // turn heater on
      else if (Temp > 105)digitalWrite(heater, LOW);  // turn heater off
    }

    if (buttonMode == 0) {
      digitalWrite(heater, LOW);                 // turn heater off
      digitalWrite(feedValve, LOW);              // turn feed valve off    
      delay(5000);
      digitalWrite(returnValve, LOW);            // turn return valve off
    }
  }
}
Dave Tweed
  • 172,781
  • 17
  • 234
  • 402
D.W.
  • 623
  • 1
  • 6
  • 9
  • See related on switch debouncing: http://electronics.stackexchange.com/questions/41674/switch-debouncing-would-toggle-switch-still-bounce – embedded.kyle Oct 18 '12 at 12:48

3 Answers3

5

EDIT: Button is connected like this:

ButtonConnection

If there was no pull-up, one would put the following in setup()

pinMode(button, INPUT); 
digitalWrite(button, HIGH);

An interrupt is an event that 'pauses' the main program, runs a function (called an interrupt service routine or ISR for short), then returns to the main program where it left. Pins 2 and 3 have level and edge triggered interrupts. You can use them to set a flag that indicates the button has been pressed. e.g. adding this code to setup()

attachInterrupt(0, pin2_isr, FALLING);

will run the pin2_isr function when the button brings pin 2 low. Add a flag variable to the start,

volatile boolean pin2_flag = 0;

then the isr function,

void pin2_isr() {
    pin2_flag = 1;
}

EDIT - add a valve state variable so that you don't keep turning them on when they are already on.

boolean valve_state = 0;

Your main loop could then become

void loop() 
{
    if(pin2_flag == 1) 
    { 
        detachInterrupt(0);      //Interrupt received, turn ISR off
        pin2_flag = 0;           //Interrupt received, clear flag
        //Debounce
        delay(250);
        //Check button still down
        if(digitalRead(2) == 0) {
          if (buttonMode == 0) buttonMode = 1;   //Change mode
          else buttonMode = 0;
          Serial.println("button press");
        }
        //Little delay for debounce
        digitalWrite(13,LOW);
        attachInterrupt(0,pin2_isr,FALLING);   //Re-enable interrupt
    }

    if (buttonMode == 1) {
        double Temp = Thermister(analogRead(0));   // read Thermistor
        //Serial.println(Temp);
        if (Temp > 90 && valve_state == 0) {
            digitalWrite(feedValve, HIGH);           // turn on feed valve
            delay(5000);                             
            digitalWrite(returnValve, HIGH);         // turn on return valve
            valve_state = 1;
        }
        if (Temp < 100) digitalWrite(heater, HIGH);      // turn heater on
        else if (Temp > 105) digitalWrite(heater, LOW);  // turn heater off
    }

    else if (buttonMode == 0) {
        digitalWrite(heater, LOW);                 // turn heater off
        if (valve_state == 1) {
            digitalWrite(feedValve, LOW);          // turn feed valve off
            delay(5000);
            digitalWrite(returnValve, LOW);        // turn return valve off
            valve_state = 0;
        }
    }
}

Note the change of the second 'if' to an 'else if' and the addition of the buttonMode lines.

By the way, what you have now is a state machine. Add more buttonModes to do more things!

edit: changed interrupt to falling to avoid flag being set when button is held down for too long.

edit 2: changed as per daves suggestion

edit 3: added better debounce

edit 4: interrupt number should be 0 not 2

geometrikal
  • 4,931
  • 2
  • 24
  • 41
  • No, your suggested loop() function won't work: It won't control the heater temperature in heating mode because it's blocked waiting for a button press. – Dave Tweed Oct 18 '12 at 04:08
  • @DaveTweed Hows that? – geometrikal Oct 18 '12 at 04:18
  • Almost there. Now you need to remove the assignments to buttonMode at the end of the second and third blocks; otherwise, it'll keep toggling back and forth by itself. – Dave Tweed Oct 18 '12 at 04:21
  • Thanks. I tried the changes but am getting a few errors - in function void pin2_isr() pin2_flag was not declared in this scope. Also in void loop() - pin2_flag was not declared and neither was valve_state. I am still pretty new to this. Thanks – D.W. Oct 18 '12 at 04:56
  • you have to add the additional function pin2_isr as above. Put it at the end of the entire code. Also add the valve_state and pin2_flag initialisation lines (3rd and 5th code blocks) before the setup() block in your code. – geometrikal Oct 18 '12 at 05:19
  • That makes sence. I had put the valve_state and pin2_flag in the setup() block. Thanks for your help. I will try it out this evening. – D.W. Oct 18 '12 at 14:06
  • I hope it works, @DaveTweed made some edits to the answer as well. – geometrikal Oct 19 '12 at 01:36
  • @geometrikal Hey Guys. I have tried the code above and made the changes to the variables. The program compiles fine and uploads ok but does not do anything when the button is pushed. Technically the heater should come on as soon as the button is pushed. Any thoughts. – D.W. Oct 19 '12 at 01:47
3

The way your code is written, it is spending a lot of time in delay(5000) calls. This could easily explain missed button presses.

Every time the Arduino operating system calls your loop() function, as long as the state of the button is stable, you'll enter the if (val == val2) { ... } block. Inside this block are three more if() statements; the if (val != buttonState) detects and handles new button presses and only runs occasionally. But one of the other two blocks will always get executed, depending on the current state of buttonMode. Each of these blocks contains a delay(5000); the one in the if (buttonMode == 1) block gets executed whenever the temperature is greater than 90, and the one in the if (buttonMode == 0) block always gets executed.

You're going to want to find a different way to implement those delays that doesn't block your main loop, but I don't know the proper Arduino idiom for doing that.

Dave Tweed
  • 172,781
  • 17
  • 234
  • 402
0

Well not that you can't de-bounce in software but the hardware side of me would have just thrown on some little switch debouncer.

Plus I would put the push button on an interrupt line instead of polling but that's just me you don't have to do that.

Have you tried increasing your delay time to 250ms or so?

m.Alin
  • 10,738
  • 19
  • 63
  • 89
Some Hardware Guy
  • 15,895
  • 1
  • 31
  • 44
  • Yeah I have tried different delay timming. What do you mean by putting the push button on an interrupt line? I am still verry new to this. thanks – D.W. Oct 18 '12 at 03:11