Arduino Uno用一个按钮控制多个LED不同的时间

时间:2014-12-20 08:01:57

标签: while-loop arduino interrupt arduino-uno

提前感谢您的帮助。

场景概述

在现实世界中,我使用一个按钮打开两个机械阀门,但其中一个阀门应在一段时间后关闭,我们将硬编码到草图中,另一个阀门保持打开状态为止按下按钮。为了概念验证,我点亮两个LED作为阀门的替身。

伪代码

如果按下按钮一,Valve One应该打开,Valve 2也应该打开200ms然后关闭。

初始解决方案

在主循环中,我查找按钮作为if语句的一部分被推送。当这个条件通过时,我使用了一个while循环和计时器来保持“valve2”打开,直到时间结束。 LED工作,一切都表面上很好。然而...

问题

当我的伴侣开始将实际机械装置放在一起时,阀门2不会打开,因为while循环的循环速度非常快,以至于启动阀门打开所需的电压不够高。

我的问题

  1. 是否可以隔离(不使用延迟)环路和放大器。从主回路评估定时器条件,以便将全功率发送到阀门机构(或在这种情况下为LED)?或者我是否在思考整个事情(可能是这种情况)?
  2. 守则

    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];
    }
    

1 个答案:

答案 0 :(得分:0)

为了使代码同时a)保持循环以检查按钮,以及b)实现valve2的所需行为,您需要一个软件状态机来跟踪Valve2正在做什么。在下面的代码中,我重命名了你的state1和state2变量,这样我就可以引入一个控制valve2的新state变量。

state变量通常处于idle状态。

按下button1时

  • valve2已打开
  • 采用时间戳
  • state已更改为active

延迟200毫秒后

  • valve2已关闭
  • 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
            }
        }
    }
}