Trouble with buttons (Arduino) - arduino

StackOverflow! I am a teenager fairly new to Arduino coding, and am investigating a problem. I am running Linux Ubuntu 10.10 if that makes a difference. I have a setup going with a homemade board consisting of five buttons, one for each left, right, up, and down, and one center button, and a Hitachi 2x16 character LCD screen, using the Arduino Uno board.. My programs purpose is to play my splash screen, issue a countdown from three on-screen, display a helpful message, and then go into the program, which simply opens up a list of items, showing one at a time, and allows you to scroll through them using the up and down buttons, and exit the program by clicking the center button. So, here's the problem: the rest of the program works just fine, but when it comes to the menu, it correctly displays the first item, but the buttons do not serve their purpose. I checked using the serial monitor, and the state of the button doesn't change when pressed. But here's the kicker. I used a volt meter to check if the buttons were correctly using power, and they are. They just don't seem to be working digitally. I have checked my wiring, and it is all correct. I think the problem may be in the code, so I leave it to your more experienced hands:
// include the library code:
#include <LiquidCrystal.h>
int itemNum = 0;
// Declare variables for on and off states, for efficiency!
int on = LOW;
int off = HIGH;
// Declare the buttons' digital pins and states respectively
const int upbtnpin = 8;
const int dwnbtnpin = 9;
const int cntrbtnpin = 10;
int upbtnstate = off;
int dwnbtnstate = off;
int cntrbtnstate = off;
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
void setup() {
// Activate Serial Monitor
Serial.begin(9600);
// Declare buttons to be INPUT
pinMode(upbtnpin, INPUT);
pinMode(dwnbtnpin, INPUT);
pinMode(cntrbtnpin, INPUT);
// Activate Pullups
digitalWrite(upbtnpin, HIGH);
digitalWrite(dwnbtnpin, HIGH);
digitalWrite(cntrbtnpin, HIGH);
// Begin LCD
lcd.begin(16, 2);
// Splash Screen
lcd.setCursor(0, 0);
lcd.print(" _# Paradigm #_");
lcd.setCursor(0,1);
lcd.print("<-> Robotics <->");
delay(3000);
lcd.clear();
// Display Message and countdown
cntrbtnstate = digitalRead(cntrbtnpin);
lcd.setCursor(0, 0);
lcd.print("Menu Program 1.0");
lcd.setCursor(0, 1);
int i = 3;
while (i > 0) {
if (i == 3) {
lcd.setCursor(0, 1);
lcd.print("Wait 3 second(s)");
delay(1000);
i--;
}
else if (i == 2) {
lcd.setCursor(0, 1);
lcd.print("Wait 2 second(s)");
delay(1000);
i--;
}
else if (i == 1) {
lcd.setCursor(0, 1);
lcd.print("Wait 1 second(s)");
delay(1000);
i--;
}
}
lcd.clear();
delay(500);
lcd.setCursor(0, 0);
lcd.print("Press enter any");
lcd.setCursor(0, 1);
lcd.print(" time to exit. ");
delay(1200);
lcd.clear();
}
// ...And finally, to the actual program!
void loop() {
upbtnstate = digitalRead(upbtnpin);
dwnbtnstate = digitalRead(dwnbtnpin);
cntrbtnstate = digitalRead(cntrbtnpin);
while (cntrbtnstate != on) {
if (upbtnstate == on) {
delay(250);
itemNum++;
}
else if (dwnbtnstate == on) {
delay(250);
itemNum--;
}
// OPTIONAL for debugging
delay(150);
Serial.print(" ! ");
delay(150);
Serial.print(int(upbtnstate));
Serial.print(" ");
delay(150);
Serial.print(int(dwnbtnstate));
Serial.print(" ");
delay(150);
Serial.print(int(cntrbtnstate));
String item = "";
int itemNum = 0;
switch(itemNum) {
case 0:
lcd.setCursor(0, 1);
lcd.print("END OF LIST");
break;
case 1:
lcd.setCursor(0, 1);
lcd.print("Water Bottle");
break;
case 2:
lcd.setCursor(0, 1);
lcd.print("Biker Jacket");
break;
case 3:
lcd.setCursor(0, 1);
lcd.print(".44 Magnum");
break;
case 4:
lcd.setCursor(0, 1);
lcd.print(".44 Rounds (x14)");
break;
case 5:
lcd.setCursor(0, 1);
lcd.print("Machete");
break;
case 6:
lcd.setCursor(0, 1);
lcd.print("END OF LIST");
break;
default:
lcd.setCursor(0, 0);
lcd.print(" An error has ");
lcd.setCursor(0, 1);
lcd.print(" occoured ");
}
if (itemNum > 6) {
itemNum == 6;
}
else if (itemNum < 0) {
itemNum == 0;
}
lcd.setCursor(0, 1);
lcd.print(item);
}
lcd.clear();
lcd.setCursor(0, 1);
lcd.print(" Goodbye! ");
}

First, you need to de-bounce the buttons.
http://arduino.cc/it/Tutorial/Debounce
Second, immediately before your case statement, you set the itemNum to 0. That should probably be moved to the setup section, otherwise it will reset the itemNum each iteration of the loop, and you will always be stuck on "END OF LIST".
Likewise with String item = ""; You are blanking out the string each iteration of the loop, and it runs faster than you can press the buttons.
Also, I don't see any code that ever sets the String item to anything except "". Since you print the item name in the case statement, perhaps you can just remove "String item" and all references.
Finally, you can shorten the delay loop section to :
int i = 3;
while (i > 0) {
lcd.setCursor(0, 1);
lcd.print("Wait " + i + " second(s)");
delay(1000);
i--;
}

Related

LCD Arduino not displaying correctly

My problem is when I input the string in the serial monitor it shows like this:
LCD Arduino Error
The setCursor dont work and also there is another weird character created before the actual output.
This is my sample code:
void setup() {
lcd.begin(16, 2);
Serial.begin(9600);
lcd.print("hello, world!");
}
void loop() {
String readString;
String Q;
while (Serial.available()) {
delay(1);
if (Serial.available()>0) {
char c = Serial.read();
if(isControl(c)){
break;
}
readString += c;
}
}
Q = readString;
if (Q == "1"){
lcd.setCursor(0,1);
lcd.print("Hello");
}
if (Q == "2"){
lcd.setCursor(0,1);
lcd.print("World");
}
}
First of all you should understand the LCD lib functions. To set the cursorto theFirst row you need
lcd.setCursor(0,0); // row index starts with 0
if you only set the cursor back without clearing the screen there might be weird chars,sodo a
lcd.clear(); //clears the whole screen
OR define an empty String:
String lineClear =" "; // should be 16 spaces for a 16x2 display
and do as a clearing sequence (e.g. for the top line)
lcd.setCursor(0,0);
lcd.print(lineClear);
lcd.print("Hello");
Remember the syntax is
lcd.setCursor(col, row)
// index for 16x2 is col 0-15,row 0-1
// index for 20x4 is col 0-19,row 0-3
and in setup alwas do a
lcd.clear();
after initializing the lcd, to remove possible artefacts from the buffer

I can't fully understand why the program isn't working - LCD Screen problems and more

I'm working on a project for an automatic Malteser (or similar product) dispenser and I got the code to work, but after leaving it it for a bit, the screen played up and it won't work properly. The LED also is always on and it can seem to move on from the Setup
I have tried:
searching the code for faults
checking the wiring
redoing the wiring in case i missed something
Code:
#include <Servo.h>
#include <DS3231.h>
#include <Wire.h>
#include <LiquidCrystal.h>
DS3231 Clock;
bool Century = false;
bool h12;
bool PM;
byte ADay, AHour, AMinute, ASecond, ABits;
bool ADy, A12h, Apm;
int second, minute, hour, date, month, year, temp;
int button = 8;
int maltesersEaten = 0;
int lastEatenSe = 0;
int lastEatenMi = 0;
int lastEatenHo = 0;
int lastEatenDa = 0;
int lastEatenMo = 0;
int lastEatenYe = 0;
bool eat;
int ledPin = 10;
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
Servo myServo;
byte degree[8] = {
B00100,
B01010,
B00100,
B00000,
B00000,
B00000,
B00000,
};
void setup() {
**lcd.createChar(0, degree);
lcd.begin(16, 2);
// Print a message to the LCD
lcd.print("INITIALIZING");
// Start the I2C interface
Wire.begin();
// Start the serial interface
Serial.begin(9600);
pinMode(button, INPUT);
myServo.attach(9);**
myServo.write(10);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, HIGH);
delay(100);
digitalWrite(ledPin, LOW);
delay(1000);
lcd.clear();
}
void getData() {
second = Clock.getSecond();
minute = Clock.getMinute();
hour = Clock.getHour(h12, PM);
date = Clock.getDate();
month = Clock.getMonth(Century), DEC;
year = Clock.getYear();
temp = Clock.getTemperature();
lcd.setCursor(0, 0);
lcd.print(hour);
lcd.print(":");
lcd.print(minute);
lcd.print(":");
lcd.print(second);
lcd.setCursor(0, 1);
lcd.print(date);
lcd.print(",");
lcd.print(month);
lcd.print(",");
lcd.print(year);
lcd.setCursor(9, 0);
lcd.print(temp);
lcd.write(byte(0));
lcd.print("C");
lcd.setCursor(9,1);
lcd.print("ATE:");
lcd.print(maltesersEaten);
}
void mE() {
maltesersEaten = (maltesersEaten + 1);
lastEatenSe = second;
lastEatenMi = minute;
lastEatenHo = hour;
lastEatenDa = date;
lastEatenMo = month;
lastEatenYe = year;
}
void check() {
lcd.clear();
lcd.print("-Last Malteser-");
delay(500);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(hour);
lcd.print(":");
lcd.print(minute);
lcd.print(":");
lcd.print(second);
lcd.setCursor(0, 1);
lcd.print("Eaten: ");
lcd.print(maltesersEaten);
delay(5000);
lcd.clear();
}
void loop() {
if (digitalRead(button) == LOW) {
digitalWrite(ledPin, HIGH);
myServo.write(170);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("---- Have A ----");
lcd.setCursor(0, 1);
lcd.print(" Malteser ");
delay(5000);
myServo.write(10);
lcd.clear();
check();
mE();
digitalWrite(ledPin, LOW);
}
else if (digitalRead(button) == HIGH) {
getData();
}
}
The desired effect would be the screen produces a message, the LED flashes, then it shows the time, date and temperature of the room, as well as how many Maltesers have been eaten. then when the button is pressed, the servo moves, the LED turns on and the LCD changes through a few different screens, then it returns to the time, date, temp, and number of Maltesers eaten. However the actual result is that the LED turns on permanently, the LCD produces two solid blocks and nothing else, and the servo goes limp, when I press the button nothing changes. I think the problem is in the setup if that is of nay help.
In the program you call the function: check(). In there is a five second delay and in the loop there is another 5s delay. Could it be that you always press the button when the delay is on. Then the program would not notice that the button was pressed and continues with the loop again. This would also explain why the led won't turn off because it is turned on again right away.
To test if this is the case just hold the button down for at least 10s and sea if it works.
If this is the case, to fix this problem try working with an interrupt.
See documentation here: https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/

Power button IRremote

I am creating 3 LEDs that will light up by a remote. I am able to light up the LEDs individually but I need the power button to shut off all of the LEDs. How can I create a 4th case to turn off all LEDs?
#include <IRremote.h>
int RECV_PIN = 3; // the pin where you connect the output pin of TSOP4838
int led1 = 2;
int led2 = 4;
int led3 = 7;
int itsONled[] = {0,0,0,0};
/* the initial state of LEDs is OFF (zero)
the first zero must remain zero but you can
change the others to 1's if you want a certain
led to light when the board is powered */
#define code1 12495 // code received from button A
#define code2 6375 // code received from button B
#define code3 31365 // code received from button C
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup()
{
Serial.begin(9600); // you can comment this line
irrecv.enableIRIn(); // Start the receiver
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
pinMode(led3, OUTPUT);
}
void loop() {
if (irrecv.decode(&results)) {
unsigned int value = results.value;
switch(value) {
case code1:
if(itsONled[1] == 1) { // if first led is on then
digitalWrite(led1, LOW); // turn it off when button is pressed
itsONled[1] = 0; // and set its state as off
} else { // else if first led is off
digitalWrite(led1, HIGH); // turn it on when the button is pressed
itsONled[1] = 1; // and set its state as on
}
break;
case code2:
if(itsONled[2] == 1) {
digitalWrite(led2, LOW);
itsONled[2] = 0;
} else {
digitalWrite(led2, HIGH);
itsONled[2] = 1;
}
break;
case code3:
if(itsONled[3] == 1) {
digitalWrite(led3, LOW);
itsONled[3] = 0;
} else {
digitalWrite(led3, HIGH);
itsONled[3] = 1;
}
break;
}
Serial.println(value); // you can comment this line
irrecv.resume(); // Receive the next value
}
}

How to accept input from user after alarm is triggered

So as of right now when I arm the system and move my hand in front of the PIR sensor it says system triggered how do i get it to take a password from the user to deactivate the system. Also when the system is deactive it should say on the screen "Not Active"
#include <LiquidCrystal.h>
#include <Password.h>
#include <Keypad.h>
//Password
Password password = Password("1234");
LiquidCrystal lcd(0, 1, 10, 11, 12, 13);
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = { // Define the Keymap
{
'1','2','3','A' }
,
{
'4','5','6','B' }
,
{
'7','8','9','C' }
,
{
'*','0','#','D' }
};
byte rowPins[ROWS] = {9,8,7,6};
byte colPins[COLS] = {5,4,3,2};
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS);
int armed = 0;
const int pir1 = A4;
int sensorHit = 0;
int alarmStatus = 0;
int alarmActive = 0;
int zone = 0;
void setup() {
// put your setup code here, to run once:
lcd.begin(16,2);
pinMode(pir1, INPUT);
mainScreen();
keypad.addEventListener(keypadEvent);
}
void loop() {
// put your main code here, to run repeatedly:
keypad.getKey();
if(alarmActive == 1){
if(digitalRead(pir1) == HIGH){
zone = 0;
alarmTriggered();
}
}
}
void keypadEvent(KeypadEvent eKey){
switch (keypad.getState()){
case PRESSED:
lcd.print(eKey);
switch (eKey){
case '#': checkPassword(); break;
default:
password.append(eKey);
}
}
}
void alarmTriggered(){
password.reset();
alarmStatus = 1;
lcd.clear();
lcd.setCursor(0,0);
lcd.print("SYSTEM TRIGGERED");
lcd.print(0,1);
if(zone == 0){
lcd.print(" FRONT DOOR OPEN ");
}
}
void checkPassword(){
if (password.evaluate()){ //if code is correct:
lcd.clear(); //clear LCD
lcd.print("VALID PASSWORD"); //print message
password.reset(); //resets password after correct entry
delay(1500); //wait...
lcd.clear(); //clear
if (alarmStatus==0 && alarmActive == 0){ //if system is off (ie: disarmed)
lcd.print("ARMED!"); //display message
alarmActive=1; //system armed
alarmStatus=1;
delay(2000); //wait
lcd.clear(); //clear
lcd.setCursor(0, 0); //return to top left of LCD
lcd.print("Code to disarm:"); //back to where we began
}
else{
lcd.print("DISARMED!"); //display message
alarmActive=0; //system unarmed
alarmStatus=0;
delay(2000); //wait
lcd.clear(); //clear
lcd.setCursor(0, 0); //return to top left of LCD
lcd.print("Code to arm:"); //back to where we began
}
}
else{ //if password is incorrect:
lcd.clear();
lcd.print("INVALID PASSWORD");
password.reset(); //resets password after INCORRECT entry
delay(2000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Retry Code:");
}
}
void mainScreen(){
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Enter Pin:");
}
You need an input device for entering the password. A simple example can be 10 switches where each switch represent 1 so our password has to be between 0 to 10. You add the switches values together and compare with your set password. The rest should be easy for you.

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...

Resources