Дата поста: 20-08-2013
Недавно я купил 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. В ней хорошо описано использование МОСФЕТов с Ардуино. Если вы уже прочитали эту статью, то давайте двигаться дальше.
Для работы со светодиодной лентой нам понадобятся:
- MOSFET транзисторы, которые можно найти на том же EBay
- Резисторы на 10k?
- Макетная беспаечная плата (breadboard)
- Проводки для соединения ардуино с макетной платой (папа-папа)
- Светодиодная лента (Я брал на aliexpress вот эту ленту, и планирую заказать ещё пару у этого же продавца)
Теперь перейдём к схеме подключения, из неё станет понятно основная часть данной статьи:
Теперь обратимся к 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.
Идея состоит в том, что "холодная температура", как правило, синего цвета, а "горячая температура" получит красный цвет. Если вы взгляните на колесо 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);
}
}