functionality:
User presses the red dome button (is not a 2 state button), hence it has to toggle upon the first press "0"->"1" & when pressed again "1"->"0".
Therefore, when pressed, the serial monitor will print "1"s from "0"s at every 100ms. The behaviour signals that the buttonState is toggled from LOW to HIGH
Furthermore, an LED stripe is also connected to arduino. Therefore, when the buttonstate displays a HIGH in the serial monitor, the LED state will toggle to HIGH after a delay of 10s and will remain in HIGH state for 10s before toggling to a LOW state.
Lastly, the buttonState should toggle from HIGH to LOW after a delay(25s), without user physically pressing the button.
Issue:
At this point, user has to press the red dome button to toggle between LOW & HIGH state. Hence, when the button initial state is LOW, it shows "0"s in the serial monitor and when pressed, button will toggle to HIGH, shows "1"s in the serial monitor and when button is pressed again, it will toggle from HIGH to LOW, showing "0"s in the serial monitor.
Hence, I would like to ask for assistance on how to allow the buttonstate to toggle from HIGH to LOW without user pressing the button.
therefore,
correctBehaviour:
initial state: "0"s are shown in serial monitor and when user presses button buttonstate shows "1"s in serial monitor and after a count of 25s, the buttonstate will toggle to LOW without user pressing the button again.
Code:
const int buttonPin = 2; //the number of the pushbutton pin
const int Relay = 4; //the number of the LED relay pin
uint8_t stateLED = LOW;
uint8_t btnCnt = 1;
int buttonState = 0; //variable for reading the pushbutton status
int buttonLastState = 0;
int outputState = 0;
void setup() {
Serial.begin(9600);
pinMode(buttonPin, INPUT);
pinMode(Relay, OUTPUT);
digitalWrite(Relay, LOW);
}
void loop() {
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);
// Check if there is a change from LOW to HIGH
if (buttonLastState == LOW && buttonState == HIGH)
{
outputState = !outputState; // Change outputState
}
buttonLastState = buttonState; //Set the button's last state
// Print the output
if (outputState)
{
switch (btnCnt++) {
case 100:
stateLED = LOW;
digitalWrite(Relay, HIGH); // after 10s turn on
break;
case 200:
digitalWrite(Relay, LOW); // after 20s turn off
break;
case 202: // small loop at the end, to do not repeat the LED cycle
btnCnt--;
break;
}
Serial.println("1");
}else{
Serial.println("0");
if (btnCnt > 0) {
// disable all:
stateLED = LOW;
digitalWrite(Relay, LOW);
}
btnCnt = 0;
}
delay(100);
}
I guess your code is nearly correct.
In case 200: I'd toggle outputstate as well, to return to the default state.
BTW:
btncnt is a misleading name as you count your 100 ms intervals, not button presses or similar.
IMO, delay(100); is an acceptable compromise: still reacting on button presses, but without doing it properly using if (millis() - lastpressed > 20000) { ...
Related
I'm having some issues getting my code to do what I want on my Arduino Mega. What I'm aiming to do is to have the same RFID tag change an LED colour from red to green and when presented again from green to red. I also want to do this with a button. This is for a door lock so that the door can been locked and unlocked from both sides of the door.
The code below will allow an RFID tag to change the colour from red to green and vice versa but as soon as I try to test for an authenticated card it fails miserably. Also when I try to add the button to it my code ends up getting very messy and unusable. I've tried various things but I think my major problem is because the code sites inside the loop function. I've tried while(1) when trying to set the LED to a particular colour but it just doesn't work properly.
This I thought would be fairly trivial to do, maybe it is, I'm just not familiar enough with this.
Can anyone help point me in the right direction which will help me move further forward with this?
#include <SPI.h>
#include <MFRC522.h>
// constants won't change. They're used here to set pin numbers:
const int BUTTON_PIN = 2; // the number of the pushbutton pin
#define BLUE 7
#define GREEN 6
#define RED 3
#define RST_PIN 9 // Configurable, see typical pin layout above
#define SS_PIN 53 // Configurable, see typical pin layout above
// Variables will change:
String authKeyFob = "54321098765";
String card_ID="";
//int lastState = HIGH; // the previous state from the input pin
//int currentState = LOW; // the current reading from the input pin
int buttonState = 0; // current state of the button
int lastButtonState = 0; // previous state of the button
int ledState = 0; // remember current led state
int rfidState = 0;
int lastRfidState = 0;
bool toggle = false;
bool cardValid = false;
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
SPI.begin(); // Init SPI bus
mfrc522.PCD_Init(); // Init MFRC522 card
// initialize the pushbutton pin as an pull-up input
// the pull-up input pin will be HIGH when the switch is open and LOW when the switch is closed.
pinMode(BUTTON_PIN, INPUT);
pinMode(GREEN, OUTPUT);
pinMode(RED, OUTPUT);
pinMode(BLUE, OUTPUT);
}
void loop() {
// read the state of the switch/button:
buttonState = digitalRead(BUTTON_PIN);
// Look for new cards, and select one if present
if (mfrc522.PICC_IsNewCardPresent() || mfrc522.PICC_ReadCardSerial() ) {
if(toggle == false){
toggle = true;
} else {
toggle = false;
}
delay(200);
}
if(toggle == 1){
digitalWrite(GREEN, HIGH);
digitalWrite(RED, LOW);
} else if (toggle == 0) {
digitalWrite(GREEN, LOW);
digitalWrite(RED, HIGH);
}
}
All you need to do is to have another if statement that reads your button and toggles your toggle variable just like you do for the card. See if you understand what's going on here:
void loop() {
// read the state of the switch/button:
oldButtonState = LOW; // NEED TO ADD A DECLARATION FOR THIS BEFORE SETUP
buttonState = digitalRead(BUTTON_PIN);
// Look for new cards, and select one if present
if (mfrc522.PICC_IsNewCardPresent() || mfrc522.PICC_ReadCardSerial() ) {
toggle = !toggle; // A way easier way to write the if statements you had.
}
// if the button just became pressed...
if(buttonState == HIGH && oldButtonState==LOW){
toggle = !toggle; // same thing, toggle our variable.
}
oldButtonState = buttonState; // save the button state for next time
if (toggle) {
digitalWrite(GREEN, HIGH);
digitalWrite(RED, LOW);
} else {
digitalWrite(GREEN, LOW);
digitalWrite(RED, HIGH);
}
}
See the State Change Example to see why I store the old state of the button. I also changed that set of if statements to just set toggle to not toggle, that's an easier way to reverse a boolean value. I also made that last else if just an else since a boolean can only have two values. If it isn't true then it must be false.
This is my updated version with the RFID tag working consistently with the button and LED.
void loop() {
// read the state of the switch/button:
oldButtonState = LOW; // NEED TO ADD A DECLARATION FOR THIS BEFORE SETUP
buttonState = digitalRead(BUTTON_PIN);
// Look for new cards, and select one if present
if (!mfrc522.PICC_IsNewCardPresent() ) {
}
if(mfrc522.PICC_ReadCardSerial() ){
toggle = !toggle;
delay(200);
}
// if the button just became pressed...
if(buttonState == HIGH && oldButtonState==LOW){
toggle = !toggle; // same thing, toggle our variable.
delay(200);
}
oldButtonState = buttonState; // save the button state for next time
if (toggle) {
digitalWrite(GREEN, HIGH);
digitalWrite(RED, LOW);
} else {
digitalWrite(GREEN, LOW);
digitalWrite(RED, HIGH);
}
}
Functionality:
When user presses the big dome push button, the state of Arduino should turn from '0'/LOW to '1'/HIGH at the serial monitor of the Arduino.
Issue:
When I trigger on the big dome push button, the state did not trigger from LOW to HIGH, it still remained LOW.
I have connected the "Push To Make" side of the connection to digital pin 2, following the connection write-up from: BIG DOME PUSH BUTTON.
However at this point, the trigger state is not working, please assist.
const int buttonPin = 2; //the number for the pushbutton pin (DIGITALPIN)
uint8_t btnCnt = 1;
bool outputState = false;
void setup() {
Serial.begin(9600);
//for Push button pin
pinMode(buttonPin, INPUT);
}
void loop() {
outputState |= digitalRead(buttonPin); // if pushButton is high, set outputState (low does nothing)
// Print the output
if (outputState) {
switch (btnCnt++) {
case 100:
--btnCnt;
outputState = false;
break;
}
Serial.println("1");
} else {
Serial.println("0");
btnCnt = 0;
}
delay(100);
}
The statement outputState |= digitalRead(buttonPin); is using an OR assign so once outputState is set to 1 (HIGH), it will never go back to 0 (LOW) again. This is because performing an OR with anything and a 1 will always result in 1.
If you change this line to just an assignment as follows, you should see the state change you are expecting. outputState = digitalRead(buttonPin);
Functionality:
Before the red dome button is pressed (not a 2 state button), the serial monitor will print a list "0"s and when the red dome button is pressed, the button state will toggle from LOW to HIGH, hence at the serial monitor will print a list of "1"s.
However, when the button is in the state of HIGH, serial monitor print "1"s and user will not be able to toggle the button state from HIGH to LOW. Hence, the button can only toggle from HIGH to LOW automatically after a period, delay(25s).
Therefore, correct behaviour:
Initial state print => 00000000000000(when user presses the red dome button => buttonstate change LOW to HIGH)111111111111111111(when user presses the button, nothing happens)111111111111111111(after 25s delay, buttonState will toggle HIGH to LOW)0000000000000
ISSUE:
At this point in time, users are able to toggle between LOW to HIGH and HIGH to LOW. Meaning, the flow => 00..000(user press button, Toggle LOW to HIGH)111...111(user press button, toggle HIGH to LOW)0000...
And I am not really sure on how to enable the button to only toggle from LOW to HIGH but disable the button to toggle from HIGH to LOW.
Meaning when user push the button, it can change the button state from "0" to "1" but not able to change the button state when it is in "1".
Hence, I would like to request for some help that will allow the following correct behaviour.
Thanks
Code:
const int buttonPin = 2; //the number of the pushbutton pin
const int Relay = 4; //the number of the LED relay pin
uint8_t stateLED = LOW;
uint8_t btnCnt = 1;
int buttonState = 0; //variable for reading the pushbutton status
int buttonLastState = 0;
int outputState = 0;
void setup() {
Serial.begin(9600);
pinMode(buttonPin, INPUT);
pinMode(Relay, OUTPUT);
digitalWrite(Relay, LOW);
}
void loop() {
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);
// Check if there is a change from LOW to HIGH
if (buttonLastState == LOW && buttonState == HIGH)
{
outputState = !outputState; // Change outputState
}
buttonLastState = buttonState; //Set the button's last state
// Print the output
if (outputState)
{
switch (btnCnt++) {
case 100:
stateLED = LOW;
digitalWrite(Relay, HIGH); // after 10s turn on
break;
case 250:
digitalWrite(Relay, LOW); // after 20s turn off
//Toggle ButtonState to LOW from HIGH without user pressing the button
digitalWrite(buttonPin, LOW);
break;
case 252: // small loop at the end, to do not repeat the LED cycle
btnCnt--;
break;
}
Serial.println("1");
}else{
Serial.println("0");
if (btnCnt > 0) {
// disable all:
stateLED = LOW;
digitalWrite(Relay, LOW);
}
btnCnt = 0;
}
delay(100);
}
You need set outputState and let it set until it will be reset after 25 seconds. If button is still pressed then it will loop on 251.
const int buttonPin = 2; //the number of the pushbutton pin
const int Relay = 4; //the number of the LED relay pin
uint8_t stateLED = LOW;
uint8_t btnCnt = 1;
bool outputState = false;
void setup() {
Serial.begin(9600);
pinMode(buttonPin, INPUT);
pinMode(Relay, OUTPUT);
digitalWrite(Relay, LOW);
}
void loop() {
outputState |= digitalRead(buttonPin); // if pushButton is high, set outputState (low does nothing)
// Print the output
if (outputState)
{
switch (btnCnt++) {
case 100:
stateLED = LOW;
digitalWrite(Relay, HIGH); // after 10s turn on
break;
case 250:
digitalWrite(Relay, LOW); // after 20s turn off
//Toggle ButtonState to LOW from HIGH without user pressing the button
outputState = false; // reset state to low
break;
case 251: // loop (it might happen, if previous step sets outputState=false but button is still pressed -> no action)
--btnCnt;
outputState = false;
break;
}
Serial.println("1");
}else{
Serial.println("0");
if (btnCnt > 0) {
// disable all:
stateLED = LOW;
digitalWrite(Relay, LOW);
}
btnCnt = 0;
}
delay(100);
}
functionality:
Serial monitor is printing "0" at every 100ms, signalling that the buttonState is LOW.
However when user depresses the red dome button Red Dome Button, it is suppose to signal that the buttonState is HIGH and at the serial monitor, it should be printing "1" at every 100ms until the user presses the red dome button again to signal that the buttonState is LOW and serial monitor is printing "0".
Issue:
The serial monitor is outputting "0" at every 100ms initially, and when i press the red dome button, the buttonState returns a HIGH and at the serial monitor is outputting "1". However, the serial "1" doesn't hold and it reverts back to "0" immediately.
The serial "1" will only show in serial monitor when I press on the button continuously.
Meaning:
Correct behaviour:
initial state-> the serial monitor will output all serial 0 until user presses the button then the serial monitor will output all serial 1 until user presses the button again then the output will then change to serial 0
Current behaviour:
initial state-> the serial monitor will output all serial 0 until user presses the button then the serial monitor will output serial 1 but immediately, the serial will return to 0
Hence, how do I enable the serial state to remain at serial 1 after I press the button and the serial will show 0 only when I press the button again? I need some help in that . Thank you
Code:
const int buttonPin = 2; // the number of the pushbutton pin
// variables will change:
int buttonState = 0; // variable for reading the pushbutton status
void setup() {
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
Serial.begin(9600); // Open serial port to communicate
}
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) {
Serial.println("1");
}
else {
Serial.println("0");
}
delay(100);
}
It seems that your button gets unpressed after you release it (not like a 2 states button). So you need to create your own state variable that toggles when the button is pressed.
Let's say that you want to change the state when a HIGH is detected from the button. It means that you have to detect the change from LOW to HIGH and not only if it is in HIGH mode. So to do this you need to store the last state of the button. In addition you'll need to keep an output state that toggles when a change from LOW to HIGH is detected.
In your code should be something like this:
const int buttonPin = 2; // the number of the pushbutton pin
// variables will change:
int buttonState = 0; // variable for reading the pushbutton status
int buttonLastState = 0;
int outputState = 0;
void setup() {
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
Serial.begin(9600); // Open serial port to communicate
}
void loop() {
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);
// Check if there is a change from LOW to HIGH
if (buttonLastState == LOW && buttonState == HIGH)
{
outputState = !outputState; // Change outputState
}
buttonLastState = buttonState; //Set the button's last state
// Print the output
if (outputState)
{
Serial.println("1");
}
else
{
Serial.println("0");
}
delay(100);
}
I currently have an arduino LCD and one SPDT switch connected to my board. The the common pin of the SPDT is grounded and the outer pins are each connected to a digital input. My program should increment and decrement the counter being printed to the LCD screen. I have one input working that increments the counter I do not know how to implement code for the input to decrement the counter. Code posted below.
Thank you
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5,4,3,2);
const byte buttonPin = 8;
int counter = 0; // set your counter to zero to begin with
byte buttonState; // the current reading from the input pin
byte lastButtonState = HIGH; // the previous reading from the input pin
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;
void setup()
{
Serial.begin(9600);
pinMode(buttonPin, INPUT_PULLUP);
lcd.begin(16, 2); // for 2x16 lcd display
}
void loop() {
// read the state of the switch into a local variable:
byte reading = digitalRead(buttonPin);
// check to see if you just pressed the button
// (i.e. the input went from HIGH to LOW), 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;
if (buttonState == LOW) {
counter ++;
Serial.println(counter);
lcd.setCursor(0, 1);
lcd.print(counter);
}
}
}
lastButtonState = reading;
}
You cannot simply connect one pole of a switch to an input pin an other to the ground. This will detect LOW but when when you are suppose to detect HIGH on the pin, it will be floating. Connect a pull-up resistor to your input pins.
Or you can use pinMode(InPin, INPUT_PULLUP);
This will pull your input pin to high internally and then you can detect the swithces and implememnt the code.