我正在使用带键盘的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());
}
}
}
}
答案 0 :(得分:0)
在您的设置中,您将GreenLED
,BlueLED
,RedLED
设置为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天就会出现一次故障。