Настольная RGB лампа с часами, температурой и регулировкой яркости и цвета.

Нет ответов
amvolkov
Offline
Зарегистрирован: 22.12.2013

Наконец-то она заработала. Начал знакомство с Arduino с 20 декабря, имея кучу выходных (праздники), облазив кучу сайтов (в основном с нашего форума), более-менее освоив IDE, запустил  Arduino Nano. С участием 1.8 inch TFT color display (HY-1.8 SPI), часы DS1302, датчик температуры и влажности DHT11, Bluetooth модуль HC-05, энкодер с кнопкой и кучей проводов. 

Цель. Достаточно мощные светодиоды 5 - 10Вт, в настольном светильнике , что бы можно было использовать и как мощный источник света. Регулировка яркости и цвета (не всегда настроение красное, бывает слегка зеленое). Можно использовать как довесок к будильнику - просыпаешься и подсветка есть, приятного, утреннего цвета. Со смартфона управлять светом - ну, всяко бывает... Опять же термометр (как без него?).

В планах поменять часы на DS1307 (DS1302 не смог правильно подключить - спешат, при питании от 5 вольт сбои в показаниях). Пробовать другой датчик температуры и влажности (DHT11 не корректно работает с библиотекой PWM.h (тема "analogWrite() на любом выводе") - при опросе датчика мигают светодиоды) или использовать дополнительно контроллер на PWM. Добавить фукций при работе с Bluetooth -ом. Сейчас в качестве светодиодов использую ленту 60 штук SMD на метр, управление BUZ11 (были под рукой и не греются).

Скетч собран из разных источников и, бесспорно, не идеален. После компиляции 21 460 байт. Наверняка упростить можно (в будущем, наверное). Вывод инфы на экран и в блютуз больше для наглядности. Убедится, что работает.

Надеюсь на предложения по усовершенствованию.

Вот, собственно код... 





/* Скетч с подключением библиотеки ШИМ - на все выходы
 аналоговые выходы 14 - 19 описание метода 
 http://arduino.ru/forum/programmirovanie/analogwrite-na-lyubom-vyvode
 + рандом лампа настроения (нажать на кнопку энкодера)
 скорость изменения цвета переменная time
 + управление яркостью RGB светодиодов через Bluetooth или Serial 
 (переход в режим: передать лат.'A')
 */

#include <PWM.h> // ПОДКЛ.БИБЛИОТЕКУ ШИМ-НА ВСЕ ВЫХОДЫ
#include <Adafruit_GFX.h>    // библиотека для TFT дисплеяAdafruit Grafik
#include <Adafruit_ST7735.h> //                           Adafruit ST7735
#include <SPI.h>
#include <DS1302.h> // библиотека часов
DS1302 rtc(2, 7, 4); // Инициализация библиотеки с указанием
// пинов подключения к Arduino платы часов
#include "DHT.h"
#include <EEPROM.h> // Библиотека записи в память
//#include <SerialInput.h> // работа с сериал и bluetooth

#define DHTPIN 3    // what pin we're connected to
#define cs   10 // Arduino-Pin an Display CS   
#define dc   9  // Arduino-Pin an 
#define rst  8  // Arduino Reset-Pin
#define PIN_A 14 //2 энкодер  А
#define PIN_B 15 // 3 энкодер В
#define PIN_C 16  // КНОПКА ЭНКОДЕРА
// Uncomment whatever type you're using!
#define DHTTYPE DHT11   // DHT 11 
//#define DHTTYPE DHT22   // DHT 22  (AM2302)
//#define DHTTYPE DHT21   // DHT 21 (AM2301)
Adafruit_ST7735 tft = Adafruit_ST7735(cs, dc, rst);  // Display-Bibliothek Setup

volatile bool PinAH = 0;
volatile bool PinBH = 0;
volatile bool PinAB = 0;
volatile bool PinBA = 0;
int Enc_v = 0;
int encValue=0;
int fadeAmount = 5; // шаг изменения яркости LED
int brightness=120; // при старте средняя яркость
int color,i,value,time=100;  // how long does it take each step
int kn = 0; // переменная значений кнопки
int kn_ret=0; // возврат из loop rgb()
int flag=0; 
int r=0;                            
int g=0;                           
int b=0;
int old_t; 
int old_h;
Time t; // Инициализация структуры 
String old_time; // для проверки времени очищать дисплей или нет
String date_old; // новая дата - очистка дисплея
char incomingByte; 
int bt=0;  // входящие данные для БТ
DHT dht(DHTPIN, DHTTYPE);

void setup(){
  Serial.begin(9600); 
  //  Serial.println("Ready");
  digitalWrite(PIN_A, HIGH); //подтяжка
  digitalWrite(PIN_B, HIGH); //подтяжка
  digitalWrite(PIN_C, HIGH); //подтяжка
  //digitalWrite(PIN, HIGH); //подтяжка
  analog.Mode(17, OUTPUT); // R
  analog.Mode(18, OUTPUT); // G
  analog.Mode(19, OUTPUT);  // B
  dht.begin();
  tft.initR(INITR_BLACKTAB);   // ST7735-Chip инициализация дисплея
  rtc.halt(false); // Установка режимов 
  rtc.writeProtect(false); // работы часов
  // Следующих три строки нужно закомментировать после 
  // установки времени и загрузить скетч в плату повторно 
  //  rtc.setDOW(THURSDAY);        // Установка дня недели
  //  rtc.setTime(16, 39, 30);  // Установка времени 10:59:10 
  //  rtc.setDate(2, 1, 2014);   // Установка даты 20 июля 2013//
  tft.fillScreen(ST7735_BLACK);
  // vremia();

}
void loop(){
  knopka();
  if (old_time != rtc.getTimeStr(FORMAT_SHORT)) //---- проверяем,
  {   // если время изменилось, то выводим на экран
    vremia(); // функция вывода часов на дисплей
    temra(); // вывод температуры
  } //----------------
  if(Serial.available()){
    delay(2);
    value=Serial.read();

    switch (value)
    {
    case 'A': 
      bluser();
      break;
    case 'L': 
      // На потом... digitalWrite(led_pin, LOW); 
      break;
    case 'M': 
      //На потом....led_mix(); 
      break;
    }
  }
}
void knopka(){
  if(digitalRead(PIN_C)==HIGH&&flag==0)//если кнопка нажата
    // и перемення flag равна 0 , то ... 
  { 
    flag=1; 
    kn++; 
    //это нужно для того что бы с каждым нажатием кнопки 
    //происходило только одно действие 
    // плюс защита от "дребезга"  100%
  } 
  if(digitalRead(PIN_C)==LOW&&flag==1)//если кнопка НЕ нажата 
    //и переменная flag равна - 1 ,то ... 
  { 
    flag=0; //kn=0; //обнуляем переменную flag 
  }
  if (kn > 2) {
    kn=1;
  }
  if (kn_ret==1) {
    return;
  }  
  //kn_ret=0;
  //    Serial.print("kn = ");Serial.println(kn);    
  switch (kn) {
  case 1:
    encoder();
    break;
  case 2:
    rgb();
    break;
  }
  return;
}// ------ end void knopka

void encoder() // ----- start  encoder ------
{
  tft.fillRect(0,120,int((brightness/2)),5,ST7735_WHITE);// рисуем линию
  analog.Write(17, brightness); // устанавливаем яркость
  analog.Write(18, brightness); // устанавливаем яркость
  analog.Write(19, brightness); // устанавливаем яркость 
  if(digitalRead(PIN_A)== HIGH && PinBH == 0 && PinBA == 0)
  {
    PinAH = 1;
    PinAB = 1;
    if(digitalRead(PIN_B)== HIGH)
    {
      PinBH = 1; 
      Enc_v--;
      if(brightness - fadeAmount >= 0) brightness -= fadeAmount;
    }
  }
  if(digitalRead(PIN_A)== LOW && digitalRead(PIN_B)== LOW){
    PinAH = 0; 
    PinBH = 0;
    PinAB = 0;
    PinBA = 0;
  }   

  if(digitalRead(PIN_B)== HIGH && PinAH == 0 && PinAB == 0)
  {
    PinBH = 1; 
    PinBA = 1;
    if(digitalRead(PIN_A)== HIGH)
    {
      PinAH = 1; 
      Enc_v++;
      if(brightness + fadeAmount <= 255) brightness += fadeAmount;
    }
  }
  if(digitalRead(PIN_A)== LOW && digitalRead(PIN_B)== LOW){
    PinAH = 0; 
    PinBH = 0;
    PinAB = 0;
    PinBA = 0;
  } 
  if(encValue != Enc_v){
    if(Enc_v <= 255) Enc_v = 255; 
    if(Enc_v >= 0) Enc_v = 0;

    encValue = Enc_v;
    tft.fillRect(0,120,128,5,ST7735_BLACK); //полоса уровня энкодера 
    analog.Write(17, brightness); // устанавливаем яркость
    analog.Write(18, brightness); // устанавливаем яркость
    analog.Write(19, brightness); // устанавливаем яркость 
    tft.fillRect(0,120,int(brightness/2),5,ST7735_WHITE); //полоса уровня энкодера
  }
  return; 
}// конец void ecoder


// ----- start mood light -----------
void rgb() 
{ 
  //tft.fillRect(0,120,128,5,ST7735_BLACK); //вытираем линию
  int color,i,value,time=300;  // how long does it take each step  
  color=random(1,4);    // which color to dim now 
  value=random(0,256);  // new value of that color
  switch(color) {
  case 1: 
    tft.fillCircle(int(value/2),122, 2, ST7735_BLUE);
    if(r>value) for(i=r;i>value;i--) {
      rgb(i,g,b); 
      //      delay(time); 
      for (int i1=0; i1 <= time; i1++){
        if (kn==1) {
          break;
        }
        kn_ret=1; 
        knopka();
      }
      kn_ret=0;
    }
    for(i=r;i<value;i++) {
      rgb(i,g,b); 
      //      delay(time); 
      for (int i1=0; i1 <= time; i1++){
        if (kn==1) {
          break;
        }
        kn_ret=1; 
        knopka();
      }
      kn_ret=0;
    }
    r=value;
    break;
  case 2: 
    tft.fillCircle(int(value/2),122, 2, ST7735_RED);
    if(g>value) for(i=g;i>value;i--) {
      rgb(r,i,b); 
      //      delay(time); 
      for (int i1=0; i1 <= time; i1++){
        if (kn==1) {
          break;
        }
        kn_ret=1; 
        knopka();
      }
      kn_ret=0;
    }
    else for(i=g;i<value;i++) {
      rgb(r,i,b); 
      //      delay(time); 
      for (int i1=0; i1 <= time; i1++){
        if (kn==1) {
          break;
        }
        kn_ret=1; 
        knopka();
      }
      kn_ret=0;
    }
    g=value;
    break;
  case 3:
    tft.fillCircle(int(value/2),122, 2, ST7735_GREEN);
    if(b>value) for(i=b;i>value;i--) {
      rgb(r,g,i); 
      //      delay(time); 
      for (int i1=0; i1 <= time; i1++){
        if (kn==1) {
          break;
        }
        kn_ret=1; 
        knopka();
      }
      kn_ret=0;
    }
    else for(i=b;i<value;i++) {
      rgb(r,g,i); 
      //      delay(time); 
      for (int i1=0; i1 <= time; i1++){
        if (kn==1) {
          break;
        }
        kn_ret=1; 
        knopka();
      }
      kn_ret=0;
    }
    b=value;
    break;
  } 
  for (int i1=0; i1 <= time; i1++){
    if (kn==1) {
      break;
    }
    kn_ret=1; 
    knopka();
  }
  kn_ret=0;
}
void rgb(int r, int g, int b) {
  analog.Write(17,r);
  analog.Write(18,g);
  analog.Write(19,b);
}
void vremia()
{
  t = rtc.getTime(); // Получение времени и его запись в структуру t
  if (rtc.getTimeStr(FORMAT_SHORT)==("00:00")) {
    return;
  }
  tft.setTextSize(1);
  tft.setTextColor(ST7735_YELLOW);
  tft.setCursor(0,10);
  tft.print(" Hello!!! Do not worry!!!");
  if (old_time != rtc.getTimeStr(FORMAT_SHORT)) //---- проверяем,
  {   // если время изменилось, то старое рисуем черным цветом
    tft.setTextSize(3);
    tft.setCursor(20,25);
    tft.setTextColor(ST7735_BLACK);
    tft.print(old_time);
    tft.setTextSize(1);
    tft.setCursor(34,60);
    tft.print("00.00.2000");  //rtc.getDateStr());
    tft.setCursor(45,50);
    tft.print("Xxxxxxxxxxx"); //rtc.getDOWStr());
  } //----------------
  tft.setTextSize(3);
  tft.setCursor(20,25);
  tft.setTextColor(ST7735_YELLOW);
  tft.print(rtc.getTimeStr(FORMAT_SHORT));
  tft.setTextSize(1);
  tft.setCursor(34,60);
  tft.print(rtc.getDateStr());
  tft.setCursor(45,50);
  tft.print(rtc.getDOWStr());
  if (date_old != rtc.getDateStr(FORMAT_SHORT)) //---- проверяем,
  {   // если дата изменилось, то очистка экрана
    tft.fillScreen(ST7735_BLACK);
  } //----------------
  // tft.print(rtc.getDateStr());
  old_time = rtc.getTimeStr(FORMAT_SHORT);
  date_old = rtc.getDateStr(FORMAT_SHORT);
} // ------------ конец время
void temra()
{
  // ----- температура и влажность ----
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  // check if returns are valid, if they are NaN (not a number) then something went wrong!
  if (isnan(t) || isnan(h)) {
    //    Serial.println("Failed to read from DHT");
    tft.setTextSize(2);
    tft.setCursor(30,90);
    tft.setTextColor(ST7735_BLACK);
    tft.print("XX");
    tft.setCursor(30,90);
    tft.setTextColor(ST7735_RED);
    tft.print(" don't work :(");
  }
  else {
    tft.setTextSize(2);
    tft.setTextColor(ST7735_BLACK);
    tft.setCursor(15,90);
    tft.print(old_t);
    tft.print("C  ");
    tft.print(old_h); 
    tft.print("%");
    tft.setCursor(15,90);
    tft.setTextColor(ST7735_RED);
    tft.print(int (t)); 
    tft.print("C  ");
    tft.print(int (h)); 
    tft.print("%");
    old_t=int(t);
    old_h=int(h);
  }
}
void bluser(){ // -----------------------------
  bt=1; //переменная для выхода из БТ выход когда 0
  //r=50; g=50; b=50; // начальные значения для ШИМ
  r=EEPROM.read(1); 
  g=EEPROM.read(2); 
  b=EEPROM.read(3);
  analog.Write(17,r);
  analog.Write(18,g);
  analog.Write(19,b);
  Serial.print("R=");
  Serial.print(r);
  Serial.print(" G=");
  Serial.print(g);
  Serial.print(" B");
  Serial.println(b);
  tft.fillScreen(ST7735_BLACK);
  tft.setTextSize(1); 
  tft.setTextColor(ST7735_RED);
  tft.setCursor(0,0);
  tft.print("Bluetooth is active ");
  tft.setCursor(0,10);
  tft.print("Send  E  to exit!");
  tft.setCursor(0,20); 
  tft.print("Send  H  to Help!");
  Serial.print("Send  E  to exit! "); 
  Serial.println("Send  H  to Help!"); // и выводим обратно сообщение

  do
  {
    tft.setTextSize(1); 
    tft.setTextColor(ST7735_RED);
    tft.setCursor(0,0);
    tft.print("Bluetooth is active ");
    tft.drawLine(121,2,127,8,ST7735_RED);
    tft.drawLine(127,8,124,11,ST7735_RED);
    tft.drawLine(124,11,124,0,ST7735_RED);// значёк Bluetooth
    tft.drawLine(124,0,127,3,ST7735_RED);
    tft.drawLine(127,3,121,9,ST7735_RED);
    tft.setTextSize(1); 
    tft.setTextColor(ST7735_WHITE);
    tft.setCursor(0,0);
    tft.print("Bluetooth is active ");
    tft.drawLine(121,2,127,8,ST7735_GREEN);
    tft.drawLine(127,8,124,11,ST7735_GREEN);
    tft.drawLine(124,11,124,0,ST7735_GREEN);
    tft.drawLine(124,0,127,3,ST7735_GREEN);
    tft.drawLine(127,3,121,9,ST7735_GREEN);
    value=Serial.read();          
    switch (value)
    {
    case '1': 
      Serial.print("Red +1 = "); 
      Serial.println(r);
      tft.setTextSize(2); 
      tft.setTextColor(ST7735_BLACK); 
      tft.setCursor(50,30); 
      tft.print(r);
      r=r+5; 
      if(r >= 255) r = 255; 
      analog.Write(17,r);
      tft.setTextSize(2); 
      tft.setTextColor(ST7735_RED); 
      tft.setCursor(50,30); 
      tft.print(r);
      break;
    case '2': 
      Serial.print("Red -1 = ");
      Serial.println(r);
      tft.setTextSize(2); 
      tft.setTextColor(ST7735_BLACK); 
      tft.setCursor(50,30); 
      tft.print(r);
      r=r-5; 
      if(r <= 0) r = 0;        
      analog.Write(17,r);
      tft.setTextSize(2); 
      tft.setTextColor(ST7735_RED); 
      tft.setCursor(50,30); 
      tft.print(r);
      break;
    case '3': 
      Serial.print("Green +1 = "); 
      Serial.println(g);
      tft.setTextSize(2); 
      tft.setTextColor(ST7735_BLACK); 
      tft.setCursor(50,50); 
      tft.print(g);
      g=g+5; 
      if(g >= 255) g = 255; 
      analog.Write(18,g);
      tft.setTextSize(2); 
      tft.setTextColor(ST7735_GREEN); 
      tft.setCursor(50,50); 
      tft.print(g);
      break;
    case '4': 
      Serial.print("Green -1 = ");
      Serial.println(g);
      tft.setTextSize(2); 
      tft.setTextColor(ST7735_BLACK); 
      tft.setCursor(50,50); 
      tft.print(g);
      g=g-5; 
      if(g <= 0) g = 0;        
      analog.Write(18,g);
      tft.setTextSize(2); 
      tft.setTextColor(ST7735_GREEN); 
      tft.setCursor(50,50); 
      tft.print(g);
      break;
    case '5': 
      Serial.print("Blue +1 = "); 
      Serial.println(b);
      tft.setTextSize(2); 
      tft.setTextColor(ST7735_BLACK); 
      tft.setCursor(50,70); 
      tft.print(b);        
      b=b+5; 
      if(b >= 255) b = 255;         
      analog.Write(19,b);
      tft.setTextSize(2); 
      tft.setTextColor(ST7735_BLUE); 
      tft.setCursor(50,70); 
      tft.print(b);        
      break;
    case '6': 
      Serial.print("Blue -1 = ");
      Serial.println(b);
      tft.setTextSize(2); 
      tft.setTextColor(ST7735_BLACK); 
      tft.setCursor(50,70); 
      tft.print(b);       
      b=b-5; 
      if(b <= 0) b = 0;        
      analog.Write(19,b);
      tft.setTextSize(2); 
      tft.setTextColor(ST7735_BLUE); 
      tft.setCursor(50,70); 
      tft.print(b);
      break;
    case 'E': 
      Serial.println("exit BT. Send 'A' to return"); 
      bt=0; 
      break; // Выход в главное меню
    case 'H': 
      help(); 
      break;
      // ---- вывод на экран ----
    }
  } 
  while (!bt==0); //пока 1 - работает БТ---------!Serial.available());
  tft.fillScreen(ST7735_BLACK);
  tft.setTextSize(1); 
  tft.setTextColor(ST7735_WHITE);
  tft.setCursor(0,20); 
  tft.print("Save color to EERPOM ...");
  Serial.print("R=");
  Serial.print(r);
  Serial.print(" G=");
  Serial.print(g);
  Serial.print(" B=");
  Serial.println(b);
  tft.setCursor(0,30); 
  tft.print("Exit Bluetooth. Bye!");
  EEPROM.write(1, r); 
  EEPROM.write(2, g); 
  EEPROM.write(3, b);
  delay(1500);        
  tft.fillScreen(ST7735_BLACK);
  return;
}
void help(){
  Serial.println("Help! Help! Help!!!");
  Serial.println("A - enter bluetooth mode.");
  Serial.println("E - exit bluetooth mode.");
  Serial.println("H - this text message");
  Serial.println("Red +- 1/2, G +- 3/4 B +- 5/6");
}