#c #if-statement #arduino
#c #if-statement #arduino
Вопрос:
В настоящее время я создаю проект для своей школы, и у меня возникает проблема, когда код выполняется несколько раз. Я использую Arduino Mega 2560. Проект, который я делаю, — это создание сейфа / ящика, для открытия которого требуется PIN-код. В порядке того, как все должно работать, следует:
- ИК-приемник получает сигнал от пульта дистанционного управления, который активирует сигнал. Когда система активна, загорается синий светодиод. Когда система неактивна, она ничего не делает.
- Когда система активна, она может считывать входные данные с контактной площадки 4×4. Если он получает неправильный код, он загорается красным светодиодом, а затем очищает данные, чтобы снова использовать код. Если задан правильный код, включается зеленый светодиод и поворачивает серводвигатель на 90 градусов.
- После включения правильного кода нажимается кнопка для возврата двигателя в положение 0 градусов и деактивации системы.
Проблема в том, что после нажатия кнопки я не могу повторно активировать систему. По сути, это становится 1 и готово. Код для проекта можно найти ниже.
#include <Keypad.h>
#include <Servo.h>
#include <IRremote.h>
Servo servo;
const byte ROWS = 4;
const byte COLS = 4;
#define Passcode_L 5
char Data[Passcode_L];
char Master[Passcode_L]="14B6";
char hexaKeys[ROWS][COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {22, 24, 26, 28};
byte colPins[COLS] = {30, 32, 34, 36};
byte data_count = 0;
char customKey;
Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
const int led_blue = 23;
const int led_green = 25;
const int led_red = 27;
const int BUTTON = 47;
int BUTTONstate = 0;
const int RECV_PIN = 44;
int togglestate = 0;
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup(){
Serial.begin(9600);
irrecv.enableIRIn();
servo.attach(38);
servo.write(0);
pinMode(led_blue, OUTPUT);
pinMode(led_green, OUTPUT);
pinMode(led_red, OUTPUT);
pinMode(BUTTON, INPUT);
}
void loop(){
char customKey = customKeypad.getKey();
BUTTONstate = digitalRead(BUTTON);
if (irrecv.decode(amp;results)){
switch(results.value){
case 0xFFA25D:
// Toggle BLUE LED On or Off
if(togglestate==0){
digitalWrite(led_blue, HIGH);
togglestate=1;
}
else {
digitalWrite(led_blue, LOW);
togglestate=0;
}
break;
}
irrecv.resume();
}
if (customKey){
Data[data_count] = customKey;
data_count ;
}
if (data_count == Passcode_L - 1 amp;amp; togglestate==1) {
if (!strcmp(Data, Master)) {
//password is correct
digitalWrite(led_green, HIGH);
delay(500);
servo.write(90);
delay(1500);
digitalWrite(led_green, LOW);
}
else {
// Password is incorrect
digitalWrite(led_red, HIGH);
delay(1000);
digitalWrite(led_red, LOW);
}
clearData();
}
if (BUTTONstate !=0){
servo.write(0);
togglestate=0;
digitalWrite(led_blue, LOW);
}
}
void clearData() {
// Go through array and clear data
while (data_count != 0) {
Data[data_count--] = 0;
}
return;
}
Комментарии:
1. Вы составили блок-схему того, как ожидается, что элемент будет работать? Если это так, сравните его с написанным вами кодом. В противном случае построение блок-схемы, которая документирует ожидаемый поток программы, значительно упростит оценку того, где в вашем коде вы попросили микропроцессор сделать что-то, чего вы бы предпочли, чтобы он не делал..
Ответ №1:
Логике в вашей программе довольно сложно следовать, и ее можно изменить, не нарушая все… Я думаю, что проблема заключается в проблеме дизайна. Ваш код написан для реагирования на события, но не отслеживает должным образом, в каком состоянии находится ваше устройство. И состояние есть. Отслеживание состояния очень важно. Это, вероятно, самое важное, что нужно делать при программировании встроенных устройств. И для блокировки, я действительно думаю, что это определенно самая важная вещь, которую нужно отслеживать.
Попробуйте это: у вас есть блокировка, у нее есть эти разные состояния:
- заблокировано (стабильное состояние)
- ввод пароля (переходный -> ошибка или разблокировка) (требуется прерванный тайм-аут ввода?)
- показать ошибку пароля (переходный -> заблокировано)
- разблокировка (переходный -> разблокированный)
- разблокировано (стабильно)
- блокировка (переходный -> заблокирован)
Если вы будете отслеживать состояние своего устройства и разделять логику для каждого состояния, управлять логикой и отлаживать ее станет намного проще. Это также делает добавление функций и дополнительной логики почти тривиальным. Я думаю, вам следует попробовать что-то вроде этого:
#include <Keypad.h>
#include <Servo.h>
#include <IRremote.h>
const byte ROWS = 4;
const byte COLS = 4;
// IO pins
byte rowPins[ROWS] = {22, 24, 26, 28};
byte colPins[COLS] = {30, 32, 34, 36};
const int led_blue = 23;
const int led_green = 25;
const int led_red = 27;
const int BUTTON = 47;
const int RECV_PIN = 44;
// devices
Servo servo;
IRrecv irrecv(RECV_PIN);
char hexaKeys[ROWS][COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
// lock states
class enum LockState
{
locked,
passcodeEntry,
passcodeError,
unlocking,
unlocked,
locking,
};
// lock data
LockState lockState = locked;
byte data_count = 0;
bool passcodeOK = false;
unsigned int timeoutTS;
const char Master[] = "14B6";
#define Passcode_L (sizeof(Master) - 1)
#define TIMEOUT (30000) // 30 seconds timeout for data entry
void setup()
{
Serial.begin(9600);
irrecv.enableIRIn();
servo.attach(38);
servo.write(0);
pinMode(led_blue, OUTPUT);
pinMode(led_green, OUTPUT);
pinMode(led_red, OUTPUT);
pinMode(BUTTON, INPUT);
}
void loop()
{
switch (lockState)
{
default:
case LockState::locked:
{
// locked, resting. turn LEDs off, and clear received key code.
digitalWrite(led_blue, LOW);
digitalWrite(led_red, LOW);
digitalWrite(led_green, LOW);
data_count = 0;
decode_results results;
if (irrecv.decode(amp;results) amp;amp; results.value == 0xFFA25D)
{
timeoutTS = (unsigned int)millis();
lockState = LockState::passcodeEntry;
}
}
break;
case LockState::passcodeEntry:
{
// read keypad, blue LED is on.
digitalWrite(led_blue, HIGH);
// this assumes customKeypad debounces the key and returns a non-zero
// value only once for each key, when it is initially pressed.
char customKey = customKeypad.getKey();
if (customKey)
{
timeoutTS = (unsigned int)millis();
if (data_count == 0)
passcodeOK = true;
// check passcode.
passcodeOK amp;= (customKey == Master[data_count ]);
if (data_count >= Passcode_L)
{
if (passcodeOK)
lockState = LockState::unlocking;
else
lockState = LockState::passcodeError;
}
// check for timeout, we wouldn't want to let anyone enter codes
// if the owner leaves the room now with the IR remote in his pocket
if ((unsigned int)millis() - timeoutTS > TIMEOUT)
lockState = LockState::locked;
}
break;
case LockState::passcodeError:
{
// turn on red LED for 1 second. then let use retry a passcode.
digitalWrite(led_red, HIGH);
delay(1000);
digitalWrite(led_red, LOW);
data_count = 0;
lockState = LockState::passcodeEntry;
}
break;
case LockState::unlocking:
{
digitalWrite(led_green, HIGH);
servo.write(90);
delay(1500);
digitalWrite(led_green, LOW);
lockState = LockState::unlocked;
}
break;
case LockState::unlocked:
{
// wait for button press.
if (digitalRead(BUTTON))
lockState = LockState::locking;
}
break;
case LockState::locking:
{
// turn the lock back, go back to locked state
servo.write(0);
loackState = LockState::locked;
}
break;
}
}
У меня нет с собой arduino, и в данный момент я не настроен на компиляцию эскиза, поэтому может быть пара ошибок компиляции, но логика должна быть очень близка к тому, чего вы хотите достичь.