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
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!!!
}
}
}
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;
}
}
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
I am using keil c51 compiler. I transmit data from my pc to MCU using serial port it works best.
When I transmit data from my MCU to PC then also it works best.
But when I transmit data to MCU and then store it to buffer character pointer and again from that character pointer buffer I transmit return to PC then it does not work and give garbage values?
My code for both function as below.
#include <REG51.H>
#include "uart.c"
void delay_ms(unsigned int x) // delays x msec (at fosc=11.0592MHz)
{
unsigned char j=0;
while(x-- > 0)
{
for (j=0; j<125; j++){;}
}
}
sbit SW = P3^2;
sbit LED = P3^3;
bit x = 0;
void main ()
{
char *buf;
int len=0;
int len1 = 0;
uart_init();
while(1){
if(RI == 1){
UART_RxString(buf,&len);
buf -= (len-1) ;
x = 1;
}
if(x == 1 && SW == 0){
UART_TxString(buf,&len1);
x = 0;
}
}
}
And below are the functions.
1.
void UART_TxString(char *string_ptr, int *l)
{
int count = 0;
while(*string_ptr){
UART_TxChar(*string_ptr++);
count++;
}
*l = count;
}
void UART_RxString(char *string_ptr, int *l)
{
char ch;
int count = 0;
while(1)
{
ch=UART_RxChar(); //Reaceive a char
//UART_TxChar(ch); //Echo back the received char
count++;
if((ch=='\r') || (ch=='\n')) //read till enter key is pressed
{ //once enter key is pressed
*string_ptr=0; //null terminate the string
break; //and break the loop
}
*string_ptr=ch; //copy the char into string.
string_ptr++; //and increment the pointer
}
*l = count;
}
I communicate with Arduino via Serial using a program that sends a series of bytes.
In order for the Arduino to realize it is receiving a message rather than junk, I have tagged the start of my byte array with the chars 'S' 'T' 'A' 'R' 'T'. After this will eventually follow a series of bytes that will be assigned to internal variables (not yet implemented).
The Arduino must read each byte sequentially and compare it to the byte array and if all are present in the correct order it will continue with the next part of the program, otherwise it will should discard current byte and wait for more bytes to arrive.
I am trying to implement it in the most efficient and readable way rather than using a series of nested if statements.
So far I have got:
byte inByte = 0;
byte handShake[] = {'S','T','A','R','T'};
void setup() {
Serial.begin(9600);
}
void loop()
{
while (Serial.available())
{
for (int x =0; x < sizeof(handShake) ; x++)
{
inByte = Serial.read();
Serial.println(x);
if (inByte == handShake[x])
{
if (x == (sizeof(handShake)-1)) {setArduino();}
}
else break;
}
}
}
void setArduino () {
Serial.println("Ready To Set Parameters");
}
This however doesn't seem to get past the second byte and I'm not sure why.
Worked it out :
Here is the answer:
byte inByte = 0;
char handShake[] = {'S','T','A','R','T'};
void setup() {
Serial.begin(9600);
}
void loop()
{
while (Serial.available())
{
for (int x =0; x < sizeof(handShake) ; x++)
{
inByte = Serial.read();
Serial.println(x);
if (inByte == handShake[x])
{
if (x == (sizeof(handShake)-1)) {setArduino();}
while(!Serial.available()) {delay(1);}
}
else {break;}
}
}
}
void setArduino () {
Serial.println("Ready To Set Parameters");
}
This may not be the most efficient way perhaps, but I can't see a problem with it currently.
Better answer : This allows the rest of the loop to iterate while waiting for the message to finish and if the full handshake message isn't received the counter will reset.
byte inByte = 0;
char handShake[] = {'S','T','A','R','T'};
int messageIndex = 0;
void setup() {
Serial.begin(9600);
}
void loop()
{
while (Serial.available())
{
inByte = Serial.read();
Serial.println(messageIndex);
if (inByte == handShake[messageIndex])
{
messageIndex++;
if (messageIndex == sizeof(handShake)) {messageIndex = 0; setArduino();}
}
else {messageIndex=0;}
}
// Other code while waiting for message to finish
Serial.println("tick");
}
void setArduino () {
Serial.println("Ready To Set Parameters");
}
You could try to calculate your message. CRC is old and good solution. I use it and it works perfect for me. I am not sure what kind of device are you communicating with.
//define
const uint32_t Polynomial = 0xEDB88320;
const uint16_t NumBytes = 256;
uint8_t data[NumBytes];
/// compute CRC32
uint32_t crc32_bitwise(const void* data, uint16_t length, uint32_t previousCrc32 = 0)
{
uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF
uint8_t* current = (uint8_t*) data;
while (length--)
{
crc ^= *current++;
for (uint8_t j = 0; j < 8; j++)
{
uint8_t lowestBit = crc & 1;
crc >>= 1;
if (lowestBit)
crc ^= Polynomial;
}
}
return ~crc; // same as crc ^ 0xFFFFFFFF
}
void setup() {
// put your setup code here, to run once:
}
void loop() {
// put your main code here, to run repeatedly:
}
when you need to calculate CRC
uint32_t crc = crc32_bitwise(data_bytes, sizeof(data_bytes));
data_bytes is byte array.
Then you can get all settings or message in byte data[x] and calculate CRC. Then you can add CRC to the message and send message byte data[x+sizeof(CRC)]
P.S. Use byte instead of int. For ex. for(byte x =0; x<sizeof(handShake); x++)