Включение и выключение светодиода с помощью Arduino. Часть 3 — 3 LED и 3 переключателя

Это третья часть руководства по Bluetooth-управлению светодиодами между Arduino и Android. В этом руководстве мы управляем 3 светодиодами и 3 переключателями через Arduino, Bluetooth (HC-05/HC-06) и Android-приложение, созданное с помощью MIT App Inventor 2.

Я рекомендую посмотреть код из Части 2, попытаться понять, как он работает, а затем сравнить его с кодом в этой Части 3.

Компоненты

Аппаратное обеспечение:

  • Плата Arduino (Uno, Nano, Leonardo или Mega с корректировкой пинов)

  • Bluetooth-модуль HC-05 или HC-06

  • 3 светодиода с резисторами 220 Ом

  • 3 кнопки с подтягивающими резисторами 10 кОм

  • Библиотека AltSoftSerial для последовательной связи

Распиновка:

  • Светодиоды: пины 2, 3, 4

  • Переключатели: пины 5, 6, 7

  • Bluetooth TX/RX: зависит от платы (Leonardo использует пины 5, 13; Mega — пины 46, 48)

Схема

https://alashed-media.s3.eu-north-1.amazonaws.com/wiki/martyncurrey/turning-a-led-on-and-off-part3-1.jpg https://alashed-media.s3.eu-north-1.amazonaws.com/wiki/martyncurrey/turning-a-led-on-and-off-part3-2.jpg

Android-приложение

Приложение использует MIT App Inventor 2 с тремя горизонтальными контейнерами, кнопками состояния LED с цветовой обратной связью.

https://alashed-media.s3.eu-north-1.amazonaws.com/wiki/martyncurrey/turning-a-led-on-and-off-part3-3.jpg

Структура команд: L10 (LED1 выкл), L11 (LED1 вкл), L20 (LED2 выкл), L21 (LED2 вкл), L30 (LED3 выкл), L31 (LED3 вкл).

https://alashed-media.s3.eu-north-1.amazonaws.com/wiki/martyncurrey/turning-a-led-on-and-off-part3-4.jpg

Блоки App Inventor

https://alashed-media.s3.eu-north-1.amazonaws.com/wiki/martyncurrey/turning-a-led-on-and-off-part3-5.jpg https://alashed-media.s3.eu-north-1.amazonaws.com/wiki/martyncurrey/turning-a-led-on-and-off-part3-6.jpg https://alashed-media.s3.eu-north-1.amazonaws.com/wiki/martyncurrey/turning-a-led-on-and-off-part3-7.jpg https://alashed-media.s3.eu-north-1.amazonaws.com/wiki/martyncurrey/turning-a-led-on-and-off-part3-8.jpg

Скетч Arduino — простой подход

Два подхода реализации показаны здесь.

Простой подход: прямое дублирование блоков кода для каждого светодиода/переключателя, приоритет отдаётся читаемости.

Константы и переменные:

// Константы для аппаратного обеспечения
const byte LED1_PIN = 2;
const byte LED2_PIN = 3;
const byte LED3_PIN = 4;
const byte SWITCH1_PIN = 5;
const byte SWITCH2_PIN = 6;
const byte SWITCH3_PIN = 7;

// Общие переменные
boolean LED1_State = false;
boolean LED2_State = false;
boolean LED3_State = false;
boolean switch1_State = false;
boolean switch2_State = false;
boolean switch3_State = false;
boolean oldswitch1_State = false;
boolean oldswitch2_State = false;
boolean oldswitch3_State = false;

Обработка команд (простой подход):

if (strcmp ("L10",receivedChars) == 0)
    {
        digitalWrite(LED1_PIN,LOW);
        LED1_State = LOW;
        Serial.println("LED1 LOW");
    }

    else if (strcmp ("L11",receivedChars) == 0)
    {
        digitalWrite(LED1_PIN,HIGH);
        LED1_State = HIGH;
        Serial.println("LED1 HIGH");
    }

    else if (strcmp ("L20",receivedChars) == 0)
    {
        digitalWrite(LED2_PIN,LOW);
        LED2_State = LOW;
        Serial.println("LED2 LOW");
    }

    else if (strcmp ("L21",receivedChars) == 0)
    {
        digitalWrite(LED2_PIN,HIGH);
        LED2_State = HIGH;
        Serial.println("LED2 HIGH");
    }
    else if (strcmp ("L30",receivedChars) == 0)
    {
        digitalWrite(LED3_PIN,LOW);
        LED3_State = LOW;
        Serial.println("LED3 LOW");
    }

    else if (strcmp ("L31",receivedChars) == 0)
    {
        digitalWrite(LED3_PIN,HIGH);
        LED3_State = HIGH;
        Serial.println("LED3 HIGH");
    }

Альтернативный подход с разбором символов:

if (receivedChars[0] == 'L')                  //  Команда LED?
     {
          if  (receivedChars[1] == '1')            // Команда для LED номер 1?
          {
               if  (receivedChars[2] == '0')       // LED выключен?
               {
                    digitalWrite(LED1_PIN,LOW);
                    LED1_State = LOW;
                    Serial.println("LED1 LOW");
               }
               else if (receivedChars[2] == '1')   // Или LED включён?
               {
                    digitalWrite(LED1_PIN,LOW);
                    LED1_State = LOW;
                    Serial.println("LED1 LOW");
               }
          }

          // Мы уже знаем, что это команда LED, не нужно перепроверять.
          if  (receivedChars[1] == '2')            // Команда для LED номер 2?

          {
               if  (receivedChars[2] == '0')       // LED выключен?
               {
                    digitalWrite(LED2_PIN,LOW);
                    LED2_State = LOW;
                    Serial.println("LED2 LOW");
               }
               else if (receivedChars[2] == '1')   // Или LED включён?
               {
                    digitalWrite(LED2_PIN,LOW);
                    LED1_State = LOW;
                    Serial.println("LED2 LOW");
               }
          }

          // код для LED #3 не показан.
     }

Хотя использование strcmp() — самый прямолинейный подход:

if (strcmp ("L10",receivedChars) == 0)

Функция checkSwitch (простой подход):

void checkSwitch()
{
     // Простая функция переключения с простым дребезгоподавлением
     boolean state1 = digitalRead(SWITCH1_PIN); delay(1);
     boolean state2 = digitalRead(SWITCH1_PIN); delay(1);
     boolean state3 = digitalRead(SWITCH1_PIN); delay(1);
     if ((state1 == state2) && (state1==state3))
     {

          switch1_State = state1;
          if ( (switch1_State == HIGH) && (oldswitch1_State == LOW) )
          {
               LED1_State = ! LED1_State;
               if ( LED1_State == HIGH)
               {
                    BTserial.print("<L,1,1>" );
                    digitalWrite(LED1_PIN,HIGH);
                    Serial.println("Sent - <L,1,1>");
               }

               else
               {
                   BTserial.print("<L,1,0>");
                   digitalWrite(LED1_PIN,LOW);
                   Serial.println("Sent - <L,1,0>");
               }
          }
          oldswitch1_State = switch1_State;
      }

     // Простая функция переключения с простым дребезгоподавлением
     state1 = digitalRead(SWITCH2_PIN); delay(1);
     state2 = digitalRead(SWITCH2_PIN); delay(1);
     state3 = digitalRead(SWITCH2_PIN); delay(1);
     if ((state1 == state2) && (state1==state3))
     {
          switch2_State = state1;
          if ( (switch2_State == HIGH) && (oldswitch2_State == LOW) )
          {
               LED2_State = ! LED2_State;
               if ( LED2_State == HIGH)
               {
                    BTserial.print("<L,2,1>" );
                    digitalWrite(LED2_PIN,HIGH);
                    Serial.println("Sent - <L,2,1>");
               }

               else
               {
                   BTserial.print("<L,2,0>");
                   digitalWrite(LED2_PIN,LOW);
                   Serial.println("Sent - <L,2,0>");
               }
          }
          oldswitch2_State = switch2_State;
      }

     // Простая функция переключения с простым дребезгоподавлением
     state1 = digitalRead(SWITCH3_PIN); delay(1);
     state2 = digitalRead(SWITCH3_PIN); delay(1);
     state3 = digitalRead(SWITCH3_PIN); delay(1);
     if ((state1 == state2) && (state1==state3))
     {
          switch3_State = state1;
          if ( (switch3_State == HIGH) && (oldswitch3_State == LOW) )
          {
               LED3_State = ! LED3_State;
               if ( LED3_State == HIGH)
               {
                    BTserial.print("<L,3,1>" );
                    digitalWrite(LED3_PIN,HIGH);
                    Serial.println("Sent - <L,3,1>");
               }

               else
               {
                   BTserial.print("<L,3,0>");
                   digitalWrite(LED3_PIN,LOW);
                   Serial.println("Sent - <L,3,0>");
               }
          }
          oldswitch3_State = switch3_State;
      }
}

Скетч Arduino — компактный подход

Компактный подход: использует массивы для пинов и состояний, уменьшая объём кода, но увеличивая сложность.

// Константы для аппаратного обеспечения
const byte LED_PIN[] = {2,3,4};
const byte SWITCH_PIN[] = {5,6,7};

// Общие переменные
boolean LED_State[] = {false,false,false};
boolean switch_State[] = {false,false,false};
boolean oldswitch_State[] = {false,false,false};
void setup()
{
    for (byte pin = 0; pin < 3; pin++)
    {
         // Устанавливаем пины кнопок на вход
         pinMode(SWITCH_PIN[pin], INPUT);

         // Устанавливаем пины LED на выход и LOW
         pinMode(LED_PIN[pin], OUTPUT);  digitalWrite(LED_PIN[pin],LOW);
    }
void loop()
{
    for (byte switchNum = 1; switchNum < 4; switchNum++)
    {
           checkSwitch(switchNum);
    }
    recvWithStartEndMarkers();                // проверяем новые команды
    if (newData)  {   processCommand();  }    // обрабатываем команду
}
void checkSwitch( byte pos)
{
     // pos = 1,2,3. Индекс массива = 0,1,2, поэтому вычитаем 1
     pos = pos-1;

     // очень простое дребезгоподавление
     boolean state1 = digitalRead(SWITCH_PIN[pos]); delay(1);
     boolean state2 = digitalRead(SWITCH_PIN[pos]); delay(1);
     boolean state3 = digitalRead(SWITCH_PIN[pos]); delay(1);
     if ((state1 == state2) && (state1==state3))
     {
          switch_State[pos] = state1;
          if ( (switch_State[pos] == HIGH) && (oldswitch_State[pos] == LOW) )
          {
               LED_State[pos] = ! LED_State[pos];  // переключаем состояние

               char TMPcmd[8] = "<L,1,0>";
               TMPcmd[3] = pos+1+48;             // pos+1 — номер LED; 1,2 или 3
                                                 // Преобразуем числовое значение в ASCII, добавив 48
               TMPcmd[5] = LED_State[pos]+48;    // LED_State должен быть 0 или 1
               BTserial.print(TMPcmd);

               digitalWrite(LED_PIN[pos],LED_State[pos]);
               Serial.println(TMPcmd);
          }
          oldswitch_State[pos] = switch_State[pos];
      }
}
void processCommand()
{
     Serial.print("receivedChars = ");   Serial.println(receivedChars);

    if (receivedChars[0] == 'L')      // команда LED?
    {
        // мы знаем, что команда LED имеет фиксированную длину "L10"
        // значение по позиции 1 — номер LED, по позиции 2 — 0 или 1 (вкл/выкл)
        // 0 и 1 совпадают с LOW и HIGH

        byte LEDnum = receivedChars[1] - 48;          // преобразуем ASCII в число, вычитая 48
        boolean LEDstatus = receivedChars[2] - 48;

        digitalWrite(LED_PIN[LEDnum-1],LEDstatus);
        LED_State[LEDnum-1] = LEDstatus;
    }
    receivedChars[0] = '\0';
    newData = false;
}

Ещё более компактная версия с одной строкой:

digitalWrite(LED_PIN[(receivedChars[2]-48)-1],receivedChars[2]-48);
LED_State[(receivedChars[1]-48)-1] = receivedChars[2]-48;

Скачать

Скачать полные скетчи и файлы App Inventor 2 можно на странице оригинальной статьи.