0

好吧,我现在有一个半完整的 Arduino 草图。基本上,如果一串字符等于 *{blink_Flow_A}*,则下面的草图将在 kegboard-mini shield 上闪烁 LED,但是 LED 仅在当前草图加载到 Arduino 时闪烁一次。我希望 Arduino 反复闪烁,直到“停止”命令发送到 Arduino。我最终想打开一个阀门,让它保持打开状态,直到阀门收到关闭命令,然后关闭阀门。草图如下所示,

/*
 * kegboard-serial-simple-blink07
 * This code is public domain
 *
 * This sketch sends a receives a multibyte String from the iPhone
 * and performs functions on it.
 *
 * Examples:
 * http://arduino.cc/en/Tutorial/SerialEvent
 * http://arduino.cc/en/Serial/read
 */

 // global variables should be identified with _

 // flow_A LED
 int led = 4;

 // relay_A
 const int RELAY_A = A0;

 // variables from sketch example
 String inputString = ""; // a string to hold incoming data
 boolean stringComplete = false; // whether the string is complete

 void setup() {

   Serial.begin(2400); // open serial port, sets data rate to 2400bps
   Serial.println("Power on test");
   inputString.reserve(200);

   pinMode(RELAY_A, OUTPUT);
}

void open_valve() {

  digitalWrite(RELAY_A, HIGH); // turn RELAY_A on

}

void close_valve() {

  digitalWrite(RELAY_A, LOW); // turn RELAY_A off
}

void flow_A_blink() {

  digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
  delay(1000);              // wait for one second
  digitalWrite(led, LOW);   // turn the LED off by making the voltage LOW
  delay(1000);              // wait for a second
}

void flow_A_blink_stop() {

  digitalWrite(led, LOW);
}

void loop() {
  // print the string when newline arrives:
  if (stringComplete) {
    Serial.println(inputString);
    // clear the string:
    inputString = "";
    stringComplete = false;
  }

  if (inputString == "{blink_Flow_A}") {
    flow_A_blink();
  }
}

//SerialEvent occurs whenever a new data comes in the
//hardware serial RX.  This routine is run between each
//time loop() runs, so using delay inside loop can delay
//response.  Multiple bytes of data may be available.

void serialEvent() {
  while(Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag
    // so the main loop can do something about it:
    if (inChar == '\n') {
      stringComplete = true;
    }
  }
}

如果这有什么不同的话,IRC 上的某个人告诉我研究状态机会挠头

4

4 回答 4

1

要在不阻塞程序的情况下闪烁 LED,我建议您使用 Timer(和TimerOne 库)。我制作了一个快速示例代码:

#include "TimerOne.h" //Include the librart, follow the previous link to download and install.

int LED = 4;
const int RELAY_A = A0;  
boolean ledOn;

void setup()
{
    pinMode(LED, OUTPUT)
    Timer1.initialise(500000) // Initialise timer1 with a 1/2 second (500000µs) period
    ledOn = false;
}

void blinkCallback() // Callback function call every 1/2 second when attached to the timer
{
    if(ledOn){
        digitalWrite(LED,LOW);
        ledOn = false;
    }
    else{
        digitalWrite(LED,HIGH);     
        ledOn = true;
    }
}

void open_valve() {

  digitalWrite(RELAY_A, HIGH); // turn RELAY_A on

}

void close_valve() {

  digitalWrite(RELAY_A, LOW); // turn RELAY_A off
}

void serialEvent() {
  while(Serial.available()) {
    char inChar = (char)Serial.read();
    inputString += inChar;
    if (inChar == '\n') {
      stringComplete = true;
    }
  }
}

void loop()
{
    // print the string when newline arrives:
  if (stringComplete) {
    Serial.println(inputString);
    // clear the string:
    inputString = "";
    stringComplete = false;
  }


  if (inputString == "{blink_Flow_A}") {
    Timer1.attachInterupt(blinkCallback); //Start blinking
  }
  if (inputString == "{stop}") {
    Timer1.detachInterrupt(); //Stop blinking
  }
  if (inputString == "{open_valve}") {
    open_valve();
  }
  if (inputString == "{close_valve}") {
    close_valve();
  }
}  

注意:
考虑将标记“c”或“java”放在代码上以突出显示语法。

于 2013-05-14T07:09:02.950 回答
0

可能类似于IDE中的“立即闪烁”示例。您检查时间并决定何时以及如何更改 LED/数字输出。

// Variables will change:
int ledState = LOW;             // ledState used to set the LED
long previousMillis = 0;        // will store last time LED was updated

// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval = 1000;           // interval at which to blink (milliseconds)

void setup(){
    // Your stuff here
}


void loop()
{
 // Your stuff here.

 // check to see if it's time to blink the LED; that is, if the 
 // difference between the current time and last time you blinked 
 // the LED is bigger than the interval at which you want to 
 // blink the LED.
 unsigned long currentMillis = millis();

if(currentMillis - previousMillis > interval) {
  // save the last time you blinked the LED 
  previousMillis = currentMillis;   

  // if the LED is off turn it on and vice-versa:
  if (ledState == LOW)
    ledState = HIGH;
  else
    ledState = LOW;

  // set the LED with the ledState of the variable:
  digitalWrite(ledPin, ledState);
}
}
于 2013-05-13T23:55:36.803 回答
0

状态机(最简单 - 它可能更复杂)可以只是一组条件语句(if/else 或 switch/case),您可以在其中根据变量的状态执行某些行为,并更改该变量状态。所以它可以被认为是一种处理或通过一系列条件的方式。

所以你有你的 LED/阀门的状态——它要么闪烁(打开),要么不闪烁(关闭)。在这里的伪代码中:

boolean LED_state = false;  //init to false/closed

void loop(){

 if (checkForCorrectCommand() == true){ //

   if (LED_State == false){
     open_valve();
     LED_State = true;

   } else {
     close_valve();
     LED_State = false;
   }
 }
}

如果您了解了上面代码的要点,闪烁的 LED 部分应该很容易实现。该checkForCorrectCommand()位是您编写的一个函数,用于检查您的输入是什么 - 键、串行、按钮等。它应该返回一个布尔值。

于 2013-05-14T02:07:03.733 回答
0

让我提供一个建议的草图,并进行一些更改。Bastyen 使用计时器的想法非常好,并且使代码更容易。我建议的方法是让计时器以固定的间隔(在我的草图中为 100 毫秒)永远弹出。如果 LED 不应该闪烁,它会保持关闭状态。如果 LED 应该闪烁,它会在每次定时器关闭时从关闭切换到打开,反之亦然。

#include "TimerOne.h"
/*
 * kegboard-serial-simple-blink07
 * This code is public domain
 *
 * This sketch sends a receives a multibyte String from the iPhone
 * and performs functions on it.
 *
 * Examples:
 * http://arduino.cc/en/Tutorial/SerialEvent
 * http://arduino.cc/en/Serial/read
 */

 // global variables should be identified with _

 // flow_A LED
 int led = 4;
 // relay_A
 const int RELAY_A = A0;

 // variables from sketch example
 String  inputString = ""; // a string to hold incoming data
 boolean stringComplete = false; // whether the string is complete

 boolean shouldBeBlinking = false;
 boolean ledOn = false;

void setup() {
   Serial.begin(9600); // open serial port, sets data rate to 2400bps
   Serial.println("Power on test");
   inputString.reserve(200);
   pinMode(RELAY_A, OUTPUT);
   pinMode(led, OUTPUT);
   digitalWrite(led, LOW);
   Timer1.initialize(100000);
   Timer1.attachInterrupt(timer1Callback);
}

void loop() {  
  if (!stringComplete)
    return;
  if (inputString == "{blink_Flow_A}") 
    flow_A_blink_start();    
  if (inputString == "{blink_Flow_B}") 
    flow_A_blink_stop();
  inputString = "";
  stringComplete = false;
}

void timer1Callback() {
  /* If we are not in blinking mode, just make sure the LED is off */  
  if (!shouldBeBlinking) {
    digitalWrite(led, LOW);
    ledOn = false;
    return;
  }
  /* Since we are in blinking mode, check the state of the LED. Turn
     it off if it is on and vice versa. */
  ledOn = (ledOn) ? false : true; 
  digitalWrite(led, ledOn);
}  

void flow_A_blink_start() {
  shouldBeBlinking = true;
  open_valve();
}

void flow_A_blink_stop() {
  shouldBeBlinking = false;
  close_valve();  
}

void close_valve() {
  digitalWrite(RELAY_A, LOW); // turn RELAY_A off
}

void open_valve() {
  digitalWrite(RELAY_A, HIGH); // turn RELAY_A on
}


//SerialEvent occurs whenever a new data comes in the
//hardware serial RX.  This routine is run between each
//time loop() runs, so using delay inside loop can delay
//response.  Multiple bytes of data may be available.

void serialEvent() {
  if (stringComplete)
    return;  
  while(Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString unless it is a newline
    if (inChar != '\n')
      inputString += inChar;
    // if the incoming character is a newline, set a flag
    // so the main loop can do something about it:
    else {
      stringComplete = true;
    }
  }
}

几点注意事项:

  1. setup 函数以 100 毫秒的间隔建立计时器并附加回调例程。根据我的测试,这只需要执行一次。

  2. 除非输入字符串完整,否则主循环会忽略所有内容。如果输入字符串已准备好,则检查输入字符串的两个已知值并采取适当的步骤。然后丢弃输入字符串。

  3. 如果我们不处于闪烁模式,定时器回调例程会强制关闭 LED。否则,它只会切换 LED 的状态。

  4. 流量打开和流量关闭程序根据需要设置闪烁状态并控制阀门

  5. 串行事件例程有两个变化。首先,如果输入字符串已经完成,则忽略输入(并保留在缓冲区中)。这将保留在处理当前命令时发送到 Arduino 的命令。其次,换行符不会添加到输入字符串中。这使得检查输入字符串稍微容易一些。

于 2013-11-10T17:53:58.743 回答