Changing blinking duration of LED by using 2 pushbuttons and arduino - arduino

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) );
}

Related

Pulsein() function blocks other tasks from running silmultaneously

I am using a zumo bot with a reflectance sensor used to follow a black line. I want to use an arduino to make the zumo bot stop once it gets a certain distance from an obstacle.
I have an ultrasonic sensor (HC-SR04) which ive connected to the bot.
Both of these tasks work independently but once i merge the code together(so it follows the line aswell as stoping when it detects an object using the ultrasonic sensor), it doesn't work properly.. (the zumo bot no longer follows the line)
I THINK it is to do with the pulsein() function blocking any other tasks but not sure.
My code is below. Can anyone help please?
#include <ZumoShield.h>
ZumoBuzzer buzzer;
ZumoReflectanceSensorArray reflectanceSensors;
ZumoMotors motors;
Pushbutton button(ZUMO_BUTTON);
int lastError = 0;
// This is the maximum speed the motors will be allowed to turn.
// (400 lets the motors go at top speed; decrease to impose a speed limit)
const int MAX_SPEED = 400;
#define echoPin A4
#define trigPin A5
// defines variables
long duration; // variable for the duration of sound wave travel
int distance; // variable for the distance measurement
void setup()
{
reflectanceSensors.init();
pinMode(trigPin, OUTPUT); // Sets the trigPin as an OUTPUT
pinMode(echoPin, INPUT); // Sets the echoPin as an INPUT
// Initialize the reflectance sensors module
// Wait for the user button to be pressed and released
button.waitForButton();
// Turn on LED to indicate we are in calibration mode
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
// Wait 1 second and then begin automatic sensor calibration
// by rotating in place to sweep the sensors over the line
delay(1000);
int i;
for(i = 0; i < 80; i++)
{
if ((i > 10 && i <= 30) || (i > 50 && i <= 70))
motors.setSpeeds(-200, 200);
else
motors.setSpeeds(200, -200);
reflectanceSensors.calibrate();
// Since our counter runs to 80, the total delay will be
// 80*20 = 1600 ms.
delay(20);
}
motors.setSpeeds(0,0);
// Turn off LED to indicate we are through with calibration
digitalWrite(13, LOW);
// Wait for the user button to be pressed and released
button.waitForButton();
Serial.begin(9600); // // Serial Communication is starting with 9600 of baudrate speed
Serial.println("Ultrasonic Sensor HC-SR04 Test"); // print some text in Serial Monitor
Serial.println("with Arduino UNO R3");
}
void loop()
{
unsigned int sensors[6];
// Get the position of the line. Note that we *must* provide the "sensors"
// argument to readLine() here, even though we are not interested in the
// individual sensor readings
int position = reflectanceSensors.readLine(sensors);
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin HIGH (ACTIVE) for 10 microseconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
// Our "error" is how far we are away from the center of the line, which
// corresponds to position 2500.
int error = position - 2500;
// Get motor speed difference using proportional and derivative PID terms
// (the integral term is generally not very useful for line following).
// Here we are using a proportional constant of 1/4 and a derivative
// constant of 6, which should work decently for many Zumo motor choices.
int speedDifference = error / 4 + 6 * (error - lastError);
lastError = error;
// Get individual motor speeds. The sign of speedDifference
// determines if the robot turns left or right.
int m1Speed = MAX_SPEED + speedDifference;
int m2Speed = MAX_SPEED - speedDifference;
if (m1Speed < 0)
m1Speed = 0;
if (m2Speed < 0)
m2Speed = 0;
if (m1Speed > MAX_SPEED)
m1Speed = MAX_SPEED;
if (m2Speed > MAX_SPEED)
m2Speed = MAX_SPEED;
motors.setSpeeds(m1Speed, m2Speed);
//if (distance <20){
// motors.setSpeeds(0,0);
// }
////////////////////////////////////////////
// Calculating the distance
distance = duration * 0.034 / 2; // Speed of sound wave divided by 2 (go and back)
// Displays the distance on the Serial Monitor
Serial.print("Distance: ");
Serial.print(distance);
Serial.println(" cm");
} ```
Of course pulseIn is blocking function. Arduino project is open source, you can easily check source code
Here is C equivalent countPulseASM function which does measurement.
unsigned long pulseInSimpl(volatile uint8_t *port, uint8_t bit, uint8_t stateMask, unsigned long maxloops)
{
unsigned long width = 0;
// wait for any previous pulse to end
while ((*port & bit) == stateMask)
if (--maxloops == 0)
return 0;
// wait for the pulse to start
while ((*port & bit) != stateMask)
if (--maxloops == 0)
return 0;
// wait for the pulse to stop
while ((*port & bit) == stateMask) {
if (++width == maxloops)
return 0;
}
return width;
}
If you need measure pulse length in non blocking way, use hw counters.

How can I make an LED blink every n seconds without developing a lag?

I'm using an Arduino Uno to control LED. I want the LED to turn on every m seconds and remain ON for n seconds.
I've tried this code using the delay() function (by adding delays after LED is turned ON and OFF) and also using the millis() function (by keeping a track of the time passed since the previous event - ON/OFF). However, in both the approaches, the LED develops a lag of ~1 second after a few (!10) iterations of the ON-OFF cycle. What can I do to increase the accuracy of the time at which the events occur?
int led = 13;
long experimentTime = 240000;
long ledOFFDuration = 8000;
void setup() {
pinMode(led, OUTPUT);
pinMode(button, INPUT);
}
void loop() {
for (int i = 0; i < 100; i++){
digitalWrite(led, HIGH);
delay(10000);
digitalWrite(led, LOW);
delay(10000);
}
}
I've also tried using the watchdog timer (shown below). However, it has the same issue:
#include <avr/wdt.h>
int led = 13;
volatile byte watchDogState = 0b01000000;
volatile int counter = 0;
int counterMax = 5;
bool state = 1;
void setup() {
// put your setup code here, to run once:
wdt_disable();
pinMode(led, OUTPUT);
digitalWrite(led, 1);
setWDT(watchDogState);
}
void loop() {
// put your main code here, to run repeatedly:
// if (time_elapsed == 40){
//state = !state;
//}
}
void setWDT(byte sWDT){
WDTCSR |= 0b00011000;
WDTCSR = sWDT | WDTO_2S;
wdt_reset();
}
ISR (WDT_vect){
counter++;
if (counter >= counterMax){
state = !state;
digitalWrite(led, state);
counter = 0;
}
}
I tried using the port registers directly to avoid using digitalWrite completely. But that doesn't work either. There's a lag of ~5s after 20 minutes using the following code:
int led = 13;
int m = 10;
int n = 10;
boolean on;
long change;
void setup() {
pinMode(led, OUTPUT);
}
void loop() {
long now = millis();
if (!on && change < now) {
on = true; //led is now on
change = now + n*1000; //turn off in <n> seconds
PORTB |= B00100000;
}
else if (on && change < now){
on = false; //led is now off
change = now + m*1000; //turn on in <m> seconds
PORTB &= B11011111; // Set pin 4 to 0
}
}
The lag is caused by the digitalWrite-calls. Your processing application waits until digitalWrite has finished and this may take 0.05 seconds or so. To fix your problem I would save the current time in milliseconds.
int led = 13;
int m = 24;
int n = 8;
boolean on;
long change;
void setup() {
pinMode(led, OUTPUT);
}
void loop() {
long now = System.currentTimeMillis();
if (!on && change < now) { //led is off and time for change has come
on = true; //led is now on
change = += n*1000; //turn off in <n> seconds
digitalWrite(led, HIGH); //turn on led
} else if (on && change < now) { //led is on and time for change has come
on = false; //led is now off
change = += m*1000; //turn on in <m> seconds
digitalWrite(led, LOW); //turn off led
}
}
the lamp will now instantly turn on on startup, wait n seconds, turn off, wait m seconds and restart from the beginning.
If you want to create a delay at the beginning so that the lamp doesn't get turned on immediately you can simply add this to your setup-function:
change = now + SECONDS*1000;
EDIT
You pointed out that it still gives you lag.
One problem might be that loop() is not run every millisecond. So I maybe got a solution for you.
Replace the following two lines:
change = now + n*1000; //turn off in <n> seconds
...
change = now + m*1000; //turn on in <m> seconds
to this:
change += n*1000; //turn off in <n> seconds
...
change += m*1000; //turn on in <m> seconds
Now it won't take the current time anymore which means that even if loop is only run every second or two it should still not cause any lag.
If this won't work I'm afraid it looks like the timer on the arduino might not be the most precise one. If this is the case try to measure the exact offset and then create a miltiplicator for the time.

Motion controlled light

I'm trying to create an motion controlled light that doesn't turn on unless it's dark.
I want the light to turn on and off slowly with pwm when motion is detected. Right now my code works and does almost everything I want it to.
The problem is that I'm using the delay function to keep the light on after it reaches full brightness. And because of this if motion is detected while the light is on it doesn't reset the timer. Once the delay timer runs out and motion is detected the brightness will go down and then back up.
I would like to have the motion detector reset the timer that keeps the led on but haven't been able to get it working.
I have looked at these:
http://playground.arduino.cc/Code/AvoidDelay
https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
But because of my somewhat limited understanding of arduino code I haven't been able to get it working. I would really appreciate any help.
SOLVED
The working code below:
const byte MotionPin = 4; // Motionsensor
int LightSensorPin = 2; // Lightsensor
const byte LedPin = 11; // LED
unsigned long MotionDetectedMillis; // When motion was detected
unsigned long ledTurnedOnAt; // when led was turned on
unsigned long turnOnDelay = 50; // wait to turn on LED
unsigned long turnOffDelay = 5000; // turn off LED after this time
bool ledReady = false; // Has motion been detected
bool ledState = false; // Led on or off
int LightSensorState = 0;
int fadeAmount = 5; // How much to fade in a loop
byte brightness = 0;
void setup() {
pinMode(MotionPin, INPUT);
pinMode(LightSensorPin, INPUT);
pinMode(LedPin, OUTPUT);
digitalWrite(LedPin, LOW);
}
void loop() {
// get the time at the start of this loop()
unsigned long currentMillis = millis();
if (digitalRead(MotionPin) == HIGH && digitalRead(LightSensorPin)== HIGH)
{
MotionDetectedMillis = millis();
ledReady = true;
}
if (ledReady)
{
if ((unsigned long)(currentMillis - MotionDetectedMillis) >= turnOnDelay)
{
while (brightness < 255)
{
brightness = brightness + fadeAmount;
analogWrite(LedPin, brightness);
delay(30);
}
// setup our next "state"
ledState = true;
// save when the LED turned on
ledTurnedOnAt = currentMillis;
ledReady = false;
}
}
// see if we are watching for the time to turn off LED
if (ledState)
{
if ((unsigned long)(currentMillis - ledTurnedOnAt) >= turnOffDelay)
{
while (brightness >0)
{
brightness = brightness - fadeAmount;
analogWrite(LedPin, brightness);
delay(30);
}
ledState = false;
}
}
}
what you want is a state machine; you have to keep track in the loop of which state you currently are and what is the condition to trigger next state; because your loop will execute an action only if something happen to trigger a new state, instead of using delay() you will use a 'waiting for timeout' state (remember to keep a way to know what is the next state).
If this confuses you, imagine each state as step in the instruction manual;
turn on led 1, wait x, turn on led 1 a bit more, wait y, etc..
And because you have no more delay, before or after manage the "normal flow" of the state, you can add some special case like "if input 2 is high and current state is X or Y then set current state to Z".
So, what you want could be easily archived with an interrupt, but with a simple project like this one, you can get the same result just by removing the delay(OnTime) function.
If you want more on the interrupts of the atmega328 which is the one the Arduino UNO uses, go here

Arduino Button with LED

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;
}

Arduino - To begin a timer when a button is pressed

I would like to start a timer once a button is pressed. The timer will light up an LED for five minutes. After the five minutes has expired I would like it to wait two minutes before registering another button press.
I have figured out how to do this.
I will use the Delay command for a period of time whilst LED is on high
then after the period of time I will set LED to low
and so on and so forth.
I have all the code that I have used here.
const int LED2 = 12;
const int LED = 13;
const int BUTTON = 7;
int var = 0;
int val = 0;
int old_val = 0;
int state = 0;
void setup(){ //telling the computer what the LED and the button are
pinMode (LED2,OUTPUT);
pinMode (LED,OUTPUT);
pinMode (BUTTON,INPUT);
}
void loop(){
val = digitalRead(BUTTON);
if ((val == HIGH) && (old_val == LOW)){
digitalWrite(LED,HIGH);
delay(240000); //The period of time to wait before turning on the LED2
digitalWrite(LED2,HIGH);
delay (1000);
digitalWrite(LED2,LOW);
delay (490000);
var = 0;
while(var < 10){ //A while loop to flash the LED2 on and off
digitalWrite(LED2,HIGH);
delay (500);
digitalWrite(LED2,LOW);
delay (500);
var++;
}
digitalWrite(LED,LOW);
delay(120000); //A two minute delay before the button can be pressed again
}
}
Use the built-in example program "Blink without Delay" and combine it with "Button". Both programs are available as tutorials at http://arduino.cc/en/Tutorial/HomePage Try to avoid the delay() function because it wastes the processors time and has timing inaccuracies if there are interrupts.

Resources