Датчик движения и подсветка на базе CROW MH-20 и ATTiny
- Войдите на сайт для отправки комментариев
Суть вопроса такова. Есть датчик безопасности 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);
}
}
}
}
Заранее всем спасибо.
а зачем стоит return из loop - это не корректно как то?
В случае включения света прерывается выполнение программы, выполняется возврат к первому условию и снимается напряжение с базы транзистора VT1. В первой версии кода было по другому, решил, что так удобнее и понятнее. Ардуино такую конструкцию обрабатывает без затруднений.
Ау. Гуру, подскажите, в чем моя ошибка?
Спасибо.
mySerial.println("LIGHT IS ON");light = !light;пишите лучше light=true;
да и вообще условия скомбинировать лучше, понятнее будет и правильнее
И корова Ваша может не отпускать, проверьте=)
attiny45 - проверьте питание, может недостаточно
Спасибо за комментарий.
light = true или light = false не играет роли, разве что упрощает чтение кода.
Не совсем ясно про корову, она питается отдельной шиной в 12В. На attiny подается 5В по отдельной шине стабильно. Единственная разница между тинькой и мегой в тактовой частоте. Но я не совсем понимаю, как разница в тактовой частоте может влиять на исполнение кода.
Важно проверить, при каких условиях отваливается 4й пин. Советую проверить работу пина на простейшем скетче, может даже заново переписать код, часто помогает, а писать относительно пина. Если проблема хардварная, она всплывет=)
Корова (у меня - другой PIR сенсор) порой не сползает в LOW при отсутствии движения, может быть еще в этом проблема..
Можете пояснить, зачем такая штука используется? SendOnlySoftwareSerial
Не слышал о таком=)
используется, т.к. ног в микрухе для отладки не хватает.
Эта библиотека позволяет использовать только одну ногу для отправки сообщений в UART.
Проблема в том, что данная проблема (с пропаданием HIGH на ноге) наблюдается как на ATTiny13, так и на ATTiny45, т.е. она не является аппаратной. На Ардуино все ОК.
Переписал код. Поудалял булевы переменные, бесконечные условия и отладочный вывод 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); } }Пришел домой, проверил. Парадокс. На ATTiny45 код работает корректно, а на ATTiny13 не хочет включать PB1 ни в какую через программу в функции _watchDog(). Eсли залить скетч с мигалкой на этой ноге, то все работает.
При этом парадоксально, но если поменять порядок использования ног в контроллере, т.е. использовать PB1 в качестве OUTPUT до использования PB4 в этом же качестве в цикле loop(), то все отрабатывает корректно.
Т.е. вместо:
Задаем переменные следующего порядка:
И изменяем коммутацию в схеме.
Не спроста все же твердят "учите матчасть, с ардуиной далеко на эмбеддед не уедешь")
Вчера, играясь с макетной платой, заметил одну особенность. В момент снятия логической 1 с ноги mosfetPin, кратковременно снимается 1 с ноги npnPin. Это можно компенсировать, установив фильтрующий конденсатор, но сама физика явления не ясна. На эмуляторе никаких скачков напряжения нет:
Некорректно подписал луч npnPin.
OFF - свет выключен, npnPin == HIGH
ON - свет включен, npnPin == LOW.