Включение и выключение светодиода с помощью 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)
Схема
Android-приложение
Приложение использует MIT App Inventor 2 с тремя горизонтальными контейнерами, кнопками состояния LED с цветовой обратной связью.
Структура команд: L10 (LED1 выкл), L11 (LED1 вкл), L20 (LED2 выкл), L21 (LED2 вкл), L30 (LED3 выкл), L31 (LED3 вкл).
Блоки App Inventor
Скетч 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 можно на странице оригинальной статьи.