I've just started tinkering with the arduino and i'm getting my head around the basics. I have a push button hooked up so so i get a serial print when it's pushed.
int button = 3;
void setup() {
Serial.begin(9600);
pinMode(button, INPUT_PULLUP);
}
void loop() {
if (digitalRead(button) == LOW) {
Serial.print("pressed\n");
}
}
Now when the button is pressed it'll print pressed a bunch until released. Now my next step is hook up an LED and I want to use the button as a toggle. Press it the first time, it'll come on, press it a second, it'll turn off. But this will run hundreds of times while the button is pressed. How do I get around this? Thanks
int led = 5;
int button = 3;
void setup() {
Serial.begin(9600);
pinMode(button, INPUT_PULLUP);
pinMode(led, OUTPUT);
digitalWrite(led, LOW);
}
void loop() {
if (digitalRead(button) == LOW) {
Serial.print("pressed\n");
toggleLed(led);
}
}
int toggleLed(int led){
if (digitalRead(led) == LOW) {
Serial.print("set on");
digitalWrite(led, HIGH);
} else {
Serial.print("set off");
digitalWrite(led, LOW);
}
}
There is an example code that comes with the Arduino IDE called the State Change Example. Study it. Basically you need to have a variable to remember the state of the button the last time you pressed it and you only react to changes in the button state. Instead of running your code anytime the button pin IS low, you run your code anytime the button pin changes from high to low.
Related
I'm not proffessional in arduino coding,and i have an question about sketch. I need code to control relay with push buttons. I have 3 push buttons 3 leds and 2 relays. When 1 button push then select first led if twice push then select second led. When push second button once then select first relay,if twice push then select second relay,and in the end start button to start all this commands an then lights third led.
Pls Help!
int button1=2;
int button2=3;
int button3=4;
int relay1=8;
int relay2=9;
int led=5;
int led2=6;
int led3=7;
int button1State=0;
int button2State=0;
int button3State=0;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(button1, INPUT_PULLUP);
pinMode(button2,INPUT_PULLUP);
pinMode(button3,INPUT_PULLUP):
pinMode(relay1, OUTPUT);
digitalWrite(relay1, HIGH);
pinMode(relay2,OUTPUT);
digitalWrite(relay2, HIGH);
pinMode(led,OUTPUT);
pinMode(led2,OUTPUT);
pinMode(led3,OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
button1State = digitalRead(button1);//when once click turn led
if(button1State==HIGH){
digitalWrite(led,HIGH);
delay(wait);
if(button1State==HIGH){ //when clicked twice then turn on led 2, but i dont know how to do it
digitalWrite(led2,HIGH);
delay(wait)
}
}
if (button2State== HIGH){
digitalWrite(relay1,HIGH);
delay(wait);
if(button2State==HIGH){ //when clicked twice turn on second relay but i dont know how to do this
digitalWrite(relay2,HIGH);
delay(wait);
}
if(button2State==HIGH){
digitalWrite(relay1&&relay2,HIGH);
delay(wait);
}
}
//and click start i dont kknow how to do this :((
//when select led then circuits run for 10 sec,if led 2 select then circuit runs for 20 sec
}
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);
}
}
When I push the button it turns the KY008 off but when I click it again it won't turn it off, but if I jiggle the Laser Diode a little bit the KY008 turns back on.
Code:
int LED = 12;
int BUTTON = 4;
void setup(){
pinMode(LED,OUTPUT);
pinMode(BUTTON,INPUT);
}
void loop(){
if(digitalRead(BUTTON) == HIGH){
digitalWrite(LED,HIGH);
}else{
digitalWrite(LED,LOW);
}
}
If you use INPUT you need to have a physical pullup (or pulldown) resistor (typically 10k).
Otherwise use INPUT_PULLUP to use the Arduino internal pullup resistors
pinMode(BUTTON, INPUT_PULLUP);
Make sure that your button closes the circuit to ground when pressed.
Also when reading a button you will have a lot of bouncing.
The easiest way to prevent the bouncing is to add a delay between reads.
void loop(){
if(digitalRead(BUTTON) == HIGH){
digitalWrite(LED,HIGH);
}else{
digitalWrite(LED,LOW);
}
delay(100);
}
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.
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;
}
}
}