Эскиз, который отвечает на определенные команды, как это делается?

Хорошо, у меня есть наполовину полный эскиз Arduino на данный момент. В основном, скриншот ниже будет мигать светодиодом на мини-экране kegboard, если строка символов равна *{blink_Flow_A}* Однако светодиод только мигает один раз, когда текущий скетч загружен в 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 ответа

Решение

Конечный автомат (в самом простом - он может быть намного более сложным) может быть просто набором условных операторов (if/else или switch/case), где вы выполняете определенные действия, основанные на состоянии переменной, а также изменяете эту переменную государство. Таким образом, его можно рассматривать как способ обработки или прохождения ряда условий.

Итак, у вас есть состояние вашего светодиода / клапана - он либо мигает (открыт), либо не мигает (закрыт). В псевдокоде здесь:

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

Мигающая светодиодная часть должна быть легко реализована, если вы понимаете суть кода выше. checkForCorrectCommand() bit - это функция, которую вы пишете для проверки того, что вы вводите - ключ, последовательный порт, кнопка и т. д. Он должен возвращать логическое значение.

Чтобы мигать светодиодом, не блокируя программу, я предлагаю вам использовать 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" для подсветки синтаксиса кода.

Позвольте мне предложить предложенный эскиз с несколькими изменениями. Идея Бастиена об использовании таймера довольно хороша и делает код намного проще. Подход, который я бы предложил, заключается в том, чтобы таймер срабатывал вечно с фиксированным интервалом (100 миллисекунд в моем эскизе). Если светодиод не должен мигать, он остается выключенным. Если светодиод должен мигать, он выключается и включается или наоборот при каждом выключении таймера.

#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. Функция настройки устанавливает таймер с интервалом в 100 миллисекунд и присоединяет процедуру обратного вызова. Основываясь на моем тестировании, это нужно сделать только один раз.

  2. Основной цикл просто игнорирует все, если входная строка не завершена. Если входная строка готова, то входная строка проверяется на наличие двух известных значений и предпринимаются соответствующие шаги. Входная строка затем отбрасывается.

  3. Процедура обратного вызова таймера выключает светодиод, если мы не находимся в режиме мигания. В противном случае он просто переключает состояние светодиода.

  4. Процедуры притока и оттока устанавливают состояние мигания по мере необходимости и управляют клапаном

  5. Процедура последовательного события имеет два изменения. Во-первых, ввод игнорируется (и сохраняется в буфере), если строка ввода уже завершена. Это сохранит команды, которые отправляются в Arduino во время обработки текущей команды. Во-вторых, символ новой строки не добавляется во входную строку. Это делает проверку входной строки немного проще.

Возможно, что-то вроде примера "мигать без задержки" в IDE. Вы проверяете время и решаете, когда и как заменить светодиод / цифровой выход.

// 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);
}
}
Другие вопросы по тегам