Фоторезистор плюс PIR

RuslanDNA
Offline
Зарегистрирован: 26.01.2017

Здраствуйте. Пытаюсь собрать датчик движения на Arduino Nano, фоторезистор, PIR HC-SR501 и реле для ардуино.

Цель сделать что бы реле включалось только когда темно, в сети нашел скетчи примеры для работы с реле, PIR и фоторезистор и все это как смог объеденил воедино. Впринципе получился работоспособный скетч, но работает не много не так как хотелось бы. Сейчас он работает так: Считывает показания с PIR и если есть движение, то проверяется темно ли и если темно то включается реле, но если станет светло реле тут же отключается. И так может бесконечно пока идет сигнал движения с датчика движения.

А вот как переделать что бы сначало проверялось темно ли, а потом в зависимости от показаний PIR включалось реле, не могу... 

Хотелось бы что бы когда темно реле включалось от показаний PIR и если станет светло не отключалось пока идет сигнал с датчика движения.

 


int ledPin = 13;  // инициализируем пин для светодиода
int ldr = 0; // фоторезистора
int inputPin = 2;  // инициализируем пин для получения сигнала от пироэлектрического датчика движения
int relePin = 4;
int pirState = LOW;  // начинаем работу программы, предполагая, что движения нет
int releState = LOW;

int val = 0;  // переменная для чтения состояния пина

void setup() {

pinMode(ledPin, OUTPUT);  // объявляем светодиод в качестве  OUTPUT
pinMode(inputPin, INPUT);  // объявляем датчик в качестве INPUT
pinMode(relePin, OUTPUT);

Serial.begin(9600);

}

void loop(){


 val = digitalRead(inputPin) ;  // считываем значение с датчика
if (val == HIGH && (analogRead(ldr) < 300)) {  // проверяем, соответствует ли считанное значение HIGH
digitalWrite(ledPin, HIGH);  // включаем светодиод
digitalWrite(relePin, LOW);
delay (1000);
if (pirState == LOW) {

// мы только что включили

Serial.println("Motion detected!");
// мы выводим на серийный монитор изменение, а не состояние

pirState = HIGH;

}

} else {

digitalWrite(ledPin, LOW); // выключаем светодиод
digitalWrite(relePin, HIGH);
if (pirState == HIGH){

// мы только что его выключили

Serial.println("Motion ended!");

// мы выводим на серийный монитор изменение, а не состояние

pirState = LOW;

}

}

}

В программировании полный ноль((

Спасибо всем.

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

RuslanDNA пишет:

Хотелось бы что бы когда темно реле включалось от показаний PIR и если станет светло не отключалось пока идет сигнал с датчика движения.

Сами поняли чего написали ? я нет, растолкуйте.

El
Offline
Зарегистрирован: 10.03.2016

RuslanDNA пишет:

Здраствуйте. Пытаюсь собрать датчик движения на Arduino Nano, фоторезистор, PIR HC-SR501 и реле для ардуино.

Пытался понять, что делает твое устройство, но не понял.

Я делал похожее устройство, которе сейчас исправно работает, вот ссылка http://arduino.ru/forum/programmirovanie/khochu-posmotret-vo-chto-prevratyat-moi-kod-professionaly.

Код я потом дописывал по советам бывалых, но на работоспособность еще не проверял. Прилагаю измененный код:

#include <LiquidCrystal.h> //дисплей использовался только для выяснения % освещенности на месте, чтоб не таскать с собой бук. Когда нужный процент освещенности найден, то можно удалить все упоминания об экране.
#include <EEPROM.h> 
#define buttonPin 12 //пин датчика движения
#define ledPin 11 //пин подключения светодиодной ленты
#define lightMeterPin A0 //пин подключения датчика освещенности - фоторезистор, х/з что за марка, какой-то валялся
#define persentLight EEPROM.read(1) //чтоб каждый раз не писать этот еепром.
#define potentiometr A1 //подстроечник для настройки предела освещенности. используется для настройки уровня освещенности для включения ленты.
#define buttonValuePin 3 //пин кнопки для записи мануального значения освещенности в память устройства. можно и без нее, но я классную кнопку выпаял из старого сидюка, и мне захотелось её израсходовать.
#define step_delay 8 //замедление циклов зажигания и затухания ленты.
#define max_val 200 //максимальное значение яркости ленты.
byte lightLevel = 0; //переменная со значением уровня яркости ленты.
LiquidCrystal lcd(9, 8, 7, 6, 5, 4);
byte persentLightVal = persentLight;
//===================================================================================================================================================================================================================
void setup() {
  if (persentLightVal > 100) { //если нас не устраивает значение сохраненного уровня минимальной освещенности, то записываем дефолтное значение.
    EEPROM.write(1, byte(25)); //если значение освещенности в памяти больше 100%, то пишем в память значение 25.
  }
  { //описываем типы пинов
    pinMode (buttonPin, INPUT); //датчик движения - вход
    pinMode (ledPin, OUTPUT); //лента - выход
    //digitalWrite(ledPin, LOW); // подстраховаться и отключить подсветку при загрузке устройства.
    pinMode (lightMeterPin, INPUT); //датчик освещенности - вход
    pinMode(A1, INPUT); //подстроечный резистор для настройки минимального уровня освещенности.
    pinMode(buttonValuePin, INPUT); //кнопка для записи в память значения минимальной освещенности.
  }
  { //занимаемся ерундой, пока тупит датчик движения. время протупления извещателя - 70 секунд (моему датчику движения необходимо 65 секунд, чтоб загрузиться)
    uint32_t old_m = millis();
    const uint32_t start_time = old_m;
    boolean sostoyanie = false;
    while (start_time + 70000 > millis()) {
      if (old_m + 2000 < millis()) {
        old_m = millis();
        analogWrite(ledPin, max_val * sostoyanie);
        sostoyanie = !sostoyanie;
      }
    }
    digitalWrite(ledPin, LOW);
  }
  { // пишем названия полей на ЛЦД
    lcd.begin(20, 4);
    lcd.setCursor(0, 0);
    lcd.print("Fotoresist."); //значение АЦП с фоторезистора/значение минимальной освещенности
    lcd.setCursor(0, 1);
    lcd.print("DD relay"); //статус датчика движения
    lcd.setCursor(0, 2);
    lcd.print("Value"); //отсчет секунд с момента старта платы. Просто была строчка на экране лишняя.
    lcd.setCursor(0, 3);
    lcd.print("Manual val."); //значение АЦП с подстроечника установки уровня минимальной освещенности.
  }
}

void loop() {
  //объявление переменных более правильным способом
  //======== <a data-cke-saved-href="http://arduino.ru/forum/programmirovanie/etyudy-dlya-nachinayushchikh-pamyat-2-staticheskie-peremennye" href="http://arduino.ru/forum/programmirovanie/etyudy-dlya-nachinayushchikh-pamyat-2-staticheskie-peremennye" rel="nofollow">http://arduino.ru/forum/programmirovanie/etyudy-dlya-nachinayushchikh-pamyat-2-staticheskie-peremennye</a> ========
  static byte manualValue; //значение подстроечника для записи в память приведенное к %
  static uint32_t timer1 = 0; //таймер для параметра timeToLive
  static boolean powerOn = false; //параметр 1-лента включена, 2 - лента выключена
  static uint32_t timeToLive = 5000; //время, которое должна прогореть лента, до проверки условий выхода из цыкла
  static boolean napravlenie = false; //переменная для определения включения/выключения ленты.
  if (digitalRead(buttonPin) == LOW && lightMeter() <= persentLightVal && powerOn == false && lightLevel >= 0) { //проверка условий для включения ленты
    napravlenie = true;
    powerOn = true;
    timer1  = millis(); //по нему отсчитывать жизненный цикл включенной ленты
  }
  if (napravlenie == true && lightLevel < max_val) { //плавно зажигаем ленту
    vmestoFor(napravlenie);
  }
  if (millis() >= timer1 + timeToLive - 2000 && millis < timer1 + timeToLive && lightMeter() <= persentLightVal && digitalRead(buttonPin) == LOW) { //продлеваем TTL ввиду того, что люди еще шевелятся, а освещенность недостаточная.
    timer1 = millis();
  }
  if (powerOn == true && timer1 + timeToLive <= millis() && (lightMeter() > persentLightVal || digitalRead(buttonPin) == HIGH) && lightLevel > 0) { //проверка условий для выключения ленты.
    napravlenie = false;
    powerOn = false;
  }
  if (napravlenie == false && lightLevel > 0) { //плавно гасим ленту
    vmestoFor(napravlenie);
  }
  { //обработка уровня минимальной освещенности.
    manualValue = map(analogRead(potentiometr), 0, 1024, 1, 100); //значение в % с подстроечника, которым мы будем регулировать минимальный уровень освещенности.
    if (digitalRead (buttonValuePin) == HIGH) { //записываем значение минимального уровня освещенности в еепром, если мы нажали спец.кнопочку.
      if (persentLightVal != manualValue) { //заись нового уровня освещенности в память
        EEPROM.write(1, manualValue);
        persentLightVal = EEPROM.read(1);
      }
    }
  }
  { //вот с этого места выводим всякую инфу на экран. после настройки можно все это отключить.
    lcd.setCursor(12, 2);
    lcd.print(lightLevel);
    lcd.print ("  ");
    static uint32_t timer2 = 0; //используется для экрана, чтоб изображение не мельтешило. если от экрана отказываться, то спокойно можно удалять.
    if (timer2 + 500 <= millis()) {
      lcd.setCursor(12, 0); //АЦП фоторезистор
      lcd.print("       ");
      lcd.setCursor(12, 0);
      lcd.print(lightMeter());
      lcd.print("/");
      lcd.print(persentLightVal);
      timer2 = millis();
      lcd.setCursor(12, 3);
      lcd.print(manualValue);
      lcd.print("  ");
      lcd.setCursor(12, 1);
      if (digitalRead(buttonPin) == HIGH) {
        lcd.print("ON ");
      } else {
        lcd.print("OFF");
      }
    }
  }
}

byte lightMeter () { //функция для определения уровня освещенности в относительных единицах
  byte persents = map(analogRead(lightMeterPin), 0, 1024, 1, 100); //byte(analogRead(lightMeterPin) / (1024 / 100)); //не уверен, что в байте это значение считается правильно, но в данной конструкции это не играет существенной роли.
  return persents;
}
byte vmestoFor (boolean napravlenie) {//функция замены цикла ФОР. тру - вверх, фолс - вниз
  static byte val = 0;
  static uint32_t om = millis();
  uint32_t nm = millis();
  if (nm - om > step_delay) {
    om = nm;
    if (napravlenie == true) {// направление вверх
      val++;
    }
    if (napravlenie == false) {//направление вниз
      val--;
    }
    lightLevel = val;
  }
  analogWrite(ledPin, val);
}

Все, что связано с экраном можешь спокойно удалять, просто моя плата или ее хозяин не умеет с монитором порта общаться.

Есть одна бага (я так изначально не задумывал), которую я считаю фичей: если у тебя начинает гаснуть лента, но датчик движения в это время сработал, то она снова набирает яркость. Знаю как это устранить, но мне так больше нравится.

реле воткнешь в нужную часть кода.

RuslanDNA
Offline
Зарегистрирован: 26.01.2017

Я имею ввиду следующие. Когда при показаниях фоторезистора темно реле включалось от показаний датчика движения, сигнал движения идет например 15 секунд и если в этом промежуток времени станет светло надо что бы реле не отключалась.

bwn
Offline
Зарегистрирован: 25.08.2014

Определил - темно+сработка датчика. Следующее определение темно-светло после выключения света.
Или - запрещено определять темно-светло пока включен свет.

RuslanDNA
Offline
Зарегистрирован: 26.01.2017

Так вот как это в коде написать я не могу додуматься

bwn
Offline
Зарегистрирован: 25.08.2014

digitalRead (pinSvet); вставляем в if и смотрим, надо проверять на темно-светло или нет.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Задача совершенно элементарная: у нас два внешних условия:

- движение / нет движения,

- светло / темно.

И одно внутреннее состояние:

- свет горит / не горит.

Очевидно, что изменение внутреннего состояния нужно синхронмизировать с изменением внешнего, а для этого его нужно хранить в переменной.

Очевидно, что есть 4-х внешних комбинации:

1. движение, светло.

2. движение, темно.

3. нет движения, светло.

4. нет движения, темно.

это дает 12 возможных переходов (расписывать лень).

остается лишь посадить на нужные переходы нужные варианты реакции, а остальные игнорировать.

Все это пишется в одну строчку. Точнее, в две: одну на включение и одну на выключение.

balex72
Offline
Зарегистрирован: 30.12.2016

Задача действительно элементарная - впаять фоторезистор в предназначенное для него место в SR-501. После этого он(PIR-сенсор) будет выдавать сигнал об обнаружении движения только в темноте.  У меня таким образом работает ночная подсветка на Tiny13 и светодиодах.

 

RuslanDNA
Offline
Зарегистрирован: 26.01.2017

Я не спорю что элементарная, но для меня это сложно, можете сказать какую строчку добавить что бы что бы включение и выключение реле работало только когда темно.

RuslanDNA
Offline
Зарегистрирован: 26.01.2017

Я так понимаю надо перед строкой 23 добавить строчку которая бы проверяла темно ли или нет, и если темно то выполняла строки ниже, светло пропускала

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

RuslanDNA пишет:
Я не спорю что элементарная, но для меня это сложно, можете сказать какую строчку добавить

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

Цитата:
что бы что бы включение и выключение реле работало только когда темно.

Мне кажется, в этом и есть Ваша проблема: Вы сами не знаете, что Вам нужно.

По логике, как Вы описали, оно в принципе никогда не сможет выключиться, т.к. при включенном свете никогда не будет темно.

RuslanDNA
Offline
Зарегистрирован: 26.01.2017

Ну да проще унизить автора чем, какая цель тогда этого форума. мне надо что бы ночью ардуино включало свет когда движение есть, а когда день не реагировало. Спасибо всем за помощь.

gena
Offline
Зарегистрирован: 04.11.2012

Есть свет - обесточили датчик движения, нет  - запитали. И ардуины не нужно.

Насколько знаю, на самой плате датчика движения есть места, где не установленны радиодетали, что бы учитывать наличие освещения. И снова ардуина не нужна.

 "// начинаем работу программы, предполагая, что движения нет" - //  начинайте работу программы выяснив, если ли свет. И только убедившись, что его нет, идти дальше . Думаю будет попроще.

RuslanDNA
Offline
Зарегистрирован: 26.01.2017

1

RuslanDNA
Offline
Зарегистрирован: 26.01.2017

Ардуино нужно что бы реле включать, на прямую от датчика не работает

gena
Offline
Зарегистрирован: 04.11.2012

  Поправьте грамматику постом выше, читается весело.

gena
Offline
Зарегистрирован: 04.11.2012

  Кто напрямую от датчика не работает?

Почитайте о назначении вывода 9 в микросхеме этого датчика.

RuslanDNA
Offline
Зарегистрирован: 26.01.2017

gena пишет:

  Кто напрямую от датчика не работает?

Реле для ардуино не работает на прямую от датчика PIR. 

RuslanDNA
Offline
Зарегистрирован: 26.01.2017

А в ардуино можно разделить void loop на две части? Что бы когда первая часть была "верна" выполнялась вторая часть.

gena
Offline
Зарегистрирован: 04.11.2012

  Для этого можно применить оператор IF.  

Не уверен, что нельзя заставить реле для ардуины, работать не от ардуины.

bwn
Offline
Зарегистрирован: 25.08.2014

RuslanDNA пишет:

А в ардуино можно разделить void loop на две части? Что бы когда первая часть была "верна" выполнялась вторая часть.

УПС, а функции уже отменили?

RuslanDNA
Offline
Зарегистрирован: 26.01.2017

Я не знаю языка совсем, есть статьи по функциям хорошие?

RuslanDNA
Offline
Зарегистрирован: 26.01.2017

добавил if (analogRead (ldr)<300) перед всем, да вроде бы как надо, темно появилось движение реле включилось и пока идет сигнал с датчика движения не тухнет, но когда сигнал с PIR пропал потухнет только когда станет темно. А если реле будет вкл свет, то получается никогда он не потухнет

bwn
Offline
Зарегистрирован: 25.08.2014

Прожиточный минимум здесь

 

gena
Offline
Зарегистрирован: 04.11.2012

  Значит меняйте логику работы. Ищите движение и после его обнаружения проверяйте наличие света.  Или датчик света выносите подальше от лампы, что бы не засвечивался.

А язык, хотя бы примитивно, изучить придётся. Как же иначе ардуиной командовать?

Изучайте, задача не кажется сложной.

RuslanDNA
Offline
Зарегистрирован: 26.01.2017

у меня в шапке как раз такая логика как Вы написали, но в даном случае если становится светло реле сразу отклчается. И в итоге будет свет включился фоторезистор засветился, свет выключился стало темно и опять свет вкл и так пока идет сигнал с PIR

gena
Offline
Зарегистрирован: 04.11.2012

Кстати. Если включили свет, то можно и не заниматься проверкой его величины, пока свет включен. Вот когда погасите лампу, лишь когда начинайте снова проверять уровень освещённости.

А разве свет включают не на какой то промежуток времени (дойти до двери)?

RuslanDNA
Offline
Зарегистрирован: 26.01.2017

Вот именно это я и хочу узнать как сделать) функцией воспользоваться нужно какой либо?

gena
Offline
Зарегистрирован: 04.11.2012

  Длительность сигнала с RIP можно регулировать (подстроечным резистором). Сделайте сигнал коротким, а время свечения продолжительнее.

gena
Offline
Зарегистрирован: 04.11.2012

  "Какую либо" функцию Вы напишите сами, когда освоите, хотя бы, пять...семь операторов.

Не научившись ходить, бегать не научишься.

RuslanDNA
Offline
Зарегистрирован: 26.01.2017

данной базы хватит? http://arduino.ru/Reference

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

RuslanDNA пишет:

данной базы хватит? http://arduino.ru/Reference

Этого достаточно для тех, кто умеет программировать, но этого совершенно недостаточно, чтобы научиться программировать.

gena
Offline
Зарегистрирован: 04.11.2012
RuslanDNA
Offline
Зарегистрирован: 26.01.2017

Спасибо

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

Попробовал исправить Ваш код. Проверяйте:

#define ledPin 13  // инициализируем пин для светодиода
#define ldr 0 // фоторезистора
#define inputPin 2  // инициализируем пин для получения сигнала от пироэлектрического датчика движения
#define relePin 4
int pirState = LOW;  // начинаем работу программы, предполагая, что движения нет
int releState = LOW;
unsigned long time = 0;

int val = 0;  // переменная для чтения состояния пина

void setup() {

  pinMode(ledPin, OUTPUT);  // объявляем светодиод в качестве  OUTPUT
  pinMode(inputPin, INPUT);  // объявляем датчик в качестве INPUT
  pinMode(relePin, OUTPUT);

  Serial.begin(9600);

}

void loop(){
  val = digitalRead(inputPin) ;  // считываем значение с датчика
  
  if (val == HIGH && (analogRead(ldr) < 300)) {  // проверяем, соответствует ли считанное значение HIGH
   digitalWrite(ledPin, HIGH);  // включаем светодиод
   digitalWrite(relePin, LOW);
   time = millis();  
   pirState = 1;   
  }
  
  if (val == HIGH) time = millis();
  
  if(pirState == 1 && millis()- time >= 1000){
    digitalWrite(ledPin, LOW); // выключаем светодиод
    digitalWrite(relePin, HIGH);
    pirState = 0;
  }
  
  if (pirState)Serial.println("Motion ended!");
  else Serial.println("Motion detected!");
  
}

 

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

RuslanDNA пишет:

Реле для ардуино не работает на прямую от датчика PIR. 


Неправда, работает.

RuslanDNA
Offline
Зарегистрирован: 26.01.2017

Свою мечту я осуществил как смог, да может тупо, не красиво, не правильно, но как смог так и сделал и работает так как я и хотел.

Вот что у меня получилось.

 

/*

Делаем датчик движения

*/

int ledPin = 13;  // инициализируем пин для светодиода
int ldr = 0; // пин фоторезистора
int inputPin = 2;  // инициализируем пин для получения сигнала от пироэлектрического датчика движения
int relePin = 4;   // пин реле
int pirState = LOW;  // начинаем работу программы, предполагая, что движения нет
int releState = LOW; 
int val = 0;  // переменная для чтения состояния пина

void setup() {

pinMode(ledPin, OUTPUT);  // объявляем светодиод в качестве  OUTPUT
pinMode(inputPin, INPUT);  // объявляем датчик в качестве INPUT
pinMode(relePin, OUTPUT); // объявляем реле в качестве  OUTPUT

Serial.begin(9600);

}

void loop()

{
  if (analogRead (ldr)>300) // проверяет темно ли?
  {
    digitalWrite(relePin, HIGH); // если светло то реле выключено
  }
  else if (digitalRead(inputPin) == HIGH) // если темно проверяет есть ли сигнал с PIR
  {
    while (digitalRead(inputPin) == HIGH) { // если есть выполняет цикл void releon
    releon();
  }
  }
  else
  {
    digitalWrite(relePin, HIGH); // если нет сигнала реле оф
  }
  
}

void releon()
{
  digitalWrite(relePin, LOW); // цикл реле он
}

Спасибо всем кто помог идиоту т.е. мне)

RuslanDNA
Offline
Зарегистрирован: 26.01.2017

И подскажите пожалуйста как прятать под спойлер)

bwn
Offline
Зарегистрирован: 25.08.2014

Когда вставляете код, вкладка "дополнительно", "свернуть".