I have this code which I try to process is entering a password "78486" to shut down the sensor function !
The problem is, when I enter the code using the keypad .. It doesn't work ..
So please help me to make it work .. I think the problem is in the if condition !
#include <Keypad.h>
char* secretCode = "78486";
int position = 0;
int minSecsBetweenEmails = 60; // 1 min
int val = 0;
long lastSend = -minSecsBetweenEmails * 1000l;
const byte rows = 4;
const byte cols = 3;
char keys[rows][cols] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}
};
byte rowPins[rows] = {8, 7, 6, 5};
byte colPins[cols] = {4, 3, 2};
Keypad keypad = Keypad(makeKeymap(keys),
rowPins, colPins,
rows, cols);
void setup()
{
pinMode (9, OUTPUT);
Serial.begin(9600);
}
void loop()
{
long now = millis();
char key = keypad.getKey();
if (key == '*') {
pinMode (9, INPUT); }
if(key == '2') {
pinMode (9, OUTPUT);
// if(key == secretCode[position])
// {
// position++;
// }
// if (position == 5){
// pinMode (9, OUTPUT);
// }
}
if(digitalRead(9) == HIGH)
{
if (now > (lastSend + minSecsBetweenEmails * 1000l))
{
Serial.println("MOVEMENT");
lastSend = now;
}
else
{
Serial.println("Too soon");
}
}
}
Personally I'd check the value at the end of the reading phase: this way it's harder to guess what is the wrong char (if it exits every time a char is wrong, you will have to do at most 50 tries; if it exits at the end you will need to do at most 100000).
Moreover you need a way to reset the position and start a new password: since you didn't use the # char I used it.
Lastly I definitely prefer the switch case in this case. So
// In the main definition part:
uint8_t position = 0;
char readingCode[5];
char secretCode[] = "78486";
// In the loop:
char key = keypad.getKey();
switch (key)
{
case '*': // shut down sensor
pinMode (9, INPUT);
break;
case '#':
position = 0;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (position < 5)
{
readingCode[position] = key;
position++;
}
if (position >= 5)
{ // check the code
bool correct = true;
uint8_t i;
for (i = 0; i < 5; i++)
if (readingCode[i] != secretCode[i])
correct = false;
if (correct)
pinMode (9, OUTPUT);
position = 0;
}
break;
}
Just one more thing: I don't know what does getKey return when no keys are pressed. Just verify it
Related
I am having trouble with a 16x2 I2C LCD screen using a 4x3 keyboard.
The following are the steps I need to do:
1.Take a numeric value through the keyboard onto the top line of the screen. This numeric value should not exceed 3 digits.
2. The keyboard should only be active (and the screen editable) when * key is pressed once.
3. The keyboard should again become inactive when # key is pressed once.
4. Whatever value has been placed in the screen should be remembered so when a sensor runs it should be able to compare its value to the screen value, achieving equality to which the core process stops.
Below is my code which is not doing the job. Can someone suggest a solution? Thanks.
#include <Keypad.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
LiquidCrystal_I2C lcd(0x27, 16, 4);
#include<stdio.h>
const int ROW_NUM = 4;
const int COLUMN_NUM = 3;
char keys[ROW_NUM][COLUMN_NUM] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'},
};
byte pin_rows[ROW_NUM] = {8,7,6,5};
byte pin_column[COLUMN_NUM] = {4,3,2};
Keypad keypad = Keypad( makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM );
int counter = 0;
void setup() {
// put your setup code here, to run once:
lcd.init();
lcd.clear();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Volume. ml");
lcd.setCursor(0, 1);
lcd.print("Filled ml");
}
void loop() {
// put your main code here, to run repeatedly:
keypadfunction();
}
void keypadfunction()
{
char key = keypad.getKey();
if (key)
{
}
if (key == '*')
{
while (key != '#' || counter <=3)
{
lcd.setCursor(8, 1);
lcd.setCursor(8+counter, 1);
lcd.print(key);
counter = counter+1;
}
}
}
changes after suggestions from #C1sc0:
#include <Keypad.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
LiquidCrystal_I2C lcd(0x27, 16, 4);
#include<stdio.h>
const int ROW_NUM = 4;
const int COLUMN_NUM = 3;
char keys[ROW_NUM][COLUMN_NUM] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'},
};
byte pin_rows[ROW_NUM] = {8,7,6,5};
byte pin_column[COLUMN_NUM] = {4,3,2};
Keypad keypad = Keypad( makeKeymap(keys), pin_rows, pin_column,
ROW_NUM, COLUMN_NUM );
char volume[3];
byte volumeCount = 0;
bool edit = 0;
int finalValue = 0;
void setup()
{
// put your setup code here, to run once:
lcd.init();
lcd.clear();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Volume ml");
lcd.setCursor(0, 1);
lcd.print("Filled ml");
}
void loop()
{
char key = keypad.getKey();
if(key) // check if any key was pressed
{
if(key == '*') // if * was pressed switch to edit mode
{
lcd.setCursor(0,0); // set your cursor at columnt 0, row 0
lcd.clear();
lcd.print("Enter volume: ");
edit = true;
lcd.setCursor(0,1); // set your cursor to second row
volumeCount = 0;
volume[0] = '0';
volume[1] = '0';
volume[2] = '0';
}
if(edit && volumeCount < 3) // enter edit mode
{
volume[volumeCount] = key; // save key to a char array
lcd.setCursor(volumeCount,1); // set your cursor to the
next position
lcd.print(volume[volumeCount]); // print the pressed button to lcd
volumeCount++; // increment the array index (cursor position)
}
if(volumeCount == 3 || key == '#') // array.length == 3 OR you pressed #
{
edit = false; // disable edit mode
volumeCount = 0; // reset your counter
lcd.setCursor(0,0);
lcd.clear();//new
lcd.print(volume);
finalValue = atoi(volume); // save your entered value for further usage
//volume[0] = '0';
//volume[1] = '0';
//volume[2] = '0';
}
}
buttonState1 = digitalRead(buttonPin1);
if (buttonState1 == HIGH)
{
//do process basis 'finalValue'
}
}
Screen output
Create a bool (or byte) variable, for signaling the "edit" state
if (key == '*') { edit= true; }
in your loop (this will be your first if condition).
Create another if and here check the edit flag (if it is true, then you are waiting for the 3 values. You can read the pressed keys to a char array
char values[3];
// create this variable, before setup()
Here for the index you can use a counter (which is already present in your code as I saw. So, put all these lines in your second if condition, and increment your counter by one here. And you can display the entered character here too:
lcd.setCursor(8+counter, 1);
lcd.print(key);
Create a third if block, and check the counter is # key or counter == 3. If this condition will be satisfied you have to do 3 things reset the counter to zero, reset the edit state to false, and finally convert your value to an int (with atoi function).
After it works, you can refactor your code to make it more efficient/readable.
You need something like this:
char volume[3];
byte volumeCount = 0;
bool edit = 0;
int finalValue = 0;
void loop()
{
char key = keypad.getKey();
if(key) // check if any key was pressed
{
if(key == '*') // if * was pressed switch to edit mode
{
lcd.setCursor(0,0); // set your cursor at columnt 0, row 0
lcd.print("Enter volume: ");
edit = true;
lcd.setCursor(0,1); // set your cursor to second row
volumeCount = 0;
volume[0] = '0';
volume[1] = '0';
volume[2] = '0';
}
if(edit && volumeCount < 3 && key != '*' && key != '#')
{
volume[volumeCount] = key; // save key to a char array
lcd.setCursor(volumeCount,1); // set your cursor to the next position
lcd.print(volume[volumeCount]); // print the pressed button to lcd
volumeCount++; // increment the array index (cursor position)
}
if(volumeCount == 3 || key == '#') // array.length == 3 OR you pressed #
{
edit = false; // disable edit mode
volumeCount = 0; // reset your counter
finalValue = atoi(volume); // save your entered value for further usage
volume[0] = '0';
volume[1] = '0';
volume[2] = '0'; # ty for the fix!!!
}
}
}
My goal is to transfer a speed value from an encoder from a slave Arduino to a master Arduino via SPI. I am currently getting zeros on the master side serial print and I'm not sure what I am doing wrong. I have increased the amount of time to wait several times to see if it was a processing time issue but I had it waiting for 100mS with still no change. I know an unsigned int is 4 bytes and I am unsure if a union is the best option in this case seeing I might be overwriting my data due to the separate interrupts but I am unsure. I thought to use a struct since I'll have to move to transferring an array of floats and ints over SPI from various sensors including this encoder later. Below is my code and thank you for any help received:
Slave
#include "math.h"
#define M_PI
byte command = 0;
const int encoder_a = 2; // Green - pin 2 - Digital
const int encoder_b = 3; // White - pin 3 - Digital
long encoder = 0;
int Diameter = 6; // inches
float previous_distance = 0;
unsigned long previous_time = 0;
void setup (void)
{
Serial.begin(115200);
pinMode(MOSI, INPUT);
pinMode(SCK, INPUT);
pinMode(SS, INPUT);
pinMode(MISO, OUTPUT);
// turn on SPI in slave mode
SPCR |= _BV(SPE);
// turn on interrupts
SPCR |= _BV(SPIE);
pinMode(encoder_a, INPUT_PULLUP);
pinMode(encoder_b, INPUT_PULLUP);
attachInterrupt(0, encoderPinChangeA, CHANGE);
attachInterrupt(1, encoderPinChangeB, CHANGE);
}
// SPI interrupt routine
ISR (SPI_STC_vect)
{
union Data{
float f;
byte buff[4];}
data;
byte c = SPDR;
data.f = assembly_speed();
command = c;
switch (command)
{
// no command? then this is the command
case 0:
SPDR = 0;
break;
// incoming byte, return byte result
case 'a':
SPDR = data.buff[0];
break;
// incoming byte, return byte result
case 'b':
SPDR = data.buff[1];
break;
// incoming byte, return byte result
case 'c':
SPDR = data.buff[2];
break;
// incoming byte, return byte result
case 'd':
SPDR = data.buff[3];
break;
}
}
void loop (void)
{
// if SPI not active, clear current command
if (digitalRead (SS) == HIGH)
command = 0;
}
void encoderPinChangeA()
{
encoder += digitalRead(encoder_a) == digitalRead(encoder_b) ? -1 : 1;
}
void encoderPinChangeB()
{
encoder += digitalRead(encoder_a) != digitalRead(encoder_b) ? -1 : 1;
}
float distance_rolled()
{
float distance_traveled = (float (rotation()) / 8) * PI * Diameter;
return distance_traveled;
}
int rotation()
{
float eigth_rotation = encoder / 300;
return eigth_rotation;
}
float assembly_speed()
{
float current_distance = (float (rotation()) / 8) * PI * Diameter;
unsigned long current_time = millis();
unsigned long assemblySpeed = (((current_distance - previous_distance) /
12) * 1000) / (current_time - previous_time); // gives ft/s
previous_distance = current_distance;
previous_time = current_time;
return assemblySpeed;
}
Master
#include <SPI.h>
void setup (void)
{
pinMode(MOSI, OUTPUT);
pinMode(MISO, INPUT);
pinMode(SCK, OUTPUT);
pinMode(SS, OUTPUT);
Serial.begin (115200);
Serial.println ();
digitalWrite(SS, HIGH);
SPI.begin ();
SPI.setClockDivider(SPI_CLOCK_DIV8);
}
byte transferAndWait (const byte what)
{
byte a = SPI.transfer (what);
delayMicroseconds(10000);
return a;
}
union Data
{
float f;
byte buff[4];
}
data;
void loop (void)
{
digitalWrite(SS, LOW);
transferAndWait ('a');
data.buff[0] = transferAndWait ('b');
data.buff[1] = transferAndWait ('c');
data.buff[2] = transferAndWait ('d');
data.buff[3] = transferAndWait (0);
digitalWrite(SS, HIGH);
Serial.print("data.f = ");Serial.print(data.f);Serial.println(" Ft/s");
delay(200);
}
I'm working on a project on which I'm using a keypad to type a password, what I've done is that I'm reading keys typed by the user and collect it in an array to compare it with the password. The problem that I'm facing is that when I compare the typed word and and the correct password I'm getting always "wrong password".
Here is my code:
#include "Keypad.h"
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}
};
char passwrd[7];
char cst[7]="*1998#";
byte rowPins[ROWS] = {28, 27, 26, 25}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {24, 23, 22}; //connect to the column pinouts of the keypad
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
void setup()
{
Serial.begin(9600);
}
void loop()
{
int i=0;
do
{
char key = keypad.getKey();
if (key != NO_KEY)
{
passwrd[i]=key;
i++;
Serial.println(key);
}
}while (i!=6);
Serial.println(passwrd);
Serial.println(cst);
if (passwrd==cst)
{
Serial.println("correct passwrd");
}
else
{
Serial.println("wrong passwrd");
}
}
Here is what I'm getting from the serial com:
*
1
9
9
8
#
*1998#
*1998#
wrong passwrd
Where is the problem?
Using == on a char* will compare the address that the pointer points to in memory, since a c-type string is a pointer. You need to use the strcmp() function.
strcmp() returns 0 if the c-strings are identical.
This should work:
if (strcmp(passwrd, cst) == 0)
{
Serial.println("correct passwrd");
}
else
{
Serial.println("wrong passwrd");
}
Demonstration
Put this on your Arduino to demonstrate this:
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
}
char* are_the_same(int val) {
if(val == 0)
return "No";
return "Yes";
}
void loop() {
// put your main code here, to run repeatedly:
char* one = "test";
char two[5];
// We are copying 'test' into string two. If we don't do this the compiler will optimise and make them point to the same piece of memory and ruin the demonstration.
int i;
for (i = 0; i < 5; i++)
two[i] = one[i];
Serial.print("one == two, are they the same? ");
Serial.println(are_the_same(one == two));
Serial.print("strcmp(one, two) == 0, are they the same? ");
Serial.println(are_the_same(strcmp(one, two) == 0));
Serial.println();
delay(1000);
}
This will give you:
one == two, are they the same? No
strcmp(one, two) == 0, are they the same? Yes
So I run into a problem when I am trying to disarm the system. When I upload the code to the arduino it asks me to enter a pin and then it activates the system right away. But then when I try to deactivate the system it takes the pin and just clears the screen and execute the mainScreen function that i have set.
The code is provided below:
#include "Keypad.h"
#include "LiquidCrystal.h"
#include "Password.h"
LiquidCrystal lcd(0,1,10,11,12,13);
char newPasswordString; //hold the new password
char newPassword[4]; //charater string of newPasswordString
//initialize password to 1234
//you can use password.set(newPassword) to overwrite it
Password password = Password("1234");
byte maxPasswordLength = 4;
byte currentPasswordLength = 4;
// keypad type definition
const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {9,8,7,6}; //Rows 0 to 3
byte colPins[COLS]= {5,4,3,2}; //Columns 0 to 3
int count=0;
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
void setup()
{
lcd.begin(16, 2);
mainScreen();
}
void loop(){
char key = keypad.getKey();
if (key != NO_KEY){
delay(60);
switch (key){
case 'A': activate(); break;
case 'B': break;
case 'C': break;
case 'D': deactivate(); break;
case '#': break;
case '*': break;
default: processNumberKey(key);
}
}
}
void processNumberKey(char key) {
lcd.print(key);
currentPasswordLength++;
password.append(key);
if(password.evaluate()){
activate();
}
}
void activate() {
if (password.evaluate()){
lcd.clear();
lcd.print("Activated.");
delay(1000);
mainScreen();
} else {
lcd.clear();
lcd.print("Wrong Password!");
mainScreen();
}
}
void deactivate(){
if (password.evaluate()){
lcd.clear();
lcd.print("Deactivated.");
delay(1000);
} else {
lcd.clear();
lcd.print("Wrong Password!");
mainScreen();
}
}
void mainScreen(){
lcd.clear();
lcd.print("Enter Pin:");
keypad.getKey();
}
As noted in Arduino keypad 4x4 to LCD activate/deactivate you have to keep current state and you have to CLEAR the password and currenPasswordLength. See the WORKING example in the answer.
It won't help that you set byte currenPasswordLength = 4. If you press first key, it will be incremented to 5, next key increments it to the 6 and so on.
You'll get 4 again after the 256 key-presses!!!!!!! And as you don't clear previously checked password, you'll get "wrong password" result (and eventually stack overflow).
I have a problem with an activation/deactivation system for Arduino. I can get the code to activate or deactivate once I upload a fresh copy of the code, but once I activate it after upload and try to deactivate the security system, it only takes in 2 numbers and then prompts me to Wrong password.
#include "Keypad.h"
#include "LiquidCrystal.h"
#include "Password.h"
LiquidCrystal lcd(0,1,10,11,12,13);
char newPasswordString; //hold the new password
char newPassword[4]; //character string of newPasswordString
//initialize password to 1234
//you can use password.set(newPassword) to overwrite it
Password password = Password("1234");
byte maxPasswordLength = 6;
byte currentPasswordLength = 0;
// keypad type definition
const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {9,8,7,6}; //Rows 0 to 4
byte colPins[COLS]= {5,4,3,2}; //Columns 0 to 4
int count=0;
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
void setup()
{
lcd.begin(16, 2);
mainScreen();
}
void loop(){
char key = keypad.getKey();
if (key != NO_KEY){
delay(60);
switch (key){
case 'A': activate(); break;
case 'B': break;
case 'C': break;
case 'D': deactivate(); break;
case '#': break;
case '*': break;
default: processNumberKey(key);
}
}
}
void processNumberKey(char key) {
lcd.print(key);
currentPasswordLength++;
password.append(key);
if (currentPasswordLength == maxPasswordLength) {
activate();
}
}
void activate() {
if (password.evaluate()){
lcd.clear();
lcd.print("Activated.");
delay(1000);
mainScreen();
} else {
lcd.clear();
lcd.print("Wrong Password!");
}
}
void deactivate(){
if (password.evaluate()){
lcd.clear();
lcd.print("Deactivated.");
delay(1000);
mainScreen();
} else {
lcd.clear();
lcd.print("Wrong Password!");
delay(1000);
mainScreen();
}
}
void mainScreen(){
lcd.clear();
lcd.print("Enter Pin:");
keypad.getKey();
}
So for the first time it works (activation) and next time (deactivation) it doesn't?
The only occurrences of currentPasswordLenght are these:
Global variable declaration and initialization: byte currentPasswordLength = 0;
Incrementation in processNumberKey: currentPasswordLength++;
Compare and call activate in processNumberKey: if (currentPasswordLength == maxPasswordLength) {
The third one also explains why the deactivation (second round) fails after the second key press as maxPasswordLength is 6 and after the activation the currentPasswordLength is 4.
Example of working code:
#include <Key.h>
#include <Keypad.h>
#include <Password.h>
const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
const char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
const byte rowPins[ROWS] = {9,8,7,6};
const byte colPins[COLS] = {5,4,3,2};
Keypad keypad { makeKeymap(keys), rowPins, colPins, ROWS, COLS };
Password passwd { "1234" };
bool activated = false;
byte count = 0;
uint32_t timeout = 0;
void setup() {
Serial.begin(115200);
}
void loop() {
char key = keypad.getKey();
switch (key) {
case '0' ... '9':
Serial.print(key);
passwd << key;
timeout = millis() + 5000;
if (++count == 4) {
Serial.println();
if (passwd.evaluate()) {
activated = !activated;
Serial.println(activated ? F("Activated") : F("Deactivated"));
} else {
Serial.println(F("Wrong password"));
}
passwd.reset();
count = 0;
}
break;
case 'A' ... 'D':
break;
default:
delay(60);
break;
}
if ((count != 0) && (millis() > timeout)) {
Serial.println(F("\nTimeout"));
passwd.reset();
count = 0;
}
}