Как стать автором
Обновить
2691.29
RUVDS.com
VDS/VPS-хостинг. Скидка 15% по коду HABR15

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

Уровень сложностиПростой
Время на прочтение14 мин
Количество просмотров15K


Привет, Хабр! Вас тоже огорчало, что 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);
}


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


Две красные светодиодные матрицы 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 ?
Теги:
Хабы:
Всего голосов 50: ↑50 и ↓0+53
Комментарии32

Публикации

Информация

Сайт
ruvds.com
Дата регистрации
Дата основания
Численность
11–30 человек
Местоположение
Россия
Представитель
ruvds