Паяем Ардуино-совместимый контроллер и играем с интереснейшим шилдом

от автора

Привет, Хабр! Вас тоже огорчало, что PLS-разъёмы плат Arduino Uno и Mega установлены без соблюдения сетки с шагом 2.54 мм, отчего невозможно создать собственный шилд на базе обычной макетки под пайку?

А ещё обидно, что на упомянутых платах не предусмотрено никаких кнопок, кроме сброса, а программно управляемый светодиод есть, но всего один, если не считать присоединённых к линиям Tx и Rx, задействованным при загрузке скетча и обмене данными с компьютером. То есть, без подключения внешних компонентов почти ничего нельзя сделать.

Сегодня я соберу вариант Arduino Uno с тремя подключёнными к GPIO светодиодами и тремя кнопками, не считая сброса. А расположение разъёмов остаётся стандартным, чтобы не терять совместимости с шилдами.

Если вам нужны компактность и шаг 2.54 мм для паечных и беспаечных макетных плат, то лучше будет воспользоваться Arduino Nano. Но к нему не получится подключить стандартный шилд, в отличие от контроллера из набора OPEN-SMART UNO R3, сборкой которого мы займёмся.

▍ Процесс монтажа

При определении последовательности установки деталей на печатные платы обычно соблюдается простое правило: первыми монтируются компоненты с меньшей высотой.

Наш сегодняшний радиоконструктор — не исключение, и начинать мы будем с резисторов. Их здесь всего пять штук, четыре из которых номиналом 1 килоом и один 10-килоомный.

Лично я сначала устанавливаю те компоненты, которые имеются в большем количестве. Идея в том, что находить их посадочные места получается быстрее. По мере заполнения платы будет легче искать места под следующие компоненты среди меньшего числа пустых.

Далее следует припаять модуль преобразователя интерфейсов USB-UART, соблюдая ключ, который выглядит как кружочек на шелкографии платы и модуля.

Следующий этап — установка кнопки сброса, цангового разъёма под кварцевый резонатор и пяти керамических конденсаторов, три из которых служат фильтрами питания и имеют ёмкость 100 нанофарад. Два других конденсатора по 22 пикофарады задействованы в обвязке кварца.

Затем паяем кроватку под микроконтроллер, не забывая о соблюдении ключа.

Теперь настаёт очередь разъёма для внутрисхемного последовательного программирования, пищалки, электролитического конденсатора и светодиодов.

Все эти компоненты, кроме разъёма, имеют полярность. Следует быть внимательными, чтобы не установить какую-нибудь из деталей вверх ногами.

Сборка нашего Ардуино близится к завершению, и теперь нужно установить разъёмы для присоединения шилдов.

В последнюю очередь паяем разъём USB-B и три красивые большие кнопки. Останется только вставить в панельки кварц и микроконтроллер.

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

После подачи питания по USB-кабелю плата весело замигала светодиодом. Микроконтроллер в комплекте оказался прошит скетчем «Blink a LED», что в мире Ардуино является эквивалентом «Hello, world!» — «Привет, мир!».

Благодаря этому, для проверки работоспособности собранного устройства даже не нужен компьютер. Достаточно USB повербанка или блока питания напряжением 5 вольт.

Отметим, что стабилизатор питания на плате OPEN-SMART UNO R3, в отличие от классического Arduino Uno, не предусмотрен.

▍ Что может Ардуино?

Для дальнейшего знакомства с возможностями платы загрузим простейший демонстрационный скетч, написанный Стефаном Фамбахом.

#include "OpenSmartUnoR3.h"  void setup() {   Board.init(true); }  void loop() {   Board.loop();  }

Как видим, этот скетч просто инициализирует плату и запускает бесконечный цикл из демонстрационной библиотеки.

#ifndef OpenSmartUnoR3_h #define OpenSmartUnoR3_h #include "EasyBuzzer.h"  #define BUZZER 6  class OpenSmartUnoR3 {    protected:    bool _test;    EasyBuzzerClass eb;    public:     enum SWITCH {       SW1 = 2,       SW2 = 3,       SW3 = 4     };      enum LED {       LED1 = 7,       LED2 = 8,       LED3 = 13     };      void init(bool test = false) {       _test = test;       pinMode(LED1, OUTPUT);       pinMode(LED2, OUTPUT);       pinMode(LED3, OUTPUT);       pinMode(BUZZER, OUTPUT);        pinMode(SW1, INPUT_PULLUP);       pinMode(SW2, INPUT_PULLUP);       pinMode(SW3, INPUT_PULLUP);     }      void loop() {       if (_test) {           setLED(LED1, getSwitch(SW1));           setLED(LED2, getSwitch(SW2));           setLED(LED3, getSwitch(SW3));            if(getSwitch(SW1) && getSwitch(SW2)){             eb.beep(1000);           }else {             eb.stopBeep();           }       }     }      bool getSwitch(SWITCH sw) {         return !digitalRead(sw);     }      static void setLED(LED selected, bool status) {         digitalWrite(selected, status);     }  };

В свою очередь, библиотека определяет, к каким выводам Ардуино подключены кнопки и светодиоды, и что нужно делать в бесконечном цикле. Скетч зажигает светодиоды с номерами, соответствующими номерам нажатых кнопок. Если одновременно нажать вторую и третью кнопки, запищит зуммер, прямо как в устройстве для голосования на логических микросхемах. Для управления зуммером автор воспользовался сторонней библиотекой EasyBuzzer.

▍ Смотрим видео

Итак, мы убедились в работоспособности нашей платы. Теперь давайте сделаем что-нибудь более интересное. Для этого подключим к свежесобранному контроллеру Rich Shield Two от того же OPEN-SMART.

▍ Индикатор заряда батареи

Этот шилд содержит красивый светодиодный столбчатый индикатор, выполненный в виде батарейки с десятью светодиодами четырёх разных цветов — алого, янтарного, изумрудного и лазурного.

Для управления этим индикатором используется специализированная микросхема TM1651 — драйвер светодиодов с цифровой регулировкой яркости, функцией сканирования клавиатуры и двухпроводным последовательным интерфейсом.

Скетч устанавливает яркость светодиодов на максимум и имитирует индикацию процесса заряда аккумулятора.

#include "TM1651.h" #define CLK 10 // определяем, куда подключены выводы TM1651  #define DIO 11 TM1651 batteryDisplay(CLK,DIO); void setup() {   batteryDisplay.init();   batteryDisplay.set(BRIGHTEST);//BRIGHT_TYPICAL = 2,BRIGHT_DARKEST = 0,BRIGHTEST = 7;   batteryDisplay.frame(FRAME_ON); } void loop() {   charging(); }  void charging() {   for(uint8_t level = 0; level < 8; level ++)   {     batteryDisplay.displayLevel(level); delay(500);   } }

Для этого используется библиотека Battery Display.

TM1651.h

//  Author:Fred.Chu //  Date:14 August, 2014 // //  Applicable Module: //                     Battery Display v1.0 // //  This library is free software; you can redistribute it and/or //  modify it under the terms of the GNU Lesser General Public //  License as published by the Free Software Foundation; either //  version 2.1 of the License, or (at your option) any later version. // //  This library is distributed in the hope that it will be useful, //  but WITHOUT ANY WARRANTY; without even the implied warranty of //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU //  Lesser General Public License for more details. // //  You should have received a copy of the GNU Lesser General Public //  License along with this library; if not, write to the Free Software //  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA // //  Modified record: // /*******************************************************************************/  #ifndef TM1651_H #define TM1651_H #include <inttypes.h> #include <Arduino.h> //************definitions for TM1651********************* #define ADDR_AUTO  0x40 #define ADDR_FIXED 0x44  #define STARTADDR  0xc0  /**** definitions for the frame of the battery display *******/ #define FRAME_ON   1 #define FRAME_OFF  0 /**************definitions for brightness***********************/ #define  BRIGHT_DARKEST 0 #define  BRIGHT_TYPICAL 2 #define  BRIGHTEST      7  class TM1651 {   public: uint8_t Cmd_SetData; uint8_t Cmd_SetAddr; uint8_t Cmd_DispCtrl; TM1651(uint8_t, uint8_t); void init(); void writeByte(int8_t wr_data);//write 8bit data to tm1651 void start(void);//send start bits void stop(void); //send stop bits void displayLevel(uint8_t Level); void frame(boolean FrameFlag); void clearDisplay(void); void set(uint8_t = BRIGHT_TYPICAL,uint8_t = 0x40,uint8_t = 0xc0);//To take effect the next time it displays.   private: uint8_t Clkpin; uint8_t Datapin; void bitDelay(); }; #endif
TM1651.cpp

//  Author:Fred.Chu //  Date:14 August, 2014 // //  Applicable Module: //                     Battery Display v1.0 // //  This library is free software; you can redistribute it and/or //  modify it under the terms of the GNU Lesser General Public //  License as published by the Free Software Foundation; either //  version 2.1 of the License, or (at your option) any later version. // //  This library is distributed in the hope that it will be useful, //  but WITHOUT ANY WARRANTY; without even the implied warranty of //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU //  Lesser General Public License for more details. // //  You should have received a copy of the GNU Lesser General Public //  License along with this library; if not, write to the Free Software //  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA // //  Modified record: // /*******************************************************************************/ #include "TM1651.h" #include <Arduino.h> static int8_t LevelTab[] = {0x00,0x40,0x60,0x70,0x78,0x7c,0x7e,0x7f};//Level 0~7  TM1651::TM1651(uint8_t Clk, uint8_t Data) {   Clkpin = Clk;   Datapin = Data;   pinMode(Clkpin,OUTPUT);   pinMode(Datapin,OUTPUT); }  void TM1651::init() {   set(BRIGHT_TYPICAL);   clearDisplay(); }  void TM1651::writeByte(int8_t wr_data) {  uint8_t data = wr_data;   // 8 Data Bits  for(uint8_t i = 0; i < 8; i++) {    // CLK low    pinMode(Clkpin, OUTPUT);    bitDelay();     // Set data bit    if (data & 0x01)  pinMode(Datapin, INPUT);    else  pinMode(Datapin, OUTPUT);     bitDelay();     // CLK high    pinMode(Clkpin, INPUT);    bitDelay();    data = data >> 1;  }   // Wait for acknowledge  // CLK to zero  pinMode(Clkpin, OUTPUT);  pinMode(Datapin, INPUT);  bitDelay();   // CLK to high  pinMode(Clkpin, INPUT);  bitDelay();  uint8_t ack = digitalRead(Datapin);  if (ack == 0)    pinMode(Datapin, OUTPUT);    bitDelay();  pinMode(Clkpin, OUTPUT);  bitDelay();    } //send start signal to TM1651 void TM1651::start(void) { pinMode(Datapin, OUTPUT);  bitDelay(); }  //End of transmission void TM1651::stop(void) {   pinMode(Datapin, OUTPUT);   bitDelay();   pinMode(Clkpin, INPUT);   bitDelay();   pinMode(Datapin, INPUT);   bitDelay();    } //****************************************** void TM1651::displayLevel(uint8_t Level) {   if(Level > 7)return;//Level should be 0~7   start();          //start signal sent to TM1651 from MCU   writeByte(ADDR_FIXED);//   stop();           //   start();          //   writeByte(0xc0);//   writeByte(LevelTab[Level]);//   stop();            //   start();          //   writeByte(Cmd_DispCtrl);//   stop();           // }  void TM1651::frame(boolean FrameFlag) {   int8_t SegData;   if (FrameFlag == 1) SegData = 0x40;   else SegData = 0x00;   start();          //start signal sent to TM1651 from MCU   writeByte(ADDR_AUTO);//   stop();           //   start();          //   writeByte(0xc1);//   for(uint8_t i=0;i < 3;i ++)   {     writeByte(SegData);        //   }   stop();           //   start();          //   writeByte(Cmd_DispCtrl);//   stop();           // }  void TM1651::clearDisplay(void) {   displayLevel(0);   frame(FRAME_OFF); } //To take effect the next time it displays. void TM1651::set(uint8_t brightness,uint8_t SetData,uint8_t SetAddr) {   Cmd_SetData = SetData;   Cmd_SetAddr = SetAddr;   Cmd_DispCtrl = 0x88 + brightness;//Set the brightness and it takes effect the next time it displays. }  void TM1651::bitDelay() { delayMicroseconds(50); }

▍ Индикатор громкости

На плате шилда имеются простой микрофонный предусилитель и миниатюрный электретный микрофон.

А вот и скетч индикатора громкости звука. Он использует всю ту же библиотеку и просто считывает аналоговое значение с входа А2, а затем передаёт его столбчатому индикатору.

#include "TM1651.h"  #define CLK 10 // определяем, куда подключены выводы TM1651        #define DIO 11 TM1651 batteryDisplay(CLK,DIO);  #define SOUND_PIN A2 #define MAX_SENSORVALUE 1000 #define MIN_SENSORVALUE 8  void setup() {     batteryDisplay.init();     batteryDisplay.set(BRIGHTEST);//BRIGHT_TYPICAL = 2,BRIGHT_DARKEST = 0,BRIGHTEST = 7; } void loop() { int sensorValue = analogRead(SOUND_PIN);  int level = map(sensorValue, 0, MAX_SENSORVALUE, 0, MIN_SENSORVALUE);  batteryDisplay.displayLevel(level); }

▍ Светодиодная матрица

Две красные светодиодные матрицы 8×8 управляются с помощью одной микросхемы HT16K33.

Как и TM1651, она представляет собой драйвер светодиодов со сканером клавиатуры и интерфейсом I²C, только гораздо более продвинутый.

Графические библиотеки Adafruit позволяют выводить на светодиодную матрицу геометрические фигуры, текст и растровые изображения.

#include <Wire.h> #include <Adafruit_GFX.h> #include "Adafruit_LEDBackpack.h" #include <Adafruit_NeoPixel.h>  #define PIN A3 #define NUM 4 Adafruit_NeoPixel rgb = Adafruit_NeoPixel(NUM, PIN, NEO_GRB + NEO_KHZ800);  Adafruit_8x16matrix matrix = Adafruit_8x16matrix();  void setup() {   rgb.begin();   rgb.clear();   rgb.show();   matrix.begin(0x70);  // I²C адрес контроллера HT16K33 }  static const uint8_t PROGMEM   smile_bmp[] =   { B00111100,     B01000010,     B10100101,     B10000001,     B10100101,     B10011001,     B01000010,     B00111100 },   neutral_bmp[] =   { B00111100,     B01000010,     B10100101,     B10000001,     B10111101,     B10000001,     B01000010,     B00111100 },   frown_bmp[] =   { B00111100,     B01000010,     B10100101,     B10000001,     B10011001,     B10100101,     B01000010,     B00111100 };  void loop() {      matrix.clear();   matrix.drawBitmap(0, 0, smile_bmp, 8, 8, LED_ON);   matrix.writeDisplay();   delay(500);      matrix.clear();   matrix.drawBitmap(0, 8, neutral_bmp, 8, 8, LED_ON);   matrix.writeDisplay();   delay(500);    matrix.clear();   matrix.drawBitmap(0, 0, frown_bmp, 8, 8, LED_ON);   matrix.writeDisplay();   delay(500);    matrix.clear();      // очищаем дисплей   matrix.drawPixel(0, 0, LED_ON); // рисуем пиксель в программном буфере     matrix.writeDisplay();  // выгружаем изменения в дисплей   delay(500);    matrix.clear();   matrix.drawLine(0,0, 7,15, LED_ON);   matrix.writeDisplay();     delay(500);    matrix.clear();   matrix.drawRect(0,0, 8,16, LED_ON);   matrix.fillRect(2,2, 4,12, LED_ON);   matrix.writeDisplay();     delay(500);    matrix.clear();   matrix.drawCircle(3,8, 3, LED_ON);   matrix.writeDisplay();     delay(500);    matrix.setTextSize(1);   matrix.setTextWrap(false);     matrix.setTextColor(LED_ON);   matrix.setRotation(1);   for (int8_t x=7; x>=-69; x--) {     matrix.clear();     matrix.setCursor(x,0);     matrix.print("RUVDS @ Habr");     matrix.writeDisplay();     delay(100);   }   delay(2000);   matrix.setRotation(0); }

▍ Энкодер

На этом аппаратные богатства нашего маленького шилда не заканчиваются. В распоряжение экспериментатора предоставляются микросхема цифрового термометра DS18B20, аналоговый джойстик и нажимной относительный энкодер.

Вращение ручки энкодера преобразуется в угол наклона линии на матричном светодиодном экране.

А если нажать эту ручку, то экран погаснет до следующего её поворота.

#include <Wire.h> #include <Adafruit_GFX.h> #include "Adafruit_LEDBackpack.h" #include <RotaryEncoder.h> #include <Adafruit_NeoPixel.h>  #define PIN A3 #define NUM 4 Adafruit_NeoPixel rgb = Adafruit_NeoPixel(NUM, PIN, NEO_GRB + NEO_KHZ800); #define encoder_button 4 RotaryEncoder encoder(3, 2);  #define CLOCKWISE 1 #define ANTI_CLOCKWISE -0  Adafruit_8x16matrix matrix = Adafruit_8x16matrix(); void rotatePointer(uint8_t,uint8_t);  void setup() {   rgb.begin();   rgb.clear();   rgb.show();   pinMode(encoder_button,INPUT);   matrix.begin(0x70);     matrix.setRotation(1);   matrix.drawLine(0,3, 15,4, LED_ON);   matrix.writeDisplay();  }  void loop() {   static int pos = 0;   if(digitalRead(encoder_button)==1)   {     delay(10);     if(digitalRead(encoder_button)==1)     {        matrix.clear();        matrix.writeDisplay();       }    }   encoder.tick();   int newPos = encoder.getPosition();   uint8_t pointerDirection;   if (pos != newPos) {     RotaryEncoder::Direction currentDirection = encoder.getDirection(); if (currentDirection == RotaryEncoder::Direction::COUNTERCLOCKWISE) {           pointerDirection = ANTI_CLOCKWISE;         } else pointerDirection = CLOCKWISE;     rotatePointer(pointerDirection,1); rotatePointer(pointerDirection,1);     pos = newPos;   } // if }  int8_t x1=0; int8_t x2=15; int8_t y1=3; int8_t y2=4; void rotatePointer(uint8_t direction, uint8_t steps) {     if(direction==CLOCKWISE){   if(x1==0 && y1>0)y1 -= steps;   else if(y1==0 && x1<15) x1 += steps;   else if(x1==15 && y1<7) y1 += steps;   else if(y1==7 && x1>0) x1 -= steps;    if(x2==0 && y2>0)y2 -= steps;   else if(y2==0 && x2<15) x2 += steps;   else if(x2==15 && y2<7) y2 += steps;   else if(y2==7 && x2>0) x2 -= steps; } else{ if(x1==0 && y1<7)y1 += steps;   else if(y1==7 && x1<15) x1 += steps;   else if(x1==15 && y1>0) y1 -= steps;   else if(y1==0 && x1>0) x1 -= steps;    if(x2==0 && y2<7)y2 += steps;   else if(y2==7 && x2<15) x2 += steps;   else if(x2==15 && y2>0) y2 -= steps;   else if(y2==0 && x2>0) x2 -= steps; }   matrix.clear();   matrix.drawLine(x1,y1, x2,y2, LED_ON);   matrix.writeDisplay();   } 

▍ Джойстик

Аналоговый джойстик представляет собой два переменных резистора, положение бегунков которых считывается аналогово-цифровыми преобразователями в виде двух напряжений и преобразуются в числа, означающие координаты по горизонтальной и вертикальной осям.

Данный скетч перемещает по матричному экрану светящуюся точку согласно командам с джойстика.

#include <OS_SingleJoystick.h> #include <Wire.h> #include <Adafruit_GFX.h> #include "Adafruit_LEDBackpack.h" #include <Adafruit_NeoPixel.h>  #define PIN A3 #define NUM 4 Adafruit_NeoPixel rgb = Adafruit_NeoPixel(NUM, PIN, NEO_GRB + NEO_KHZ800);  Adafruit_8x16matrix matrix = Adafruit_8x16matrix(); #define SW_PIN 0xff // Джойстик не нажимной. #define JOYSTCK_X A0 #define JOYSTCK_Y A1  SingleJoystick joystick(JOYSTCK_X, JOYSTCK_Y);  uint8_t coordinate_x = 7; uint8_t coordinate_y = 3; void setup() {   rgb.begin();   rgb.clear();   rgb.show();   matrix.begin(0x70);     matrix.setRotation(1);   matrix.clear();       matrix.drawPixel(coordinate_x, coordinate_y, LED_ON);     matrix.writeDisplay();     }  void loop() {   joystickControlLED();   delay(100);  }  void joystickControlLED() { if(joystick.isChange())   { int x,y;      x=joystick.nowX;     y=joystick.nowY; uint8_t operation;     operation = joystick.multipleRead();      switch (operation) {       case MOVE_UP: if(coordinate_y>0) coordinate_y -= 1;  break;       case MOVE_DOWN: if(coordinate_y<7) coordinate_y += 1;  break;       case MOVE_RIGHT: if(coordinate_x<15) coordinate_x += 1; break;       case MOVE_LEFT:    if(coordinate_x>0) coordinate_x -= 1;     break;       default:        break;     }     matrix.clear();         matrix.drawPixel(coordinate_x, coordinate_y, LED_ON);       matrix.writeDisplay();   } }

▍ Электронный термометр

А этот скетч выводит на матричный дисплей показания температуры и отображает её изменения на столбчатом индикаторе.

#include <OneWire.h> #include <Wire.h> #include <Adafruit_GFX.h> #include "Adafruit_LEDBackpack.h" #include "TM1651.h" #include <Adafruit_NeoPixel.h>  #define PIN A3 #define NUM 4 Adafruit_NeoPixel rgb = Adafruit_NeoPixel(NUM, PIN, NEO_GRB + NEO_KHZ800);  #define CLK 10     #define DIO 11 TM1651 batteryDisplay(CLK,DIO); OneWire  ds(5);   Adafruit_8x16matrix matrix = Adafruit_8x16matrix(); uint8_t level = 2; int8_t temp0; void setup() {   rgb.begin();   rgb.clear();   rgb.show();   matrix.begin(0x70);     matrix.setRotation(1);   batteryDisplay.init();   batteryDisplay.set(BRIGHTEST);//BRIGHT_TYPICAL = 2,BRIGHT_DARKEST = 0,BRIGHTEST = 7;   temp0 = readTemp();   batteryDisplay.displayLevel(level); } void loop() {   int8_t celsius;   celsius = readTemp();   displayTemp(celsius);   batteryDisplay.displayLevel(level+celsius-temp0); } int8_t readTemp() { byte data[12];   float celsius;   ds.reset();   ds.skip();   ds.write(0x44, 0);         delay(750);        ds.reset();   ds.skip();   ds.write(0xBE);            for (unsigned char i = 0; i < 9; i++) {            data[i] = ds.read();   }      int16_t raw = (data[1] << 8) | data[0];   byte cfg = (data[4] & 0x60);   if (cfg == 0x00) raw = raw & ~7;    else if (cfg == 0x20) raw = raw & ~3;    else if (cfg == 0x40) raw = raw & ~1;    celsius = (float)raw / 16.0;   return celsius; } void displayTemp(int8_t temp) { matrix.clear();     matrix.setCursor(0,0);     matrix.print(temp); matrix.print('c');     matrix.writeDisplay(); }

▍ Адресуемые RGB светодиоды

И напоследок поиграем с четырьмя умными светодиодами, внутри каждого из которых имеются три светоизлучающих кристалла и собственный микроконтроллер.

Мы будем зажигать всю линейку разными цветами, чередуя это с эффектом жёлтых бегущих огней.

#include <Adafruit_NeoPixel.h>#define PIN A3 #define NUM 4 Adafruit_NeoPixel rgb = Adafruit_NeoPixel(NUM, PIN, NEO_GRB + NEO_KHZ800); #define LEFT_TO_RIGHT 0 #define RIGHT_TO_LEFT 1  void setup() {   rgb.begin();   rgb.clear();   rgb.show(); }  void loop() {  rgb.setBrightness(40);   colorWipe(rgb.Color(100, 100, 100), 0); // Белый   delay(600);   colorWipe(rgb.Color(50, 0, 0), 0); // Красный   delay(600);   colorWipe(rgb.Color(0, 50, 0), 0); // Зелёный   delay(600);   colorWipe(rgb.Color(0, 0, 50), 0); // Синий   delay(600);   colorWipe(rgb.Color(0, 0, 0), 0); // Чёрный   delay(600);   runLED(0xffff00, LEFT_TO_RIGHT); // Жёлтый   delay(600);   colorWipe(rgb.Color(0, 0, 0), 0); // Чёрный   delay(600);   runLED(0xffff00, RIGHT_TO_LEFT);// Жёлтый   delay(600); }  // Последовательно заполняем пиксели цветом один за другим void colorWipe(uint32_t c, uint8_t wait) {   for(uint16_t i=0; i<NUM; i++) {       rgb.setPixelColor(i, c);   }   rgb.show(); } void runLED(uint32_t c,  uint8_t direction) {   if(direction==LEFT_TO_RIGHT)      for(uint8_t i=0; i<NUM; i++) {       rgb.setPixelColor(i, c);   rgb.show();       delay(150);     }   else      for(uint8_t i=NUM; i>0; i--) {       rgb.setPixelColor(i-1, c);   rgb.show();       delay(150);     } }  void theaterChase(uint32_t c, uint8_t wait) {   for (int j=0; j<10; j++) {       for (int q=0; q < 3; q++) {       for (int i=0; i < rgb.numPixels(); i=i+3) {         rgb.setPixelColor(i+q, c);    // зажигаем каждый третий пиксель       }       rgb.show();            delay(wait);            for (int i=0; i < rgb.numPixels(); i=i+3) {         rgb.setPixelColor(i+q, 0);        // гасим каждый третий пиксель       }     }   } }

▍ Наблюдения и выводы

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

Нажатие кнопки сброса центрального контроллера на них также не влияет, и «лишние» светодиоды гаснут только после выключения питания платы. Так и должно быть, ведь контроллеры светодиодов работают автономно, и линия общего сброса, к которой можно было бы просто присоединить кнопку, не предусмотрена.

Напишите в комментариях свои идеи по использованию Ардуино-совместимой платы с тремя светодиодами и тремя кнопками самого по себе, а также в сочетании с Rich Shield Two.

Telegram-канал со скидками, розыгрышами призов и новостями IT ?


ссылка на оригинал статьи https://habr.com/ru/articles/802457/