Привет, Хабр! Вас тоже огорчало, что 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.
// 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
// 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);
}
▍ Светодиодная матрица
Две красные светодиодные матрицы 8x8 управляются с помощью одной микросхемы 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 ?
Комментарии (26)
NickDoom
04.04.2024 09:55+1И снова пЧичка на фотке предвещает занимательные электронные игрушки :)
Если я всё-таки доберусь до своего кухонного таймера с минимумом ног у контра — надо будет не забыть сделать на фотке узнаваемый силуэт и написать в нём «а у меня такой пЧички нет!» :-D
ThingCrimson
04.04.2024 09:55+1О! Ардуина! А я как раз вчера перед сном ворочался, и думал — а не попробовать ли мне запилить необычный метроном, который совсем молчит, только светодиодом мигает? Скажем, Arduino Nano, красный LED для первой доли, 4 зелёных (для ритмов от 2/4 до 5/4 и придумать как задавать число долей), энкодер для задания темпа, ну и наверно дисплейчик мелкий или несколько 7-сегментных индикаторов для отображения темпа…
Но потом подумал, а хватит ли realtime-вости для слабенького МК, программируемого не в машинных кодах, а через IDE на С++? И заснул.
Lunathecat Автор
04.04.2024 09:55+1Хорошая идея! Таймеры у МК есть, обработчик прерывания написать можно.
ThingCrimson
04.04.2024 09:55+1Спасибо! Тогда сделаю запись в ToDo, может и дойдут руки хотя бы до макета. Мне ведь не много надо: чтобы при, скажем, 120 BPM длительность доли была 500 мс (пусть ±5 мс), а не то 430, а то 550.
VladimirFarshatov
04.04.2024 09:55За глаза хватит. Он ещё и траекторию спутника на орбите отследит междду делом .. не очень точно (нет встроенного float) .. так, "плюс-минус" .. ;)
geher
04.04.2024 09:55+3Вас тоже огорчало, что PLS-разъёмы плат Arduino Uno и Mega установлены без соблюдения сетки с шагом 2.54 мм, отчего невозможно создать собственный шилд на базе обычной макетки под пайку?
Для ленивых и неэкономных есть специальные готовые макетки под шилды.
NetBUG
04.04.2024 09:55+1Почему неэкономных? Оно стоит меньше доллара вроде
geher
04.04.2024 09:55+1То, что я видел под разъемы ардуины, стоит дороже "просто макеток". Не намного, но все же. А если разъемы уже распаяны (для истинно ленивого - лучший выбор), то еще дороже
NetBUG
04.04.2024 09:55+1Ну, ёжику понятно, что дешевле делать квадратные километры макетки с шагом 0.1", а не выпиливать фигурную плату, оно там центов по десять будет получаться.
Но, условно, 43 цента за такую платку (не реклама, просто нашлось в выдаче) – это дешевле, чем делать самому на фрезере (даже если он есть и полностью настроен и готов к работе), дешевле (с учётом доставки), чем делать по промоакции за $2 на jlcpcb и тем более где-то вне Азии.
Я не представляю, как человек, у которого есть хоть какая-то работа, может сделать дешевле и не принципиально хуже в домашних условиях
Что не отменяет вопросов к тому, зачем двадцать лет назад сделали непонятно какой шаг на плате с тогда-ещё-не-древней атмегой :)
geher
04.04.2024 09:55+2Не ленивый и экономный спаяет свою "ардуину" и свои модули к ней без этой ерунды с нарушением шага.
А еще можно пользоваться ардуиной линейки MKR, у которой такой проблемы в дизайне нет. Правда она габаритами меньше, на макетке в ее габаритах особо не разгуляешься.
Что не отменяет вопросов к тому, зачем двадцать лет назад сделали непонятно какой шаг на плате с тогда-ещё-не-древней атмегой
Наверное, они ее просто развели по принципу "как получилось", не особо думая о том, что потом появится народ с параллельно-перпендикулярными макетками, который захочет эти макетки присоединить к ардуине.
VladimirFarshatov
04.04.2024 09:55Насколько помню, там были дебаты в Сети "какую макетку пилить" .. победила, та что победила. Почему? А хз, не помню уже. Тоже дивился зачем?
serafims
04.04.2024 09:55+1Дмэумаю, имеет смысл прошивать МК загрузчиком и ставить сразу без кроваток в плату, заодно и ISP разъем не нужен будет.
VladimirFarshatov
Хорошая и развернутая статья, но вот такая Ардуинка может много больше:
https://vk.com/id484853030?z=photo484853030_456239018%2Fphoto_feed484853030
К ней была сделана дополнительная плата ОЗУ, расширяющая внутреннее ОЗУ до 520килобайт сегментированно-прямой адресации. С ней возможностей стало ещё больше.. ;)
f45d07
Не у всех есть возможность посмотреть публикацию в ВК, где требуется авторизация
trinxery
Hidden text
Lunathecat Автор
Спасибо!
voldemar_d
520 кБ - это хорошо, но если достаточно 128 кБ, можно к любой Arduino подключить по SPI маленькую микросхему 23LC1024 вместо целой платы расширения.
VladimirFarshatov
По spi можно, но оперировать большими массивами данных медленнее на два порядка, чем напрямую.
voldemar_d
В каких задачах на Arduino может потребоваться быстро оперировать данными в пол мегабайта?
VladimirFarshatov
Ну, к примеру, был сделан "осцилоскоп" с сохранением серии снимков и их последующим усреднением перед показом.. Обработка картинок для цветного экранчика .. Ещё делал "пульсоксиметр" на базе фоторезистора, а поскольку там измерялка "пол-потолок-палец", тоже снималось много сэмплов с усреднением..
Какие-то куски выкладывал в свое время на разных ресурсах.
+512кб Меге 2560 оно может и не так уж и надо, но .. SRAM 512kb 70ns покупались за смешные 40-60руб. Почему нет-то, если шина позволяет?
Там контроллер - проще некуда.. :) Впрочем .. где-то тут уже выкладывал какие-то ссылки на АлексГауверовский сайт, что тогда публиковалось.. можно поискать ещё разок.
voldemar_d
Если найдете, было бы интересно почитать. Просто для усреднения серии снимков, кмк, уже помощнее МК нужен, чем Arduino.
VladimirFarshatov
Да вполне нормальный контроллер - 16Мгц тактовая, вполне. В Космос, в свое время летали машинки послабее и существенно. Осцилоскоп поднимал до почти 500 килосэмплов в сек. Пробовал делать несколько кадров со сдвигом на 1-2-4-8 тактов, но там оно плавает не устойчиво.. или у меня не получилось толком поднять семплированием частоту выше 500.
Не, если конечно складывать 2+2 переводя замер во double, да библиотекой на Питоне с обратным преобразованием в целое через 64 байтное в байт .. то да, слабоват.. :)