Not reaching all branches of a case statement - arduino

My project is a dead bolt that uses RF key fob. It checks for unlock or lock button press and also checks if the lock is locked or not. I use a case statement for the various choices. I think for some reason the lock state isn't changing because I am only getting cases 2 and 4.
I watered down the output actions to light blinks for each case (case 1 blinks once case 2 twice etc..)
After each case executes it changes the Boolean lock state (locked = true)
Code
/*
This code will open a deadbolt
with RF remote or buttons and
knows the position of the lock
based on last action
12 RF/Button lock
13 RF/Button unlock
10 button lock
11 button unlock
8 Buzzer
9 Servo
A0 Servo location
4 LED lock
5 LED unlock
*/
const int lockrf = 12; //input to lock rf
const int ulockrf = 13; //input to unlock rf
const int butlock = 10; // button lock
const int butulock = 11; // button unlock
const int ulockled = 4; //led in lock button
const int lockled = 2; //led in ulock button
#include <Servo.h>
boolean lockstate = true;
void setup()
{
Servo deadbolt;
deadbolt.attach(9);
pinMode(butlock,INPUT);
pinMode(butulock,INPUT);
pinMode(ulockrf,INPUT);
pinMode(lockrf,INPUT);
pinMode(ulockled,OUTPUT);
pinMode(lockled,OUTPUT);
}
void loop()
{
//variables for code
int lockdeg = 0;
int ulockdeg = 90;
int lock_case = 0;
digitalWrite(ulockled,LOW);
digitalWrite(lockled,LOW);
if (digitalRead(lockrf)==HIGH || digitalRead(butlock)==HIGH && lockstate == true ) // locked press lock
{
lock_case=1;
}
if (digitalRead(lockrf)==HIGH || digitalRead(butlock)==HIGH && lockstate == false) // ulocked press lock
{
lock_case=2;
}
if (digitalRead(ulockrf)==HIGH || digitalRead(butulock)==HIGH && lockstate == true) // locked press ulock
{
lock_case=3;
}
if (digitalRead(ulockrf)==HIGH || digitalRead(butulock)==HIGH && lockstate == false) // ulocked press ulock
{
lock_case=4;
}
switch(lock_case)
{
case 1:
{
digitalWrite(lockled,HIGH);
delay(500);
digitalWrite(lockled,LOW);
delay(10);
lockstate=true;
break;
}
case 2:
{
digitalWrite(lockled,HIGH);
delay(500);
digitalWrite(lockled,LOW);
delay(500);
digitalWrite(lockled,HIGH);
delay(500);
digitalWrite(lockled,LOW);
lockstate=true;
break;
}
case 3:
{
digitalWrite(lockled,HIGH);
delay(500);
digitalWrite(lockled,LOW);
delay(500);
digitalWrite(lockled,HIGH);
delay(500);
digitalWrite(lockled,LOW);
delay(500);
digitalWrite(lockled,HIGH);
delay(500);
digitalWrite(lockled,LOW);
lockstate=false;
break;
}
case 4:
{
digitalWrite(lockled,HIGH);
delay(500);
digitalWrite(lockled,LOW);
delay(500);
digitalWrite(lockled,HIGH);
delay(500);
digitalWrite(lockled,LOW);
delay(500);
digitalWrite(lockled,HIGH);
delay(500);
digitalWrite(lockled,LOW);
delay(500);
digitalWrite(lockled,HIGH);
delay(500);
digitalWrite(ulockled,LOW);
delay(10);
lockstate=false;
break;
}
}
}

Your problem is operator precedence. Arduino follows C-language precedence, in which && is evaluated before ||. For example, this means that your first if statement is evaluated as if you had parentheses like so:
digitalRead(lockrf)==HIGH ||
(digitalRead(butlock)==HIGH && lockstate == true)
What happens here is that if lockrf is high, both of the first two if statements are true, so you first set lock_case to 1, then to 2. You get a similar effect when ulockrf is high. This is why you get only cases 2 and 4.
To fix this, add parentheses to disambiguate:
if ((digitalRead(lockrf)==HIGH || digitalRead(butlock)==HIGH)
&& lockstate == true )
Good programming practice suggests using parentheses if there's any doubt.

Related

Use a DS3231 RTC module and Arduino to fire function every other day

I'm attempting to create a timer which reminds me to do something ever other day, however it seems that my options with the DS3231 module allows me to set an hour or a day of the week. Unfortunately neither option is good enough (if only there were 8 days in a week) and i'm at a loss on how to tell it to fire every other day.
I considered the idea of setting a 'not_today' variable which will probably work but that has the downside of relying on the arduino and not the RTC which means if it loses power then that variable will reset.
It looks like the DS3231's alarm functionality doesn't really have this option and any code-based solution will have the aforementioned power-loss problems.
Is there an RTC module which can do what I need it to do?
User #RamblinRose pointed me in the direction of EEPROM writing and reading which I wasn't aware was possible. This solved my issue. Here is the full code for anyone else coming here and wanting a more comprehensive answer:
#include <DS3231.h>
#include <EEPROM.h>
// Init the DS3231 using the hardware interface
DS3231 rtc(SDA, SCL);
Time t;
bool active = false;
void setup()
{
// Setup Serial connection
Serial.begin(115200);
// Initialize the rtc object
rtc.begin();
pinMode(12, OUTPUT);
pinMode(11, INPUT_PULLUP);
// The following lines can be uncommented to set the date and time
// rtc.setDOW(MONDAY); // Set Day-of-Week to SUNDAY
// rtc.setTime(15, 51, 0); // Set the time to 12:00:00 (24hr format)
rtc.setDate(14, 9, 2017); // Set the date to January 1st, 2014
}
int blinker(int state = 1) {
if(state == 1) {
if (active == true) {
digitalWrite(12, HIGH); // turn the LED on (HIGH is the voltage level)
delay(500); // wait for a second
digitalWrite(12, LOW); // turn the LED off by making the voltage LOW
delay(500);
buttonCheck();
}
}
}
int buttonCheck() {
if(digitalRead(11) == 0) {
active = false;
blinker(0);
}
}
void loop()
{
t = rtc.getTime();
int hour = t.hour;
int min = t.min;
int sec = t.sec;
// // Send time to serial monitor (for debugging)
// Serial.print(hour);
// Serial.print(":");
// Serial.print(min);
// Serial.println(" ");
// Put there different timers in here for demo purposes
// Set activation time
if(hour == 13 && min == 31 && sec == 00) {
if(EEPROM.read(0) == 0) {
active = true;
EEPROM.write(0, 1);
Serial.println("Not run recently, activating");
} else {
active = false;
EEPROM.write(0, 0);
Serial.println("Run recently, skipping this one");
}
}
if(hour == 13 && min == 35 && sec == 00) {
if(EEPROM.read(0) == 0) {
active = true;
EEPROM.write(0, 1);
Serial.println("Not run recently, activating");
} else {
active = false;
EEPROM.write(0, 0);
Serial.println("Run recently, skipping this one");
}
}
if(hour == 13 && min == 45 && sec == 00) {
if(EEPROM.read(0) == 0) {
active = true;
EEPROM.write(0, 1);
Serial.println("Not run recently, activating");
} else {
active = false;
EEPROM.write(0, 0);
Serial.println("Run recently, skipping this one");
}
}
blinker();
delay(1000);
}

Arduino servo and IR remote

I am trying to get a continuous (180 to 0 and back 0 to 180) movement from a servo when I press a button in remote and ONLY stop when I press the other button. So far, I have gotten it to move continuously, but then it doesn't stop when I press the 'stop' button. I know it is because of the while loop. However, I have tried switch-case, if statement, nothing has worked so far.
Please help, any advice for it make it work is appreciated.
#include <Servo.h>
#define code1 2534850111 //decimal value of button 1
#define code3 16724175 //decimal value of button 1
#define code 4294967295 //random value
#define code2 16738455 //decimal value of button 0
#define code4 3238126971 //decimal value of button 0
Servo myservo; // servo object
int RECV_PIN = 11; //receiveing pin IR remote
int pos = 0;
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup() {
Serial.begin(9600);
irrecv.enableIRIn(); //start the receiver
myservo.attach(9); //servo connect to pin 9
pinMode(2, OUTPUT); //LED connect to pin 2
}
void loop() {
if(irrecv.decode(&results)){
// if(results.value == code1 || results.value == code3){
while(results.value == code1 || results.value == code3){
digitalWrite(2,HIGH); //turn the led on
for(pos = 0; pos <= 180; pos += 1){ //servo goes form 0 to 180 degrees in steps of 1 degree
myservo.write(pos);
delay(7);
}
for(pos = 180; pos >= 0; pos -= 1){ //servo goes back from 180 to 0 degrees with 1 degree step
myservo.write(pos);
delay(7);
}
}
while(results.value == code2 || results.value == code4){
digitalWrite(2, LOW); // turn the led off
myservo.write(pos);
delay(15);
break;
}
Serial.println(results.value, DEC); //show the decimal value of the pressed button
irrecv.resume(); //receive the next value
}
}
One way to solve your problem would be to check for the presence of a "button push" deeper inside loop(). Put your checks for the button presses inside your movement for loop to catch the changes right away. Looks like you might have two startcodes (?) so you might have to alter the if statements below, but hopefully I demonstrate how to check the condition to "keep going" in the code sample below.
void loop()
{
if(irrecv.decode(&results))
{
// turn one way
for(pos = 0; pos <= 180; pos += 1)
{
// only continue if the start code(s) still active
if(results.value == STARTCODE || results.value == OTHERSTARTCODE)
{
myservo.write(pos);
delay(7);
irrecv.resume(); //receive the next value
}
}
// turn the other way
for(pos = 180; pos >= 0; pos -= 1)
{
// only continue if the start code(s) still active
if(results.value == STARTCODE || results.value == OTHERSTARTCODE)
{
myservo.write(pos);
delay(7);
irrecv.resume(); //receive the next value
}
}
}
}

I am using a button as a switch, it turns on but doesn't turn off (Arduino)

I am trying to make a button work as a switch. The code works to turn the lights "on" but the code doesn't want to turn them off.
My code works like so:
If button is pressed and the lights are off, turn on the lights.
If button is pressed and the lights are on, turn off the lights.
But number 2 doesn't work.
int buttonStatus = 0;
int check = 1;
int Status = 0;
void setup() {
pinMode(5,OUTPUT);
pinMode(7,OUTPUT);
pinMode(9,OUTPUT);
pinMode(11,OUTPUT);
pinMode(13,OUTPUT);
pinMode(2,INPUT);
}
void loop() {
if (check = 1) {
buttonStatus = digitalRead(2);
if (buttonStatus == HIGH && Status == 0) {
Status = 1;
buttonStatus = 0;
} else if (buttonStatus == HIGH && Status == 1) {
Status = 0;
buttonStatus = 0;
}
}
if (Status == 1) {
digitalWrite(5,HIGH);
delay(50);
digitalWrite(5,LOW);
digitalWrite(7,HIGH);
delay(50);
digitalWrite(7,LOW);
digitalWrite(9,HIGH);
delay(50);
digitalWrite(9,LOW);
digitalWrite(11,HIGH);
delay(100);
digitalWrite(11,LOW);
digitalWrite(13,HIGH);
delay(100);
digitalWrite(13,LOW);
} else {
digitalWrite(5,LOW);
digitalWrite(7,LOW);
digitalWrite(9,LOW);
digitalWrite(11,LOW);
digitalWrite(13,LOW);
}
}
Ok, your description and your code tell two different things. I'm try to interprete them, but if I'm wrong just tell me and I'll try to correct the answer.
This code lets you use a pushbutton to turn on and off a light on pin 5. One press will turn it on, the other will turn it off. You have to connect the button with one end to pin 2 and the other to ground (since we are using a pull-up resistor).
I also added a small debounce delay to cope with the bounces of the mechanical switch (50ms)
byte buttonStatus;
unsigned long lastEqualButtonTime;
#define debounceTimeMs 50
void setup() {
pinMode(5,OUTPUT);
pinMode(2,INPUT_PULLUP);
buttonStatus = digitalRead(2);
lastEqualButtonTime = millis();
}
void loop() {
byte currentButtonStatus = digitalRead(2);
if (currentButtonStatus == buttonStatus)
lastEqualButtonTime = millis();
else if ((millis() - lastEqualButtonTime) > debounceTimeMs)
{
lastEqualButtonTime = millis();
buttonStatus = currentButtonStatus;
// Change only on change, not on value
if (buttonStatus == LOW) {
digitalWrite(5, !digitalRead(5));
}
}
}
When you press the button the led on pin 5 will turn on, when you press it again it will turn off.
This is the behavior you asked. Your code, on the other side, lights up a sequence of LEDs when you push the button. In this case, if you want to start the cycle with a press and then stop it with another press, you have to use a sort of simple state machine, like the one in the code. I also added a small debounce to the button, which needs again to be connected between 2 and ground.
byte buttonStatus;
unsigned long lastEqualButtonTime;
#define debounceTimeMs 50
// Statuses
#define STATE_LEDSOFF 0
#define STATE_LED5ON 1
#define STATE_LED7ON 2
#define STATE_LED9ON 3
#define STATE_LED11ON 4
#define STATE_LED13ON 5
// How much time should each led be on?
// Expressed in milliseconds
#define TIME_LED5ON 50
#define TIME_LED7ON 50
#define TIME_LED9ON 50
#define TIME_LED11ON 100
#define TIME_LED13ON 100
byte stateMachineStatus;
unsigned long stateMachineTime;
void setup() {
pinMode(5,OUTPUT);
pinMode(7,OUTPUT);
pinMode(9,OUTPUT);
pinMode(11,OUTPUT);
pinMode(13,OUTPUT);
pinMode(2,INPUT_PULLUP);
buttonStatus = digitalRead(2);
lastEqualButtonTime = millis();
stateMachineStatus = STATE_LEDSOFF;
}
void loop() {
byte currentButtonStatus = digitalRead(2);
if (currentButtonStatus == buttonStatus)
lastEqualButtonTime = millis();
else if ((millis() - lastEqualButtonTime) > debounceTimeMs)
{
lastEqualButtonTime = millis();
buttonStatus = currentButtonStatus;
// Change only on change, not on value
if (buttonStatus == LOW) {
// Turn on the LEDs sequence if it was off
if (stateMachineStatus == STATE_LEDSOFF)
{
stateMachineStatus = STATE_LED5ON;
stateMachineTime = millis();
}
else // Turn it off if it was on
stateMachineStatus = STATE_LEDSOFF;
}
}
switch (stateMachineStatus)
{
case STATE_LEDSOFF:
digitalWrite(5,LOW);
break;
case STATE_LED5ON:
digitalWrite(5,HIGH);
if ((millis() > stateMachineTime) > TIME_LED5ON)
{
stateMachineTime += TIME_LED5ON;
digitalWrite(5,LOW);
stateMachineStatus = STATE_LED7ON;
}
break;
case STATE_LED7ON:
digitalWrite(7,HIGH);
if ((millis() > stateMachineTime) > TIME_LED7ON)
{
stateMachineTime += TIME_LED7ON;
digitalWrite(7,LOW);
stateMachineStatus = STATE_LED9ON;
}
break;
case STATE_LED9ON:
digitalWrite(9,HIGH);
if ((millis() > stateMachineTime) > TIME_LED9ON)
{
stateMachineTime += TIME_LED9ON;
digitalWrite(9,LOW);
stateMachineStatus = STATE_LED11ON;
}
break;
case STATE_LED11ON:
digitalWrite(11,HIGH);
if ((millis() > stateMachineTime) > TIME_LED11ON)
{
stateMachineTime += TIME_LED11ON;
digitalWrite(11,LOW);
stateMachineStatus = STATE_LED13ON;
}
break;
case STATE_LED13ON:
digitalWrite(13,HIGH);
if ((millis() > stateMachineTime) > TIME_LED13ON)
{
stateMachineTime += TIME_LED13ON;
digitalWrite(13,LOW);
stateMachineStatus = STATE_LED5ON;
}
break;
default:
stateMachineStatus = STATE_LEDSOFF;
break;
}
}
This works in this way: you press the button and the board will start cycling through the LEDS. 5, 7, 9, 11, 13, 5, 7, 9, 11, 13, ... Until you press again the button. When you do this, it stops, then at the next press restarts from 5.
If you want that after the 13 it stops, change the line 105 from stateMachineStatus = STATE_LED5ON; to stateMachineStatus = STATE_LEDSOFF;.
One note: in your code the delay is too low (and it is the same that I put here): 50 ms between one led and the other cannot be noticed. If you want to actually see them in sequence, put values of at least 250 in the TIME_LEDxON defines.
DISCLAIMER: I haven't tested these codes since I don't have arduino ide installed at present. If there are some bugs, simply tell me and I'll fix them.
Try adding debounce delay. This is common issue with switches.
https://www.arduino.cc/en/Tutorial/Debounce
Maybe it's because of a floating pin. Have you built in a pull up or pull down resistor?
It's a common thing...

turning 3 leds on/off using serial port

I am trying to write a program that will do the following :
Write code so that if 1 then enter pressed or send clicked, and then 1 again and enter pressed or send clicked causes LED one to turn on, if ‘1’ ‘0’ is entered in a similar way then LED 1 turns off, and so on for LEDs two and three, ie: ‘2’ ‘1’ turns on LED 2, ‘3’ ’0’ turns off LED 3.
So far here is my code:
int incomingVal;
int ledPin = 16;
int ledPin2 = 15;
int ledPin3 = 14;
void setup()
{
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
Serial.println("starting");
pinMode(ledPin,OUTPUT);
pinMode(ledPin2,OUTPUT);
pinMode(ledPin3,OUTPUT);
}
void checkForRecvdChar ();
void loop()
{
if (Serial.available() > 0 ) //then chars are in the serial buffer
{
incomingVal = Serial.parseInt();
Serial.print("You entered: ");
Serial.println(incomingVal);
if (incomingVal == 10);//turns off led 1
{
digitalWrite(ledPin, LOW);
}
if (incomingVal == 11);//turns on led 1
{
digitalWrite(ledPin, HIGH);
}
if (incomingVal == 20);//turns off led 2
{
digitalWrite(ledPin2, LOW);
}
if (incomingVal == 21);//turns on led 2
{
digitalWrite(ledPin2, HIGH);
}
if (incomingVal == 30);//turns off led 3
{
digitalWrite(ledPin3, LOW);
}
if (incomingVal == 31);//turns on led 3
{
digitalWrite(ledPin3, HIGH);
}
}
}
Right now it turns all LEDs on no matter what combination I enter
you've got semi colons after your if statements, which terminates the if statement. So all your intended if blocks get executed.
for example...
if (incomingVal == 31);//turns on led 3
{
digitalWrite(ledPin3, HIGH);
}
needs to be
if (incomingVal == 31)
{
digitalWrite(ledPin3, HIGH);
}
Ok So First It Will Better To Use Switch Case in this Case:
1. You Can Just Use The Same Number To Turn The Led ON and OFF
Example:
case 1:
{
if(wFlag == false)
{
digitalWrite(LED, HIGH);
wFlag = true;
Serial.println("LED is ON");
}
else if (wFlag == true)
{
digitalWrite(LED, LOW);
wFlag = false;
Serial.println("LED is OFF");
}
break;
}
2. The Way You Do It, Your Problem Is Serial Read Gets Only Byte after Byte
So When You Press 1 or 11 It Sees 1 Because It is The First one "1" and Then Do Your If
Statment.
You Can Fix it Like This:
while (Serial.available())
{
IncomingData = Serial.parseInt();
Temp += String(IncomingData); //Temp String Var
}
DataIN = Temp.toInt(); //DataIN int Var
Temp =""; // Rest The Temp String
Switch(DataIN) // Or if(DataIN == 1)
{
}

Arduino Micro triggering with no contact

I'm using an Arduino Micro to trigger specific events on a front end I have. For some reason, however, some of the key combos are just triggering randomly. I am not even touching the arduino when this happens.
I have it set up so when you press a button, it only triggers the key stroke once, rather than repeating it while the button is pressed.
Am I missing something, or screw something up?
int escButton = 12, valEsc, valEsc2, stateEsc;
int volUp = 11, valVup, valVup2, stateVup;
int volDown = 10, valVdown, valVdown2, stateVdown;
int rebootButton = 9, valReboot, valReboot2, stateReboot;
char ctrlKey = KEY_LEFT_GUI;
char shiftKey = KEY_LEFT_SHIFT;
void pressKeyCombos(int combo){
switch(combo) {
case 1:
Keyboard.press(KEY_ESC);
delay(100);
Keyboard.releaseAll();
break;
case 2:
Keyboard.press(shiftKey);
Keyboard.press(KEY_F1);
delay(100);
Keyboard.releaseAll();
break;
case 3:
Keyboard.press(shiftKey);
Keyboard.press(KEY_F3);
delay(100);
Keyboard.releaseAll();
break;
case 4:
Keyboard.press(shiftKey);
Keyboard.press(KEY_F2);
delay(100);
Keyboard.releaseAll();
break;
}
}
void setup() {
pinMode(escButton, INPUT);
stateEsc = digitalRead(escButton);
Keyboard.begin();
}
void loop(){
valEsc = digitalRead(escButton);
delay(10);
valEsc2 = digitalRead(escButton);
valVup = digitalRead(volUp);
delay(10);
valVup2 = digitalRead(volUp);
valVdown = digitalRead(volDown);
delay(10);
valVdown2 = digitalRead(volDown);
valReboot = digitalRead(rebootButton);
delay(10);
valReboot2 = digitalRead(rebootButton);
if (valVup == valVup2) {
if (valVup != stateVup) {
if (valVup == LOW) {
pressKeyCombos(4);
}
}
stateVup = valVup;
}
if (valVdown == valVdown2) {
if (valVdown != stateVdown) {
if (valVdown == LOW) {
pressKeyCombos(3);
}
}
stateVdown = valVdown;
}
if (valReboot == valReboot2) {
if (valReboot != stateReboot) {
if (valReboot == LOW) {
pressKeyCombos(2);
}
}
stateReboot = valReboot;
}
if (valEsc == valEsc2) {
if (valEsc != stateEsc) {
if (valEsc == LOW) {
pressKeyCombos(1);
}
}
stateEsc = valEsc;
}
}
The inputs are high impedance by default. From your description of the beahvior, I can guess that you have not added external pull up/down resistor and that the pins are connected to a normally open switch. The random input would be just as expected and noted in docs for digitialRead():
Note
If the pin isn't connected to anything, digitalRead() can return
either HIGH or LOW (and this can change randomly).
see reference page for digitialRead()
The micro does have the ability to provide an internal pull up.
Your code does not show you have enabled the internal pull up resistors. This is accomplished in a manner that may seem odd, by writing to the input pin. From the Arduino docs:
There are also convenient 20K pullup resistors built into the Atmega
chip that can be accessed from software. These built-in pullup
resistors are accessed in the following manner.
pinMode(pin, INPUT); // set pin to input
digitalWrite(pin, HIGH); // turn on pullup resistors
see Digital Pins
So in your case, add four digitalWrite()'s in the setup() to enable the pull ups and you look good to go.

Resources