First of all sorry for my weak English
I have Arduino Leonardo
and I have a push-button ok?
When I click the button the letter 'W' is printed to the notepad
ok?
I Want when I keep holding the button the 'w' Letter is printed
why? like in games when I keep holding on 'W' letter the player will move, then when I release my finger the player will stop.
Please please please I need your help because I'm a beginner
This is my code
#include "Keyboard.h"
const int buttonPin = 4; // input pin for pushbutton
int previousButtonState = HIGH; // for checking the state of a pushButton
void setup() {
// make the pushButton pin an input:
pinMode(buttonPin, INPUT);
// initialize control over the keyboard:
Keyboard.begin();
}
void loop() {
// read the pushbutton:
int buttonState = digitalRead(buttonPin);
// if the button state has changed,
if ((buttonState != previousButtonState)
// and it's currently pressed:
&& (buttonState == HIGH)) {
// type out a message
Keyboard.print("W");
}
// save the current button state for comparison next time:
previousButtonState = buttonState;
}
First, the reason why your code only acts as if the button was pressed once are the following lines
// if the button state has changed,
if ((buttonState != previousButtonState)
// and it's currently pressed:
&& (buttonState == HIGH)) {
so, this will only be true once after the button gets pressed. If you remove the previous state check and only check if the button is currently high it will trigger a press every time your programm loops. This will have side effects though, like a short press will likely trigger multiple times.
Fortunately, there is another function provided by the keyboard library to solve this issue: Keyboard.press()
When called, Keyboard.press() functions as if a key were pressed and held on your keyboard. Useful when using modifier keys. To end the key press, use Keyboard.release() or Keyboard.releaseAll().
https://www.arduino.cc/reference/en/language/functions/usb/keyboard/keyboardpress/
So, if you modify your code like this:
void loop() {
// read the pushbutton:
int buttonState = digitalRead(buttonPin);
// if the button state has changed,
if (buttonState != previousButtonState){
if( buttonState == HIGH ) {
Keyboard.press('w');
}else{
Keyboard.release('w');
}
}
// save the current button state for comparison next time:
previousButtonState = buttonState;
}
it will act exactly as if the keyboard button keeps beeing pressed.
Please note that currently the script will likely act as if the button is pressed a few times per press because of bouncing. You could fix this issue by adding a small delay after the button press and release part. This will give the button time to settle to the new state. Read more about bouncing here: https://www.allaboutcircuits.com/textbook/digital/chpt-4/contact-bounce/
Related
I'm trying out some beginner Arduino programming.
The task is to make the board I have (ESP8266) play some music and then the music should stop when I press the button, and then restart when I press it again.
Here's my code,
#include "pitches.h" // contains frequencies for notes
#define PIN_BUTTON 0 // the button
#define PIN_BUZZER 13 // the digital pin the Buzzer is attached to
bool stop = false; // button pressed
void play_note(int freq){
if (freq > 0 && !stop){
analogWrite(PIN_BUZZER, 512);
analogWriteFreq(freq);
} else {
analogWrite(PIN_BUZZER, 0);
}
}
void stopMusic(){
stop = !stop;
play_note(0);
}
void setup() {
pinMode(PIN_BUZZER, OUTPUT);
pinMode(PIN_BUTTON, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(PIN_BUTTON), stopMusic, RISING);
}
void loop() {
// intro
play_note(NOTE_E7);
delay(110);
play_note(NOTE_E7);
delay(220);
play_note(NOTE_E7);
delay(220);
play_note(NOTE_C7);
delay(110);
play_note(NOTE_E7);
delay(220);
play_note(NOTE_G7);
delay(440);
play_note(NOTE_G6);
delay(440);
}
The problem is, that the button is being inconsistent. Sometimes, on pressing it, the music will immediately stop. Other times, it will keep playing and I'll have to press it once or twice more. Similarly, when I want the music to start again, it will sometimes start as soon as I press the button, but other times I will need to press it twice or more to get the music back up. I don't know whats causing this. Suggestions?
The button is most likely a mechanical one. They bounce, i.e. open and close the contacts after a press or release for a short time. You have to wait until the button has settled (typically 5-20ms, actual value depends on the button and should be specified in the datasheet) before you check for a new value.
This is called de-bouncing.
Alternatively you can check the button from a periodic timer interrupt. But that would degrade reaction time.
You should probably add some debounce logic to your code.
https://www.arduino.cc/en/Tutorial/Debounce
I need help with debounce of push button. Sometimes it send twice same string to serial link, and I don't know why. Could someone help me, where is a problem?
int reading;
int exbutton= LOW;
unsigned long ddelay= 200;
unsigned long last= 0;
void loop(){
reading= digitalRead(prkgbrake);
if (reading== HIGH && exbutton == LOW && millis() - last> ddelay){
if (brake == 0){
Serial.write("brake:1\n");
while( digitalRead(prkgbrake) == HIGH){
}
}
else{
Serial.write("brake:0\n");
while( digitalRead(prkgbrake) == HIGH){
}
}
last = millis();
}
Thank you in advance.
I hope you didn't copy this code from somewhere, some of the code doesn't make sense.
For instance, what is 'prkgbrake'? What is 'brake'? They are not declared. Why don't you have a 'setup()' function?
Nevertheless, debouncing can be achieved in many ways. I will just fix your code. That way you will understand what you did wrong.
int exbutton = LOW;
unsigned int _delay = 200;
int pushButton = 2;
void setup()
{
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
pinMode(pushButton, INPUT_PULLUP);
}
void loop()
{
while (digitalRead(pushButton) == LOW && exbutton == LOW)
{
if((millis() - last) > _delay)
{
Serial.println("Button Pressed");
while(digitalRead(pushButton) == LOW);
}
}
last = millis();
}
Explanantion: Assuming your pushbutton is connected with digital pin 2. When you use a digital pin with a button it is better to use pullup/pulldown. You can use external resistor or the internal resistor for that. The internal resistor only supports Pull-up.
To know more about pull-up/-down checkout this Arduino page. The bottom line is when you use a pin as input it acts like an antenna and can capture signals from surroundings, known as floating state. So it is better to keep the pin in a known state. If you use internal pull-up, the pin will be always HIGH. So the button configuration has to be in a way so that when it is pressed the pin should go LOW.
Pull Up Configuration
The code pinMode(pushButton, INPUT_PULLUP); enables the digital pin 2 as input with pull-up enabled.
the loop() should work like this:
1) Check if the button is pressed (i.e. if it is LOW).
2) If not update the last variable.
3) If yes then DONT update last, and enter the while loop.
4) Now keep checking if millis()-last is greater than _delay. If not it will go back to while loop and check if the button is still pressed or not. If yes then it will come back and check if millis()-last is more than _delay or not. It will continue to do so until it passed the mentioned amount of debounce delay.
5) If button get depressed (i.e. goes to HIGH) before the '_delay' time then it will update the last and will check if button is pressed or not and will start counting the delay time.
N.B. Play with the _delay variable. It will define the responsiveness of your button.
I'm having a bit of trouble with my Arduino when I try and use long wires to a switch.
If I use a shorter wire I have no problems, but as soon as they are extended, things start playing up.
What I'm trying to do is, when I press a button I would like it to output to a pin, stay on for 2 seconds, then turn off regardless whether the button is still pressed or not.
The code I use at the moment that does work with short wires is:
// 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 = 10; // the number of the LED pin
// 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);
}
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) {
// turn LED on:
digitalWrite(ledPin, HIGH);
delay(2000); // wait for a second
digitalWrite(ledPin, LOW);
}
}
I've been reading on forums that using debounce may solve this problem. However I'm new to Arduino and not sure how to implement this.
I used the Arduino button tutorial and used a 10k pull down resistor as stated. Is there any way I can allow, either with code or with a resistor / cap, to trigger via a switch that has a wire length of <2m?
Any help appreciated.
Wire length is not going to be an issue here. You either have a wiring fault or your code doesn't match your expected behaviour. (You didn't mention what the actual behaviour is right now.)
Additional debouncing of the switch won't be necessary since after you detect a button press, you are ignoring its state for some time. That is what software debouncing typically is.
stay on for 2 seconds, then turn off regardless whether the button is still pressed or not.
Right now the output will not turn off until you release the button. The reason for this is that after you write it low, you immediately check the button again and write the output high if it's still pressed. You either need to put a delay below
digitalWrite(ledPin, LOW);
or be a little fancier and make sure the button is released before you allow another press.
I'm trying to work with a simple Arduino circuit that increments a counter variable on pressing a push button in the circuit (connected as INPUT to PIN 8). My code is as simple as follows:
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int c = 0, btnPIN, btnVal;
void setup ()
{
btnPIN = 8;
pinMode(btnPIN, INPUT);
lcd.begin(16,2);
lcd.clear();
}
void void loop()
{
btnVal = digitalRead(btnPIN);
if (btnVal == LOW)
{
c++;
lcd.clear();
lcd.print(c);
}
}
Problem is the counter increases by more than 1 every time I push the button. A little bit of printing on the serial monitor indicates that each time the button is pressed and the voltage is LOW, the conditional code is executed multiple times and the counter increases by multiple times instead of 1.
Maybe, I need to write some logic that checks if the button was initially unpressed, then pushed and then released again and then these steps would trigger the required action.
The solution I'm currently working with is as under (which works just fine):
int btnStatus = 0;
void loop()
{
btnVal = digitalRead(btnPIN);
if (btnVal == LOW)
btnStatus = 1;
if(btnStatus == 1 && btnVal == HIGH)
{
c++;
lcd.clear();
lcd.print(c);
btnStatus = 0;
}
}
I'm not sure if there's a simpler solution available or if this approach is wrong for other reasons? Any advice would be most welcome!
Another problem you you may be having is that mechanical buttons bounce. That is, they jump between two positions several times quickly before settling to a final position. This is standard operation so it is necessary to "debounce" the button.
There are very many ways to do this, but Here is a tutorial using an Arduino.
The main issue, as you probably figured out, is that the loop function is getting called multiple times while the button is down. This is what is fixed by your code, and yours looks to be a good solution and I don't really see a simpler way. For another way, though, perhaps you could try just adding a call to delay at the end of loop to slow it down a bit. You would have to play with the delay amount a bit, but it could work. Really though, your solution looks just fine.
Your idea is correct, you need to track the previous state of the button to know if it is a new press or if it is simply being held down. Your code could be rewritten to look more like a state machine, however:
typedef enum {
BTN_STATE_RELEASED,
BTN_STATE_PRESSED
} ButtonState;
ButtonState btnStatus = BTN_STATE_RELEASED;
void increment_counter()
{
c++;
lcd.clear();
lcd.print(c);
}
void loop()
{
btnVal = digitalRead(btnPIN);
switch(btnStatus)
{
case BTN_STATE_PRESSED:
// Handle button release
if(btnVal == HIGH)
{
btnStatus = BTN_STATE_RELEASED;
}
break;
case BTN_STATE_RELEASED:
// Handle button press
if(btnVal == LOW)
{
increment_counter();
btnStatus = BTN_STATE_PRESSED;
}
break;
}
}
This was rewritten to use an enum to track the state of the system (a bit overkill for a simple button, but an important concept to know in case your system grows more complex).
The code to update the display was also moved into its own function to make it better separated between the display change and the actual update of the state.
I am trying to program 2 buttons (w/ an Arduino), one which will start a 5 second cycle and one which can stop the cycle at any point within this time frame. When the "Start" button is pressed "START" is printed to the serial monitor, and if the cycle is allowed to complete, "DONE" will be printed as well, followed by a new line. If the "stop" button is pressed, "STOP" is printed to the serial monitor and the cycle is terminated. At least, in theory this is how it should work. What I'm finding is that after I press the start button about 5 times, even if both buttons function perfectly beforehand, at this point the "DONE" will never be printed to the serial monitor. The last thing printed will be the "START" from the most recent button press. The only way to end this is to press the "stop" button, which prints "STOP." However, after pressing the "start" button after this, the code prints a rapid succession of "START\nDONE" couplets. Can anyone see a problem with the code I have? I thought it was a pretty straightforward task, and maybe it's just a problem with the hardware, but if it is a problem with the code, I can't see it.
int startPin = 4;
int stopPin = 7;
int motorPin = 2;
boolean startState = false;
boolean stopState = false;
void setup()
{
pinMode(startPin, INPUT);
pinMode(stopPin, INPUT);
pinMode(motorPin, OUTPUT);
Serial.begin(9600);
Serial.println("setup");
}
void loop()
{
startState = digitalRead(startPin);
if(startState == false)
{
return;
}
Serial.print("START\n");
int time = millis() + 5000;
while(millis() < time)
{
stopState = digitalRead(stopPin);
if(stopState == true) {
Serial.print("STOP\n");
return;
}
analogWrite(motorPin, 255);
}
analogWrite(motorPin, 0);
Serial.print("DONE\n\n");
}
As a final note- this is my first time using Stack Overflow, so I apologize in advance if this isn't a good question, or if it's already been answered, or if I'm doing something else that will appear overwhelmingly stupid to someone more experience than me. And thank you to anyone who can help me.
To start, change
int time = millis() + 5000;
To
unsigned long time = millis() + 5000;
millis() returns an unsigned long so if you are trying to insert that number + 5000 into a signed int, you are overflowing the int and causing weird calculations in your loop.