Start/Stop a function using pushbutton - button

I am trying to display the readings of LDR on my 0.96" Adafruit OLED. I have succeeded with obtaining that results.
Now I want to start the display of the reading only when I push the button and stop it once I push it again. This should go on a loop.
I tried to draft a code for that:
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
int sensorPin = A0; // select the input pin for ldr
int sensorValue = 0;
boolean state = false;
int buttonpin;
#define OLED_RESET 4 // not used / nicht genutzt bei diesem Display
Adafruit_SSD1306 display(OLED_RESET);
char inChar;
String string;
void setup() {
pinMode(13, OUTPUT);
buttonpin = 2; //whatever pin your button is plugged into
pinMode(buttonpin, INPUT_PULLUP);
// initialize with the I2C addr 0x3C / mit I2C-Adresse 0x3c initialisieren
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
Serial.begin(9600);
display.display();
delay(2000);
display.clearDisplay();
display.setTextColor(INVERSE);
}
void loop()
{
while (state == false)
{
if (digitalRead(buttonpin) == HIGH)
{
display.clearDisplay();
sensorValue = analogRead(sensorPin);
Serial.println(sensorValue);
display.setCursor(30,0);
display.setTextSize(1);
display.print("LDR Reading:");
display.setCursor(30,10);
display.setTextSize(2);
display.print(sensorValue);
delay(500);
display.display();
state = false;
}
}
}
But the screen starts displaying the results only when I keep the push button pressed continuously and when I release the button , the program halts with the last reading displayed on the screen.
I need the results as follows:
1st press: starts displaying readings
2nd press: screen should be blank. (display.clearDisplay() does that job)
I am unfamiliar with the usage of switch case in Arduino.

Thie is to elaborate on #shaunussain's answer.
Here is an exampole of a toggle:
Create a boolean variable : bool toggle = false; The variable state is at false at the beginning. Thus, the screen will start blank.
Then do something like this. This is just a logic.
If the button is pressed
if( buttonPressed() ) {
Change toggle's state. So if it was ON / true, it will change to OFF / false.
toggle = !toggle;
Now, we wait until the button has been released, otherwise the code might go a little crazy! And then we close the brackets.
while ( buttonPressed() );
}
Then in your loop, you will have a switch case. We start by innitializing the switch case.
switch( toggle ) {
Then we set up a case for when the toggle is on ON / true. 1 is true, 0 is false.
case 1 :
Then we write the code body.
displayTextOnScreen();
Then we exit the switch case because toggle matched with our case.
break;
Then, if we toggle isn't true or it is something else (because there was a glitch in the code), we will have a default case.
default:
In the default, we want the screen to be off, so if it isn't suppose to be on, or if there is a bug, it will be off. Then we will close the switch case and exit it because default is the last possible case in a switch case.
display.clearDisplay();
}

Thank you so much, it helped me a lot. The code is working fine. Updated code :
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
int sensorPin = A0; // select the input pin for ldr
int sensorValue = 0;
bool toggle = false;
int buttonpin;
#define OLED_RESET 4 // not used / nicht genutzt bei diesem Display
Adafruit_SSD1306 display(OLED_RESET);
char inChar;
String string;
void setup() {
pinMode(13, OUTPUT);
buttonpin = 2;
pinMode(buttonpin, INPUT_PULLUP);
// initialize with the I2C addr 0x3C / mit I2C-Adresse 0x3c initialisieren
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
Serial.begin(9600);
display.display();
delay(2000);
display.clearDisplay();
display.setTextColor(INVERSE);
}
void loop()
{
if (digitalRead(buttonpin) == HIGH)
{
toggle = !toggle;
while(digitalRead(buttonpin) == HIGH);
}
switch( toggle )
{
case 1:
display.clearDisplay();
sensorValue = analogRead(sensorPin);
Serial.println(sensorValue);
display.setCursor(30,0);
display.setTextSize(1);
display.print("LDR Reading:");
display.setCursor(30,10);
display.setTextSize(2);
display.print(sensorValue);
delay(500);
break;
case 0:
display.clearDisplay();
break;
}
display.display();
}

Keep a Boolean to track the toggle state and a Boolean to keep the state of the button from the previous loop. If the button goes from low to high between loop iterations then update the toggle Boolean,
toggle = !togggle
Base your condition for the display state then on the toggle instead of directly on the button.

Related

Arduino: Why doesn't my stepper move in reverse direction?

I have verified that its not a wiring problem by using some non library example code, so it seems the problem is not with the circuit.
I'm expecting the following code to run the motor in one direction 200 steps then run 200 steps in the opposite direction. It seems to run the initial 200 steps but then stops, why?
In the setup function:
stepper.setCurrentPosition(0);
// Set the maximum speed in steps per second:
stepper.setMaxSpeed(1000);
In the loop function:
while(stepper.currentPosition() < 300){
stepper.moveTo(200);
stepper.setSpeed(200);
stepper.run();
if (stepper.distanceToGo() == 0) {
stepper.moveTo(-stepper.currentPosition());
stepper.setSpeed(200);
stepper.run();
}
}
Here's my entire code. The if/else at the bottom is where I want to run the motor. I've put in some non working example code in this block as an example:
#include <deprecated.h>
#include <MFRC522.h>
#include <MFRC522Extended.h>
#include <require_cpp11.h>
// Include the AccelStepper library:
#include <AccelStepper.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
#define dirPin 10
#define stepPin 11
#define motorInterfaceType 1
// Variables will change:
String authKeyFob = "123456789";
String card_ID="";
int ledState = 0; // remember current led state
int buttonState = 0;
int oldButtonState = 0;
bool toggle = false;
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance
AccelStepper stepper = AccelStepper(motorInterfaceType, stepPin, dirPin);
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);
stepper.setCurrentPosition(0);
stepper.setMaxSpeed(1000);
stepper.setAcceleration(50);
// stepper.setSpeed(200);
// stepper.moveTo(200);
}
void loop() {
/*
// Change direction once the motor reaches target position
if (stepper.distanceToGo() == 0) {
stepper.moveTo(-stepper.currentPosition());
}
// Move the motor one step
stepper.run();
*/
buttonState = digitalRead(BUTTON_PIN);
// 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() ){
card_ID="";
for (byte i = 0; i < mfrc522.uid.size; i++) {
card_ID += mfrc522.uid.uidByte[i];
}
if(card_ID == authKeyFob){
toggle = !toggle;
delay(200);
}
}
// if the button just became pressed...
if(buttonState == HIGH && oldButtonState==LOW){
toggle = !toggle; // same thing, toggle our variable.
delay(200);
}
if (toggle) {
digitalWrite(GREEN, HIGH);
digitalWrite(RED, LOW);
stepper.moveTo(200);
stepper.setSpeed(200);
stepper.run();
} else {
digitalWrite(GREEN, LOW);
digitalWrite(RED, HIGH);
stepper.moveTo(200);
stepper.setSpeed(200);
stepper.run();
}
oldButtonState = buttonState; // save the button state for next time
}
The run method doesn't block. It just takes one step if it is time. So let's step through your code. First we enter the while loop and tell it to step to 200 and set the speed and call run. We keep repeating that over and over. If we get to a point where we have 0 to go then you say moveTo the negative position, set the speed, call run once and then the while loop exits and repeats. On that repeat we say move to 200 and start calling run on that. So you're only calling run once with the moveTo set to the negative number.
You need to rethink the logic on this. I don't know what else is in your loop, so it's hard to say what exactly you want. If you really insist on it being blocking in the while loop then:
stepper.moveTo(200);
stepper.setSpeed(200);
while(stepper.distanceToGo() != 0){
stepper.run();
}
stepper.moveTo(-200);
while(stepper.distanceToGo != 0){
stepper.run();
}
This code moves the stepper in each direction.
if (toggle) {
digitalWrite(GREEN, HIGH);
digitalWrite(RED, LOW);
while(stepper.currentPosition() <= 200){
stepper.moveTo(200);
stepper.setSpeed(200);
stepper.runSpeedToPosition();
if(stepper.currentPosition()==200){
break;
}
}
} else {
digitalWrite(GREEN, LOW);
digitalWrite(RED, HIGH);
while(stepper.currentPosition() >= -200){
stepper.moveTo(-200);
stepper.setSpeed(200);
stepper.runSpeedToPosition();
if(stepper.currentPosition()==-200){
break;
}
}
}

Arduino Mega: How do I switch an LED's colour using the same authenticated RFID tag and using a button too?

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

Pin mode is always LOW when it should be HIGH

I'm working with simple Arduino where I'm trying to turn on a LED light by using serial print and turning off the LED Light when I click the button or use the switch on the board, when the pin is in the ground.
At the moment, I can turn on the led light by serial, however when I click the button the LED light will switch off but then never switch on, and that's happening because the state is being stuck at low all the time and never switching back to high.
Here's the code:
// 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 = 3; // the number of the LED pin
int state = 0;
// variables will change:
int buttonState = 0; // variable for reading the pushbutton status
void setup() {
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
Serial.begin(9600);
}
void loop() {
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);
if (Serial.available())
{
state = Serial.parseInt();
if (state == 1)
{
digitalWrite(ledPin, HIGH);
Serial.println("ON");
}
}
// check if the pushbutton is pressed.
// if it is, the buttonState is HIGH:
if (buttonState == LOW) {
state = 0;
// turn LED OFF:
Serial.println("off");
digitalWrite(ledPin, LOW);
}
// IMP : This Never runs. the state is always off therefore when i send to serial " 1" the led just blinks
else {
Serial.println("off");
}
}
The state is always off therefore when I send to serial " 1" the LED just blinks
I think you are reading state from PIN using wrong function.
if (Serial.available())
{
state = Serial.parseInt();
Why not use https://www.arduino.cc/reference/en/language/functions/digital-io/digitalread/ ?
Are you sure this condition is evaluated to true? if (Serial.available()) ?
You are making the logic too much complicate. Just check the serial if it is available and have the desire value turn led on else check the button and if it pressed turn the led off. On other conditions DO NOTHING. That is all you need.
// set pin numbers:
const int buttonPin = 2; // the number of the pushbutton pin
const int ledPin = 3; // the number of the LED pin
int state = 0;
// variables will change:
int buttonState = 0; // variable for reading the pushbutton status
void setup()
{
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
Serial.begin(9600);
}
void loop()
{
if (Serial.available())
{
state = Serial.parseInt();
if (state == 1)
{
digitalWrite(ledPin, HIGH);
Serial.println("ON");
}
}
// check if the pushbutton is pressed.
// if it is, the buttonState is HIGH:
else if (digitalRead(buttonPin) == HIGH)
{
// turn LED OFF:
Serial.println("off");
digitalWrite(ledPin, LOW);
}
}

Arduino-uno sketch not working properly after power gone

I'm relatively new to Arduino, and here are what I was trying to do.
I want to control a relay circuit using IR(InfarRet) remote. Here is the code what I'm using :
#include <IRremote.h>
int RECV_PIN = 6;
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
irrecv.enableIRIn();
pinMode (5 ,OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
if (irrecv.decode(&results)){
Serial.println(results.value,DEC);
irrecv.resume();
switch (results.value){
case 3150073167:
digitalWrite(5,HIGH);
break;
case 68850955:
digitalWrite (5,LOW);
break;
}
}
}
circuit is working properly,
but after power restart it is not working properly, hear is a snap :
Error :
how to fix this error ?
Usually, a controller is meant to run forever ("24/7").
In the rare case of a restart, the whole system should be set to a defined initial safe state. (That should usually be the same as during power off)
How come your relay remains ON while the arduino is OFF?
If you really want to store a previous state, EEPROM is a good place.
(Fully agree with KIIV)
RAM is volatile memory, and after power loss it is lost too (IO Ports are reset to INPUT mode without pull-ups).
You can use EEPROM to store last state and restore it in setup() function.
For AVR based arduinos something like this can be used:
#include <EEPROM.h>
#include <IRremote.h>
const int RELAY_PIN = 5;
const int RECV_PIN = 6;
const int address = 0;
byte state = 0;
decode_results results;
IRrecv irrecv(RECV_PIN);
void setup() {
Serial.begin(9600);
irrecv.enableIRIn();
state = EEPROM.read(address);
pinMode (RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, state);
}
void loop() {
if (irrecv.decode(&results)) {
Serial.println(results.value,DEC);
irrecv.resume();
switch (results.value){
case 3150073167LU:
if (state == LOW) {
state = HIGH;
EEPROM.write(address, state);
}
break;
case 68850955LU:
if (state == HIGH) {
state = LOW;
EEPROM.write(address, state);
}
break;
default:
break;
}
digitalWrite(RELAY_PIN, state);
}
}

Sending IR signal from Arduino to F&D speakers

I am using below code to send an IR signal to my speaker but they don't respond.
#include <IRremote.h>
IRsend irsend;
const int buttonPin = 8; // the number of the pushbutton pin
//const int ledPin = 3;
int buttonState = 0; // variable for reading the pushbutton status
void setup()
{
// pinMode(ledPin, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
Serial.begin(9600);
}
void loop() {
buttonState = digitalRead(buttonPin);
// check if the pushbutton is pressed.
// if it is, the buttonState is HIGH:
if (buttonState == HIGH) {
// turn LED on:
digitalWrite(7,HIGH);
irsend.sendNEC(0x1FE08F7,32);
}else{
digitalWrite(7,LOW);
}
}
IR Reciever on my other Arduino receives signal but also they vary sometime it shows UNKNOWN and sometime NEC. I am using below code:
#include <IRremote.h>
const int RECV_PIN = 11;
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup()
{
Serial.begin(9600);
irrecv.enableIRIn(); // Start the receiver
irrecv.blink13(true);
}
void loop() {
if (irrecv.decode(&results)) {
if (results.decode_type == NEC) {
Serial.print("NEC: ");
} else if (results.decode_type == SONY) {
Serial.print("SONY: ");
} else if (results.decode_type == RC5) {
Serial.print("RC5: ");
} else if (results.decode_type == RC6) {
Serial.print("RC6: ");
} else if (results.decode_type == UNKNOWN) {
Serial.print("UNKNOWN: ");
}
Serial.println(results.value, HEX);
Serial.println(results.value);
irrecv.resume(); // Receive the next value
}
}
The NEC code that I recieved is correct but on that code speaker does not respond. I double checked the HEX code with the remote that came along with speaker but nothing seem to work.
I think that you could have problem with the HEX literal.
From Arduino API:
By default, an integer constant is treated as an int with the attendant limitations in values. To specify an integer constant with another data type, follow it with:
a 'u' or 'U' to force the constant into an unsigned data format. Example: 33u
a 'l' or 'L' to force the constant into a long data format. Example: 100000L
a 'ul' or 'UL' to force the constant into an unsigned long constant. Example: 32767ul
And from GitHub:
void sendNEC (unsigned long data, int nbits) ;
So, try:
irsend.sendNEC(0x01FE08F7UL,32);

Resources