Почему DHT22 и плавный диммер не дружат?
- Войдите на сайт для отправки комментариев
Пнд, 30/05/2016 - 22:48
Отдельно ДНТ22 и диммер работают исправно. Но нужно было программы объединить.
Стало достаточно часто зависать.В инете подробно только про "помигать",а более серьёзнее научиться,так не найдешь.Я думаю во время считывания днт22 ,зеро прерывания диммера не уместны.Так ли это?Объясните пожалуйста!
прога диммера
int AC_LOAD = 10; // Output to Opto Triac pin
int dimming = 128; // Dimming level (0-128) 0 = ON, 128 = OFF
// zero na pin 2
void setup()
{
pinMode(AC_LOAD, OUTPUT);// Set AC Load pin as output
attachInterrupt(0, zero_crosss_int, RISING); // Choose the zero cross interrupt # from the table above
}
// the interrupt function must take no parameters and return nothing
void zero_crosss_int() // function to be fired at the zero crossing to dim the light
{
// Firing angle calculation : 1 full 50Hz wave =1/50=20ms
// Every zerocrossing thus: (50Hz)-> 10ms (1/2 Cycle) For 60Hz => 8.33ms
// 10ms=10000us
// (10000us - 10us) / 128 = 75 (Approx) For 60Hz =>65
int dimtime = (75*dimming); // For 60Hz =>65
delayMicroseconds(dimtime); // Off cycle
digitalWrite(AC_LOAD, HIGH); // triac firing
delayMicroseconds(10); // triac On propogation delay (for 60Hz use 8.33)
digitalWrite(AC_LOAD, LOW); // triac Off
}
void loop() {
for (int i=5; i <= 128; i++){ dimming=i;delay(30); }
for (int i=128; i >= 5; i--){ dimming=i;delay(30); }
}
Вот прога днт22
#include <Wire.h> // добавляем необходимые библиотеки
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7 );
#include "DHT.h"
#define DHTPIN 2
#define DHTTYPE DHT22 // DHT 22 (AM2302)
DHT dht(DHTPIN, DHTTYPE);
void setup()
{
lcd.begin(16, 2);
lcd.print(" P R I V E T");
dht.begin();
}
void loop()
{
float h = dht.readHumidity();
float t = dht.readTemperature();
if (isnan(t) || isnan(h))
{
lcd.print("Failed to read from DHT");
} else
{
lcd.setCursor(0, 0);
lcd.print("H ");
lcd.print(h);
lcd.print(" ");
lcd.print("T+");
lcd.print(t);
lcd.setCursor(0,2);
lcd.print("Vot Takie Pirogi");
}
}
И вот так я их объединил днт22 перевёл на 3й пин. Запускается и виснет или пару раз отпишет днт22 и виснет.Помогите советом!
#include <Wire.h> // добавляем необходимые библиотеки
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7 );
#include "DHT.h"
#define DHTPIN 3
#define DHTTYPE DHT22 // DHT 22 (AM2302)
DHT dht(DHTPIN, DHTTYPE);
int AC_LOAD = 10; // Output to Opto Triac pin
int dimming = 128;
void setup()
{
pinMode(AC_LOAD, OUTPUT);// Set AC Load pin as output
attachInterrupt(0, zero_crosss_int, RISING);
lcd.begin(16, 2);
lcd.print(" P R I V E T");
dht.begin();
}
void zero_crosss_int()
{
int dimtime = (75*dimming); // For 60Hz =>65
delayMicroseconds(dimtime); // Off cycle
digitalWrite(AC_LOAD, HIGH); // triac firing
delayMicroseconds(10); // triac On propogation delay (for 60Hz use 8.33)
digitalWrite(AC_LOAD, LOW); // triac Off
}
void loop()
{
float h = dht.readHumidity();
float t = dht.readTemperature();
if (isnan(t) || isnan(h))
{
lcd.print("Failed to read from DHT");
} else
{
lcd.setCursor(0, 0);
lcd.print("H ");
lcd.print(h);
lcd.print(" ");
lcd.print("T+");
lcd.print(t);
lcd.setCursor(0,2);
lcd.print("Vot Takie Pirogi");
}
for (int i=5; i <= 128; i++){ dimming=i;delay(10); }
for (int i=128; i >= 5; i--){ dimming=i;delay(30); }
}
А как оно у вас вообще работало до этого, если вы в обработчике прерывания delay юзаете? И да - оформите плз нормально код - в редакторе есть кнопка для вставки кода, без этого - читать невозможно.
Вы про это? delayMicroseconds(10);
Вы про это? delayMicroseconds(10);
Ага, про это. Не работают делеи в обработчиках прерываний.
Вы про это? delayMicroseconds(10);
Ага, про это. Не работают делеи в обработчиках прерываний.
А вы бы посмотрели как устроена delayMicroseconds() (да заодно и delay()). И вставляли бы что-то вроде IMHO.
Поверьте программа димера прекрасно работает отдельно!
Проблемы начинаются при совмещении с датчиком DHT22. Вопрос как их подружить?
Не знаю о диммере (увы), но его zero_cross_int() прерывание "крутится" (может крутиться для dimming=128) до 10 мс (миллисекунд), вызываясь каждые 20 мс. (50 Гц, RISING end).
Знаю, как устроены большинство публичных библиотек DHT. Там характерное время считывания измерений (грубо, max) составляет 5*8*120 мкс = 4.8 мс, причем процесс измерения прерывать нельзя (ну или в пределах нескольких микросекунд).
Вы и сами в первом посте все правильно написали по поводу причин - DHT и диммер "толкаются", побеждает диммер, измерения сбиваются.
Вижу только два способа подружить устройства.
1. На время работы с DHT отключать диммер ( detachInterrupt() ), потом снова включать прерывание zero_cross_int(). Как это отразится на работе системы не знаю. Считывание DHT займет грубо (130 мс + 5) мс около 140 мс., т.е. не менее 7-ми пропусков zero_cross_int() за время работы работы с DHT.
2. Наиболее (IMHO) грамотно написали публичную библиотеку для DHT парни из Adafruit, предусмотрев отключение прерываний при считывании данных с датчика. В этом случае отключение диммера не дольше нескольких миллисекунд (3-4 мс) и нечастое (20 мс против 5 мс). Вроде может сработать.
Я как то так и думал. Только датчик гад думает гораздо дольше. Если учесть, что у меня их два (нижний,верхний в инкубаторе) то и вообще весело. Торможение изменений уровня диммера за 10 сек ничего не изменят(выкл,ВКЛ) прерывания. Только ,что будет в это время он выдавать?
Или точнее я не совсем понимаю алгоритм его работы. Зеро ему надо считать каждый раз перед выдачей импульса на симистр или только перед изменением сдвига фазы? Если первое то как идёт выдача во время (делай)?
Думают два датчика прим 4сек
Ясности ради. Почему вы считаете, что DHT "думает гораздо дольше"? Китайские товарищи приводят временнУю диаграмму протокола работы с датчиком, там есть числа. Я считываю DHT, измеряя длительность его импульсов (т.е. ориентируюсь на временнУю диаграмму), поэтому представляю, сколько времени занимает работа с DHT, включая его длин-нн-нную инициализацию.
Ну и опрашивать DHT все-таки нужно не каждую секунду. Наверное температура или влажнось вряд ли скачками изменяются, наверное разумный интервал составляет минуты.
А с диммером... Тут случай, когда интуиция заменяет информацию. Ничего не могу сказать.
Не стал придираться к скетчу DHT. Там потенциальная ошибка в том, что опрос следует проводить не чаще одного раза в 2 сек, иначе, вроде (если правильно помню документацию) возникают тормоза. Некоторые библиотеки это учитывают и пытаются ограничить частоту обращения к DHT 2-мя сек (выдавая старые измерения), некоторые этого не делают.
Диммер это симисторная прокладка между ардо и теном 2квт. Зеро прерывания указывает ардо когда нулевой переход фазы в сети. Два цикла и миллисекунды это дэмо версия плавного включения и выкл нагрузки. В реале там переменная зависящая от температуры в инкубаторе. Это думаю убьёт инерционность нагревателя и скачки температуры
Спасибо понял. Просто на дисплее показания как раз обновляются через 2сек для одного. Думал их косяк. Я ардуино взял в руки впервые неделю назад. До того всё транзисторы и к 561. Этот вариант без сомнения удобнее. Но глубже поверхностного ознакомления информацию найти трудновато.
Может подскажите какую хорошую книгу. Я начал (и забуксовал в плане отсутствия взрослой информации) с Петин В.А Проекты с использованием ардуино.
Ну во-от. Если два ужасных цикла (скетча диммера) только демо плавного включения, то все вы подружите. И, думается, без особых проблем.
Так прерывания происходят 100 раз в секунду всегда пока идёт импульс зеро?
Увы, мой ответ может показаться высокомерным, что ли, но быстро ушел от проекта "ардуино", оставшись на "их" железе.
Основная информация - тех. документация, она же даташиты, на всё - от МК до периферийных устройств. Нудно, времени требует, все такое... Но это работает.
В самом начале мне очень помог этот сайт, а форум продолжает помогать и сегодня. Вы быстро привыкните его фильтровать, здесь достаточно компентентных и благожелательных людей.
Павел, я же сказал, что мои познания в электротехнике смехотворны. Если "импульс зеро" это то, о чем подумал, если частота бытовой электросети 50 Гц, то прерывание, вызываемое по нарастанию фронта (RISING) вызывается 50 раз в сек.
А вы бы посмотрели как устроена delayMicroseconds() (да заодно и delay()). И вставляли бы что-то вроде IMHO.
Спасибо, гляну обязательно. Просто руководствовался докой:
Inside the attached function, delay() won't work and the value returned by millis() will not increment. Serial data received while in the function may be lost. You should declare as volatile any variables that you modify within the attached function. See the section on ISRs below for more information.
А вы бы посмотрели как устроена delayMicroseconds() (да заодно и delay()). И вставляли бы что-то вроде IMHO.
Да, глянул, был неправ - delayMicroseconds micros немного по-другому устроена, можно юзать, но - ооочень осторожно :)
Да, DIYMan, воистину так. Скажу больше - micros() тоже работает внутри прерываний. Но очень недолго, менее 1 мс. Ну насколько понял из ее конструкции (считывает Timer0, которому пофиг на прерывания, чтобы просто считать). На это заложиться, конечно, стрёмно.
И признаю свою реплику несколько э-ээ... некорректной.
Всем большое спасибо! Сделал так и всё хорошо работает, только прерывается для одного датчика на ~0.5 сек но это не критично.
А библиотеку эту имели в виду? С встроенным запретом прерываний
https://github.com/adafruit/DHT-sensor-library
Павел, я же сказал, что мои познания в электротехнике смехотворны. Если "импульс зеро" это то, о чем подумал, если частота бытовой электросети 50 Гц, то прерывание, вызываемое по нарастанию фронта (RISING) вызывается 50 раз в сек.
Что бы не потерять отрицательную полуволну 50гц выпрямляется мостиком и выходит 100гц положительных импульсов для симистора.Для тиристора (он управляемый диод) хватает 50. Может пригодится
А библиотеку эту имели в виду? С встроенным запретом прерываний
https://github.com/adafruit/DHT-sensor-library
Лучшая библиотека, если их использовать, IMHO, которая работает. В той, что по ссылке, прерывания запрещают, да. Это единственное хорошее, что могу о ней сказать.
Несть им числа для DHT. Имел в виду кое-что по-проще, когда-то у меня работала. Тоже помечена Adafruit'ом. За давностью не могу дать ссылку, "где-то в далеком Инете...". Но она маленькая.
Файл DHT.h
И файл DHT.cpp
Просто, ничего лишнего. Видимо тогда Adafruit еще не заматерела. И файл примера DHTtester.ino
Повторю - останавливайтесь на той, которая работает.
Благодарю за помощь!
Удачного творчества
Простите. Ещё вопрос.
Как дёрганья 100 раз в сек отразятся на количестве зависаний программы?
Сбой программы приведёт к потери партии яиц. Вы можете подсказать чего в программе делать не желательно, что бы по возможности оградить её от сбоя?
Если программа - это объединение двух приведенных скетчей ("подруженных"), и пропуск нескольких zero_crosss_int() подряд некритичен, то никак не отразится. Динамическая индикация 4-х разрядного 7-индикатора "отжирает" 240 Гц, и с этим живут без особых проблем.
Все предыдущие посты суммируются (вырванной из контекста) фразой Стругацких из ТББ. "Марко было бы тукнуть по пестрякам. Да хохари облыго ружуют. На том и покалим сростень."
Но есть осадок. Прав был DIYMan, сразу же отреагировав на очевидное - временнЫе задержки в прерывании zero_crosss_int() нестерпимо режут глаз. Особенно в несколько миллисекунд. Понимаю, этот код всюду в Инете, но это очень, очень плохой код.
По приходу события zero_cross нужно запускать микросекундный таймер и его прерываниями (настраиваемыми текущим значением dimtime) управлять этим, как его... триаком. Код выложу позже, освобожусь только.
Тогда же покажу один из возможных и часто применяемых способов борьбы со сбоями программы - использование сторожевого таймера watchdog. Яйца нужно беречь.
1. Вот пример "правильной" работы с zero_cross().
Демо код, который вы прислали для диммера (повторю здесь).
Вот версия "без задержек", написанная поверх демо кода.
Второй код должен компилироваться в IDE ардуино, проверить не могу, но ничего "чужого" там, вроде, нет. (Что мог - повытаскивал). Комментирую.
1. Долгую обработку простого события "включить - выключить" триак заменили на 3 (три) обработки, каждая из которых вызывается 100 раз в сек. Но. Все они очень короткие (т.е. быстрые). Сначала срабатывает прерывание по нарастающему фронту сигнала zero cross, это обработчик прерывания INT0 (RISING), который вычисляет время dimtime в мкс и настраивает Timer1 на прерывание по истечении dimtime, затем запускает его. Ранее Timer1 был настроен для 16 МГц МК на счет тиками по 0.5 мкс.
Затем срабатывает первое (COMPA) прерывание Timer1, и пин триака выставляется в HIGH. Тут же считывается Timer1, значение увеличивается на 20 тиков (10 мкс), настраивается значение счетчика для следующего прерывания (COMPB).
Прерывание COMPB следует примерно через 10 мкс (тут, как понимаю, особая точность не важна) и переключает пин триака в LOW.
Между этими 3-мя прерываниями выполняется что-нибудь в loop().
Вот теперь важно ОТКЛЮЧИТЬ ОТКЛЮЧЕНИЕ прерываний для DHT. Длительность рассмотренных ранее прерываний существенно меньше характерных времён замера длительности поступающих от DHT импульсов (десятки мкс). То же самое другими словами. Прерывания диммера (теперь их 3) кратковременные и не собъют работу с DHT.
ОТКЛЮЧИТЬ ОТКЛЮЧЕНИЕ прерываний для DHT означает в моем приведенном ранее примере отыскать cli() и закомментировать его (заодно и sei(), он теперь лишний). Если у вас другая библиотека DHT, ищите и отключайте что-то вроде noInterrupts().
Ну и медлительной LiquidCrystal короткие прерывания не страшны.
2. Закон Мэрфи гласит... ну вы знаете. Последним рубежом защиты от зависаний, сбоев служит сторожевой таймер (watchdog). О нем много написано, стоит ознакомиться. В приведенном здесь примере кода в конце setup() активируется watchdog и настраивается на сброс и перезагрузку МК через 1 сек. (soft reset). Если ничего не делать, через 1 сек. код приложения перезапустится. В нормальных условиях этого не требуется, поэтому watchdog регулярно сбрасывается командой WDR, начиная отсчет заново.
В примере сброс watchdog'а в первой строке прерывания zero_cross_int(), но, может быть имеет смысл перенести его сброс в loop() и увеличить интервал с 1 сек до, допустим, 4 или 8 сек. Над этим в спешке не думал. Может быть кто-то посоветует лучший вариант сброса watchdog'а. (Допускаю, что внешние события zero cross поступают, а что-то невероятное случилось в loop().)
Да, код примера расчитан на МК ATmega168/328 (UNO, Pro mini, NANO).
Да... !
Слов нет. Ясно Почему в IDE вам тесно. Завтра попробую, должно работать красиво. Я почти закончил код, но за меню меня здесь расстреляют, сплошные if и delay. Оно вобщем подгоняется один раз перед началом работы - критические значения темп и влаги,калибровка датчиков,время переворотов. Требований.... удобство. А как я боролся с частотой морганий от считывания датчиков, это песня.Чем димминг больше, тем на программу времени меньше. Получилось конечно жуть,но р а б о т а е т и моргает при разном димминг почти одинаково через прим 10сек. Если хотите от души улыбнуться могу выложить "шедевр".
Спасибо за потраченное время!!! Код всё таки скину - улыбнётесь вечером, чур доброй улыбкой ,я всёж сильно старался и даже смачно покуривал сигаретку наблюдая за разговором датчика и лампы(вместо тена).
Если по "железу" нужна будет помощь,буду рад pavekat4@mail.ru
Вы правильно сделали, что выложили _работающий_ код. Не ошибается тот, кто... И мы не знаем, может кто-то читает тему и поможет критикой, советом. Работающий код не может вызвать улыбки. Усмешку вызывают хотелки и настоятельные просьбы их реализовать.
После наших разговоров конечно посмотрю с любопытством (без обязательств с моей стороны). Думаю, мы еще поговорим по теме.
Думаю, что долгое и нудное обсуждение кода лучше провести в личной переписке, неторопливо., не загромождая форум. Если тема этой ветки до конца не раскрыта, то хоть пообсуждалась.