使用4x4键盘arduino停止循环RGB LED

时间:2017-10-22 22:24:34

标签: arduino

我正在使用带键盘的RGB LED。按' 1'在按下' 2'的同时打开灯关掉灯。在我按下' 3'我希望LED循环显示颜色,并且只有当按下不同的按钮时代码才会离开循环。我的问题是在循环键盘状态HIGH或LOW时没有改变,因此保存为按下的键不能改变。我需要一些方法来摆脱这个循环而不停止循环。

#include <Keypad.h>

const int GreenLED=9;
const int BlueLED=10;
const int RedLED=11;

const byte numRows=4;
const byte numCols=4;

char keymap[numRows][numCols] = 
{
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
};

byte rowPins[numRows] = {5,4,3,2};
byte colPins[numCols] = {13,8,7,6};

char keypressed;
boolean ledPin_stateGreen;
boolean ledPin_stateRed;
boolean ledPin_stateBlue;

Keypad myKeypad = Keypad(makeKeymap(keymap), rowPins, colPins, numRows, 
numCols);

void setup() {
  pinMode(GreenLED, OUTPUT);
  pinMode(BlueLED, OUTPUT);
  pinMode(RedLED, OUTPUT);
  ledPin_stateGreen = digitalRead(GreenLED);
  ledPin_stateRed = digitalRead(RedLED);
  ledPin_stateBlue = digitalRead(BlueLED);
  Serial.begin(9600);
}

void loop() {
      char key = myKeypad.getKey();

      if(key != NO_KEY)
      {
        Serial.println(key);
  }

  //Serial.println(myKeypad.getState());

  keypadEvent(key);
}

  void setColor(int red, int green, int blue)
    {
       #ifdef COMMON_ANODE
       red = 255 - red;
       green = 255 - green;
       blue = 255 - blue;
      #endif
       analogWrite(RedLED, red);
  analogWrite(GreenLED, green);
  analogWrite(BlueLED, blue);  
}

void keypadEvent (KeypadEvent key)
{
  switch (myKeypad.getState())
  {
    case PRESSED:
    if (key == '1')
    {
      digitalWrite(GreenLED, HIGH);
      digitalWrite(BlueLED, HIGH);
      digitalWrite(RedLED, HIGH);
    }  
    if (key == '2')
    {
     digitalWrite(GreenLED, LOW);
     digitalWrite(BlueLED, LOW);
     digitalWrite(RedLED, LOW);         
    }
    if (key == '3')
    {
      int previousState= myKeypad.getState();
      while(key == '3')
      {
        key = myKeypad.getKey();       
        setColor(255, 0, 0);  // red
        delay(200);
        Serial.println(myKeypad.getState());
        setColor (50,50,50); //white
        delay (200);
        setColor (255,40,0);
        delay(200);
        setColor(0, 255, 0);  // green
        delay(200);
        setColor(0, 0, 255);  // blue
        delay(200);
        setColor(255, 255, 0);  // yellow
        delay(200);
        setColor(80, 0, 80);  // purple
        delay(200);
        setColor(0, 255, 255);  // aqua
        delay(200);
        Serial.println(myKeypad.getState());

      }
  }
  }

}

2 个答案:

答案 0 :(得分:0)

在您的设置中,您将GreenLEDBlueLEDRedLED设置为OUTPUT,然后尝试digitalRead()来自他们......

void setup() {
  pinMode(GreenLED, OUTPUT);
  pinMode(BlueLED, OUTPUT);
  pinMode(RedLED, OUTPUT);
  ledPin_stateGreen = digitalRead(GreenLED);
  ledPin_stateRed = digitalRead(RedLED);
  ledPin_stateBlue = digitalRead(BlueLED);
  Serial.begin(9600);
}

答案 1 :(得分:0)

您的循环阻止键盘被读取约1.6秒。然后你有一个非常小的窗口,按下按键来取出钥匙。此外,正如您所说,一旦您处于循环中,由于您没有检查按键操作,您无法退出。 Arduino Playground上的tutorial声明:

  

但是,考虑一下,当你编写代码时,每个延迟()   您使用将使处理时间远离键盘。有点像   延迟(250)可以使键盘看起来非常反应迟钝。和   如果你撒上一堆延迟(10),那就会发生同样的事情   通过你的代码。

解决此问题的一种方法是从循环中删除延迟并将程序转换为状态机,持续轮询键盘以进行按键操作。现在有很多方法可以做到这一点,其中我只选择了一个,实际上我真的把它变成了2个状态机。最高级别是程序的整体状态(即根据按下的键,我们的状态是什么)。第二个是表示循环的状态机,它可以改变LED的颜色。您可以了解有关状态机here的更多信息。

这是你的程序变成上面的状态机:

#include <Keypad.h>

const int GreenLED=9;
const int BlueLED=10;
const int RedLED=11;

const byte numRows=4;
const byte numCols=4;

char keymap[numRows][numCols] = 
{
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
};

byte rowPins[numRows] = {5,4,3,2};
byte colPins[numCols] = {13,8,7,6};

char keypressed;
boolean ledPin_stateGreen;
boolean ledPin_stateRed;
boolean ledPin_stateBlue;

enum MyState {
  LIGHT_ON,
  LIGHT_OFF,
  LIGHT_LOOPING
};

enum LightState {
  COLOR_1,
  COLOR_2,
  COLOR_3,
  COLOR_4,
  COLOR_5,
  COLOR_6,
  COLOR_7,
  COLOR_8
};

//Our current state for lights
MyState currentState = LIGHT_LOOPING;
LightState currentLightState = COLOR_1;
//The previous time in milliseconds
unsigned long prevTimeMS = 0;

Keypad myKeypad = Keypad(makeKeymap(keymap), rowPins, colPins, numRows, 
numCols);

void setup() {
  pinMode(GreenLED, OUTPUT);
  pinMode(BlueLED, OUTPUT);
  pinMode(RedLED, OUTPUT);
  ledPin_stateGreen = digitalRead(GreenLED);
  ledPin_stateRed = digitalRead(RedLED);
  ledPin_stateBlue = digitalRead(BlueLED);
  Serial.begin(9600);
  prevTimeMS = millis();
}

void loop() {
      char key = myKeypad.getKey();

      if(key != NO_KEY)
      {
        Serial.println(key);
  }

  //Serial.println(myKeypad.getState());
  //This function is really checking to see if we need to perform a state
  //transition or not for the currentState
  keypadEvent(key);

  //Do stuff based on the state We are in
  unsigned long currentTimeMS = millis();
  switch(currentState)
  {
    case LIGHT_ON:
      //Don't really need to do anything since we perform
      //the work on the state transition
      break;

    case LIGHT_OFF:
      //Don't really need to do anything since we perform
      //the work on the state transition
      break;

    case LIGHT_LOOPING:
      //Now switch based on the current color state to see if we
      //need to change to the next state
      switch(currentLightState)
      {
        case COLOR_1:
          if(checkDelay(currentTimeMS,prevTimeMS,200))
          {
            //We need to transition to the next state
            transitionLightState(COLOR_2);
          }
          break;

        case COLOR_2:
          if(checkDelay(currentTimeMS,prevTimeMS,200))
          {
            //We need to transition to the next state
            transitionLightState(COLOR_3);
          }
          break;

        case COLOR_3:
          if(checkDelay(currentTimeMS,prevTimeMS,200))
          {
            //We need to transition to the next state
            transitionLightState(COLOR_4);
          }
          break;

        case COLOR_4:
          if(checkDelay(currentTimeMS,prevTimeMS,200))
          {
            //We need to transition to the next state
            transitionLightState(COLOR_5);
          }
          break;

        case COLOR_5:
          if(checkDelay(currentTimeMS,prevTimeMS,200))
          {
            //We need to transition to the next state
            transitionLightState(COLOR_6);
          }
          break;

        case COLOR_6:
          if(checkDelay(currentTimeMS,prevTimeMS,200))
          {
            //We need to transition to the next state
            transitionLightState(COLOR_7);
          }
          break;

        case COLOR_7:
          if(checkDelay(currentTimeMS,prevTimeMS,200))
          {
            //We need to transition to the next state
            transitionLightState(COLOR_8);
          }
          break;

        case COLOR_8:
          if(checkDelay(currentTimeMS,prevTimeMS,200))
          {
            //We need to transition to the next state
            //which is back to the first state so we loop
            transitionLightState(COLOR_1);
          }
          break;
      }
      break;
  }
}

//This will return true if the correct amount of time has passed
boolean checkDelay(unsigned long currentMS, unsigned long prevMS, unsigned long delayMS)
{
  if((currentMS - prevMS) >= delayMS)
  {
    return true;
  }

  return false;
}

void transitionMyState(MyState newState)
{
  switch(newState)
  {
    case LIGHT_ON:
      digitalWrite(GreenLED, HIGH);
      digitalWrite(BlueLED, HIGH);
      digitalWrite(RedLED, HIGH);
      break;

    case LIGHT_OFF:
      digitalWrite(GreenLED, LOW);
      digitalWrite(BlueLED, LOW);
      digitalWrite(RedLED, LOW);
      break;

    case LIGHT_LOOPING:
      //We want to transition to the COLOR_1 state here
      transitionLightState(COLOR_1);
      break;
  }

  currentState = newState;
  //need to save off a new prevTimeMS
  prevTimeMS = millis();
}

void transitionLightState(LightState newState)
{
  //perform the action for the state transition
  switch(newState)
  {
    case COLOR_1:
      setColor(255, 0, 0);  // red
      break;

    case COLOR_2:
      setColor (50,50,50); //white
      break;

    case COLOR_3:
      setColor (255,40,0);
      break;

    case COLOR_4:
      setColor(0, 255, 0);  // green
      break;

    case COLOR_5:
      setColor(0, 0, 255);  // blue
      break;

    case COLOR_6:
      setColor(255, 255, 0);  // yellow
      break;

    case COLOR_7:
      setColor(80, 0, 80);  // purple
      break;

    case COLOR_8:
      setColor(0, 255, 255);  // aqua
      break;
  }

  currentLightState = newState;
  //need to save off a new prevTimeMS
  prevTimeMS = millis();
}

void setColor(int red, int green, int blue)
{
  #ifdef COMMON_ANODE
  red = 255 - red;
  green = 255 - green;
  blue = 255 - blue;
  #endif
  analogWrite(RedLED, red);
  analogWrite(GreenLED, green);
  analogWrite(BlueLED, blue);  
}

void keypadEvent (KeypadEvent key)
{
  switch (myKeypad.getState())
  {
    case PRESSED:
    if (key == '1')
    {
      transitionMyState(LIGHT_ON);
    }  
    if (key == '2')
    {
     transitionMyState(LIGHT_OFF);         
    }
    if (key == '3')
    {
      transitionMyState(LIGHT_LOOPING);
    }
  }
}

实现更多的是为了可读性,然后最小化代码。我添加了两个状态变量,它们保存了我们处于密钥处理程序状态机和循环状态机的状态。关于此实现需要注意的重要事项是,每次循环迭代都会检查按键,并且没有实现延迟。这允许我们随时突破循环颜色状态机。你也可以说颜色的循环变成了一个轮询&#34;我现在需要改变颜色吗?&#34;

另一个需要注意的重要事项是,现在需要跟踪时间,以便循环状态机可以确定何时已经过了正确的时间量,以便知道何时更改状态。当发生状态转换时,将保存当前时间。注意:在此示例中不考虑毫秒计数器的翻转。根据Arduino文档,这大约每50天发生一次。因此,如果您处于LIGHT_LOOPING状态,每50天就会出现一次故障。