#1 2015-03-12 10:58:31

brigadir
Учасник
Зареєстрований: 2015-03-04
Повідомлень: 17

LED лента з автоматичною підсвіткою

На старті в мене була світодіодна лента, захована під тажерками на кухні. Коли потрібно, вона підсвічувала кухонний стіл. Включалася переключателем на ланцюжку. Щоб розкрити мотив цього проекту, опишу для прикладу таку ситуацію: стоїмо на кухні, заварюємо чай. Кладемо сито в кружку, насипаємо зілля і усвідомлюємо, що було б краще, якби ми бачили, скільки зілля насипали. Згадуємо, що є лента під тажерками, кладемо зілля на стіл, тягнемо бурульку на ланцюжку і продовжуємо заварювати чай. Вкінці ще раз тягнемо за бурульку. Якщо підсумувати ці всі дії, то вийде, що КПД нашої праці під час заварювання чаю менше 50%. В 21 столітті така трата ресурсів недопустима :)

Задачу проекту поставив так: зробити світодіодну ленту адаптивною, щоб користувач в принципі не тягнувся до виключателя, і навіть не думав, що йому потрібно більше світла.

Лента живиться від 12В, тому для Arduino (а саме Pro Mini from China) беремо стабілізатор напруги на 5В L7805CV.
Слідкувати за обстановкою під тажерками будемо PIR датчиком руху HC-SR501.
Контроль ленти покладемо на мосфет IRLZ14 і підключимо його до PWM піна Arduino.
Щоб наше творіння виглядало красиво, розміщуємо всі компоненти на білому картоні (взяв, що було під рукою) і прив’язуємо капроновою ниткою.
2.jpg

Завдяки порадам тутешнього форумчанина CJ, добавив до мосфета пару резисторів: 500 Ом між затвором і Arduino і 47 кОм між затвором і витоком.

Переходимо до логіки.
Рівень яскравості регулюється через PWM. Коли датчик бачить рух, включається режим накопичення, в протилежному випадку - режим спаду. Щоб світло на гасло зразу, як тільки користувач перестав рухатися, додамо буферний діапазон.

Спрощений скетч виглядає так:

void loop() 
{
  int motionDetected = digitalRead(PIR_PIN);
  if (motionDetected == HIGH)
    motionBuffer++;
  else
    motionBuffer--;

  if (motionBuffer > THRESHOLD_LEVEL)
    brightness = min(brightness + 1, PWM_CAPACITY - 1);
  else
    brightness = max(brightness - 1, 0);

  analogWrite(LED_PIN, brightness);
  delay(TIMER_DELAY);
}

В бойових умовах я зустрівся таким моментом: коли brightness спадає до нуля, світло гасне скачками. Виявилося, що глибини PWM недостатньо на малих значеннях: якщо міняємо brightness з 0 на 1 - лента засвічується забагато. Спочатку я проводив різні магічні ритуали над резисторами мосфета, але не досяг результату. Основна причина в тому, що я зелений в електроніці. Тому рішив цю проблему програмно: PWM на Arduino має точність в 10 біт (0-1023) на деяких пінах. Використати цю фішку нам допоможе бібліотека Timer1. Взяв форк PaulStoffregen/TimerOne на GitHub, оскільки її автор пише, що оптимізував стандартний код.
Для нашого випадку точність brightness зросла в 4 рази. Перевірив на тестовому стенді - перфектно.

На цьому етапі проект досягнув зрілості і можна вважати його закінченим.
5.jpeg

Робочий скетч:

#include <TimerOne.h>

const int LED_PIN = TIMER1_A_PIN;    // 9 onATMega328P
const int PIR_PIN = 12;
const int LED_TEST_PIN = 13;
const int TIMER_DELAY = 10;
const int PWM_CAPACITY = 1024;    // 10 bit
const int THRESHOLD_LEVEL = 10;    // motion buffer must reach threshold level to fade LEDs on
const int SATURATION_LEVEL = (30 * 1000 / TIMER_DELAY);  // 30 seconds
int motionBuffer = 0;
int brightness = 0;

void setup()
{
  pinMode(LED_PIN, OUTPUT);
  pinMode(PIR_PIN, INPUT);
  pinMode(LED_TEST_PIN, OUTPUT);
  Timer1.initialize(5000);      // 5000 ns => 200Hz
  Timer1.pwm(LED_PIN, PWM_CAPACITY/2);
  Serial.begin(9600);

  // test on start-up:
  Serial.println("Start-up test...");
  for (int i = 0; i < PWM_CAPACITY; i++)
  {
    //analogWrite(LED_PIN, i);
    Timer1.setPwmDuty(LED_PIN, i);
    delay(1);
  }
  for (int i = (PWM_CAPACITY - 1); i >= 0; i--)
  {
    //analogWrite(LED_PIN, i);
    Timer1.setPwmDuty(LED_PIN, i);
    delay(1);
  }
  Serial.println("...test finished");
}

void loop() 
{
  int motionDetected = digitalRead(PIR_PIN);
  if (motionDetected == HIGH)
  {
    motionBuffer++;
    digitalWrite(LED_TEST_PIN, HIGH);
    if (motionBuffer > THRESHOLD_LEVEL)
      motionBuffer = SATURATION_LEVEL;
  }
  else
  {
    motionBuffer--;
    motionBuffer = max(motionBuffer, 0);
    digitalWrite(LED_TEST_PIN, LOW);
  }
  if (motionBuffer > THRESHOLD_LEVEL)
    brightness = min(brightness + 1, PWM_CAPACITY - 1);
  else
    brightness = max(brightness - 1, 0);

  //analogWrite(LED_PIN, brightness);
  Timer1.setPwmDuty(LED_PIN, brightness);
  Serial.print("Motion buffer: ");
  Serial.println(motionBuffer);
  delay(TIMER_DELAY);
}

Відео з чайником:

Неактивний

#2 2015-06-16 12:13:17

Саня Паскаль
Гість

Re: LED лента з автоматичною підсвіткою

А ви впевнені, що точність ШІМ(PWM) є 10 біт ?? Мені здається, що точність ШІМ - 8 біт(0-255). Якщо Ви в тому впевнені, напишіть, як коирстуватися такою фішкою.

#3 2015-06-16 13:01:04

NoName
Customer
З Київ
Зареєстрований: 2014-07-08
Повідомлень: 1,446

Re: LED лента з автоматичною підсвіткою

Неактивний

#4 2015-06-17 16:49:32

brigadir
Учасник
Зареєстрований: 2015-03-04
Повідомлень: 17

Re: LED лента з автоматичною підсвіткою

Саня Паскаль пише:

А ви впевнені, що точність ШІМ(PWM) є 10 біт ?? Мені здається, що точність ШІМ - 8 біт(0-255). Якщо Ви в тому впевнені, напишіть, як коирстуватися такою фішкою.

Стандартний PWM 8-бітний. Тому я шукав альтернативу.
Ось що пишуть про Timer1::pwm(pin, duty, period)
Generates a PWM waveform on the specified pin. Output pins for Timer1 are PORTB pins 1 and 2, so you have to choose between these two, anything else is ignored. On Arduino, these are digital pins 9 and 10, so those aliases also work. Output pins for Timer3 are from PORTE and correspond to 2,3 & 5 on the Arduino Mega. The duty cycle is specified as a 10 bit value, so anything between 0 and 1023. Note that you can optionally set the period with this function if you include a value in microseconds as the last parameter when you call it.

Фізично timer1 підтримує 16-бітний лічильник.

Тут пояснюють, як користуватися цією фішкою: http://sphinx.mythic-beasts.com/~markt/ … imers.html

Неактивний

#5 2015-11-19 01:36:07

alexis
Гість

Re: LED лента з автоматичною підсвіткою

А не проще было поставить датчик движения ,он дешевле.

#6 2015-12-04 20:28:23

taras
Гість

Re: LED лента з автоматичною підсвіткою

int led = 9;
int sens = 7;
int dn;
int time;
int handly ;
const int dayNight = A0;
const int delayTime = A1;
const int hand = A2;
int sensor = 0;
int x = 0;
void setup()
{
   Serial.begin(9600);
pinMode(sens, INPUT);
pinMode(led, OUTPUT);
}

void loop()
{
handly = analogRead(hand);
  dn = analogRead(dayNight);
  Serial.print("  sensor = " );                           
  Serial.println(dn);
Serial.print("  fotoresistor = " );                           
  Serial.print(handly); 
  Serial.print(" time = " );                           
  Serial.print((time*2)/17.05);
  if(dn<handly)
  {
  time = analogRead(delayTime); 
  sensor = digitalRead(sens);
    if(sensor==HIGH)
    {
      for(int w=0; w<255; w++)
     {Serial.println(w);
        analogWrite(led, w);
        delay(30);
      }
    Serial.println("pause"); 
               for (x=0; x<(time*12); x++)
              {         
                  Serial.print(x/100);
                 Serial.println("sec");
                     delay(1);       
                 
          sensor = digitalRead(sens);
    if(sensor==HIGH)
                {   Serial.println("sensor");
               x = 0;
                }
              }
               
               
                for(int w=255; w>-1; w--)
      {Serial.println(w);
        analogWrite(led, w);
        delay(50);
        sensor = digitalRead(sens);
    if(sensor==HIGH)
         {
           break;
         }
     }

}

}

скетч один світлодіод один сенсор та датчик освіьленості

#7 2015-12-04 20:38:10

taras
Гість

Re: LED лента з автоматичною підсвіткою

#include "Tlc5940.h"
int x;
int val;


int stails = 14;


int sensorPin1 = A1;
int sensorPin2 = A2;
int sensorPin3 = A3;
int sensorPin4 = A4;


int sensdown = 0;
int sensup = 0;
int bitreyd_stails = 4000;
int delay_stairs = 0;
int bitreyd_first_last = 0;
int fotoresistor = 0;
int stairsdelay = 0;

void setup()
{
//  Serial.begin(9600);
Tlc.init();
  pinMode( 5 , INPUT);
  pinMode(4 , INPUT);
 
}

void loop()
{ Tlc.set( 0, 0); //яскравість першої
  Tlc.set( 13, 0);
  Tlc.update();
   fotoresistor = analogRead(sensorPin4);
 
  val = analogRead(0);
      if (val<fotoresistor)
      {

     

      delay_stairs = analogRead(sensorPin2);
      bitreyd_first_last = analogRead(sensorPin3);
      stairsdelay = analogRead(sensorPin1);
       
          Tlc.set( 0,  (bitreyd_first_last * 4)); //яскравість першої
          Tlc.set( 13, (bitreyd_first_last * 4)); // яскравість чотирнадцятої
           Tlc.update();//це незабувати воно відпрасляє код на ТЛЦ

sensdown = digitalRead(5);
   if (sensdown == HIGH)
      {Serial.println("sens down");
     
       {  int direction = 1;
        for (int channel = 0; channel < NUM_TLCS * stails; channel += direction)
           {Serial.print("on up =");
             Serial.println(channel);
        for(int i = 0; i<(bitreyd_stails); i++)
       
        {
          Tlc.set(channel , i);
          Tlc.update();
         delayMicroseconds((delay_stairs/10));
         }
         delayMicroseconds(1);
    }
  }
     
// Serial.println("pause"); 
               for (x=0; x < stairsdelay; x++)
              {         
  //                Serial.print(x/100);
    //             Serial.println("sec");
                    delay(10);       
                 
          sensdown = digitalRead(5);
                  if (sensdown == HIGH)
                {  // Serial.println("sensdown");
                   
               x = 0;
                }
          sensup = digitalRead(4);
                   if (sensup == HIGH)
              { //Serial.println("sensup");
                x = 0;
              }
              }
         {
     
           int direction = 1; //бодя павук
           // напрямок від 0 до 16
           
      for (int channel = 0; channel < NUM_TLCS * stails; channel += direction)
     
     {Serial.print("off up =");
             Serial.println(channel);
       
     for(int i = (bitreyd_stails); i>0; i--)
              {   
        Tlc.set(channel, i);
        Tlc.update();
         delayMicroseconds((delay_stairs/10)); // затримка ШИМ
     }
     delayMicroseconds(1);
Tlc.set(channel, 0);
sensdown = digitalRead(5);
if(sensdown == HIGH)
        {
               
        break;
        }
     sensup = digitalRead(4);
        if(sensup == HIGH)
        {
          break;
        }   
}
}
}

         
sensup = digitalRead(4);
   if (sensup == HIGH)
      {
             
       {  int direction = 1;
        for (int channel = (NUM_TLCS * stails)-1; channel > -1 ; channel -= direction)
           {Serial.print("on down =");
             Serial.println(channel);
        for(int i = 0; i<(bitreyd_stails); i++)
        {
          Tlc.set(channel, i);
          Tlc.update();
         delayMicroseconds((delay_stairs/10));
         }
         delayMicroseconds(1);
}
  }
     
//Serial.println("pause"); 
               for (x=0; x < stairsdelay; x++)
              {         
  //                Serial.print(x/100);
    //             Serial.println("sec");
                    delay(10);       
                 
          sensdown = digitalRead(5);
                  if (sensdown == HIGH)
                {  // Serial.println("sensdown");
               
               x = 0;
                }
          sensup = digitalRead(4);
                   if (sensup == HIGH)
              { //Serial.println("sensup");
                         
                x = 0;
              }
              }

         {
      // це напрямок
           int direction = 1;
           // напрямок від 0 до 16
           
      for (int channel = (NUM_TLCS * stails)-1; channel > 0 ; channel -= direction)
     
     {Serial.print("off duwn =");
             Serial.println(channel);
       
     for(int i = (bitreyd_stails); i>0; i--)
              {   
        Tlc.set(channel, i);
        Tlc.update();
         delayMicroseconds((delay_stairs/10)); // затримка ШИМ


     }
     delayMicroseconds(1);
     sensup = digitalRead(4);
        if(sensup == HIGH)
        {
          break;
        }
        sensdown = digitalRead(5);
if(sensdown == HIGH)
        {
               
        break;
        }
Tlc.set(channel, 0);
}
}
  }
       
}

}


підсвітка сходів з датчиками руху та драйвер світлодіодний TLC5940

#8 2015-12-04 20:38:15

taras
Гість

Re: LED лента з автоматичною підсвіткою

#include "Tlc5940.h"
int x;
int val;


int stails = 14;


int sensorPin1 = A1;
int sensorPin2 = A2;
int sensorPin3 = A3;
int sensorPin4 = A4;


int sensdown = 0;
int sensup = 0;
int bitreyd_stails = 4000;
int delay_stairs = 0;
int bitreyd_first_last = 0;
int fotoresistor = 0;
int stairsdelay = 0;

void setup()
{
//  Serial.begin(9600);
Tlc.init();
  pinMode( 5 , INPUT);
  pinMode(4 , INPUT);
 
}

void loop()
{ Tlc.set( 0, 0); //яскравість першої
  Tlc.set( 13, 0);
  Tlc.update();
   fotoresistor = analogRead(sensorPin4);
 
  val = analogRead(0);
      if (val<fotoresistor)
      {

     

      delay_stairs = analogRead(sensorPin2);
      bitreyd_first_last = analogRead(sensorPin3);
      stairsdelay = analogRead(sensorPin1);
       
          Tlc.set( 0,  (bitreyd_first_last * 4)); //яскравість першої
          Tlc.set( 13, (bitreyd_first_last * 4)); // яскравість чотирнадцятої
           Tlc.update();//це незабувати воно відпрасляє код на ТЛЦ

sensdown = digitalRead(5);
   if (sensdown == HIGH)
      {Serial.println("sens down");
     
       {  int direction = 1;
        for (int channel = 0; channel < NUM_TLCS * stails; channel += direction)
           {Serial.print("on up =");
             Serial.println(channel);
        for(int i = 0; i<(bitreyd_stails); i++)
       
        {
          Tlc.set(channel , i);
          Tlc.update();
         delayMicroseconds((delay_stairs/10));
         }
         delayMicroseconds(1);
    }
  }
     
// Serial.println("pause"); 
               for (x=0; x < stairsdelay; x++)
              {         
  //                Serial.print(x/100);
    //             Serial.println("sec");
                    delay(10);       
                 
          sensdown = digitalRead(5);
                  if (sensdown == HIGH)
                {  // Serial.println("sensdown");
                   
               x = 0;
                }
          sensup = digitalRead(4);
                   if (sensup == HIGH)
              { //Serial.println("sensup");
                x = 0;
              }
              }
         {
     
           int direction = 1; //бодя павук
           // напрямок від 0 до 16
           
      for (int channel = 0; channel < NUM_TLCS * stails; channel += direction)
     
     {Serial.print("off up =");
             Serial.println(channel);
       
     for(int i = (bitreyd_stails); i>0; i--)
              {   
        Tlc.set(channel, i);
        Tlc.update();
         delayMicroseconds((delay_stairs/10)); // затримка ШИМ
     }
     delayMicroseconds(1);
Tlc.set(channel, 0);
sensdown = digitalRead(5);
if(sensdown == HIGH)
        {
               
        break;
        }
     sensup = digitalRead(4);
        if(sensup == HIGH)
        {
          break;
        }   
}
}
}

         
sensup = digitalRead(4);
   if (sensup == HIGH)
      {
             
       {  int direction = 1;
        for (int channel = (NUM_TLCS * stails)-1; channel > -1 ; channel -= direction)
           {Serial.print("on down =");
             Serial.println(channel);
        for(int i = 0; i<(bitreyd_stails); i++)
        {
          Tlc.set(channel, i);
          Tlc.update();
         delayMicroseconds((delay_stairs/10));
         }
         delayMicroseconds(1);
}
  }
     
//Serial.println("pause"); 
               for (x=0; x < stairsdelay; x++)
              {         
  //                Serial.print(x/100);
    //             Serial.println("sec");
                    delay(10);       
                 
          sensdown = digitalRead(5);
                  if (sensdown == HIGH)
                {  // Serial.println("sensdown");
               
               x = 0;
                }
          sensup = digitalRead(4);
                   if (sensup == HIGH)
              { //Serial.println("sensup");
                         
                x = 0;
              }
              }

         {
      // це напрямок
           int direction = 1;
           // напрямок від 0 до 16
           
      for (int channel = (NUM_TLCS * stails)-1; channel > 0 ; channel -= direction)
     
     {Serial.print("off duwn =");
             Serial.println(channel);
       
     for(int i = (bitreyd_stails); i>0; i--)
              {   
        Tlc.set(channel, i);
        Tlc.update();
         delayMicroseconds((delay_stairs/10)); // затримка ШИМ


     }
     delayMicroseconds(1);
     sensup = digitalRead(4);
        if(sensup == HIGH)
        {
          break;
        }
        sensdown = digitalRead(5);
if(sensdown == HIGH)
        {
               
        break;
        }
Tlc.set(channel, 0);
}
}
  }
       
}

}


підсвітка сходів з датчиками руху та драйвер світлодіодний TLC5940

Швидке повідомлення

Введіть повідомлення і натисніть Надіслати

Підвал форуму