Страница 1 из 1

Motion sensor (PIR) | Датчик движения (инфракрасный)

Добавлено: 26 авг 2018, 22:42
Berk
Приветствую всех форумчан. Решил поделится своим проектом - Датчик движения для сети Майсенсорс на батарейках. Срок работы на одном комплекте батареек > 3 лет.
Что может этот датчик движения:
Прошивка по воздуху.
Работа на всех бутлоадерах.
Отправка состояния датчика движения на контролер
Три режима работы датчика движения (Ночь|День|Круглосуточно)
Регулируемая задержка (без задержки|1минута - 4 часа)
Отправка остатка заряда батарейки в процентах
Отправка уровня освещенности в Люксах
Настройка через модуль Майсенсорс в Мажордомо(да впринципе и через любой другой контролер):
Интервал отправки остатка заряда батарейки
Интервал отправки уровня освещенности
Настройка режима работы сигнального светодиода (RGB) - Скрытый режим|Красный|Зеленый|Синий
Настройка уровня границы освещенности при которой датчик движения будет работать
Настройка времени удержания тригера датчика движения в активном состоянии. Так же программно применен рестарт указанного интервала при повторном движении во время уже сработавшего детекта движения.

На борту есть плата криптографии atsha204a-stucz-t
Так же присутствует внешняя SPI Flash AT25F512B-SSH-T
Применен очень интересный понижающий преобразователь 3.3-10в в 3.3 в очень классным собственным потреблением 360 наноампер (наноамперы Карл!!!)
|Dual-cell Ultra Low IQ Step Down Converter for Low Power Wireless Applications|

выведены как FTDI так и ICSP, так что полная свобода в манипуляциях над девайсом. Можете использовать мое ПО, можете написать крутое свое. Я только ЗА!!!

Если все это описать в двух словах = девайс работает круто :)

Скрин страницы датчика движения в модуле Майсенсорс в Мажордомо
IMG_26082018_205438_0.png
IMG_26082018_205438_0.png (106.57 КБ) 24162 просмотра
Код скетча для датчика движения написанный мною:

Код: Выделить всё

#include <Wire.h>
#include <BH1750.h>
BH1750 lightMeter;

#define MY_DEBUG
//#define MY_DISABLED_SERIAL
#define MY_RADIO_RF24
#define MY_OTA_FIRMWARE_FEATURE
//#define MY_SIGNING_ATSHA204
//#define MY_SIGNING_ATSHA204_PIN A3
//#define MY_SIGNING_REQUEST_SIGNATURES

#define MOTION_SENS_ID 1
#define LUX_SENS_ID 2
#define SETTING_LED_SENS_ID 100
#define DELAY_TIME_SENS_ID 101
#define MOTION_MODE_ID 102
#define SETTING_LUX_SENS_ID 103
#define BATTARY_SEND_SENS_ID 104

#define MYLED_ON 1
#define MYLED_OFF 0
#define BAT_COOF 7.4
#define BAT_MIN 350
#define BAT_MAX 720
#define SLEEP_TIME 300000

static uint8_t motion_pin = 3;
static uint8_t bled_pin = 14;
static uint8_t rled_pin = 15;
static uint8_t gled_pin = 16;
uint8_t selected_led;
uint8_t selected_motion_mode;
uint16_t count_batteryTime = 0;
uint16_t lux;
uint16_t boundary_DNlux;
uint32_t send_batteryTime;
uint32_t delayTime;
int8_t battery;
int8_t old_battery;
int8_t woke_up_from;
boolean flag = 0;
boolean flag2 = 0;
boolean flag3 = 0;
boolean sleep_mode = 1;
boolean tripped;
boolean first_send_battery = 1;
boolean flag_motion_mode;

#include <MySensors.h>

MyMessage msg_motion(MOTION_SENS_ID, V_TRIPPED);
MyMessage msg_lux(LUX_SENS_ID, V_LEVEL);
MyMessage msg_setting_led(SETTING_LED_SENS_ID, V_VAR1);
MyMessage msg_delay_time(DELAY_TIME_SENS_ID, V_VAR1);
MyMessage msg_motion_mode(MOTION_MODE_ID, V_VAR1);
MyMessage msg_setting_lux(SETTING_LUX_SENS_ID, V_LEVEL);
MyMessage msg_battary_send(BATTARY_SEND_SENS_ID, V_VAR1);


void preHwInit()
{
  pinMode(motion_pin, INPUT);
  pinMode(gled_pin, OUTPUT);
  pinMode(rled_pin, OUTPUT);
  pinMode(bled_pin, OUTPUT);
  digitalWrite(bled_pin, HIGH);
  digitalWrite(rled_pin, HIGH);
  digitalWrite(gled_pin, HIGH);
}

void before()
{
  selected_led = loadState(100);
  if (selected_led == 255) {
    selected_led = 0;
    saveState(100, selected_led);
  }

  delayTime = loadState(101);
  if (delayTime > 240) {
    delayTime = 1;
    saveState(101, delayTime);
  }

  send_batteryTime = loadState(102);
  if (send_batteryTime > 250) {
    send_batteryTime = 1;
    saveState(102, send_batteryTime);
  }
  send_batteryTime = send_batteryTime * 10;

  boundary_DNlux = loadState(103);
  if (boundary_DNlux > 250) {
    boundary_DNlux = 0;
    saveState(103, boundary_DNlux);
  }

  selected_motion_mode = loadState(104);
  if (selected_motion_mode > 2) {
    selected_motion_mode = 0;
    saveState(104, selected_motion_mode);
  }
}



void presentation()
{
  sendSketchInfo("Motion Sensor", "1.2");
  wait(100);
  present(MOTION_SENS_ID, S_MOTION, "MOTION STATUS");
  wait(100);
  present(LUX_SENS_ID, S_LIGHT_LEVEL, "LUX LEVEL");
  wait(100);
  present(SETTING_LED_SENS_ID, S_CUSTOM, "LED MODE (R,G,B)");
  wait(100);
  present(DELAY_TIME_SENS_ID, S_CUSTOM, "DELAY TIME/MIN");
  wait(100);
  present(MOTION_MODE_ID, S_CUSTOM, "MOTION MODE (D|N|ALL");
  wait(100);
  present(SETTING_LUX_SENS_ID, S_LIGHT_LEVEL, "LUX MODE");
  wait(100);
  present(BATTARY_SEND_SENS_ID, S_CUSTOM, "BATTERY SEND TIME X10");
}


void setup()
{
  lightMeter.begin();
  readBatLev();
  wait(100);
  lux = lightMeter.readLightLevel();
  send(msg_lux.set(lux));
  wait(100);
  tripped = digitalRead(motion_pin);
  send(msg_motion.set(tripped));
  wait(100);
  send(msg_setting_led.set(selected_led));
  wait(100);
  send(msg_motion_mode.set(selected_motion_mode));
  wait(100);
  send(msg_setting_lux.set(boundary_DNlux));
  wait(100);
  send(msg_battary_send.set(send_batteryTime));
}


void loop()
{
  if (delayTime != 0) {
    if (sleep_mode == 0) {
      woke_up_from = sleep(digitalPinToInterrupt(motion_pin), RISING, delayTime * 60 * 1000, false);
    }
    if (sleep_mode == 1) {
      woke_up_from = sleep(digitalPinToInterrupt(motion_pin), RISING, delayTime * 60 * 1000, true);
      sleep_mode = 0;
    }
  } else {
    if (sleep_mode == 0) {
      woke_up_from = sleep(digitalPinToInterrupt(motion_pin), CHANGE, 0, false);
    }
    if (sleep_mode == 1) {
      woke_up_from = sleep(digitalPinToInterrupt(motion_pin), CHANGE, 0, true);
      sleep_mode = 0;
    }
  }
  if (flag != 1) {
    if (selected_motion_mode != 2) {
      lux = lightMeter.readLightLevel();
      if (selected_motion_mode == 0) {
        if (lux <= boundary_DNlux) {
          flag_motion_mode = 1;
        }
      } else {
        if (lux > boundary_DNlux) {
          flag_motion_mode = 1;
        }
      }
    } else {
      flag_motion_mode = 1;
    }
  }else{
   flag_motion_mode = 1; 
  }


  if (woke_up_from == 1) {
    if (flag_motion_mode == 1) {
      tripped = digitalRead(motion_pin);
      if (delayTime != 0) {
        if (flag == 0) {
          flag = 1;
          led_show_detect(selected_led, MYLED_ON);
          TRANSPORT_DEBUG(PSTR("MyS: STATUS MOTION: DETECTED\n"));
          send(msg_motion.set(1));
          TRANSPORT_DEBUG(PSTR("MyS: SEND STATUS TO GW\n"));
          if (count_batteryTime < send_batteryTime) {
            TRANSPORT_DEBUG(PSTR("MyS: COUNTER BATTERY SEND: %d, < %d\n"), count_batteryTime, send_batteryTime);
            count_batteryTime++;
          }
          else {
            readBatLev();
            count_batteryTime = 0;
            TRANSPORT_DEBUG(PSTR("MyS: COUNTER BATTERY SEND: 0\n"));
            if (selected_motion_mode == 2) {
              lux = lightMeter.readLightLevel();
              send(msg_lux.set(lux));
              TRANSPORT_DEBUG(PSTR("MyS: LUX LEVEL SEND\n"));
            } else {
              send(msg_lux.set(lux));
              TRANSPORT_DEBUG(PSTR("MyS: LUX LEVEL SEND\n"));
            }
            sleep_mode = 1;
          }
        }
        else {
          TRANSPORT_DEBUG(PSTR("MyS: UPDATE DELAY STATUS MOTION: DETECTED\n"));
        }
      } else {
        if (tripped == 0) {
          flag = 1;
          led_show_detect(selected_led, MYLED_OFF);
          TRANSPORT_DEBUG(PSTR("MyS: STATUS MOTION: NOT DETECTED\n"));
          send(msg_motion.set(0));
          TRANSPORT_DEBUG(PSTR("MyS: SEND STATUS TO GW\n"));
        } else {
          flag = 0;
          led_show_detect(selected_led, MYLED_ON);
          TRANSPORT_DEBUG(PSTR("MyS: STATUS MOTION: DETECTED\n"));
          send(msg_motion.set(1));
          TRANSPORT_DEBUG(PSTR("MyS: SEND STATUS TO GW\n"));
          if (count_batteryTime < send_batteryTime * 10) {
            TRANSPORT_DEBUG(PSTR("MyS: COUNTER BATTERY SEND: %d, < %d\n"), count_batteryTime, send_batteryTime);
            count_batteryTime++;
          }
          else {
            readBatLev();
            count_batteryTime = 0;
            TRANSPORT_DEBUG(PSTR("MyS: COUNTER BATTERY SEND: 0\n"));
            if (selected_motion_mode == 2) {
              lux = lightMeter.readLightLevel();
              send(msg_lux.set(lux));
              TRANSPORT_DEBUG(PSTR("MyS: LUX LEVEL SEND\n"));
            } else {
              send(msg_lux.set(lux));
              TRANSPORT_DEBUG(PSTR("MyS: LUX LEVEL SEND\n"));
            }
            sleep_mode = 1;
          }
        }
      }
      flag_motion_mode = 0;
    }
  }

  if (woke_up_from == -1) {
    if (flag == 0) {
      if (count_batteryTime < send_batteryTime) {
        count_batteryTime++;
        TRANSPORT_DEBUG(PSTR("MyS: COUNTER BATTERY SEND: %d, < %d\n"), count_batteryTime, send_batteryTime);
      }
      else {
        readBatLev();
        count_batteryTime = 0;
        TRANSPORT_DEBUG(PSTR("MyS: COUNTER BATTERY SEND: 0\n"));
        if (selected_motion_mode == 2) {
          lux = lightMeter.readLightLevel();
          send(msg_lux.set(lux));
          TRANSPORT_DEBUG(PSTR("MyS: LUX LEVEL SEND\n"));
        } else {
          send(msg_lux.set(lux));
          TRANSPORT_DEBUG(PSTR("MyS: LUX LEVEL SEND\n"));
        }
        sleep_mode = 1;
      }

    } else {
      flag = 0;
      led_show_detect(selected_led, MYLED_OFF);
      TRANSPORT_DEBUG(PSTR("MyS: STATUS MOTION: NOT DETECTED\n"));
      send(msg_motion.set(0));
      TRANSPORT_DEBUG(PSTR("MyS: SEND STATUS TO GW\n"));
    }
    flag_motion_mode = 0;
  }
}


void receive(const MyMessage & message)
{
  if (message.sensor == SETTING_LED_SENS_ID) {
    if (message.type == V_VAR1) {
      if (message.getByte() <= 3) {
        selected_led = message.getByte();
        saveState(100, selected_led);
        send(msg_setting_led.set(selected_led));
        if (selected_led == 0) {
          TRANSPORT_DEBUG(PSTR("MyS: STATUS MOTION LED: OFF\n"));
        }
        if (selected_led == 1) {
          TRANSPORT_DEBUG(PSTR("MyS: STATUS MOTION LED: GREEN\n"));
        }
        if (selected_led == 2) {
          TRANSPORT_DEBUG(PSTR("MyS: STATUS MOTION LED: RED\n"));
        }
        if (selected_led == 3) {
          TRANSPORT_DEBUG(PSTR("MyS: STATUS MOTION LED: BLUE\n"));
        }
      }
    }
  }
  if (message.sensor == DELAY_TIME_SENS_ID) {
    if (message.type == V_VAR1) {
      if (message.getULong() <= 240) {
        delayTime = message.getULong();
        saveState(101, delayTime);
        send(msg_delay_time.set(delayTime));
        TRANSPORT_DEBUG(PSTR("MyS: THE NEW DELAY VALUE IS SET: %d MIN.\n"), delayTime);
      }
    }
  }
  if (message.sensor == BATTARY_SEND_SENS_ID) {
    if (message.type == V_VAR1) {
      if (message.getULong() <= 250) {
        send_batteryTime = message.getULong();
        saveState(102, send_batteryTime);
        send(msg_battary_send.set(send_batteryTime));
        send_batteryTime = send_batteryTime * 10;
        TRANSPORT_DEBUG(PSTR("MyS: THE NEW BATTERY TIME SEND IS SET: %d MOTION SENSOR OPERATIONS\n"), send_batteryTime);
      }
    }
  }

  if (message.sensor == MOTION_MODE_ID) {
    if (message.type == V_VAR1) {
      if (message.getByte() <= 2) {
        selected_motion_mode = message.getByte();
        saveState(104, selected_motion_mode);
        send(msg_motion_mode.set(selected_motion_mode));
        if (selected_motion_mode == 0) {
          TRANSPORT_DEBUG(PSTR("MyS: STATUS MOTION MODE: WORK IN THE DARK\n"));
        }
        if (selected_motion_mode == 1) {
          TRANSPORT_DEBUG(PSTR("MyS: STATUS MOTION MODE: WORK IN THE LIGHT\n"));
        }
        if (selected_motion_mode == 2) {
          TRANSPORT_DEBUG(PSTR("MyS: STATUS MOTION MODE: ALWAYS WORK\n"));
        }
      }
    }
  }
  if (message.sensor == SETTING_LUX_SENS_ID) {
    if (message.type == V_LEVEL) {
      if (message.getUInt() <= 250) {
        boundary_DNlux = message.getUInt();
        saveState(103, boundary_DNlux);
        send(msg_setting_lux.set(boundary_DNlux));
        TRANSPORT_DEBUG(PSTR("MyS: THE NEW BORDER LIGHT LUX IS SET: %d\n"), boundary_DNlux);
      }
    }
  }
}

void readBatLev() {
  wait(100);
  ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX2) | _BV(MUX1);
  wait(100);
  ADCSRA |= _BV(ADSC);
  while (bit_is_set(ADCSRA, ADSC));
  uint8_t low  = ADCL;
  uint8_t high = ADCH;
  long temp = (high << 8) | low;
  float vcc = temp * 1.1 / 1023 * BAT_COOF * 100;
  battery = map((int)vcc, BAT_MIN, BAT_MAX, 0, 100);
  if (battery < 0) {
    battery = 0;
  }
  if (battery > 100) {
    battery = 100;
  }
  TRANSPORT_DEBUG(PSTR("MyS: BATTERY LEVEL: %d, PREVIUS BATTERY LEVEL: %d\n"), battery, old_battery);
  if (first_send_battery == 1) {
    first_send_battery = 0;
    sendBatteryLevel(battery);
    TRANSPORT_DEBUG(PSTR("MyS: SEND BATTERY LEVEL\n"));
    old_battery = battery;
  } else {
    if (old_battery != battery) {
      if (battery < old_battery) {
        old_battery = battery;
        sendBatteryLevel(battery);
        TRANSPORT_DEBUG(PSTR("MyS: SEND BATTERY LEVEL\n"));
      } else {
        battery = old_battery;
      }
    }
  }
}


void led_show_detect(uint8_t led, uint8_t mode) {
  if (led == 1) {
    if (mode == 1) {
      digitalWrite(gled_pin, LOW);
      TRANSPORT_DEBUG(PSTR("MyS: STATUS LED GREEN: ON\n"));
    } else {
      digitalWrite(gled_pin, HIGH);
      TRANSPORT_DEBUG(PSTR("MyS: STATUS LED GREEN: OFF\n"));
    }
  }
  if (led == 2) {
    if (mode == 1) {
      digitalWrite(rled_pin, LOW);
      TRANSPORT_DEBUG(PSTR("MyS: STATUS LED RED: ON\n"));
    } else {
      digitalWrite(rled_pin, HIGH);
      TRANSPORT_DEBUG(PSTR("MyS: STATUS LED RED: OFF\n"));
    }
  }
  if (led == 3) {
    if (mode == 1) {
      digitalWrite(bled_pin, LOW);
      TRANSPORT_DEBUG(PSTR("MyS: STATUS LED BLUE: ON\n"));
    } else {
      digitalWrite(bled_pin, HIGH);
      TRANSPORT_DEBUG(PSTR("MyS: STATUS LED BLUE: OFF\n"));
    }
  }
}

Доп. библиотека:
BH1750_master.rar
(3.11 КБ) 1102 скачивания


Список компонентов которые присутствуют у датчика:
Плата PCB - 50 руб.

Держатель батареи 4 шт - 146 руб.
http://ali.ski/0j22k8

Кварц 8 мГц - 26.5 руб.
http://ali.ski/3wpZcC

Кнопки тактовые смд 2 шт - 14 руб.
http://ali.ski/TIXuLK

Линза Френеля - 18 руб.
http://ali.ski/PyfAb

Разьем 2x3 P6 1.27мм 2 шт - 17.7 руб.
http://ali.ski/2GRtq

NRF24L01 - 68.2 руб.
http://ali.ski/Jx3z00

Конденсатор 100nf 8 шт - 10.25 руб.
http://ali.ski/ctayFM

BH1750FVI-TR - 92.4 руб.
http://ali.ski/d9RYX5

TPS62745DSSR - 97 руб.
http://ali.ski/wD_r6G

AM312 - 110 руб.
http://ali.ski/ZqJSAW

Atmega328p-au - 155 руб.
http://ali.ski/B2JbY

Atsha204a-stucz-t - 66.2 руб.
http://ali.ski/88sem_

RGB SMD 0805 (2012) - 5 руб.
http://ali.ski/GxnHju

Конденсатор 10uf 25в 1206 XTR7 - 6 руб.
http://ali.ski/RiAZ8F

Конденсатор 10uf 16в 1206 XTR5 - 1.2 руб.
http://ali.ski/1OQW2

Индуктивность 4.7uh 1210 - 5 руб.
http://ali.ski/JC2n1

AT25F512B-SSH-T - 48 руб.
http://ali.ski/vfpdL

Конденсатор тантал 1uf 16в 0805 - 6.2 руб.
http://ali.ski/CHz126

Переключатель dsc0011 smd - 24.5 руб.
http://ali.ski/acHKDe

Резисторы 10К 1% 0805 6 шт - 1.2 руб.
http://ali.ski/i1tnsM

Резисторы 1M 1% 0805 1 шт - 0.24 руб.
http://ali.ski/i1tnsM

Резисторы 160К 1% 0805 1 шт - 0.18 руб.
http://ali.ski/i1tnsM

Резисторы 11К 1% 0805 1 шт - 0.18 руб.
http://ali.ski/i1tnsM

Резисторы 27К 1% 0805 1 шт - 0.18 руб.
http://ali.ski/i1tnsM

Резисторы 20К 1% 0805 1 шт - 0.18 руб.
http://ali.ski/i1tnsM

Себестоимость девайса - 969 рублей 31копейка (это в полной комплектации)

Батарейка 3.6в 14250 2шт. - 240 руб.
http://ali.ski/Bf7ny

Прикрепляю архив с платой в формате программы Диптрейс - разводка под ЛУТ
pir_lut.rar
(19.07 КБ) 1128 скачиваний


Вы можете самостоятельно собрать сей девайс, так же можете приобрести этот датчик движения готовым у меня за 1500 рублей, кроме самого датчика можно приобрести готовые изготовленные на промышленном оборудовании платы PCB под самостоятельную сборку - 10 плат - 1000 рублей.

Принимаются любые варианты оплаты, отправка осуществляется в любою точку на нашем шарике.


Фотки датчика движения:
IMG_26082018_205438_0.png
IMG_26082018_205438_0.png (106.57 КБ) 24162 просмотра
IMG_26082018_205438_0.png
IMG_26082018_205438_0.png (106.57 КБ) 24162 просмотра