How can I get the duration of how long a button is unpressed? And when the duration excceds 30 seconds I have to perform an event in arduino. Any help would be appreciated
I would use a code like this who save the last press time and wait until the 30th milliseconds to execute the code. Let me know if it is working, since I haven't tested it.
#define BUTTON_PIN 4
unsigned long startTime;
unsigned long lastPress;
void setup()
{
Serial.begin(9600);
pinMode(BUTTON_PIN, INPUT_PULLUP);
}
void loop()
{
byte buttonState = digitalRead(BUTTON_PIN);
if (buttonState == HIGH) // save the last time button was pressed in milliseconds
{
lastPress = millis();
}
if ((millis() - lastPress) > 30000)
{
// execute any code you want after 30 seconds
// reset the counter
startTime = 0;
}
}
Related
I'm trying to make an arduino UNO circuit that allows me to set the blinking duration of an LED with two pushbuttons, but I'm having trouble with the program. First of all, the default blinking duration is 0,5 s. And I want to program the first pushbutton to be able to extend the blinking duration by 0,1 seconds, whereas the second one is for speeding up the duration by 0,1 seconds.
So in my current code, I use if statements to check whether the two buttons are pressed or not. If the inc button is pressed, the program should increase the duration by 100 ms, whereas when dec button is pressed, the program should decrease the duration by 100 ms.
However when I run it on the arduino circuit, the duration is stuck in 600 and 500. So in every loop, the program adds 100 ms to the duration time and then decreases it again by 100, even when I do nothing to the buttons.
Here's my code so far:
const int led = 7;
const int buttonUp = 6;
const int buttonDown = 5;
int duration = 500;
void setup(){
pinMode(led, OUTPUT);
pinMode(buttonUp, INPUT);
pinMode(buttonDown, INPUT);
Serial.begin(9600);
}
void loop(){
int inc = digitalRead(buttonUp);
int dec = digitalRead(buttonDown);
if(inc == HIGH){
duration += 100;
Serial.println(duration);
}
if(dec == HIGH){
duration -= 100;
if(duration < 0){
duration = 100;
}
Serial.println(duration);
}
digitalWrite(led, HIGH);
delay(duration);
digitalWrite(led, LOW);
delay(duration);
}
the code and circuit
serial monitor
Will be extremely grateful if anyone can point out any mistakes!! Thank you!
duration is 500ms. So you basically poll your button states once every second. The time window where you can detect a button click is very short compared to the time you cannot detect it. So chances that you register a click are very little. You need to push the button for at least a second to capture the signal every time.
If you push both buttons you add and subtract 100. That's a total change of 0. What do you expect?
This can be avoided by checking your button state more frequently or by using interrupts.
Find out how to use non-blocking delays and interrupts. The internet is full of tutorials.
bool blink(unsigned int duration) {
// demo code only
// (usable only once per sketch, due to static variables)
static unsigned long last;
static bool state;
if (millis() - last >= duration) {
last = millis();
state = ! state;
}
return state;
}
This is the BlinkWithoutDelay pattern. Usage:
digitalWrite(led,blink(duration));
Button handling is trickier than a beginner thinks: often you want to detect a state change between pressed and released, and you want to ignore the bouncing of a mechanical switch happening during a state change. Or you want to repeat some action, when the button is pressed for a long time.
Easiest you do a little delay(10); after detecting a state change to pass the bouncing time. Or look for libraries doing all that button handling.
Or do such a lazy delay anyway, to slow down your fast microcontroller below button bouncing speed.
const int led = 7;
const int buttonUp = 6;
const int buttonDown = 5;
void setup(){
pinMode(led, OUTPUT);
pinMode(buttonUp, INPUT);
pinMode(buttonDown, INPUT);
Serial.begin(9600);
}
unsigned int duration = 500;
int lastbutton = 0; // 0 / -100 / +100 to detect button changes
void loop(){
bool inc = digitalRead(buttonUp);
bool dec = digitalRead(buttonDown);
delay(5); // debounce
if( (inc || dec) && lastbutton == 0){
lastbutton = (inc - dec) * 100;
duration += lastbutton;
if (duration == 0) duration = 100; // Minimum
Serial.println(duration);
}
if (lastbutton != 0 && !inc && !dec) lastbutton = 0;
digitalWrite(led, blink(duration) );
}
This is what I am trying to achieve:
User inputs time using a rotary encoder.
The Arduino Serial Monitor must display real-time values of time as the user keeps rotating the encoder.
The user then hits a physical switch (push switch) to initiate the countdown.
Initially, my code worked perfectly with delay() function.
But my application also requires me to run a motor as long as the timer lasts. For this, I need a non-blocking delay. I am having a hard time with that. Please help. Here is my code:
unsigned long previousMillis = 0; // will store last time LED was updated
// constants won't change:
const long interval = 1000; // interval at which to blink (milliseconds)
#define outputA 6
#define outputB 7
int i;
int button=5;
int counter = 0;
int aState;
int aLastState;
void setup() {
pinMode (outputA,INPUT);
pinMode (outputB,INPUT);
pinMode (button,INPUT);
Serial.begin (9600);
// Reads the initial state of the outputA
aLastState = digitalRead(outputA);
}
void loop() {
// here is where you'd put code that needs to be running all the time.
aState = digitalRead(outputA); // Reads the "current" state of the outputA
// If the previous and the current state of the outputA are different, that means a Pulse has occured
if (aState != aLastState) {
// If the outputB state is different to the outputA state, that means the encoder is rotating clockwise
if (digitalRead(outputB) != aState) {
counter = counter+1;
} else {
counter = counter-1;
}
Serial.print("Time (secs): ");
Serial.println(counter);
i = counter;
if (digitalRead(button) == HIGH) {
while (i != 0) {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis == interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
i--;
Serial.println(i);
}
}
}
aLastState = aState;
}
}
If I understand well you are decrementing i only when entering if (currentMillis - previousMillis == interval). It means you are decrementing very slowly, and not millisecond by milliseconds…
To correct this I'm suggesting:
unsigned long startMillis = millis();
while (millis() - startMillis() < counter){ //check if your time has elapsed
unsigned long currentMillis = millis();
if (currentMillis - previousMillis == interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
Serial.println((int) counter - (millis() - startMillis()));
}
}
Hope it helps!
I have a simple code with delays.
I'd like to know how to convert this code to millis? Is there a function to do so?
long revers = 1000;
void setup() {
pinMode(D1, OUTPUT);
pinMode(D2, OUTPUT);
}
void loop() {
digitalWrite(D1, LOW);
delay(revers);
digitalWrite(D2, HIGH);
delay(revers);
digitalWrite(D2, LOW);
delay(revers);
digitalWrite(D1, HIGH);
delay(revers);
}
The basic concept is this: record the millis() at a given moment in a variable - say 'starttime'. Now, during every loop(), check the time that has elapsed by subtracting millis() from 'starttime'. If the elapsed time is greater than the delaytime you set, execute code. Reset the starttime to create a repeating pattern.
That may be too short of an explanation for you, so before you dive into the code, I highly advise you to read this introduction about using millis() for timing. It's lengthy, but it explains the principle extensively. This will help you understand the code below.
Lastly, there are several libraries written to make the use of timing easier. For instance the SimpleTimer-library, but you can google "arduino timer library" for others. I've included an example below.
1 second on, 3 seconds off:
unsigned long startMillis; //some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 1000; //the value is a number of milliseconds
int fase; //value used to determine what action to perform
void setup() {
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
startMillis = millis(); //initial start time
fase = 0;
}
void loop() {
currentMillis = millis(); //get the current "time" (actually the number of milliseconds since the program started)
if (currentMillis - startMillis >= period) //test whether the period has elapsed
{
if (fase == 0)
{
digitalWrite(8, LOW);
startMillis = currentMillis; //IMPORTANT to save the start time of the current LED state.
fase = 1; //increment fase, so next action will be different
}
else if (fase == 1)
{
digitalWrite(7, HIGH);
startMillis = currentMillis;
fase = 2;
}
else if (fase == 2)
{
digitalWrite(7, LOW);
startMillis = currentMillis;
fase = 3;
}
else if (fase == 3)
{
digitalWrite(8, HIGH);
fase = 0;
startMillis = currentMillis;
}
}
}
Example of a flashing led using the SimpleTimer library
#include <SimpleTimer.h>
// the timer object
SimpleTimer timer;
int ledPin = 13;
// a function to be executed periodically
void repeatMe() {
digitalWrite(ledPin, !digitalRead(ledPin));
}
void setup() {
pinMode(ledPin, OUTPUT);
timer.setInterval(1000, repeatMe);
}
void loop() {
timer.run();
}
I want to implement a simple LED controller with an Arduino Uno, that goes to sleep and has different buttons.
Functions of buttons are:
Digital 2: Button for ON OFF
Digital 3: Button for Wake up
Everything works ok, but when it goes to sleep, the LEDs also turn off. I want that after 30 seconds, when Arduino goes to sleep, lights stays on.
Here is my code:
#include <avr/sleep.h>
#define REDPIN 10
#define GREENPIN 11
#define BLUEPIN 9
#define delayTime 20 //za fading cas
unsigned long interval= 30000;
unsigned long previousMillis = 0;
const int ledPin = 12; // the pin that the LED is attached to
const int buttonPin1 = 2; //on off
bool vklop = false;
int bela = 10;
int barva;
int prejsnja_barva = 0;
int buttonPushCounter1 = 0; // counter for the number of button presses
int buttonState1 = 0; // current state of the button
int lastButtonState1 = 0; // previous state of the button
/////////////////////////////////////*SETUP*/////////////////////////////////////////
void setup()
{
pinMode(buttonPin1, INPUT);
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
pinMode(3,INPUT); //because of interrupts PIN digital 3
digitalWrite(3,HIGH);
}
/////////////////////////////////////*LOOP*/////////////////////////////////////////
void loop()
{
unsigned long currentMillis = millis();
if ((currentMillis-previousMillis) > interval) //15s timer
{
previousMillis = currentMillis;
Serial.println("SLEEP!"); // kaj delaj po preteku 5s
delay(50);
sleepSetup(); //sleep mode
}
else
{
buttonState1 = digitalRead(buttonPin1);
/////////////////////////////////////ON/OFF/////////////////////////////////////////
/////////////////////////////////////ON/OFF/////////////////////////////////////////
if (buttonState1 != lastButtonState1) // compare the buttonState to its previous state
{
if (buttonState1 == HIGH) // if the state has changed, increment the counter
{
buttonPushCounter1++; // if the current state is HIGH then the button went from off to on:
Serial.println("on");
Serial.print("number of BUTTON1 pushes: ");
Serial.println(buttonPushCounter1);
digitalWrite(ledPin, HIGH);
if(buttonPushCounter1 % 2 == 0)
{
setColor(bela, bela, bela);
vklop = true;
barva = 13;
}
else
{
setColor(0, 0, 0);
vklop = false;
}
}
else // if the current state is LOW then the button went from on to off:
{
Serial.println("off");
digitalWrite(ledPin, LOW);
}
delay(50); // Delay a little bit to avoid bouncing
}
lastButtonState1 = buttonState1; // save the current state as the last state, for next time through the loop
}
}
/////////////////////////////////functions/////////////////////////////////////////////
/////////////////////////////////functions/////////////////////////////////////////////
/////////////////////////////////functions/////////////////////////////////////////////
void setColor(int red, int green, int blue)
{
analogWrite(REDPIN, red);
analogWrite(GREENPIN, green);
analogWrite(BLUEPIN, blue);
}
void sleepSetup(void)
{
sleep_enable(); // Set sleep enable (SE) bit:
attachInterrupt(1, pinInterrupt, LOW); // Set pin 2 as interrupt and attach handler:
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // define our preferred sleep mode:
digitalWrite(13,LOW);
sleep_cpu();
Serial.println("Just woke up!"); //OD TU SE NADALJUJE PO PRITISKU TIPKE
digitalWrite(13,HIGH);
}
void pinInterrupt() //ISR
{
sleep_disable();
detachInterrupt(0);
}
You're using AVR's Power Down sleep mode. In this mode all timers are turned off to save power.
No timers -> no PWM -> no analogue output -> no PWM driven LEDs
To keep the LED on use another sleep mode.
See
http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf for details.
But to be honest I am not quite sure if this makes any sense. If you're driving an LED through 3 outputs the power you can save by putting the MCU into sleep is maybe a few percent.
And as sleep stops the CPU and hence your program you won't be able to have the LEDs turn off after 30s.
Why not just wait 30s befor going to sleep? The alternative would be some external timing circuitry that would also consume power. So I guess having a few milliamps more for 30 seconds is still a better alternative.
I have put together an Arduino circuit that turns the led's off when the button is pressed. How do I code it so when I press it once it comes on and stays on and will only turn off once its pressed again? Any help would be appreciated
My Current code is:
int ledred = 12;
int ledgreen = 8;
int BUTTON = 4;
int speakerPin = 1;
void setup() {
// initialize the digital pin as an output.
Serial.begin(9600);
pinMode(ledgreen, OUTPUT);
pinMode(ledred, OUTPUT);
pinMode(BUTTON,INPUT);
}
void loop() {
if(digitalRead(BUTTON) == HIGH){
digitalWrite(ledred,HIGH);
digitalWrite(ledgreen,HIGH);
}else
{
digitalWrite(ledred,LOW);
digitalWrite(ledgreen,LOW);
}
}
If all you want is do this, you can use one of the interrupt pins and watch for the RISING (or FALLING) event.
Something similar to this example:
const byte ledPin = 13;
const byte interruptPin = 2;
volatile byte state = LOW;
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), blink, RISING);
}
void loop() {
digitalWrite(ledPin, state);
}
void blink() {
state = !state;
}
Mind that you may still need some debouncing strategy.
Also, you don't need to use an interrupt for that, but then you'd need some edge-detection algorithm. These are quite well explained in the debouncing article above. I personally prefer these, since interrupt pins in the UNO board are precious enough not to be used with humble button pressings... :o)
/*
Debounce
Each time the input pin goes from LOW to HIGH (e.g. because of a push-button
press), the output pin is toggled from LOW to HIGH or HIGH to LOW. There's a
minimum delay between toggles to debounce the circuit (i.e. to ignore noise).
The circuit:
- LED attached from pin 13 to ground
- pushbutton attached from pin 2 to +5V
- 10 kilohm resistor attached from pin 2 to ground
- Note: On most Arduino boards, there is already an LED on the board connected
to pin 13, so you don't need any extra components for this example.
created 21 Nov 2006
by David A. Mellis
modified 30 Aug 2011
by Limor Fried
modified 28 Dec 2012
by Mike Walters
modified 30 Aug 2016
by Arturo Guadalupi
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/Debounce
*/
// constants won't change. They're used here to set pin numbers:
const int buttonPin = 2; // the number of the pushbutton pin
const int ledPin = 13; // the number of the LED pin
// Variables will change:
int ledState = HIGH; // the current state of the output pin
int buttonState; // the current reading from the input pin
int lastButtonState = LOW; // the previous reading from the input pin
// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers
void setup() {
pinMode(buttonPin, INPUT);
pinMode(ledPin, OUTPUT);
// set initial LED state
digitalWrite(ledPin, ledState);
}
void loop() {
// read the state of the switch into a local variable:
int reading = digitalRead(buttonPin);
// check to see if you just pressed the button
// (i.e. the input went from LOW to HIGH), and you've waited long enough
// since the last press to ignore any noise:
// If the switch changed, due to noise or pressing:
if (reading != lastButtonState) {
// reset the debouncing timer
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
// whatever the reading is at, it's been there for longer than the debounce
// delay, so take it as the actual current state:
// if the button state has changed:
if (reading != buttonState) {
buttonState = reading;
// only toggle the LED if the new button state is HIGH
if (buttonState == HIGH) {
ledState = !ledState;
}
}
}
// set the LED:
digitalWrite(ledPin, ledState);
// save the reading. Next time through the loop, it'll be the lastButtonState:
lastButtonState = reading;
}