Hi,
I'm doing a project for school and my team needs some help.
Our goal is to push a button that will then run a motor for 3 seconds then stop. Holding down the button shouldn't do anything to affect the motor, unless it's released and pressed again. We aren't sure whether it is the code, wiring or both. Our current code is:
const int buttonPin = 9; // the number of the pushbutton pin
const int ledPin = 13; // the number of the LED pin
// variables will change:
int buttonState = 0; // variable for reading the pushbutton status
void setup() {
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
millis();
}
void loop() {
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);
// check if the pushbutton is pressed. If it is, the buttonState is HIGH:
if ((buttonState == HIGH) && millis() <=3000){
digitalWrite(ledPin, HIGH);
delay(3000);
digitalWrite(ledPin, LOW);
}
else {
// turn LED off:
digitalWrite(ledPin, LOW);
}
}
unless the purpose is only to respond during the first 3000 msecs after the Arduino starts. After that time millis() will not be less than 3000 for about 49 days.
team member of the original poster here.
Our new code is this:
const int buttonPin = 9; // the number of the pushbutton pin
const int ledPin = 13; // the number of the LED pin
unsigned long currentMillis = 0;
unsigned long runDuration=3000;
unsigned long previousButtonMillis = 0; // time when button press last checked
int buttonState = 0; // variable for reading the pushbutton status
void setup() {
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
}
void loop() {
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);
currentMillis=millis();
updateOnBoardState();
}
void updateOnBoardState() {
if (buttonState == HIGH) {
// if the Led is off, we must wait for the interval to expire before turning it on
if (currentMillis - previousButtonMillis <= runDuration) {
// time isnt up, so change the state to HIGH
digitalWrite(ledPin,HIGH);
// and save the time when we made the change
previousButtonMillis = currentMillis;
} else
digitalWrite(ledPin,LOW);
}
else { // i.e. if onBoardLedState is LOW
digitalWrite(ledPin,LOW);
previousButtonMillis = currentMillis;
}
}
I don't see the problem. When I press the button the motor just goes on forever. Is there something wrong with
previusButtonMillis = currentMillis ?
That seems like the most likely mistake to me. Everything's from the recommended post
const int buttonPin = 9; // the number of the pushbutton pin
const int ledPin = 13; // the number of the LED pin
unsigned long currentMillis = 0;
unsigned long runDuration=3000;
unsigned long previousButtonMillis = 0; // time when button press last checked
int buttonState = 0; // variable for reading the pushbutton status
void setup() {
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
Serial.begin(9600);
}
void loop() {
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);
currentMillis=millis();
updateOnBoardState();
}
void updateOnBoardState() {
if ((buttonState == HIGH) && (currentMillis - previousButtonMillis <= runDuration)){
// if the Led is off, we must wait for the interval to expire before turning it on
if (currentMillis - previousButtonMillis <= runDuration) {
// time isnt up, so change the state to HIGH
digitalWrite(ledPin,HIGH);
// and save the time when we made the change
} else
digitalWrite(ledPin,LOW);
Serial.println(currentMillis-previousButtonMillis);
}
else { // i.e. if onBoardLedState is LOW
digitalWrite(ledPin,LOW);
previousButtonMillis = currentMillis;
}
}
with the serial.println it goes from 0 to 3000 then resets as we want, but only the first time the button is pressed does the motor stop at 3000. every other time its pressed it stops after a couple loops of 3000, generally 2-4. (We removed currentmillis=previousbuttonmillis from the second if)
Why have you the same test on two successive lines?
if ((buttonState == HIGH) && (currentMillis - previousButtonMillis <= runDuration)){
// if the Led is off, we must wait for the interval to expire before turning it on
if (currentMillis - previousButtonMillis <= runDuration) {
What happens if you simplify the first line to
if ((buttonState == HIGH) {
It is usual to update the time variable after testing it - like this
if (currentMillis - previousButtonMillis <= runDuration) {
previousButtonMillis = currentMillis;
It may be correct not to, but why are you not doing that?
It would help if you write down in English the steps that you want your program to take.
Having the same test twice was just sloppy coding to get both else statements that I now realize i don't need. Whenever I have the line to update the variable in the loop the time stays at 0 according to serial.print and the motor stays on. When I have it update in the else statement it resets properly after the 3 seconds are up in the if part. Also I fixed the issue where it runs for multiples of 3 seconds by putting a short delay at the end of the else statement. Here's a cleaned up version with explanations.
const int buttonPin = 9;
const int ledPin = 13; // the number of the Motor pin
unsigned long currentMillis = 0;
unsigned long runDuration=3000;
unsigned long previousButtonMillis = 0; // time of previous button press
int buttonState = LOW; // variable for reading the pushbutton status
void setup() {
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
Serial.begin(9600);
}
void loop() {
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);
//create variable of total time
currentMillis=millis();
//To make a new void part. I don't know why but it was in the example
updateOnBoardState();
}
void updateOnBoardState() {
if ((buttonState == HIGH) && (currentMillis - previousButtonMillis <= runDuration)){
// if the button is pressed and if motor has been running for less then 3 seconds
digitalWrite(ledPin,HIGH);
// activate the motor
Serial.println(currentMillis-previousButtonMillis);
//Display how long the motors been running
}
else {
//if the button isnt pressed or the motor has been on more than 3 seconds
digitalWrite(ledPin,LOW);
//Turn off motor
previousButtonMillis = currentMillis;
// Record the time the motor automaticly shut off after 3 seconds
delay(100);
} }
Now the only problem is getting the motor to stop if the button is still being held down after 3 seconds. I don't know if this is physically possible with our circuit. We have the power running through the switch to the motor with the arduino board in parallel as in this picture.
It's a nice photograph but I can't see its value for sorting out this problem. If you want to show us your connections then make a pencil drawing of the circuit and post a photo of the drawing.
The else part is to , i believe, deal with either when the button is low or the time is wrong. Because the if is only true if both statements are true either one being false will activate the else and turn off the motor. As for using millis() and delay() thats the only way i found to make it work. I couldn't make just delay do anything and just millis seems to stop the motor at random times, sometimes it stops at 3 seconds like i want, sometimes less but mostly a seemingly random high number. Putting a small delay before the code checks if there's a new input made the motor stop at 3 seconds every time.
Our end goal is to have the motor run for only 3 seconds no matter how short or long the button is pressed. The only way to get it to run again is to press the button again, releasing and pressing it if it was held down, again running for just 3 seconds and so on.
spoc66:
Our end goal is to have the motor run for only 3 seconds no matter how short or long the button is pressed. The only way to get it to run again is to press the button again, releasing and pressing it if it was held down, again running for just 3 seconds and so on.
Then you need edge detection and a variable to 'remember' that an edge was detected.
Well this is a problem. That's what I've been using to test it. Once its working its going to be installed in a small electric car and using its motor and 6v battery. Should I be using this? https://www.arduino.cc/en/Tutorial/TransistorMotorControl
@spoc66, the drawing in Reply #11 was much easier to understand than the Fritzing picture. Please do another drawing with the correct connections. It is much too easy to misunderstand the Fritzing picture.