提前感谢您的帮助。
在现实世界中,我使用一个按钮打开两个机械阀门,但其中一个阀门应在一段时间后关闭,我们将硬编码到草图中,另一个阀门保持打开状态为止按下按钮。为了概念验证,我点亮两个LED作为阀门的替身。
如果按下按钮一,Valve One应该打开,Valve 2也应该打开200ms然后关闭。
在主循环中,我查找按钮作为if语句的一部分被推送。当这个条件通过时,我使用了一个while循环和计时器来保持“valve2”打开,直到时间结束。 LED工作,一切都表面上很好。然而...
当我的伴侣开始将实际机械装置放在一起时,阀门2不会打开,因为while循环的循环速度非常快,以至于启动阀门打开所需的电压不够高。
const int button1 = 2; //Pin for switch 1
const int button2 = 3; //Pin for switch 2
const int valve1 = 12; //Pin for relay 1
const int valve2 = 13; //Pin for relay 2
// variables will change:
int state1 = 0; // variable for reading the pushbutton status
int state2 = 0; // variable for reading the pushbutton status
//THIS IS THE TIME IN MILLISECONDS FOR valve2 WHEN button1 IS DEPRESSED
int valve2time = 200;
void setup() {
//switches
pinMode(button1,INPUT); //Set button1 as input
pinMode(button2, INPUT); //Set button2 as input
//relays
pinMode(valve1, OUTPUT); //Set valve1 as output
pinMode(valve2, OUTPUT); //Set valve2 as output
Serial.begin(9600);
}
void loop(){
state1 = digitalRead(button1); //state1 returns the state of button1, up or down.
state2 = digitalRead(button2); //state2 returns the state of button2, up or down.
int duration = switchTime(); //Create variable to capture duration of switch press
if (state1 == LOW && state2 == LOW){ //if no buttons are pressed
digitalWrite(valve1,LOW); //make sure valve1 is off
digitalWrite(valve2,LOW); //make sure valve2 is off
}
else if (state1 == HIGH && state2 == LOW) { //if JUST button one is pressed
digitalWrite(valve1,HIGH); //turn on valve1
while (duration <= valve2time){ //as long as the timer is below or = to what we defined up top....
digitalWrite(valve2,HIGH); //...Turn on valve2...
break; //...Then stop the while loop...
}
digitalWrite(valve2,LOW); //...and finally turn off valve2
}
else if (state2 == HIGH){ //final condition, if button two is pressed
digitalWrite(valve1,HIGH); //turn on valve1
digitalWrite(valve2,HIGH); //turn on valve2
}
}
//return the time in ms that the switch has been pressed (LOW)
long switchTime(){
//these variables are static
static unsigned long startTime = 0; //the time the switch state was first detected
static boolean state; //the current state of the switch
if(digitalRead(button1) != state){ //check to see if the switch has changed state
state = ! state; //yes, invert the state
startTime = millis(); //store the time
}
if(state == HIGH){
return millis() - startTime; //switch pushed, return time in ms
}
else{
return 0; //return 0 if the switch is not pushed (in the HIGH state)
}
}
//button pins
const int BUTTON1_PIN = 2;
const int BUTTON2_PIN = 3;
const int VALVE1_PIN = 0; //mml for tiny
const int VALVE2_PIN = 1; //mml for tiny
// IO Channels - Used to simulate arduino IO
boolean inputChannels[] = {LOW, LOW}; // digital input channels "Button1" and "Button2"
boolean outputChannels[] = {LOW, LOW}; // digital output channels "Valve1" and "Valve2"
// =============================================================================================================
// You can probably ignore everything above this line
// State machine variables
const int STATE_CLOSED = 0;
const int STATE_BUTTON1_PRESSED = 1;
const int STATE_BUTTON1_RELEASED = 2;
const int STATE_BUTTON2_PRESSED = 3;
const int STATE_BUTTON2_RELEASED = 4;
int currentState = 0;
int lastState = 0;
// button debounce time in ms
unsigned long BUTTON_DEBOUNCE = 200;
unsigned long BUTTON1_PRESSED_VALVE2_FLASH = 350;
unsigned long BUTTON1_RELEASE_VALVE2_FLASH = 1000;
// state tracking arrays
boolean buttonState[] = {LOW, LOW};
boolean buttonDebounce[] = {LOW, LOW};
unsigned long buttonTimers[] = {0, 0};
unsigned long valveTimers[] = {0, 0};
void setup(){
pinMode(BUTTON1_PIN, INPUT);
digitalWrite(BUTTON1_PIN, HIGH); //MML
pinMode(BUTTON2_PIN, INPUT);
digitalWrite(BUTTON2_PIN, HIGH); //MML
pinMode(VALVE1_PIN, OUTPUT);
pinMode(VALVE2_PIN, OUTPUT);
}
/**
* Main control loop
*/
void loop() {
switch (currentState) {
case STATE_CLOSED:
handleClosedState();
lastState = STATE_CLOSED;
break;
case STATE_BUTTON1_PRESSED:
handleButton1PressedState();
lastState = STATE_BUTTON1_PRESSED;
break;
case STATE_BUTTON1_RELEASED:
handleButton1ReleasedState();
lastState = STATE_BUTTON1_RELEASED;
break;
case STATE_BUTTON2_PRESSED:
handleButton2PressedState();
lastState = STATE_BUTTON2_PRESSED;
break;
case STATE_BUTTON2_RELEASED:
handleButton2ReleasedState();
lastState = STATE_BUTTON2_RELEASED;
break;
default:;
}
}
/**
* Handler method for STATE_CLOSED
*/
void handleClosedState() {
// ensure valves are closed
if (digitalRead(VALVE1_PIN) == HIGH) {
digitalWrite(VALVE1_PIN, LOW);
}
if (digitalRead(VALVE1_PIN) == HIGH) {
digitalWrite(VALVE2_PIN, LOW);
}
// wait for button1 press
if (LOW == debouncedDigitalRead(BUTTON1_PIN, BUTTON_DEBOUNCE)) {
buttonState[BUTTON1_PIN] = LOW;
currentState = STATE_BUTTON1_PRESSED;
}
}
/**
* Handler method for STATE_BUTTON1_PRESSED
*/
void handleButton1PressedState() {
// check for button1 release
if (HIGH == debouncedDigitalRead(BUTTON1_PIN, BUTTON_DEBOUNCE)) {
currentState = STATE_BUTTON1_RELEASED;
return;
}
// open valve1
if (digitalRead(VALVE1_PIN) == LOW) {
valveTimers[VALVE1_PIN] = millis();
digitalWrite(VALVE1_PIN, HIGH);
}
// on state change open valve2
if (lastState != currentState) {
valveTimers[VALVE2_PIN] = millis();
digitalWrite(VALVE2_PIN, HIGH);
}
// and close it after 200 ms
else if ((millis() - valveTimers[VALVE2_PIN]) > BUTTON1_PRESSED_VALVE2_FLASH && digitalRead(VALVE2_PIN) == HIGH) {
digitalWrite(VALVE2_PIN, LOW);
}
// check for button2 press
if (LOW == debouncedDigitalRead(BUTTON2_PIN, BUTTON_DEBOUNCE)) {
currentState = STATE_BUTTON2_PRESSED;
}
}
/**
* Handler method for STATE_BUTTON1_RELEASED
*/
void handleButton1ReleasedState() {
// open valve2
if (lastState != currentState) {
valveTimers[VALVE2_PIN] = millis();
digitalWrite(VALVE2_PIN, HIGH);
digitalWrite(VALVE1_PIN, LOW);
}
// and close valve2 after 1000ms
else if ((millis() - valveTimers[VALVE2_PIN] > BUTTON1_RELEASE_VALVE2_FLASH)) {
digitalWrite(VALVE2_PIN, LOW);
currentState = STATE_CLOSED;
}
}
/**
* Handler method for STATE_BUTTON2_PRESSED
*/
void handleButton2PressedState() {
// open valve2
if (digitalRead(VALVE2_PIN) == LOW){
digitalWrite(VALVE2_PIN, HIGH);
digitalWrite(VALVE1_PIN, HIGH);
}
// check for button1 release
if (HIGH == debouncedDigitalRead(BUTTON1_PIN, BUTTON_DEBOUNCE)) {
currentState = STATE_BUTTON1_RELEASED;
}
// check for button2 release
else if (HIGH == debouncedDigitalRead(BUTTON2_PIN, BUTTON_DEBOUNCE)) {
currentState = STATE_BUTTON2_RELEASED;
}
}
/**
* Handler method for STATE_BUTTON2_PRESSED
*/
void handleButton2ReleasedState() {
// open valve2
if (digitalRead(VALVE2_PIN) == HIGH){
digitalWrite(VALVE2_PIN, LOW);
digitalWrite(VALVE1_PIN, HIGH);
}
// check for button1 release
if (HIGH == debouncedDigitalRead(BUTTON1_PIN, BUTTON_DEBOUNCE)) {
currentState = STATE_BUTTON1_RELEASED;
}
// check for button2 press
else if (LOW == debouncedDigitalRead(BUTTON2_PIN, BUTTON_DEBOUNCE)) {
currentState = STATE_BUTTON2_PRESSED;
}
}
/**
* Utility for debouncing input channels
* @param channel
* @param debounce
* @return
*/
boolean debouncedDigitalRead(int channel, unsigned long debounce) {
int input = digitalRead(channel);
if (input != buttonState[channel] && HIGH == buttonDebounce[channel]) {
buttonTimers[channel] = millis();
buttonDebounce[channel] = LOW;
}
if ((millis() - buttonTimers[channel]) > debounce) {
buttonState[channel] = input;
buttonDebounce[channel] = HIGH;
}
return buttonState[channel];
}
答案 0 :(得分:0)
为了使代码同时a)保持循环以检查按钮,以及b)实现valve2的所需行为,您需要一个软件状态机来跟踪Valve2正在做什么。在下面的代码中,我重命名了你的state1和state2变量,这样我就可以引入一个控制valve2的新state
变量。
state
变量通常处于idle
状态。
按下button1时
state
已更改为active
延迟200毫秒后
state
已更改为done
state
将保持done
,直到释放button1或按下button2,因为其中任何一项操作都会将state
重置为idle
。
这是代码的样子
void loop()
{
int state = 0; //variable to keep track of valve2: 0=idle 1=active 2=done
unsigned long start; //variable to keep track of when valve2 was turned on
boolean pressed1 = (digitalRead(button1) == HIGH); //pressed1 is true if button1 is pressed
boolean pressed2 = (digitalRead(button2) == HIGH); //pressed2 is true if button2 is pressed
if ( !pressed1 && !pressed2 ) //if no buttons are pressed
{
digitalWrite(valve1,LOW); //make sure valve1 is off
digitalWrite(valve2,LOW); //make sure valve2 is off
state = 0; //clear valve2 state
}
else if ( pressed2 ) //if button2 is pressed
{
digitalWrite(valve1,HIGH); //turn on valve1
digitalWrite(valve2,HIGH); //turn on valve2
state = 0; //clear valve2 state
}
else //button1 is pressed
{
digitalWrite(valve1,HIGH); //turn on valve1
if ( state == 0 ) //if valve2 is idle
{
digitalWrite(valve2,HIGH); //turn on valve2
state = 1; //valve2 is active
start = millis(); //capture the start time
}
else if ( state == 1 ) //if valve2 is active
{
if ( millis() - start > 200 ) //has it been 200ms?
{
digitalWrite(valve2,LOW); //turn valve2 is off
state = 2; //valve2 is done
}
}
}
}