【问题标题】:Arduino Project Issues with IF Statements带有 IF 语句的 Arduino 项目问题
【发布时间】:2020-12-18 03:08:26
【问题描述】:

目前,我正在为我的学校制作一个项目,当代码多次运行时我遇到了问题。我正在使用 Arduino Mega 2560。我正在做的项目是制作一个需要 PIN 码才能打开的保险箱/盒子。按照事情应该如何运作的顺序如下:

  1. IR 接收器从激活信号的遥控器接收信号。当系统处于活动状态时,它会打开蓝色 LED。当系统处于非活动状态时,它什么也不做。
  2. 当系统处于活动状态时,它可以从 4x4 引脚焊盘读取输入。如果它得到一个错误的代码,它会打开一个红色的 LED,然后清除数据,这样它就可以再次输入代码。如果给出正确的代码,则绿色 LED 会亮起,并将伺服电机旋转 90 度。
  3. 打开正确的代码后,按下按钮可使电机返回 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(&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 && 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;
}

【问题讨论】:

  • 您是否制作了有关该项目预期工作方式的流程图?如果是这样,请将其与您编写的代码进行比较。否则,构建一个记录预期程序流程的流程图将更容易评估您在代码中的哪些位置要求微机做一些您不希望它做的事情..

标签: c if-statement arduino


【解决方案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(&results) && 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 &= (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,目前没有设置编译草图,因此可能会出现一些编译错误,但逻辑应该非常接近您想要实现的目标。

【讨论】:

    猜你喜欢
    • 2011-02-11
    • 1970-01-01
    • 1970-01-01
    • 2020-05-25
    • 1970-01-01
    • 2018-03-23
    • 1970-01-01
    • 2015-09-15
    • 1970-01-01
    相关资源
    最近更新 更多