草图响应某些命令,它是如何完成的?

好吧,我现在有一个半完整的Arduino草图。 基本上,如果一串字符等于* {blink_Flow_A},下面的草图将使kegboard-mini屏蔽上的LED闪烁*但是,只有当Arduino上加载的当前草图时,LED才会闪烁一次。 我希望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上的某人告诉我研究状态机scrapy头

状态机(最简单 – 可能要复杂得多)可以只是一组条件语句(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()位是您编写的函数,用于检查输入的内容 – 键,串行,按钮等。它应返回一个布尔值。

要在不阻止程序的情况下使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”放在代码上进行语法高亮显示。

也许类似于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); } } 

让我提供一个建议的草图,但有一些变化。 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的命令。 其次,换行符未添加到输入字符串中。 这使得检查输入字符串更容易一些。