Pages: [1] 2   Go Down
Author Topic: Kitchen Timer with Relay and Magnetic Switch  (Read 1750 times)
0 Members and 2 Guests are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello,
I am working on a program for my Arduino UNO R3.
My goals are the following:
- detect presence of magnetic switch (https://www.adafruit.com/products/375)
- IF switch is detected, allow user to set the timer using an encoder (https://www.adafruit.com/products/377) and 4 x 7 segment LED display (https://www.sparkfun.com/products/11442)
- IF the encoder button is pressed down, begin counting down  AND enable the Relay (https://www.sparkfun.com/products/11042?) for a given time period (would alternate between on and off)
- IF the button is pressed again, allow the user to again set the time and turn off the Relay
- When the timer expires, turn off the Relay
- IF the magnetic switch does not detect a magnet, PAUSE everything and wait until it does.

my code looks like this so far:

Code:
#include <SoftwareSerial.h>



//CONFIGURATION:////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//Connect 7 Segment LED with RX at Pin 7 and SS at Pin 8
SoftwareSerial Serial7Segment(8, 7);

//Configures the pins for the Encoder:
//Connect Pin A of encoder to Pin 14 (A0) and Pin C of encoder to Pin 15 (A1), Pin B goes to ground
//Connect Button to either encoder pins, other goes to ground
enum enDigitalPins
{
  dpInEncoderA=14,
  dpInEncoderB=15,
  dpInEncoderPress=12,
};

#define MagSwitch  13
#define Relay       9

// this value determines how many seconds are incremented each time the encoder is rotated
int increment = 10;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //DEFINITIONS:

long millisTimer;
byte seconds = 00;
byte minutes = 00;
byte hours = 00;

int mode = 0;
char tempString[100]; //Used for sprintf

#define COLON       4
#define Set_Timer   0
#define Run_Timer   1

boolean colonOn = false;
boolean Timer_Pause = false;

static void _ResetPins()
{
  // Rotary encoder input lines
  // Configure as input, turn on pullup resistors
  pinMode(dpInEncoderA, INPUT);
  digitalWrite(dpInEncoderA, HIGH);

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

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

  digitalWrite(MagSwitch, INPUT);
  pinMode(MagSwitch, LOW);

  digitalWrite(Relay, OUTPUT);
  pinMode(Relay, LOW);

  Serial7Segment.write(0x77);  // Decimal, colon, apostrophe control command
  Serial7Segment.write(1<<COLON);
}


void _lowlevel_ReadEncoder(int &rotate, int& press)
{
  rotate = (digitalRead(dpInEncoderB) * 2) + digitalRead(dpInEncoderA);
  press = digitalRead(dpInEncoderPress);
}

//////////////////////////////////////////////////////////////////////////////////////////////
void ReadEncoder() //Reads the State of the Encoder and adjust the Display accordingly. CW rotation = + "increment" seconds, CCW = - "increment" seconds
{
  int Position, Press;
  int isForward = 0;
  seconds = constrain (seconds, -1, 60); //constrains the seconds value between -1 and 60

    _ResetPins();
  _lowlevel_ReadEncoder(Position, Press);
  int Position2, Press2;
  do
  {
    _lowlevel_ReadEncoder(Position2, Press2);
  }
  while ((Position2 == Position) && (Press2 == Press));
  if (Position2 != Position) //if there is a poisition change:
  {
    // "Forward" is shown by the position going from (0 to 1) or (1 to 3)
    // or (3 to 2) or (2 to 0).  Anything else indicates that the user is
    // turning the device the other way.  Remember: this is Gray code, not
    // binary.
    int isFwd = ((Position == 0) && (Position2 == 1)) ||
      ((Position == 1) && (Position2 == 3)) ||
      ((Position == 3) && (Position2 == 2)) ||
      ((Position == 2) && (Position2 == 0));

    if (isFwd == 1) //if Encoder is moved forwards (CW), advance seconds by defined increment value
    {
      delay(50); // prevents bad readings
      seconds= seconds + increment;
    }
    if (isFwd == 0) // if encoder is moved backwards(CCW):
    {
      delay(50);
      if (seconds == 0)// if we are already at zero seconds, check to make sure we can reduce a minute
      {
        if (minutes > 0)// if the minutes can be reduced (i.e. not zero) then remove one minute and reset seconds to 59
        {      
          minutes --;
          seconds = 50;
        }
      }
      else
      {
        seconds = seconds - increment;//if seconds were not = 0, then decrease seconds value by the increment value
      }
    }
  }

  if (seconds>59)    // When seconds = 60:
  {
    minutes++;          // Add one minute
    seconds -= 60;      // Reset seconds
  }

  if (Press2 != Press) //if the encoder is pressed down:
  {
    mode = Run_Timer;
  }
  Position = Position2;
  Press = Press2;

  Serial7Segment.print('v');
  sprintf(tempString, "%02d%02d", minutes, seconds);
  Serial7Segment.print(tempString); //Send serial string out the soft serial port to the S7S
}

//////////////////////////////////////////////////////////////////////////////////////////////////////
void countdownTimer() //this will start counting down from the time set using the encoder. This begins when the encoder button is pressed.
{
  seconds = constrain (seconds, -1, 60);
  if (Timer_Pause == false)
  {
    if( (millis() - millisTimer) > 1000)
    {
      millisTimer += 1000; //Adjust the timer forward 1 second
      if (seconds == 0)// if we are already at zero seconds, check to make sure we can reduce a minute
      {
        if (minutes > 0)// if the minutes can be reduced (i.e. not zero) then remove one minute and reset seconds to 59
        {      
          minutes --;
          seconds = 59;
        }
      }
      else{
        seconds--;//if seconds were not = 0, then decrease seconds value by the increment value
      }

      sprintf(tempString, "%02d%02d", minutes, seconds);
      Serial7Segment.print('v'); //Send serial string out the soft serial port to the S7S
      Serial7Segment.write(0x77);  // Decimal, colon, apostrophe control command
      Serial7Segment.write(1<<COLON); // Turns on colon, apostrophoe, and far-right decimal
      Serial7Segment.print(tempString); //Send serial string out the soft serial port to the S7S
      //    Serial.println(tempString);    
    }

    if (minutes == 0 & seconds == 0)
    {
      //do nothing
    }
  }
  else
  {

  }
}


void setup()
{
  // configure the pins
  _ResetPins();

  // init serial communication
  Serial.begin(9600);
  Serial.println("Ready to begin");
  Serial7Segment.begin(9600); //Talk to the Serial7Segment at 9600 bps
  Serial7Segment.write('v'); //Reset the display - this forces the cursor to return to the beginning of the display
  Serial7Segment.print("0000"); //Send the hour and minutes to the display
}


void loop()
{
  if (digitalRead(MagSwitch) == LOW){ //if magnetic switch is detected
    // switches modes depending on button press
    switch(mode){
      case (Set_Timer): //reads encoder and sets time
      ReadEncoder();
      break;

      case (Run_Timer): //counts down timer
      Timer_Pause = false;
      countdownTimer();
      digitalWrite(Relay, HIGH); //SHOULD turn on the Relay (loops too fast?)
      break;
    }
  }
  else if (digitalRead(MagSwitch) == HIGH) //if no magnetic switch detected
  {
    Timer_Pause = true; //pause the timer
  }  
}


I pieced it together with various bits of code I found online. I am pretty new to Arduino programming, and would love some help.

Currently, my program works well to set the time and count down. I am having issues with the timer stopping when the magnetic switch isn't there. In addition, my Relay won't turn off!

Any help is appreciated!

Thanks,
Sam


Moderator edit: [code] [/code] tags added.
edit: added links to parts
« Last Edit: January 31, 2013, 08:19:29 pm by sholland91 » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 610
Posts: 49040
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
    if (minutes == 0 & seconds == 0)
    {
      //do nothing
    }
Do nothing? I thought you wanted to turn the relay off.

Code:
  if (digitalRead(MagSwitch) == LOW){ //if magnetic switch is detected
  else if (digitalRead(MagSwitch) == HIGH) //if no magnetic switch detected
If the output from digtialRead() isn't HIGH and it isn't LOW, what is it?

No Serial.print() statements outside of setup(). I'm sure that there is a reason for that, but what it could possibly be escapes me.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
    if (minutes == 0 & seconds == 0)
    {
      //do nothing
    }
Do nothing? I thought you wanted to turn the relay off.


Yeah, I do, but it wasn't doing anything earlier when it was part of a loop statement. When I changed the HIGH to LOW's, I saw that the relay LED was flickering occasionally.


Code:
  if (digitalRead(MagSwitch) == LOW){ //if magnetic switch is detected
  else if (digitalRead(MagSwitch) == HIGH) //if no magnetic switch detected
If the output from digtialRead() isn't HIGH and it isn't LOW, what is it?

No Serial.print() statements outside of setup(). I'm sure that there is a reason for that, but what it could possibly be escapes me.

I added some Serial.println() statements to debug earlier, making sure the switch was working and that my timer was correct. Is it bad to keep it in the setup right now?


Thanks for the advice
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 610
Posts: 49040
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I added some Serial.println() statements to debug earlier, making sure the switch was working and that my timer was correct. Is it bad to keep it in the setup right now?
Is it bad to keep what in the setup()? The Serial.print() statement? No. In fact, you need more of them, in loop() and other functions to see what is happening.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I added some Serial.println() statements to debug earlier, making sure the switch was working and that my timer was correct. Is it bad to keep it in the setup right now?
Is it bad to keep what in the setup()? The Serial.print() statement? No. In fact, you need more of them, in loop() and other functions to see what is happening.

Okay, thanks
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So I have worked some more on this project and can control the Relay now by using pinMode(Relay, LOW) and HIGH.
I noticed that sometimes when I turn on the timer, it is much faster than 1 second between counting down seconds. It quickly drops to zero. This only happens after I disconnect the switch and reconnect it a couple of times... Any ideas why this is happening?

Thanks!

Code:
#include <SoftwareSerial.h>



//CONFIGURATION:////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//Connect 7 Segment LED with RX at Pin 7 and SS at Pin 8
SoftwareSerial Serial7Segment(8, 7);

//Configures the pins for the Encoder:
//Connect Pin A of encoder to Pin 14 (A0) and Pin C of encoder to Pin 15 (A1), Pin B goes to ground
//Connect Button to either encoder pins, other goes to ground
enum enDigitalPins
{
  dpInEncoderA=14,
  dpInEncoderB=15,
  dpInEncoderPress=12,
};

#define MagSwitch  13
#define Relay       2

// this value determines how many seconds are incremented each time the encoder is rotated
int increment = 10;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

long millisTimer;
byte seconds = 00;
byte minutes = 00;
byte hours = 00;

int mode = 0;
char tempString[100]; //Used for sprintf

#define COLON       4
#define Set_Timer   0
#define Run_Timer   1

boolean colonOn = false;
boolean Timer_Pause = false;
boolean Relay_On = false;

static void _ResetPins()
{
  // Rotary encoder input lines
  // Configure as input, turn on pullup resistors
  pinMode(dpInEncoderA, INPUT);
  digitalWrite(dpInEncoderA, HIGH);

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

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

  digitalWrite(MagSwitch, INPUT);
  pinMode(MagSwitch, LOW);

  digitalWrite(Relay, OUTPUT);
  //  pinMode(Relay, LOW);

  Serial7Segment.write(0x77);  // Decimal, colon, apostrophe control command
  Serial7Segment.write(1<<COLON);
}


void _lowlevel_ReadEncoder(int &rotate, int& press)
{
  rotate = (digitalRead(dpInEncoderB) * 2) + digitalRead(dpInEncoderA);
  press = digitalRead(dpInEncoderPress);
}

//////////////////////////////////////////////////////////////////////////////////////////////
void ReadEncoder() //Reads the State of the Encoder and adjust the Display accordingly. CW rotation = + "increment" seconds, CCW = - "increment" seconds
{
  int Position, Press;
  int isForward = 0;
  seconds = constrain (seconds, -1, 60); //constrains the seconds value between -1 and 60

    _ResetPins();
  _lowlevel_ReadEncoder(Position, Press);
  int Position2, Press2;
  do
  {
    _lowlevel_ReadEncoder(Position2, Press2);
  }
  while ((Position2 == Position) && (Press2 == Press));
  if (Position2 != Position) //if there is a poisition change:
  {
    // "Forward" is shown by the position going from (0 to 1) or (1 to 3)
    // or (3 to 2) or (2 to 0).  Anything else indicates that the user is
    // turning the device the other way.  Remember: this is Gray code, not
    // binary.
    int isFwd = ((Position == 0) && (Position2 == 1)) ||
      ((Position == 1) && (Position2 == 3)) ||
      ((Position == 3) && (Position2 == 2)) ||
      ((Position == 2) && (Position2 == 0));

    if (isFwd == 1) //if Encoder is moved forwards (CW), advance seconds by defined increment value
    {
      delay(75); // prevents bad readings
      seconds= seconds + increment;
    }
    if (isFwd == 0) // if encoder is moved backwards(CCW):
    {
      delay(75);
      if (seconds == 0)// if we are already at zero seconds, check to make sure we can reduce a minute
      {
        if (minutes > 0)// if the minutes can be reduced (i.e. not zero) then remove one minute and reset seconds to 59
        {       
          minutes --;
          seconds = 50;
        }
      }
      else
      {
        seconds = seconds - increment;//if seconds were not = 0, then decrease seconds value by the increment value
      }
    }
  }

  if (seconds>59)    // When seconds = 60:
  {
    minutes++;          // Add one minute
    seconds -= 60;      // Reset seconds
  }

  if (Press2 != Press) //if the encoder is pressed down:
  {
    mode = Run_Timer;
  }
  Position = Position2;
  Press = Press2;

  Serial7Segment.print('v');
  sprintf(tempString, "%02d%02d", minutes, seconds);
  Serial7Segment.print(tempString); //Send serial string out the soft serial port to the S7S
}

//////////////////////////////////////////////////////////////////////////////////////////////////////
void countdownTimer() //this will start counting down from the time set using the encoder. This begins when the encoder button is pressed.
{
  seconds = constrain (seconds, -1, 60);
  if (Timer_Pause == false)
  {
    if( (millis() - millisTimer) > 1000)
    {
      millisTimer += 1000; //Adjust the timer forward 1 second
      if (seconds == 0)// if we are already at zero seconds, check to make sure we can reduce a minute
      {
        if (minutes > 0)// if the minutes can be reduced (i.e. not zero) then remove one minute and reset seconds to 59
        {       
          minutes --;
          seconds = 59;
        }
      }
      else{
        seconds--;//if seconds were not = 0, then decrease seconds value by the increment value
      }

      sprintf(tempString, "%02d%02d", minutes, seconds);
      Serial7Segment.write(0x77);  // Decimal, colon, apostrophe control command
      Serial7Segment.write(1<<COLON); // Turns on colon, apostrophoe, and far-right decimal
      Serial7Segment.print(tempString); //Send serial string out the soft serial port to the S7S
      //Serial.println(tempString);   
    }

    if (minutes == 0 & seconds == 0)
    {
      pinMode(Relay, LOW);
      Serial7Segment.print("----"); //Send the hour and minutes to the display
      mode = Set_Timer;
    }
  }
  else
  {
    mode = Set_Timer;
  }
}


void setup()
{
  // configure the pins
  _ResetPins();

  // init serial communication
  //  Serial.begin(9600);
  //  Serial.println("Ready to begin");
  Serial7Segment.begin(9600); //Talk to the Serial7Segment at 9600 bps
  Serial7Segment.write('v'); //Reset the display - this forces the cursor to return to the beginning of the display
  Serial7Segment.print("----"); //Send the hour and minutes to the display
}


void loop()
{
  //    if (Relay_On == true)
  //  {
  //    pinMode(Relay, HIGH);
  //  }
  //  else
  //  {
  //    pinMode(Relay, LOW);
  //  }
  if (digitalRead(MagSwitch) == LOW){ //if magnetic switch is detected
    // switches modes depending on button press
    Relay_On = false;

    switch(mode){
      pinMode(Relay, LOW);
      case (Set_Timer): //reads encoder and sets time
      ReadEncoder();
      break;

      case (Run_Timer): //counts down timer
      delay(175);
      pinMode(Relay, HIGH);
      countdownTimer();
      break;
    }
  }
  else if (digitalRead(MagSwitch) == HIGH) //if no magnetic switch detected
  {
    pinMode (Relay, LOW);
    minutes = 0;
    seconds = 0;
    Serial7Segment.print("----"); //Send the hour and minutes to the display
    mode = Set_Timer;
  } 
}


Logged

UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12631
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I don't know whether this is causing your problem, but you seem to be confusing pinMode and digitalWrite:

Code:
digitalWrite(Relay, OUTPUT);
pinMode(Relay, LOW);

Do you really mean to change the pin modes during the sketch?
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I don't know whether this is causing your problem, but you seem to be confusing pinMode and digitalWrite:

Code:
digitalWrite(Relay, OUTPUT);
pinMode(Relay, LOW);

Do you really mean to change the pin modes during the sketch?

I don't want to do it, but if I use digitalWrite(Relay, HIGH); or LOW, then the relay doesn't turn on or off at all. I'm using a Sparkfun Beefy Relay kit and can see the status LED quickly blink but that's it...

Is there a better way to do this? I tried making another if statement in my loop that uses a boolean Relay_On and would adjust the relay accordingly, but it doesn't work either.
Logged

UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12631
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Is there a better way to do this?

I'm not familiar with that relay board, but I assume it takes a digital output and uses it to control the relay. In that case you would call pinMode(Relay, OUTPUT); once within setup(), and then call digitalWrite(Relay, HIGH); and digitalWrite(Relay, LOW); to turn the relay on and off as required.
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Is there a better way to do this?

I'm not familiar with that relay board, but I assume it takes a digital output and uses it to control the relay. In that case you would call pinMode(Relay, OUTPUT); once within setup(), and then call digitalWrite(Relay, HIGH); and digitalWrite(Relay, LOW); to turn the relay on and off as required.

So I was messing up and used pinMode(Relay, LOW) before and after fixing it, everything works out! There is still a problem though: when I start the timer, it quickly jumps a few seconds. Usually 3, but sometimes 15, and sometimes it counts really fast all the way down.
Logged

UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12631
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

There is still a problem though: when I start the timer, it quickly jumps a few seconds. Usually 3, but sometimes 15, and sometimes it counts really fast all the way down.

Perhaps there's something wrong with your code. Difficult to see from here ...
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

UPDATE:
It seems as though the fast counting down occurs mostly after I let the device sit while powered on for a while. Could it be an issue with the millis() command?

Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 610
Posts: 49040
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Still can't see your code.

However, your functions are doing too much. ReadEncoder() should do exactly that and NOTHING more.

ReadEncoderAndDoABunchOfOtherCrap() would read the encoder and do a bunch of other crap. Of course, if you really had a function like that, I'd just hit the back button and move onto the next post.

You have very few Serial.print() statements to learn what the code is really doing.

Besides, it's hard to see the function of an encoder in a post titled "Kitchen Timer with Relay and Magnetic Switch", so some comments in the code would be helpful.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Still can't see your code.
It's posted above.... Not sure what's going on there.

Quote
However, your functions are doing too much. ReadEncoder() should do exactly that and NOTHING more.
 ReadEncoderAndDoABunchOfOtherCrap() would read the encoder and do a bunch of other crap.

So you can see my code? Not sure what you mean here either. Does it matter? Is this causing problems with my program?

Quote
Of course, if you really had a function like that, I'd just hit the back button and move onto the next post.
What does this mean?

Quote
Besides, it's hard to see the function of an encoder in a post titled "Kitchen Timer with Relay and Magnetic Switch", so some comments in the code would be helpful.
There are comments all over my code... Read the first post for some background information. The encoder is used as an input device for incrementing the seconds on a kitchen timer. When the button on the encoder is pressed in, the timer starts and the relay turns on. My problem is that the timer sometimes counts down way faster than 1 second each second. Some times it races down 45 seconds and resumes counting normally. Sometimes is races all the way down to zero. I think this has to do with the millis() command, as I wrote above.

Quote
You have very few Serial.print() statements to learn what the code is really doing.
I removed them after I set up my code and got it working, thinking that it could be the reason why the numbers are counting so fast sometimes. The only issue right now is the counter, and a serial.println of that mirrors what the 7 segment display is showing me.

Here's the updated code:

Code:
#include <SoftwareSerial.h>

//CONFIGURATION:////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//Connect 7 Segment LED with RX at Pin 7 and SS at Pin 8
SoftwareSerial Serial7Segment(8, 7);

//Configures the pins for the Encoder:
//Connect Pin A of encoder to Pin 14 (A0) and Pin C of encoder to Pin 15 (A1), Pin B goes to ground
//Connect Button to either encoder pins, other goes to ground
enum enDigitalPins
{
  dpInEncoderA=14,
  dpInEncoderB=15,
  dpInEncoderPress=12,
};

#define MagSwitch  13
#define Relay       2

// this value determines how many seconds are incremented each time the encoder is rotated
int increment = 10;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
long millisTimer;
byte seconds = 00;
byte minutes = 00;
byte hours = 00;

int mode = 0;
char tempString[100]; //Used for sprintf

#define COLON       4
#define Set_Timer   0
#define Run_Timer   1
#define Pause_Timer 2

boolean colonOn = false;

static void _ResetPins()
{
  // Rotary encoder input lines
  // Configure as input, turn on pullup resistors
  pinMode(dpInEncoderA, INPUT);
  digitalWrite(dpInEncoderA, HIGH);

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

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

  digitalWrite(MagSwitch, INPUT);
  pinMode(MagSwitch, LOW);

  pinMode(Relay, OUTPUT);

  Serial7Segment.write(0x77);  // Decimal, colon, apostrophe control command
  Serial7Segment.write(1<<COLON);
}


void _lowlevel_ReadEncoder(int &rotate, int& press)
{
  rotate = (digitalRead(dpInEncoderB) * 2) + digitalRead(dpInEncoderA);
  press = digitalRead(dpInEncoderPress);
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ReadEncoder() //Reads the State of the Encoder and adjust the Display accordingly. CW rotation = + "increment" seconds, CCW = - "increment" seconds
{
  int Position, Press;
  int isForward = 0;
  seconds = constrain (seconds, -1, 60); //constrains the seconds value between -1 and 60

    _ResetPins();
  _lowlevel_ReadEncoder(Position, Press);
  int Position2, Press2;
  do
  {
    _lowlevel_ReadEncoder(Position2, Press2);
  }
  while ((Position2 == Position) && (Press2 == Press));
  if (Position2 != Position) //if there is a poisition change:
  {
    // "Forward" is shown by the position going from (0 to 1) or (1 to 3)
    // or (3 to 2) or (2 to 0).  Anything else indicates that the user is
    // turning the device the other way.  Remember: this is Gray code, not
    // binary.
    int isFwd = ((Position == 0) && (Position2 == 1)) ||
      ((Position == 1) && (Position2 == 3)) ||
      ((Position == 3) && (Position2 == 2)) ||
      ((Position == 2) && (Position2 == 0));
    delay(100);
    if (isFwd == 1) //if Encoder is moved forwards (CW), advance seconds by defined increment value
    {
      //      delay(200); // prevents bad readings
      seconds= seconds + increment;
    }
    if (isFwd == 0) // if encoder is moved backwards(CCW):
    {
      //      delay(200);
      if (seconds == 0)// if we are already at zero seconds, check to make sure we can reduce a minute
      {
        if (minutes > 0)// if the minutes can be reduced (i.e. not zero) then remove one minute and reset seconds to 59
        {       
          minutes --;
          seconds = 50;
        }
      }
      else
      {
        seconds = seconds - increment;//if seconds were not = 0, then decrease seconds value by the increment value
      }
    }
  }

  if (seconds>59)    // When seconds = 60:
  {
    minutes++;          // Add one minute
    seconds -= 60;      // Reset seconds
  }

  if (Press2 != Press) //if the encoder is pressed down:
  {
    delay(250);
    mode = Run_Timer;
  }
  Position = Position2;
  Press = Press2;

  Serial7Segment.print('v');
  sprintf(tempString, "%02d%02d", minutes, seconds);
  Serial7Segment.print(tempString); //Send serial string out the soft serial port to the S7S
  Serial.println(tempString);
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
void countdownTimer() //this will start counting down from the time set using the encoder. This begins when the encoder button is pressed.
{
  seconds = constrain (seconds, -1, 60);
  if( (millis() - millisTimer) > 1000)
  {
    millisTimer += 1000; //Adjust the timer forward 1 second
    if (seconds == 0)// if we are already at zero seconds, check to make sure we can reduce a minute
    {
      if (minutes > 0)// if the minutes can be reduced (i.e. not zero) then remove one minute and reset seconds to 59
      {       
        minutes --;
        seconds = 59;
      }
    }
    else{
      seconds--;//if seconds were not = 0, then decrease seconds value by the increment value
    }
    sprintf(tempString, "%02d%02d", minutes, seconds);
    Serial7Segment.write(0x77);  // Decimal, colon, apostrophe control command
    Serial7Segment.write(1<<COLON); // Turns on colon, apostrophoe, and far-right decimal
    Serial7Segment.print(tempString); //Send serial string out the soft serial port to the S7S
   
    Serial.println(tempString);
  }

  if (minutes == 0 & seconds == 0)
  {
    digitalWrite(Relay, LOW);
    Serial7Segment.print("0000"); //Send the hour and minutes to the display
    mode = Set_Timer;
  }

  if (digitalRead(dpInEncoderPress)== LOW)
  {
    delay(250);
    mode = Pause_Timer;
  }
}

void PauseTimer()
{
  int seconds_hold;
  int minutes_hold;
  seconds_hold = seconds;
  minutes_hold = minutes;

  minutes = minutes_hold;
  seconds = seconds_hold;
  sprintf(tempString, "%02d%02d", minutes, seconds);
  Serial7Segment.write(0x77);  // Decimal, colon, apostrophe control command
  Serial7Segment.write(1<<COLON); // Turns on colon, apostrophoe, and far-right decimal
  Serial7Segment.print(tempString); //Send serial string out the soft serial port to the S7S

  if (digitalRead(dpInEncoderPress)== LOW)
  {
    delay(75);
    mode = Run_Timer;
  }

  mode = Set_Timer;
}

void setup()
{
  // configure the pins
  _ResetPins();
 
  Serial.begin(9600);

  Serial7Segment.begin(9600); //Talk to the Serial7Segment at 9600 bps
  Serial7Segment.write('v'); //Reset the display - this forces the cursor to return to the beginning of the display
  Serial7Segment.print("0000"); //Send the hour and minutes to the display
}

void loop()
{
  if (digitalRead(MagSwitch) == LOW) //if magnetic switch is detected
    // switches modes depending on button press
  {
    switch(mode){
      digitalWrite(Relay, LOW); //Relay off
      case (Set_Timer): //reads encoder and sets time
      ReadEncoder();
      break;

      case (Run_Timer): //counts down timer
      digitalWrite(Relay, HIGH); //relay on
      countdownTimer(); //run countdown script (above)
      break;

      case (Pause_Timer):
      digitalWrite(Relay, LOW);
      PauseTimer();
      break;     
    }
  }

  else if (digitalRead(MagSwitch) == HIGH) //if no magnetic switch detected
  {
    digitalWrite (Relay, LOW);
    minutes = 0;
    seconds = 0;
    Serial7Segment.print("OFF "); //Send the hour and minutes to the display
    mode = Set_Timer;
  } 
}


Hope this solves any issues you may have...
« Last Edit: February 17, 2013, 07:47:44 pm by sholland91 » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 610
Posts: 49040
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Hope this solves any issues you may have...
It does. But let's look at some of your comments.
Quote
So I was messing up and used pinMode(Relay, LOW) before and after fixing it, everything works out!
How did you fix this? By making code changes, right? So, we need to see them.

Quote
So you can see my code?
Your old code.

Quote
Not sure what you mean here either. Does it matter? Is this causing problems with my program?
Maybe it matters. Maybe it doesn't. If you have a function called ReadEncoder() and it uses no global variables, returns a value, and does exactly what the name says, and nothing else, then we can read through the code, determine if it is reasonable, and then forget it. When we later encounter a call to ReadEncoder(), we don't have to worry about what side effects and bizarre things that function is having on the rest of the code.

But, when we encounter a ReadEncoder() function that uses global variables and does several things, then each time a global variable appears in the code, we need to go see if ReadEncoder() is screwing with that variable. That is not conducive to quick debugging.

Quote
What does this mean?
It means that if you simply rename your function to admit that it is a grab bag of unrelated functionality, I'm not even going to make an attempt to read it, or help you.

Quote
I removed them after I set up my code and got it working,
But, your code isn't working, is it?

Code:
char tempString[100]; //Used for sprintf
A bit on the large side, isn't it?

Code:
  int seconds_hold;
  int minutes_hold;
  seconds_hold = seconds;
  minutes_hold = minutes;

  minutes = minutes_hold;
  seconds = seconds_hold;
No comments to explain this bizarre code. First, it is not necessary to declare and initialize variables as two separate steps.

Code:
int seconds_hold = seconds;
int minutes_hold = minutes;
looks better and is less typing.

Setting seconds and minutes to what they currently contain makes no sense.

Code:
  sprintf(tempString, "%02d%02d", minutes, seconds);
  Serial7Segment.write(0x77);  // Decimal, colon, apostrophe control command
  Serial7Segment.write(1<<COLON); // Turns on colon, apostrophoe, and far-right decimal
  Serial7Segment.print(tempString); //Send serial string out the soft serial port to the S7S
You do this a lot. Why not create a function to do it, once. Then, tempString could be a local variable. And, it would be clear that it was oversized.

Code:
  if (digitalRead(dpInEncoderPress)== LOW)
  {
    delay(75);
    mode = Run_Timer;
  }
Why are you delaying?

Code:
      case (Set_Timer): //reads encoder and sets time
Case values do not need parentheses around them.

Code:
void loop()
{
  if (digitalRead(MagSwitch) == LOW) //if magnetic switch is detected
    // switches modes depending on button press
  {
    switch(mode){
      digitalWrite(Relay, LOW); //Relay off
      case (Set_Timer): //reads encoder and sets time
      ReadEncoder();
      break;

      case (Run_Timer): //counts down timer
      digitalWrite(Relay, HIGH); //relay on
      countdownTimer(); //run countdown script (above)
      break;

      case (Pause_Timer):
      digitalWrite(Relay, LOW);
      PauseTimer();
      break;     
    }
  }

  else if (digitalRead(MagSwitch) == HIGH) //if no magnetic switch detected
  {
    digitalWrite (Relay, LOW);
    minutes = 0;
    seconds = 0;
    Serial7Segment.print("OFF "); //Send the hour and minutes to the display
    mode = Set_Timer;
  } 
}
This is the heart of the program. The first comment is wrong. The Arduino can not tell if the magnetic switch is present or not. All it can tell is whether the pin that the switch is supposed to be attached to is HIGH or LOW.

Then the comment about the switch statement leaves a bit to be desired. Which switch press? There is only one statement in all of loop() that sets mode to a value. It is not clear where else mode gets set.

Basically, one of three functions gets called. ReadEncoder() to get the time to count down, countdownTimer() to count down time, and PauseTimer() to stop the counting down. Just a quick look at the previous sentence will reveal inconsistencies in your code. Some functions start with upper case letters. Some start with lower case letters. Why?

But the real question is where does the problem you are trying to resolve come in? When loop() runs, and determines that you want to just run the timer, is the time being counted down wrong? Is the time being counted down changing between ReadEncoder() and countdownTimer()?

countdownTimer() has some subtle issues.
Code:
  if( (millis() - millisTimer) > 1000)
If the function is called exactly 1000 milliseconds after the last call, it will not trigger the if statement. You most likely want >= there, not >.

Code:
    millisTimer += 1000; //Adjust the timer forward 1 second
But, more than 1000 milliseconds has elapsed. millisTimer should be set to millis(), not incremented by 1000. And even that isn't perfect. What should happen is that there should be a local variable set at the top of the function:
Code:
unsigned long now = millis();
Then, no further calls to millis() should be made during this function. Instead, the value in now should be used every time the clock is to be checked. Notice that millis() returns an unsigned long, not a long.

Constraining seconds at the start of the function is wrong. An unknown amount of time may be lost doing that. Enough to account for the change you are seeing? Probably not, but it is wrong to be doing it.

I don't see any reason for any of the delay() calls in the code. Perhaps you could explain why they are there.
Logged

Pages: [1] 2   Go Up
Jump to: