Need some help with millis() and debouncing. Driving me nuts!

Hello all, thanks for reading this. It has been driving me nuts forever and I cannot find help so I turn to you. Here is what I'm trying to do. I am building (as my very first project) an automated rabbit feeder. I have a cereal dispenser that will dispense carrots by a continuous servo attached to the handle. I would like to have one button that when pressed will turn the nob every 24 hours. I also want to be able to stop the loop by pressing the button again. My problem is that I can't get the second button press (the one that stops the loop) to be recognized by the arduino. I recently was told, after about two weeks of pulling my hair out, that I can't use the "delay()" for this and that I need to use millis(). Cool. But then I was told that I need to use long, and unsigned long timers....and that's when my brain started to hurt.

Anyways, I'm a total newbie to programming and thought this would be a fairly simple first project after doing the basic "blink" this and that sketch.

Below is what I had. I know that I have to incorporate "millis()" and unsigned long. I just don't know how to format that. Before you ask, I have looked for similar examples extensively.

#include <Servo.h>
Servo myServo;        // Create Servo object to control the servo 
const int inputPin = 2; // the number of the button pin
const int debounceDelay = 10; // miliseconds to wait until stable. 

// debounce returns true if the switch in the given pin is closed and stable(int pin)
boolean debounce(int pin)
{
boolean state;
boolean previousState;

previousState = digitalRead(pin); // store switch state
for(int counter=0; counter < debounceDelay; counter++)
{
delay(1); // wait for 1 millisecond
state = digitalRead(pin); // read the pin
if( state != previousState)
{
  counter = 0; // reset the counter if the state changes
  previousState = state; // and save the current state
}
}
// here when the switch state has been stable longer than the debounce period

return state;
}


void setup() { 
myServo.attach(9);  // Servo is connected to digital pin 9 
pinMode(inputPin, INPUT);
} 

void loop() { 
  {
  if(debounce(2))
  {
myServo.writeMicroseconds(1600);  // Counter clockwise
delay(2000);                      // Wait 2 seconds. This will actually be 24 hours when completed. 
myServo.writeMicroseconds(1500);  // Stop
delay(2000); 
}
}
}

There is an example that comes with the Arduino IDE called BlinkWithoutDelay (it's under File > Examples > Digital). Play with that and study it until you know exactly how and why it works. It's been discussed extensively here, so feel free to ask questions but I might search the forum a bit first too.

Use a library for the buttons, that way you don't have to worry about details like debouncing and you can focus on the main goal. My favorite is here, but there are others out there too, GIYF.

I think I may have what you need. Here is a simple program that toggles a output from HIGH to LOW everytime you push a momenatry button. In my example I use pin 13 as the output, because of the on board LED, but you can of course make it anything you like. Try it and see if it works for you. I got the idea from one of the examples and just made a few cahnges to it. Hope this helps. You will need a pull up resistor of around 10k. I explain it in the top.

/*
So here's a simple sketch that will allow you to use a momentary switch to toggle a output from a high state to a low state. 
It DOES REQUIRE a pull up resistor of around 10k or so, But it is very simple to design and works very well. 
If you want to make the LED start in the "off" mode, simply invert the "OutputStatus = HIGH to LOW" and "PreviousOutputStatus from LOW to HIGH".
This will start you output in the "LOW" mode. In my case I needed it to be HIGH.
It doesn't matter how long you hold down the button, the status will only change when you push it from on to off. If for some reason
you are experiencing a debounce issue, simply adjust the Debounce time a bit higher and this should resolve you issue

Resistor - one side to 5V, other side to input pin. In this case 12(MomentaryPushButton)
Push button switch - one side to input pin. In this case 12(MomentaryPushButton), Other side of push button tied to ground

In this case the input see's a high when off or not presssed, assuming a normal open switch(N/O), and a low when pushed

Above I stated you can start the LED in the off mode by changes to some code, you can also use a normally closed(N/C) switch
and this should work as well to start the routine off with the output "off" or "LOW"
I'm not going to leave much in the way of notes, because this is pretty simple and figure, what the hell. You can't figure this
one out you shouldn't be bangin' out code.


*/

int MomentaryPushButton = 12;             //It was next to pin 13. So I used it. Silly I know        
int OutputPin = 13;                       //I only used this pin as a example. You can use any pin of course            
                               
int OutputStatus = HIGH;      
int Reading;           
int PreviousOutputStatus = LOW;    


long Time = 0;         
long Debounce = 50;   

void setup()
{
  pinMode(MomentaryPushButton, INPUT);
  pinMode(OutputPin, OUTPUT);
}

void loop()
{
  Reading = digitalRead(MomentaryPushButton);
  if (Reading == HIGH && PreviousOutputStatus == LOW && millis() - Time > Debounce) {
  if (OutputStatus == HIGH)
     OutputStatus = LOW;
  else
     OutputStatus = HIGH;
     Time = millis();    
  }
  digitalWrite(OutputPin, OutputStatus);
     PreviousOutputStatus = Reading;
}

Thanks for the help! I understand, now, how to make this work with an led. My issue is making it work with a continuous servo. For the continuous servo I have to use the writeMicroseconds command. I don't know how to implement that in this case. I don't know how to incorporate it into this code:

if (OutputStatus == HIGH)
OutputStatus = LOW;
else
OutputStatus = HIGH;
Time = millis();
}
digitalWrite(OutputPin, OutputStatus);
PreviousOutputStatus = Reading;
}

This is where i've hit my road block. An led I can manipulate fine. A regular servo I can manipulate fine. It's the continuous servo that is giving me such a problem.

For the continuous servo I have to use the writeMicroseconds command. I don't know how to implement that in this case.

The writeMicroseconds() method sets the speed of the servo. That is all that it does. How does that relate to needing to do something at a specific time/after a specific interval?

You are, I think, having difficulty implementing your requirements because your requirements are not well defined, rather than because of any inherent lack of skills or tools.

For a continuous servo, writeMicroseconds(1500) is the command to make it stop. That is its neutral point.

So I can't use "OutputStatus == HIGH" or "OutputStatus = LOW" in the same way as an LED. It needs to be something like "OutputStatus == writeMicroseconds(1600)" and OutputStatus = "1500")

That's where my problem lies. I don't know how to substitute the requirements to make a continuous servo work in place of the requirements for an led.

My requirements for the sketch are pretty simple.
Push a button: start the sketch to turn the servo once every 24 hours.
Push button again at any time: stop the sketch.

Literally, that's it.

Easy with a led. Easy with a regular servo. However, for whatever reason I can't find the solution to this.

My requirements for the sketch are pretty simple.
Push a button: start the sketch to turn the servo once every 24 hours.

Not sure if a servo modified for continuation can be commanded to move at such a slow rate, but if it can be it will commanded by performing a servo write value just a count or two higher or lower then the stop or neutral value of 1500usec. So either:
myServo.writeMicroseconds(1501); // Counter clockwise as slow as possible
or
myServo.writeMicroseconds(1499); // Clockwise as slow as possible

Push button again at any time: stop the sketch.

Stopping a continious rotation servo is as simple as issuing a servo write command to it's neutral value so:
myServo.writeMicroseconds(1500); // Servo stop value
By the way you can never cause a sketch to just stop running code, but you can force it to execute a 'do nothing' loop forever until you reset or power down then up the board, which will emulate the same action as a program stop.

Literally, that's it.

Note that the actual neutral value your servo requires for a full stop may have to be tweaked a little up or down from the nominal 1500usec value to account for it's specific calibration, and this would of course cause the need to adjust the minimum speed CW or CCW by an equal amount
Lefty

I apologize that wasn't concise. I meant one full rotation and then another full rotation 24 hours later.

What I had was this:
{
myServo.writeMicroseconds(1600); // spins servo for one second.
delay(1000);
myServo.writeMicroseconds(1500); // stops for 24 hours
delay(24hours);
}

However, I need to use millis() in place of delay() in order for my button press to be read properly. All of the suggestions I have been given are in reference to powering an led which uses digitalwrite and led = HIGH and led = LOW.

To recap:

  1. I am looking to push a button and turn a continuous servo a full rotation. (It is around writeMicroseconds(1600) for one second.)

  2. Stop for 24 hours. (writeMicroseconds(1500))

  3. repeat

  4. If, at any time, that button is pressed again, the sketch will stop.

I know I need to use the millis() command in order for the button press to be read properly. I just don't know how to integrate it with the writeMicroseconds().

supernuckolls:
All of the suggestions I have been given are in reference to powering an led which uses digitalwrite and led = HIGH and led = LOW.

Those suggestions were to give you an Idea on how to use millis() to replace delay. Inside the block of code, you can do whatever you want; switching an LEDs state is just an example of what you can do.

Debouncing in hardware is not difficult. One gate, one diode, one cap and two resistors.
The circuit I use is from an EDN article from 2002. It is very clean and
has never failed.

The schematic is in the datasheet for my prototyping board at
http://wiblocks.luciani.org/NB1/NB1A-PB1-index.html

(* jcl *)

http://www.wiblocks.com

Seems it's hard for you to adapt the code. try something like:

*Note - this is not debounced. Just a basic representation of how to delay for 1 second then 24 hours without delay

unsigned long timer;
boolean buttonState = digitalRead(buttonPin);
if(!buttonState){  // if button state is low then it is pressed
  myServo.writeMicroseconds(1600); // spins servo
  timer = millis(); // set timer
}
  
if (millis() - timer >= 1000) myServo.writeMicroseconds(1500); // stop servo at 1 second of running

if(millis() - timer >= (3600000*24)){ //3600000 millis per hour for 24 hours
  // it's been 24 hours so do some other stuff
}