led-logo

Недавно я купил 2 рулона rgb светодиодной ленты по 5 метров, и сразу решил поэкспериментировать с ней. В комплекте шёл блок для управления лентой, но мне показались программы малоинтересными, а под рукой был Tinyos Uno (полный китайский аналог Arduino UNO). Учитывая то, что ардуино работает максимум с 5в на выход, а чаще 3.3в то нужно было найти решение. В этой статье рассмотрено как подключить 12 вольтовую светодиодную ленту к ардуино с отдельным питанием для ленты и управлением с _ардуинки_ с использованием МОСФЕТов (MOSFETs) для управления каналами RGB ленты.

Начнём со стандартной спецификации аналоговой светодиодной ленты, которая, как мне кажется, наиболее распространена.

  • 10.5mm (0.41”) ширина, 3mm (0.12”) толщина, 100mm (3.95”) длина на каждый сегмент
  • Бывает влагозащищённые (waterproof ) и без защиты (non-waterproof )
  • Имеет клейкую ленту с обратной стороны для крепления ленты
  • Максимальное напряжение 12V и 60mA на каждый сегмент
  • 3 светодиода с общим анодом на каждом сегменте
  • Длина волн светодиодов: 630nm/530nm/475nm
  • Нет микроконтроллера или чип контроллера (чисто аналоговое управление)

Прежде чем начинать работу с Arduino и напряжением выше, чем 5 вольт очень советую прочитать про использование MOSFET и Arduino для управления высокими напряжениями, чтобы не сжечь вашу Arduino. В ней хорошо описано использование МОСФЕТов с Ардуино. Если вы уже прочитали эту статью, то давайте двигаться дальше.

Для работы со светодиодной лентой нам понадобятся:

  1. MOSFET транзисторы, которые можно найти на том же EBay
  2. Резисторы на 10k?
  3. Макетная беспаечная плата (breadboard)
  4. Проводки для соединения ардуино с макетной платой (папа-папа)
  5. Светодиодная лента (Я брал на _aliexpress_ вот эту ленту, и планирую заказать ещё пару у этого же продавца)

Теперь перейдём к схеме подключения, из неё станет понятно основная часть данной статьи:

rgb-led-strips-mosfets

Теперь обратимся к Arduino IDE, в которой напишем скетч для управления нашей лентой:

// Note that there's some legacy code left in here which seems to do nothing
// but should do no harm ...

// don't futz with these, illicit sums later
#define RED       9// pin for red LED
#define GREEN    10 // pin for green - never explicitly referenced
#define BLUE     11 // pin for blue - never explicitly referenced
#define SIZE    255
#define DELAY    20
#define HUE_MAX  6.0
#define HUE_DELTA 0.01

//long deltas[3] = { 5, 6, 7 };
long rgb[3];
long rgbval;
// for reasons unknown, if value !=0, the LED doesn't light. Hmm ...
// and saturation seems to be inverted
float hue=0.0, saturation=1, value=1;

/*
chosen LED SparkFun sku: COM-09264
 has Max Luminosity (RGB): (2800, 6500, 1200)mcd
 so we normalize them all to 1200 mcd -
 R  250/600  =  107/256
 G  250/950  =   67/256
 B  250/250  =  256/256
 */
long bright[3] = { 107, 67, 256};
//long bright[3] = { 256, 256, 256};

long k, temp_value;

void setup () {
  randomSeed(analogRead(4));
  for (k=0; k<3; k++) {
    pinMode(RED + k, OUTPUT);
    rgb[k]=0;
    analogWrite(RED + k, rgb[k] * bright[k]/256);
  }
}

void loop() {
  hue += HUE_DELTA;
  if (hue > HUE_MAX) {
    hue=0.0;
  }
  rgbval=HSV_to_RGB(hue, saturation, value);
  rgb[0] = (rgbval & 0x00FF0000) >> 16; // there must be better ways
  rgb[1] = (rgbval & 0x0000FF00) >> 8;
  rgb[2] = rgbval & 0x000000FF;
  for (k=0; k<3; k++) { // for all three colours
    analogWrite(RED + k, rgb[k] * bright[k]/256);
  }

  delay(DELAY);
}

long HSV_to_RGB( float h, float s, float v ) {
  // H is given on [0, 6]. S and V are given on [0, 1].
  // RGB is returned as a 24-bit long #rrggbb
  int i;
  float m, n, f;

  // not very elegant way of dealing with out of range: return black
  if ((s<0.0) || (s>1.0) || (v<1.0) || (v>1.0)) {
    return 0L;
  }

  if ((h < 0.0) || (h > 6.0)) {
    return long( v * 255 ) + long( v * 255 ) * 256 + long( v * 255 ) * 65536;
  }
  i = floor(h);
  f = h - i;
  if ( !(i&1) ) {
    f = 1 - f; // if i is even
  }
  m = v * (1 - s);
  n = v * (1 - s * f);
  switch (i) {
  case 6:
  case 0: 
    return long(v * 255 ) * 65536 + long( n * 255 ) * 256 + long( m * 255);
  case 1: 
    return long(n * 255 ) * 65536 + long( v * 255 ) * 256 + long( m * 255);
  case 2: 
    return long(m * 255 ) * 65536 + long( v * 255 ) * 256 + long( n * 255);
  case 3: 
    return long(m * 255 ) * 65536 + long( n * 255 ) * 256 + long( v * 255);
  case 4: 
    return long(n * 255 ) * 65536 + long( m * 255 ) * 256 + long( v * 255);
  case 5: 
    return long(v * 255 ) * 65536 + long( m * 255 ) * 256 + long( n * 255);
  }
}

Заливаем скетч на ардуино и радуемся.

Есть так же вариант с использованием температурного сенсора DS18B20, который работает по протоколу 1-Wire.

rgb-led-strips-mosfets-temperature

Идея состоит в том, что “_холодная температура”;,_ как правило, синего цвета, а “_горячая температура”; _получит красный цвет. Если вы взгляните на колесо HSV, которое мы использовали в первом скетче (цветовое колесо см. wiki), цвет будет составлять от 240 °, когда холодно и до 0 °, если горячая, двигаясь по часовой стрелке (проходя голубой, зеленый и желтый).

_Холодная температура_ в данном случае имеется ввиду 18 ° C, а _горячая_ подразумевает 30 ° C. Температура ниже холодного порога будет считаться холодной, выше горячего порога — горячей.

Окончательный код на самом деле довольно прост, когда у вас есть уже готовый код HSV:

// HSV fade/bounce for Arduino
// Note that there's some legacy code left in here which seems to do nothing
// but should do no harm ...

#include "OneWire.h"
//#include "Streaming.h"

const int DS18S20_Pin = 2; //DS18S20 Signal pin on digital 2
#define MIN_TEMP 18
#define MAX_TEMP 30

//Temperature chip i/o
OneWire ds(DS18S20_Pin); // on digital pin 2

// don't futz with these, illicit sums later
#define RED       9// pin for red LED
#define GREEN    10 // pin for green - never explicitly referenced
#define BLUE     11 // pin for blue - never explicitly referenced
#define SIZE    255
#define DELAY    0
#define HUE_MAX  6.0
#define HUE_DELTA 0.01

//long deltas[3] = { 5, 6, 7 };
long rgb[3];
long rgbval;
// for reasons unknown, if value !=0, the LED doesn't light. Hmm ...
// and saturation seems to be inverted
float hue=0.0, saturation=1, value=1;

/*
chosen LED SparkFun sku: COM-09264
 has Max Luminosity (RGB): (2800, 6500, 1200)mcd
 so we normalize them all to 1200 mcd -
 R  250/600  =  107/256
 G  250/950  =   67/256
 B  250/250  =  256/256
 */
long bright[3] = { 107, 67, 256};
//long bright[3] = { 256, 256, 256};

long k, temp_value;

void setup () {
  randomSeed(analogRead(4));
  Serial.begin(57600);
  for (k=0; k<3; k++) {
    pinMode(RED + k, OUTPUT);
    rgb[k]=0;
    analogWrite(RED + k, rgb[k] * bright[k]/256);
  }
}

void loop() {
  float temperature = constrain(getTemp(), MIN_TEMP, MAX_TEMP);

  float deltaTemp = (MAX_TEMP - MIN_TEMP);
  float deltaHue = 4 - 0;
  hue = map((temperature - MIN_TEMP) * 100, 0, deltaTemp * 100, deltaHue * 100, 0) / 100.0;

  //Serial << "Temperature: " << temperature << endl;
  //Serial << "HUE: " << hue << endl;

  rgbval=HSV_to_RGB(hue, saturation, value);
  rgb[0] = (rgbval & 0x00FF0000) >> 16; // there must be better ways
  rgb[1] = (rgbval & 0x0000FF00) >> 8;
  rgb[2] = rgbval & 0x000000FF;
  for (k=0; k<3; k++) { // for all three colours
    analogWrite(RED + k, rgb[k] * bright[k]/256);
  }

  //delay(DELAY);
}

float getTemp(){
 //returns the temperature from one DS18S20 in DEG Celsius

 byte data[12];
 byte addr[8];

 if ( !ds.search(addr)) {
   //no more sensors on chain, reset search
   ds.reset_search();
   return -1000;
 }

 if ( OneWire::crc8( addr, 7) != addr[7]) {
   Serial.println("CRC is not valid!");
   return -1000;
 }

 if ( addr[0] != 0x10 && addr[0] != 0x28) {
   Serial.print("Device is not recognized");
   return -1000;
 }

 ds.reset();
 ds.select(addr);
 ds.write(0x44,1); // start conversion, with parasite power on at the end

 byte present = ds.reset();
 ds.select(addr);  
 ds.write(0xBE); // Read Scratchpad

 for (int i = 0; i < 9; i++) { // we need 9 bytes
  data[i] = ds.read();
 }

 ds.reset_search();

 byte MSB = data[1];
 byte LSB = data[0];

 float tempRead = ((MSB << 8) | LSB); //using two's compliment
 float TemperatureSum = tempRead / 16;

 return TemperatureSum;
}

long HSV_to_RGB( float h, float s, float v ) {
  // H is given on [0, 6]. S and V are given on [0, 1].
  // RGB is returned as a 24-bit long #rrggbb
  int i;
  float m, n, f;

  // not very elegant way of dealing with out of range: return black
  if ((s<0.0) || (s>1.0) || (v<1.0) || (v>1.0)) {
    return 0L;
  }

  if ((h < 0.0) || (h > 6.0)) {
    return long( v * 255 ) + long( v * 255 ) * 256 + long( v * 255 ) * 65536;
  }
  i = floor(h);
  f = h - i;
  if ( !(i&1) ) {
    f = 1 - f; // if i is even
  }
  m = v * (1 - s);
  n = v * (1 - s * f);
  switch (i) {
  case 6:
  case 0: 
    return long(v * 255 ) * 65536 + long( n * 255 ) * 256 + long( m * 255);
  case 1: 
    return long(n * 255 ) * 65536 + long( v * 255 ) * 256 + long( m * 255);
  case 2: 
    return long(m * 255 ) * 65536 + long( v * 255 ) * 256 + long( n * 255);
  case 3: 
    return long(m * 255 ) * 65536 + long( n * 255 ) * 256 + long( v * 255);
  case 4: 
    return long(n * 255 ) * 65536 + long( m * 255 ) * 256 + long( v * 255);
  case 5: 
    return long(v * 255 ) * 65536 + long( m * 255 ) * 256 + long( n * 255);
  }
}

Ну и видео в качестве демонстрации результата:

Комментарии

comments powered by Disqus