Датчик движения и подсветка на базе CROW MH-20 и ATTiny

kashamalasha
Offline
Зарегистрирован: 01.01.2015

Суть вопроса такова. Есть датчик безопасности CROW MH-20 и светодиодная лента, питающиеся от 12В. С помощью тиньки 45 хотел сделать автоматический ночник. Написал код, который с Ардуино Уно и всем остальным работает превосходно. Лента включается, контроллер ждет по циклу заданное количество времени и выключает ленту, не выключая при этом контроллер, т.е. не снимая напряжения с ноги 4.

После переноса на attiny45 код работает странно. Он проходит одну итерацию, после чего по непонятной мне причине снимает напряжение с ноги 4, которая является ключом для контроллера. Вопрос - почему?

Прилагаю логику, принципиальную схему и код прототипа.

http://funkyimg.com/view/SrMu - логика

http://funkyimg.com/view/SrMv - принципиальная  схема

Код:

/*
 * PIR night light sensor is made from Crow MH-20 security sensor
 */

#include <SendOnlySoftwareSerial.h>
SendOnlySoftwareSerial mySerial(0); //TX

int mosfetPin = 1; // 1(pin1) - ATTiny / 4 - Arduino UNO
int lightPin = A1; // A1(pin2) - ATTiny / A0 - Arduino UNO
int relayPin = 3; // 3(pin3) - ATTiny / 2 - Arduino UNO
int npnPin = 4; // 4(pin4) - ATTiny / 3 - Arduino UNO

boolean light = false;
boolean relay = false;

void setup(){
  pinMode(relayPin, INPUT);
  pinMode(lightPin, INPUT);
  pinMode(npnPin, OUTPUT);
  pinMode(mosfetPin, OUTPUT);
  mySerial.begin(9600);
}

void loop(){
  //Если свет включен, снимаем напряжение с транзисторов
  if(analogRead(lightPin) > 300){
    if(light == true) return;
    mySerial.println("LIGHT IS ON");
    light = !light;
    digitalWrite(npnPin, LOW);
    digitalWrite(mosfetPin, LOW);
  } else {
    //Если свет выключен и флаг light был переключен в true
    //подаем напряжение на npn-транзистор, который работает в 
    //ключевом режиме для датчика безопасности MH-20
    if(light == true){
      mySerial.println("LIGHT IS OFF");
      light = !light;
      delay(500);
      digitalWrite(npnPin, HIGH);
      mySerial.println("ALARMING...");
      //Задержка на дребезг реле MH-20
      delay(3000);
      //MH-20 после запуска прогревается примерно минуту, ждем
      while(digitalRead(relayPin) == LOW){
        if (analogRead(lightPin) > 300) return;
        delay(1000);
      }
      //После прогрева переходим в режим охраны в котором замыкается
      //реле датчика MH-20
      mySerial.println("ALARM IS ON");
    } else {
      //Когда обнаружено движение - реле выключается.
      //Подаем напряжение на полевой транзистор для светодиодной ленты
      if(digitalRead(relayPin) == LOW && relay == true){
        mySerial.println("IS ANYBODY IN THERE?..");
        relay = !relay;
        digitalWrite(mosfetPin, HIGH);
        //Ждем 30 секунд до выключения
        for(int i=0; i<30; i++){
          if(analogRead(lightPin) > 300) return;
          //Если обнаружено движение, сбрасываем счетчик цикла
          if(digitalRead(relayPin) == LOW) i = 0;
          delay(1000);
          mySerial.println(i);
        }
        //Пока движения в периметре нет, реле включено,
        //напряжение с ноги полевого транзистора снято
      } else if (relay == false){
        mySerial.println("HERE IS NOBODY ELSE..");
        relay = !relay;
        digitalWrite(mosfetPin, LOW);
      }
    }
  } 
}

Заранее всем спасибо.

mihtm
Offline
Зарегистрирован: 02.09.2014

а зачем стоит return из loop - это не корректно как то?

kashamalasha
Offline
Зарегистрирован: 01.01.2015

В случае включения света прерывается выполнение программы, выполняется возврат к первому условию и снимается напряжение с базы транзистора VT1. В первой версии кода было по другому, решил, что так удобнее и понятнее. Ардуино такую конструкцию обрабатывает без затруднений.

kashamalasha
Offline
Зарегистрирован: 01.01.2015

Ау. Гуру, подскажите, в чем моя ошибка?

Спасибо.

fagci
Offline
Зарегистрирован: 12.01.2015
mySerial.println("LIGHT IS ON");
  light = !light;

пишите лучше light=true;

да и вообще условия скомбинировать лучше, понятнее будет и правильнее

И корова Ваша может не отпускать, проверьте=)

attiny45 - проверьте питание, может недостаточно

kashamalasha
Offline
Зарегистрирован: 01.01.2015

Спасибо за комментарий.

light = true или light = false не играет роли, разве что упрощает чтение кода.

Не совсем ясно про корову, она питается отдельной шиной в 12В. На attiny подается 5В по отдельной шине стабильно. Единственная разница между тинькой и мегой в тактовой частоте. Но я не совсем понимаю, как разница в тактовой частоте может влиять на исполнение кода.

fagci
Offline
Зарегистрирован: 12.01.2015

Важно проверить, при каких условиях отваливается 4й пин. Советую проверить работу пина на простейшем скетче, может даже заново переписать код, часто помогает, а писать относительно пина. Если проблема хардварная, она всплывет=)

Корова (у меня - другой PIR сенсор) порой не сползает в LOW при отсутствии движения, может быть еще в этом проблема..

Можете пояснить, зачем такая штука используется? SendOnlySoftwareSerial

Не слышал о таком=)

kashamalasha
Offline
Зарегистрирован: 01.01.2015
#include <SendOnlySoftwareSerial.h>

используется, т.к. ног в микрухе для отладки не хватает.

Эта библиотека позволяет использовать только одну ногу для отправки сообщений в UART.

Проблема в том, что данная проблема (с пропаданием HIGH на ноге) наблюдается как на ATTiny13, так и на ATTiny45, т.е. она не является аппаратной. На Ардуино все ОК.

kashamalasha
Offline
Зарегистрирован: 01.01.2015

Переписал код. Поудалял булевы переменные, бесконечные условия и отладочный вывод SoftwareSerial.

В PROTEUS заработало, вечером на прототипе проверю.

 


/*
 * mSensor using While
 */ 

#define mosfetPin  1 // PB1 (pin 6)
#define lightPin  A1 // PB2 (pin 7)
#define relayPin   3 // PB3 (pin 2)
#define npnPin     4 // PB4 (pin 3)

void setup() {
  pinMode(mosfetPin, OUTPUT); 
  pinMode(lightPin, INPUT);
  pinMode(relayPin, INPUT);
  pinMode(npnPin, OUTPUT);
}

void loop() {
  //Свет выключен
  if(analogRead(lightPin) < 300){
    //Подать напряжение на базу NPN, включив датчик
    digitalWrite(npnPin, HIGH);
    //Задержка для игнорирования дребезга реле датчика
    delay(1000);
    //Ожидание прогрева датчика
    while(digitalRead(relayPin) == LOW){
      //Свет включен - завершить выполнение
      if(analogRead(lightPin) > 300) return;
      delay(1000);
    }
    _watchDog();
  } else {
    //Свет включен - выключить датчик и ленту
    digitalWrite(npnPin, LOW);
    digitalWrite(mosfetPin, LOW);
  }
}

void _watchDog(){
  //Пока свет выключен
  while(analogRead(lightPin) < 300){
    //Замечено движение в периметре
    if(digitalRead(relayPin) == LOW){
      //Зажечь ленту
      digitalWrite(mosfetPin, HIGH);
      //Ждать 60 секунд
      for(int i=0; i<60; i++){
        //Свет включен - завершить выполнение
        if(analogRead(lightPin) > 300) return;
        //Замечено движение в периметре - сбросить таймер в 0
        if(digitalRead(relayPin) == LOW) i=0;
        delay(1000);
      }
      //Нет движения - погасить ленту
    } else digitalWrite(mosfetPin, LOW);
  }
}
kashamalasha
Offline
Зарегистрирован: 01.01.2015

Пришел домой, проверил. Парадокс. На ATTiny45 код работает корректно, а на ATTiny13 не хочет включать PB1 ни в какую через программу в функции _watchDog(). Eсли залить скетч с мигалкой на этой ноге, то все работает.

При этом парадоксально, но если поменять порядок использования ног в контроллере, т.е. использовать PB1 в качестве OUTPUT до использования PB4 в этом же качестве в цикле loop(), то все отрабатывает корректно.

Т.е. вместо:

#define mosfetPin  1 // PB1 (pin 6)
#define lightPin  A1 // PB2 (pin 7)
#define relayPin   3 // PB3 (pin 2)
#define npnPin     4 // PB4 (pin 3)

Задаем переменные следующего порядка:

#define mosfetPin  4 // PB4 (pin 3)
#define lightPin  A1 // PB2 (pin 7)
#define relayPin   3 // PB3 (pin 2)
#define npnPin     1 // PB1 (pin 6)

И изменяем коммутацию в схеме.

Не спроста все же твердят "учите матчасть, с ардуиной далеко на эмбеддед не уедешь")

kashamalasha
Offline
Зарегистрирован: 01.01.2015

Вчера, играясь с макетной платой, заметил одну особенность. В момент снятия логической 1 с ноги mosfetPin, кратковременно снимается 1 с ноги npnPin. Это можно компенсировать, установив фильтрующий конденсатор, но сама физика явления не ясна. На эмуляторе никаких скачков напряжения нет:

Free Image Hosting at FunkyIMG.com

Некорректно подписал луч npnPin.

OFF - свет выключен, npnPin == HIGH

ON - свет включен, npnPin == LOW.