Why is my single button LED light control only working sometimes? - arduino

I just started getting into Arduino and I put together a very simple led control with one button to change the on and off state. When I push the button the light will come on, but it will only stay on about 50% of the time (so I have to push it multiple times until it actually stays on), and The same thing happens when I try to turn it off.
Is there some problem with my code? Or is it likely to be a wiring issue?
//define variables
int ledPin = 5;
int btnOnPin = 9;
bool isItOn = false;
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(btnOnPin, INPUT_PULLUP);
}
void loop() {
if(digitalRead(btnOnPin) == LOW)
{
if(isItOn == false)
{
digitalWrite(ledPin, HIGH);
isItOn = true;
}
else if (isItOn == true)
{
digitalWrite(ledPin, LOW);
isItOn = false;
}
}
}
The button is connected to ground and pin9, the led is connected to ground, and pin5 through a 220ohm resistor.
This should be super simple, but for some reason I can't get it to work properly.
Thanks for any help

try putting the arduiton to sleep for a few milli seconds after changing its val
void loop() {
if(digitalRead(btnOnPin) == LOW)
{
if(isItOn == false)
{
digitalWrite(ledPin, HIGH);
isItOn = true;
}
else if (isItOn == true)
{
digitalWrite(ledPin, LOW);
isItOn = false;
}
sleep(K);
}

Related

Arduino: LCD won't turn off

a few days ago I started working with the Arduino. I've set up a small project with a DHT22 to read the temperature and humidity and write it to an LCD. That works without a problem. Now I want to only turn on the backlight of the LCD when I press a button. That mostly works too:
void loop() {
buttonState = digitalRead(BUTTONPIN);
currentMillisScreen = millis();
if (buttonState == HIGH) {
screenOn = true;
lcd.backlight();
}
// DHT22 related code in here
if (currentMillisScreen - previousMillisScreen >= SCREEN_ON_TIME) {
previousMillisScreen = currentMillisScreen;
screenOn = false;
lcd.noBacklight();
}
}
The problem is that with this code is that the Backlight won't always stay on for exactly 5 seconds. I thought putting the currentMillisScreen = millis() in the following if-Statement would fix it:
if (buttonState == HIGH) {
currentMillisScreen = millis();
screenOn = true;
lcd.backlight();
}
But if I do that, the Backlight won't turn off again and I don't understand why.
You are not updating currentMillisScreen in the loop and that is your problem. You just need to find different between currentTime (equal to millis()) and previous time that light turned on and if it reaches above the threshold then turn it off. Something like this:
#define SCREEN_ON_TIME 5000
bool screenOn = false;
void setup()
{
//setup
}
void loop()
{
buttonState = digitalRead(BUTTONPIN);
if (buttonState == HIGH)
{
previousMillisScreen = millis();
lcd.backlight();
screenOn = true;
}
// DHT22 related code in here
// if time passed above SCREEN_ON_TIME after we turned on light
if ((screenOn) && (millis() - previousMillisScreen >= SCREEN_ON_TIME))
{
lcd.noBacklight();
screenOn = false;
}
}

Loop in simple arduino code is not working

I am working on simple project, arduino relay controled via mobile phone. I am trying to create a loop, which makes the relay switch between HIGH and LOW only with sending 1 to pin 7. I tried multiple variations but it never works, I am unable to find a mistake. HereĀ“s the code, thanks in advance.`
int relay = 7;
int prev; //previous value
int val; //actual value
void setup()
{
pinMode(relay, OUTPUT);
Serial.begin(9600);
}
void loop()
{
if(Serial.available()>0) //send data when recieved
{
val = Serial.read(); //read value
}
if (val == '1')
{
if (prev == '1')
{
digitalWrite(relay, LOW);
prev=val;
}
else
{
digitalWrite(relay, HIGH);
prev=val;
}
}
else if (val == '0');
{
if (prev == '0')
{
digitalWrite(relay, HIGH);
prev=val;
}
else
{
digitalWrite(relay, LOW);
prev=val;
}
}
}
Current code attempts to read the serial port, and if has something to read sets it into variable val.
In the case of where it has read a value, but doesnt have another value, val is still set to the same value as before.
So it then probally starts toggling the high/low transition as fast as the loop can go.
Instead, you could move the logic code to within the if(Serial.available()>0) statement so that it only gets called when the key is pressed.

Arduino click, double click and hold button

I am trying to implement three different functions for one button in an Arduino project. Click, double click and hold.
I have to use interrupts and let the system sleep as much as possible, because the final product will have to run on a coin cell for a few months.
#include <Ports.h>
#include <RF12.h>
#include <avr/sleep.h>
#include <PinChangeInt.h>
#include <VirtualWire.h>
ISR(WDT_vect) { Sleepy::watchdogEvent(); }
char *controller;
const int buttonPin = 3;
bool stateSingle = false;
bool stateDouble = false;
bool stateLong = false;
void setup() {
pinMode(13, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(5, OUTPUT);
// vw_set_ptt_inverted(true);
// vw_set_tx_pin(12);
// vw_setup(4000);
//
Serial.begin(9600);
PCintPort::attachInterrupt(buttonPin, wakeUp, HIGH);
}
void wakeUp() {
}
void loop() {
cli();
int i = 0;
while (digitalRead(buttonPin) == HIGH) { // Wait until button is LOW, or has been high for more than 600ms
Sleepy::loseSomeTime(50);
if (i > 12)
break;
i++;
}
if (digitalRead(buttonPin) == HIGH)
longTapAction();
else {
i = 0;
while (digitalRead(buttonPin) == LOW) { // Wait for possible double press
Sleepy::loseSomeTime(50);
if (i > 8)
break;
i++;
}
if (digitalRead(buttonPin) == HIGH) {
doubleTapAction();
while (digitalRead(buttonPin) == HIGH)
Sleepy::loseSomeTime(50);
} else
singleTapAction();
}
}
void singleTapAction() {
stateSingle = !stateSingle;
digitalWrite(5, stateSingle ? HIGH : LOW);
sei();
Sleepy::powerDown();
}
void doubleTapAction() {
stateDouble = !stateDouble;
digitalWrite(6, stateDouble ? HIGH : LOW);
sei();
Sleepy::powerDown();
}
void longTapAction() {
stateLong = !stateLong;
digitalWrite(7, stateLong ? HIGH : LOW);
sei();
Sleepy::powerDown();
}
The problem is that this is not always correctly working.
Because I'm using interrupts, millis() inside void loop() is not reliable, for some reason.
For any double click, and for any hold action, the single click function also gets called. I suspect this is due to multiple interrupts firing, but I have no way to test this. Also, sometimes, the double click seems to need only one click. Is my thinking wrong, did I forget something?
If you are seeing singleTapAction and doubleTapAction triggering too often, the problem could be that your method doesn't really debounce the button inputs, meaning you may read spurious noise on any click as a single press or double press. E.G your first while loop will exit almost immediately if there is a noisy input, which makes the following behavior difficult to predict.
https://www.arduino.cc/en/Tutorial/Debounce
If you have a look at the linked example on the arduino site - a possible solution is to record the period of time an input has been present and ignore any inputs of less than a certain period. Modifying your code to do this could stop the spurious calls.

Arduino Code LED failure to alternate

Traffic light just stays on red rather than alternating.
Wanted it to stay on for 10s then off for 10s, continuing ad infinitum.
Dont want to use the delay function cos need to do other stuff while the LED continues to alternate.
Thanks
int red = 10; // red traffic light LED on pin 10
int redcounter;
// the setup routine runs once when you press reset:
void setup()
{
// initialize the digital pin as an output.
pinMode(red, OUTPUT);
digitalWrite(red, LOW);
redcounter = 0;
}
// the loop routine runs over and over again forever:
void loop()
{
redcounter = redcounter +1;
if(redcounter==1000)
{
redcounter=0;
if(digitalRead(red)==HIGH)
{
digitalWrite(red, LOW);
}
if(digitalRead(red)==LOW)
{
digitalWrite(red, HIGH);
}
}
You try to read a port which is configured as an OUTPUT. I don't know if this is supposed to work, but it would be more clear if you simply use another port as INPUT and feedback the signal you want to check in that port. I'm not sure however if it makes much sense to check the state of a signal you generate yourself (?). Moreover your redcounter is just "Active waiting", and arduino provides a delay function which does exactly that.
int red=10;
int signal=11;
void setup()
{
pinMode(red, OUTPUT);
pinMode(signal, INPUT);
digitalWrite(red, LOW);
}
void loop()
{
delay(1000);
if(digitalRead(signal)==HIGH)
{
digitalWrite(red, LOW);
}
if(digitalRead(signal)==LOW)
{
digitalWrite(red, HIGH);
}
}
Use elseif instead of if here:
if(digitalRead(red)==HIGH)
{
digitalWrite(red, LOW);
}
else if(digitalRead(red)==LOW)
{
digitalWrite(red, HIGH);
}
In your old solution every time red turned low, it was turned high a moment later.
Two issues in your code are that digitalread will not read an output pin and if you use an increment counter you won't be able to accurately denote time. Sorry if I missed a bracket or something I was doing this on the mobile app.
Use this:
int red = 10; // red traffic light LED on pin 10
int redcounter;
boolean pinState = false;
int delayTime = 10000;
// the setup routine runs once when you press reset:
void setup() {
// initialize the digital pin as an output.
pinMode(red, OUTPUT);
digitalWrite(red, LOW);
redcounter = millis();
}
// the loop routine runs over and over again forever:
void loop() {
if((millis() - red counter) > delayTime) {
redcounter=millis();
if(pinState) {
digitalWrite(red, LOW);
pinState = false;
}
else {
digitalWrite(red, HIGH);
pinState = true;
}
}
}

How do I fix this arduino code ?(DETAILS BELOW)

I have an Arduino Mega 2560. I have an LED grounded and connected to pin 12 by breadboard and a switch connected to pin 7 and pin 2 by breadboard. I have written this program so that a button press changes the LED's state between on and off. The components all seem to be working so I believe it is a coding issue. Here's my code:
boolean running = false;
boolean ledon = true;
void statechange() {
if(running == false) {
running = true;
ledon = !ledon;
if(led on) {
digitalWrite(12, HIGH);
} else {
digitalWrite(12, LOW);
}
delay(1000);
running = false;
}
}
void setup() {
pinMode(12, OUTPUT);
pinMode(7, OUTPUT);
digitalWrite(7, HIGH);
}
void loop() {
attachInterrupt(0,statechange,CHANGE);
}
I don't receive any errors, it just doesn't work, the LED stays off no matter what.
Are you sure this is right?
if(ledon)
{
digitalWrite(12, HIGH);
}
else
{
digitalWrite(12, LOW);
}
It looks like "If the LED is ON, turn it ON, otherwise, If the LED is OFF, turn it OFF."
Shouldn't it be:
if(ledon)
{
digitalWrite(12, LOW);
ledon = false;
}
else
{
digitalWrite(12, HIGH);
ledon = true;
}
If you're using ledon to keep track of state, but change the state independently of your if statement, the two could potentially become out of sync. Especially if code somewhere else can change the state of ledon.
The other thing that bothers me is this line: if(running == false)
If that is true (e.g. your hardware? is not running), then what is the point of trying to change I/O states at that time?
boolean ledon = true;
void statechange()
{
ledon = !ledon;
digitalWrite(12, ledon ? HIGH : LOW);
}
void setup()
{
pinMode(12, OUTPUT);
pinMode(7, OUTPUT);
digitalWrite(7, HIGH);
}
void loop()
{
attachInterrupt(0,statechange,CHANGE);
}

Resources