«Волшебная лампа» с Arduino

Оригинальный светильник, изготовленный автором Instructables под ником tuenhidiy, можно раскрыть, и он засветится изнутри. Цвет свечения настраивается при помощи переменного резистора и кнопки.

В конструкции светильника применены: сферический кожух от промышленной термопары, корпус от кнопочного поста, кабельный сальник… Посмотрите, какой красивый кожух:

Корпус кнопочного поста — фирмы Schneider, типа XAPM1501H29. Он выполнен из цинкового сплава. Можно, конечно, и что-нибудь попроще использовать, результат будет не хуже. Для красоты к корпусу приделан 20-миллиметровый полиамидный или никелевый кабельный сальник, он установлен в уже имеющееся отверстие.

Управляет всем плата Arduino Nano. Источников света два вида: модуль Neopixel Ring 16 и 16 RGB-светодиодов с общим анодом. Ещё нужны шесть микросхем: три сдвиговых регистра 74HC595 и три набора составных транзисторов ULN2803. Ну и по мелочи: три конденсатора на 0,1 мкФ, 24 резистора на 100 Ом, один транзистор A1013 и одно гнездо питания. Плата применена макетная типа perfboard, питается устройство от пятивольтового блока питания.

Схема поначалу кажется сложной, но если разобраться в ней, становится всё понятно:

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

Мастер берёт кожух от термопары:

В нём два отверстия, одно диаметром в 21 мм, другое — в 32. Первое tuenhidiy использует для соединения кожуха с корпусом кнопочного поста, второе — с «головой снеговика», на которой расположена кнопка.

На куске макетной платы типа perfboard мастер собирает двухэтажную конструкцию из RGB-светодиодов, объединив их аноды. Провода от всех катодов и точки соединения анодов выводит на разъёмы. Устанавливает рассеиватель:

Припаивает кабель с разъёмом к модулю NeoPixel Ring 16:

Собирает плату сдвиговых регистров согласно схеме:

Выходы Arduino, подключённые к плате регистров, сконфигурированы так: разрешение — 3, защёлка — 2, тактирование — 13, данные — 11.

Затем мастер на другом куске макетки собирает переходник для Arduino Nano:

Изготавливает голову того, что называет снеговиком, с шеей из куска ПВХ-трубы, помещает внутрь кнопку и выводит от неё кабель:

Объединяет голову снеговика, кожух от термопары и крышку кнопочного поста:

Устанавливает в корпус кнопочного поста переменный резистор с ручкой управления, сальник и клеммник:

Примеряет, как поместятся Arduino Nano и плата сдвиговых регистров:

Всё соединяет, как изолирует платы от металлического корпуса —непонятно:

Прошивает:

 Скетч//************************************************************************************************************//
#include
#include

#define blank_pin 3 // Defines actual BIT of PortD for blank — is Arduino UNO pin 3
#define latch_pin 2 // Defines actual BIT of PortD for latch — is Arduino UNO pin 2
#define clock_pin 13 // used by SPI, must be 13 SCK 13 on Arduino UNO
#define data_pin 11 // used by SPI, must be pin MOSI 11 on Arduino UNO

#define ROW 4
#define BUTTON 5
#define PIN 6
#define POTPIN 7

Adafruit_NeoPixel strip = Adafruit_NeoPixel(16, PIN, NEO_GRB + NEO_KHZ800);

//************************************************************************************************************//

byte red[4];
byte green[4];
byte blue[4];

int BAM_Bit, BAM_Counter=0;

//************************************************************************************************************//
#define BAM_RESOLUTION 4
#define COLOUR_WHEEL_LENGTH 256

uint8_t colourR[COLOUR_WHEEL_LENGTH];
uint8_t colourG[COLOUR_WHEEL_LENGTH];
uint8_t colourB[COLOUR_WHEEL_LENGTH];
int16_t ColPos = 0;
uint16_t colourPos;
uint8_t R, G, B;

#define myPI 3.14159265358979323846
#define myDPI 1.2732395
#define myDPI2 0.40528473

int buttonPushCounter = 0;
int buttonState = 0;
int lastButtonState = 0;
int POT;
int OLD_POT;

void setup()
{
strip.begin();
strip.setBrightness(50);
strip.show(); // Initialize all pixels to 'off'

SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
SPI.setClockDivider(SPI_CLOCK_DIV2);

noInterrupts();

TCCR1A = B00000000;
TCCR1B = B00001011;
TIMSK1 = B00000010;
OCR1A = 8;

pinMode(latch_pin, OUTPUT);
pinMode(data_pin, OUTPUT);
pinMode(clock_pin, OUTPUT);

pinMode(ROW, OUTPUT);
pinMode(BUTTON, INPUT_PULLUP);

SPI.begin();
interrupts();

fill_colour_wheel();
clearfast();
}

void loop()
{
buttonState = digitalRead(BUTTON);

if (buttonState != lastButtonState) {
if (buttonState == HIGH) {
buttonPushCounter++;
}
else {

}
}
lastButtonState = buttonState;

switch (buttonPushCounter % 5)
{
case 0:

POT = map(analogRead(POTPIN), 0, 1023, 0, 255);
if (POT < (OLD_POT * 0.95) || POT > (OLD_POT * 1.05))
{
OLD_POT = POT; // save the changed value
fillTable_colorwheelRGB(POT, R, G, B);
rainbow(POT);
}

break;
case 1:

POT = map(analogRead(POTPIN), 0, 1023, 0, 255);
if (POT < (OLD_POT * 0.95) || POT > (OLD_POT * 1.05))
{
OLD_POT = POT;
get_colour(POT, &R, &G, &B);
fillTable(R, G, B);
fillring(POT);
}

break;

case 2:

POT = map(analogRead(POTPIN), 0, 1023, 0, 255);
if (POT < (OLD_POT * 0.95) || POT > (OLD_POT * 1.05))
{
OLD_POT = POT;
get_colour(POT, &R, &G, &B);
fillTable(R, G, B);
fullWhite();
}

break;
case 3:

POT = map(analogRead(POTPIN), 0, 1023, 0, 255);
if (POT < (OLD_POT * 0.95) || POT > (OLD_POT * 1.05))
{
OLD_POT = POT;
fillTable(0, 0, 0);
rainbow(POT);
}

break;
case 4:
clearfast();
fullWhite();
break;
}
}

void LED(int Y, int R, int G, int B)
{
Y = constrain(Y, 0, 7);

R = constrain(R, 0, 15);
G = constrain(G, 0, 15);
B = constrain(B, 0, 15);

for (byte BAM = 0; BAM < BAM_RESOLUTION; BAM++)
{
bitWrite(red[BAM], Y, bitRead(R, BAM));

bitWrite(green[BAM], Y, bitRead(G, BAM));

bitWrite(blue[BAM], Y, bitRead(B, BAM));
}
}

ISR(TIMER1_COMPA_vect){

PORTD |= ((1< myPI){
x -= 2*myPI;
g = 1;
}

while(!g&(x < -myPI)){
x += 2*myPI;
}

sinr = myDPI*x — myDPI2*x*myAbs(x);
sinr = 0.225*(sinr*myAbs(sinr)-sinr)+sinr;

return sinr;
}

//FAST COSINE APPROX
float myCos(float x){
return mySin(x+myPI/2);
}

float myTan(float x){
return mySin(x)/myCos(x);
}

//SQUARE ROOT APPROX
float mySqrt(float in){
int16_t d = 0;
int16_t in_ = in;
float result = 2;

for(d = 0; in_ > 0; in_ >>= 1){
d++;
}

for(int16_t i = 0; i < d/2; i++){
result = result*2;
}

for(int16_t i = 0; i < 3; i++){
result = 0.5*(in/result + result);
}

return result;
}

//ABSOLUTE VALUE
float myAbs(float in){
return (in)>0?(in):-(in);
}

void fill_colour_wheel(void)
{
float red, green, blue;
float c, s;
int32_t phase = 0;
int16_t I = 0;

while (phase < COLOUR_WHEEL_LENGTH)
{
s = (1 << BAM_RESOLUTION)*mySin(myPI*(3 * phase — I*COLOUR_WHEEL_LENGTH) / (2 * COLOUR_WHEEL_LENGTH));
c = (1 << BAM_RESOLUTION)*myCos(myPI*(3 * phase — I*COLOUR_WHEEL_LENGTH) / (2 * COLOUR_WHEEL_LENGTH));

red = (I == 0 ? 1 : 0)*s + (I == 1 ? 1 : 0)*c;
green = (I == 1 ? 1 : 0)*s + (I == 2 ? 1 : 0)*c;
blue = (I == 2 ? 1 : 0)*s + (I == 0 ? 1 : 0)*c;

colourR[phase] = red;
colourG[phase] = green;
colourB[phase] = blue;

if (++phase >= (1 + I)*COLOUR_WHEEL_LENGTH / 3)
I++;
}
}

void get_colour(int16_t p, uint8_t *R, uint8_t *G, uint8_t *B)
{
if (p >= COLOUR_WHEEL_LENGTH)
p -= COLOUR_WHEEL_LENGTH;

*R = colourR[p];
*G = colourG[p];
*B = colourB[p];
}

void get_next_colour(uint8_t *R, uint8_t *G, uint8_t *B)
{
if (++ColPos >= COLOUR_WHEEL_LENGTH)
ColPos -= COLOUR_WHEEL_LENGTH;

*R = colourR[ColPos];
*G = colourG[ColPos];
*B = colourB[ColPos];
}

void increment_colour_pos(uint8_t i)
{
colourPos += i;
while (colourPos >= COLOUR_WHEEL_LENGTH)
{
colourPos -= COLOUR_WHEEL_LENGTH;
}
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r — g — b — back to r.
uint32_t Wheel(byte WheelPos) {
WheelPos = 255 — WheelPos;
if(WheelPos < 85) {
return strip.Color(255 — WheelPos * 3, 0, WheelPos * 3);
}
if(WheelPos < 170) {
WheelPos -= 85;
return strip.Color(0, WheelPos * 3, 255 — WheelPos * 3);
}
WheelPos -= 170;
return strip.Color(WheelPos * 3, 255 — WheelPos * 3, 0);
}

Проверяет:

Готово:

Можно и на стену:

И включить:

Повторили конструкцию? Сравните её работу с тем, что показано на видео:

Источник

Источник: usamodelkina.ru

Добавить комментарий