Асинхронное программирование на Arduino с ProtoThreads

Я изучаю Arduino. Наше текущее задание - написать программу "Железнодорожный переезд": В нормальной (безопасной) ситуации: мигать белым светом. Когда нажата кнопка или датчик освещенности получает меньше света, издайте предупреждающий звук в течение 5 секунд и дайте двум красным лампочкам мигать в течение 20 секунд.

Я написал полностью работающее решение, в котором сам запрограммировал полную оркестровку.

Но есть еще один способ - использовать многозадачную библиотеку, например ProtoThreads.

Мне удалось заставить его несколько работать, но код уродливый. У меня такое чувство, что я все еще должен слишком много оркестрировать самому, вместо того, чтобы позволить библиотеке позаботиться обо всем этом. (Я мог бы добавить время, когда зуммер должен издавать звук, как в тоне (BUZZER_PIN, 400, 5000), что бы все упростило, но я действительно хочу понять, как работает асинхронное программирование.)

Это моя первая асинхронная программа. Приветствуются любые URL-адреса с лучшими практиками.

Схема Arduino

    /*
       Train level crossing

       Design and create an electric circuit and associated program for a train level crossing.

       In a normal safe situation, a white light (LED) flashes endlessly.
       The arrival of a train can be detected in two ways: A) by mechanical means: pushing a button or B) by optical detection: by using a light sensor.
       In both cases, a warning is given by ringing a bell (Buzzer) and by flashing two red lights alternately.
       The Buzzer makes a sound for 5 seconds. The red lights flash for 20 seconds.
       After that, the train level crossing is considered safe again and everything reverts back to the normal safe situation (white lights flash).
       Pushing the button or casting a shadow on the light sensor during the warning period does not extend the warning period.

       Hint: Find out why the function millis() is a better alternative for the function delay() we have used so far.
    */

    //This solution uses ProtoThreads (pt)
    #include <pt.h>

    static struct pt pt_safe, pt_train, pt_buzzer, pt_red_lights;

    //PINs of the button, buzzer, light sensor and flashing light LEDs
    const int BUTTON_PIN = 2;  // push button
    const int BUZZER_PIN = 8;
    const int WHITE_LED_PIN = 11;
    const int RED_LED_LEFT_PIN = 12;
    const int RED_LED_RIGHT_PIN = 13;
    const int LIGHTSENSOR_PIN = A0;

    const long timeIntervalWhiteLed = 500;    //the white LED blinks twice per second: 0.5 sec ON, 0.5 sec OFF.
    const long timeIntervalRedLeds = 500;     //the red LEDs blink twice per second: 0.5 sec ON, 0.5 sec OFF. The two red lights flash alternately: when one is ON, the other is OFF.
    const long timeIntervalRedLights = 20000; //red lights must flash for 20 secs
    const long timeIntervalBuzzer = 5000;     //Buzzer must sound for 5 secs

    String stateFlag = "SAFE";  // can be "SAFE" or "TRAIN"

    void AllLightsOFF() {
      // turn all lights OFF and silence the buzzer
      // before setting any light ON, do call this function to make sure only one light will be ON
      digitalWrite(RED_LED_LEFT_PIN, LOW);
      digitalWrite(RED_LED_RIGHT_PIN, LOW);
      digitalWrite(WHITE_LED_PIN, LOW);
      noTone(BUZZER_PIN);
    }

    static int protothreadRedFlashingLights(struct pt *pt_safe)
    {
      static unsigned long TimeRedLed;
      PT_BEGIN(pt_safe);
      while (1) {
        PT_WAIT_UNTIL(pt_safe, stateFlag == "TRAIN");
        TimeRedLed = millis();
        digitalWrite(RED_LED_LEFT_PIN, LOW);
        digitalWrite(RED_LED_RIGHT_PIN, HIGH);
        PT_WAIT_UNTIL(pt_safe, millis() - TimeRedLed > timeIntervalRedLeds);
        TimeRedLed = millis();
        digitalWrite(RED_LED_LEFT_PIN, HIGH);
        digitalWrite(RED_LED_RIGHT_PIN, LOW);
        PT_WAIT_UNTIL(pt_safe, millis() - TimeRedLed > timeIntervalRedLeds);
        if (stateFlag == "SAFE") {  //had to add this code. Otherwise one red LED stays ON
          digitalWrite(RED_LED_LEFT_PIN, LOW);
          digitalWrite(RED_LED_RIGHT_PIN, LOW);
        }
      }
      PT_END(pt_safe);
    }

    static int protothreadWhiteFlashingLight(struct pt *pt)
    {
      static unsigned long TimeWhiteLed = millis();
      PT_BEGIN(pt);
      while (1) {
        PT_WAIT_UNTIL(pt, stateFlag == "SAFE");
        TimeWhiteLed = millis();
        PT_WAIT_UNTIL(pt, (millis() - TimeWhiteLed > timeIntervalWhiteLed));
        digitalWrite(WHITE_LED_PIN, HIGH);
        TimeWhiteLed = millis();
        PT_WAIT_UNTIL(pt, (millis() - TimeWhiteLed > timeIntervalWhiteLed));
        digitalWrite(WHITE_LED_PIN, LOW);
      }
      PT_END(pt);
    }

    //Sets the stateFlag to "TRAIN" when the button is pressed or a shadow is cast over the light sensor.
    //Sets the stateFlag back to "SAFE" when 20 seconds have passed since the stateFlag was set to "TRAIN".
    static int protothreadDetectTrain(struct pt *pt)
    {
      static unsigned long timeTrainSequence;
      PT_BEGIN(pt);
      while (1) {
        PT_WAIT_UNTIL(pt, analogRead(LIGHTSENSOR_PIN) <= 800 || digitalRead(BUTTON_PIN) == LOW);
        if (stateFlag == "SAFE") {
          //print debug information
          Serial.println("1) lightsensor: " + (String)analogRead(LIGHTSENSOR_PIN) + ", buttonState: " + (String)digitalRead(BUTTON_PIN) + ", stateFlag: " + stateFlag + ".");
          stateFlag = "TRAIN";
          timeTrainSequence = millis();
          AllLightsOFF();
        }
        PT_WAIT_UNTIL(pt, millis() - timeTrainSequence > timeIntervalRedLights);
        if (stateFlag = "TRAIN") {
          Serial.println("2) lightsensor: " + (String)analogRead(LIGHTSENSOR_PIN) + ", buttonState: " + (String)digitalRead(BUTTON_PIN) + ", stateFlag: " + stateFlag + ".");
          stateFlag = "SAFE";
          AllLightsOFF();
        }
      }
      PT_END(pt);
    }

    static int protothreadBuzzer(struct pt *pt)
    {
      static unsigned long timeBuzzer;
      PT_BEGIN(pt);
      while (1) {
        PT_WAIT_UNTIL(pt, stateFlag == "TRAIN");
        timeBuzzer = millis();
        tone(BUZZER_PIN, 400);
        PT_WAIT_UNTIL(pt, millis() - timeBuzzer > timeIntervalBuzzer);
        noTone(BUZZER_PIN);
        PT_WAIT_UNTIL(pt, stateFlag == "SAFE");  //this feels ugly and unnecessary
      }
      PT_END(pt);
    }

    void setup() {
      pinMode(BUTTON_PIN, INPUT_PULLUP);
      pinMode(BUZZER_PIN, OUTPUT);
      pinMode(RED_LED_LEFT_PIN, OUTPUT);
      pinMode(RED_LED_RIGHT_PIN, OUTPUT);
      pinMode(WHITE_LED_PIN, OUTPUT);
      Serial.begin(9600);  //initialise the serial communicaton for debugging

      //start with safe situation, white lights flash. Buzzer and red lights OFF
      stateFlag = "SAFE";
      AllLightsOFF();

      //initialise protothread variables
      PT_INIT(&pt_safe);
      PT_INIT(&pt_train);
      PT_INIT(&pt_buzzer);
      PT_INIT(&pt_red_lights);
    }

    void loop() {
      Serial.println("lightsensor: " + (String)analogRead(LIGHTSENSOR_PIN) + ", buttonState: " + (String)digitalRead(BUTTON_PIN) + ", stateFlag: " + stateFlag + ".");
      protothreadWhiteFlashingLight(&pt_safe);
      protothreadDetectTrain(&pt_train);
      protothreadBuzzer(&pt_buzzer);
      protothreadRedFlashingLights(&pt_red_lights);
    }

0 ответов

Другие вопросы по тегам