Почему DHT22 и плавный диммер не дружат?

pavel12
Offline
Зарегистрирован: 07.05.2016

Отдельно ДНТ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); }
}
DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

А как оно у вас вообще работало до этого, если вы в обработчике прерывания delay юзаете? И да - оформите плз нормально код - в редакторе есть кнопка для вставки кода, без этого - читать невозможно.

pavel12
Offline
Зарегистрирован: 07.05.2016

Вы про это?    delayMicroseconds(10);

pavel12
Offline
Зарегистрирован: 07.05.2016

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); }
}
pavel12
Offline
Зарегистрирован: 07.05.2016
#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");
  }
}

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

pavel12 пишет:

Вы про это?    delayMicroseconds(10);

Ага, про это. Не работают делеи в обработчиках прерываний.

dhog1
Offline
Зарегистрирован: 01.03.2016

DIYMan пишет:

pavel12 пишет:

Вы про это?    delayMicroseconds(10);

Ага, про это. Не работают делеи в обработчиках прерываний.

А вы бы посмотрели как устроена delayMicroseconds() (да заодно и delay()). И вставляли бы что-то вроде IMHO.

pavel12
Offline
Зарегистрирован: 07.05.2016

Поверьте программа димера прекрасно работает отдельно!
Проблемы начинаются при совмещении с датчиком DHT22. Вопрос как их подружить?

dhog1
Offline
Зарегистрирован: 01.03.2016

Не знаю о диммере (увы), но его 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 мс). Вроде может сработать.

pavel12
Offline
Зарегистрирован: 07.05.2016

Я как то так и думал. Только датчик гад думает гораздо дольше. Если учесть, что у меня их два (нижний,верхний в инкубаторе) то и вообще весело. Торможение изменений уровня диммера за 10 сек ничего не изменят(выкл,ВКЛ) прерывания. Только ,что будет в это время он выдавать?

pavel12
Offline
Зарегистрирован: 07.05.2016

Или точнее я не совсем понимаю алгоритм его работы. Зеро ему надо считать каждый раз перед выдачей импульса на симистр или только перед изменением сдвига фазы? Если первое то как идёт выдача во время (делай)?

pavel12
Offline
Зарегистрирован: 07.05.2016

Думают два датчика прим 4сек

dhog1
Offline
Зарегистрирован: 01.03.2016

Ясности ради. Почему вы считаете, что DHT "думает гораздо дольше"? Китайские товарищи приводят временнУю диаграмму протокола работы с датчиком, там есть числа. Я считываю DHT, измеряя длительность его импульсов (т.е. ориентируюсь на временнУю диаграмму), поэтому представляю, сколько времени занимает работа с DHT, включая его длин-нн-нную инициализацию.

Ну и опрашивать DHT все-таки нужно не каждую секунду. Наверное температура или влажнось вряд ли скачками изменяются, наверное разумный интервал составляет минуты.

А с диммером... Тут случай, когда интуиция заменяет информацию. Ничего не могу сказать.

dhog1
Offline
Зарегистрирован: 01.03.2016

Не стал придираться к скетчу DHT. Там потенциальная ошибка в том, что опрос следует проводить не чаще одного раза в 2 сек, иначе, вроде (если правильно помню документацию) возникают тормоза. Некоторые библиотеки это учитывают и пытаются ограничить частоту обращения к DHT 2-мя сек (выдавая старые измерения), некоторые этого не делают.

pavel12
Offline
Зарегистрирован: 07.05.2016

Диммер это симисторная прокладка между ардо и теном 2квт. Зеро прерывания указывает ардо когда нулевой переход фазы в сети. Два цикла и миллисекунды это дэмо версия плавного включения и выкл нагрузки. В реале там переменная зависящая от температуры в инкубаторе. Это думаю убьёт инерционность нагревателя и скачки температуры

pavel12
Offline
Зарегистрирован: 07.05.2016

Спасибо понял. Просто на дисплее показания как раз обновляются через 2сек для одного. Думал их косяк. Я ардуино взял в руки впервые неделю назад. До того всё транзисторы и к 561. Этот вариант без сомнения удобнее. Но глубже поверхностного ознакомления информацию найти трудновато.

pavel12
Offline
Зарегистрирован: 07.05.2016

Может подскажите какую хорошую книгу. Я начал (и забуксовал в плане отсутствия взрослой информации) с Петин В.А Проекты с использованием ардуино.

dhog1
Offline
Зарегистрирован: 01.03.2016

Ну во-от. Если два ужасных цикла (скетча диммера) только демо плавного включения, то все вы подружите. И, думается, без особых проблем.

pavel12
Offline
Зарегистрирован: 07.05.2016

Так прерывания происходят 100 раз в секунду всегда пока идёт импульс зеро?

dhog1
Offline
Зарегистрирован: 01.03.2016

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

Основная информация - тех. документация, она же даташиты, на всё - от МК до периферийных устройств. Нудно, времени требует, все такое... Но это работает.

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

 

dhog1
Offline
Зарегистрирован: 01.03.2016

pavel12 пишет:
Так прерывания происходят 100 раз в секунду всегда пока идёт импульс зеро?

Павел, я же сказал, что мои познания в электротехнике смехотворны. Если "импульс зеро" это то, о чем подумал, если частота бытовой электросети 50 Гц, то прерывание, вызываемое по нарастанию фронта (RISING) вызывается 50 раз в сек.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

dhog1 пишет:

А вы бы посмотрели как устроена 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.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

dhog1 пишет:

А вы бы посмотрели как устроена delayMicroseconds() (да заодно и delay()). И вставляли бы что-то вроде IMHO.

Да, глянул, был неправ - delayMicroseconds micros немного по-другому устроена, можно юзать, но - ооочень осторожно :)

 

dhog1
Offline
Зарегистрирован: 01.03.2016

Да, DIYMan, воистину так. Скажу больше - micros() тоже работает внутри прерываний. Но очень недолго, менее 1 мс. Ну насколько понял из ее конструкции (считывает Timer0, которому пофиг на прерывания, чтобы просто считать). На это заложиться, конечно, стрёмно.

И признаю свою реплику несколько э-ээ... некорректной.

pavel12
Offline
Зарегистрирован: 07.05.2016

Всем большое спасибо! Сделал так и всё хорошо работает, только прерывается для одного датчика на ~0.5 сек но это не критично.

detachInterrupt(1);
   float h1 = dht.readHumidity();
  float t1 = dht.readTemperature();
attachInterrupt(1, zero_crosss_int, RISING);

 

pavel12
Offline
Зарегистрирован: 07.05.2016

А библиотеку эту имели в виду? С встроенным запретом прерываний

https://github.com/adafruit/DHT-sensor-library

pavel12
Offline
Зарегистрирован: 07.05.2016

dhog1 пишет:

pavel12 пишет:
Так прерывания происходят 100 раз в секунду всегда пока идёт импульс зеро?

Павел, я же сказал, что мои познания в электротехнике смехотворны. Если "импульс зеро" это то, о чем подумал, если частота бытовой электросети 50 Гц, то прерывание, вызываемое по нарастанию фронта (RISING) вызывается 50 раз в сек.

Что бы не потерять отрицательную полуволну 50гц выпрямляется мостиком и выходит 100гц положительных импульсов для симистора.Для тиристора (он управляемый диод) хватает 50. Может пригодится

dhog1
Offline
Зарегистрирован: 01.03.2016

pavel12 пишет:

А библиотеку эту имели в виду? С встроенным запретом прерываний

https://github.com/adafruit/DHT-sensor-library

Лучшая библиотека, если их использовать, IMHO, которая работает. В той, что по ссылке, прерывания запрещают, да. Это единственное хорошее, что могу о ней сказать.

Несть им числа для DHT. Имел в виду кое-что по-проще, когда-то у меня работала. Тоже помечена Adafruit'ом. За давностью не могу дать ссылку, "где-то в далеком Инете...". Но она маленькая.

Файл DHT.h

#if ARDUINO >= 100
 #include "Arduino.h"
#else
 #include "WProgram.h"
#endif

/* DHT library 

MIT license
written by Adafruit Industries
*/

// how many timing transitions we need to keep track of. 2 * number bits + extra
#define MAXTIMINGS 85

#define DHT11 11
#define DHT22 22
#define DHT21 21
#define AM2301 21

class DHT {
 private:
  uint8_t data[6];
  uint8_t _pin, _type;
  boolean read(void);
  unsigned long _lastreadtime;
  boolean firstreading;

 public:
  DHT(uint8_t pin, uint8_t type);
  void begin(void);
  float readTemperature(void);
  float readHumidity(void);

};

И файл DHT.cpp

/* DHT library 

MIT license
written by Adafruit Industries
*/

#include "DHT.h"

DHT::DHT(uint8_t pin, uint8_t type) {
  _pin = pin;
  _type = type;
  firstreading = true;
}

void DHT::begin(void) {
  // set up the pins!
  pinMode(_pin, INPUT);
  digitalWrite(_pin, HIGH);
  _lastreadtime = 0;
}

float DHT::readTemperature(void) {
  float f;

  if (read()) {
    switch (_type) {
    case DHT11:
      f = data[2];
      return f;
    case DHT22:
    case DHT21:
      f = data[2] & 0x7F;
      f *= 256;
      f += data[3];
      f /= 10;
      if (data[2] & 0x80)
	f *= -1;
      return f;
    }
  }
  return NAN;
}

float DHT::readHumidity(void) {
  float f;
  if (read()) {
    switch (_type) {
    case DHT11:
      f = data[0];
      return f;
    case DHT22:
    case DHT21:
      f = data[0];
      f *= 256;
      f += data[1];
      f /= 10;
      return f;
    }
  }
  return NAN;
}


boolean DHT::read(void) {
  uint8_t laststate = HIGH;
  uint8_t counter = 0;
  uint8_t j = 0, i;
  unsigned long currenttime;

  // pull the pin high and wait 250 milliseconds
  digitalWrite(_pin, HIGH);
  delay(250);

  currenttime = millis();
  if (currenttime < _lastreadtime) {
    // ie there was a rollover
    _lastreadtime = 0;
  }
  if (!firstreading && ((currenttime - _lastreadtime) < 2000)) {
    return true; // return last correct measurement
    //delay(2000 - (currenttime - _lastreadtime));
  }
  firstreading = false;
  _lastreadtime = millis();

  data[0] = data[1] = data[2] = data[3] = data[4] = 0;
  
  // now pull it low for ~20 milliseconds
  pinMode(_pin, OUTPUT);
  digitalWrite(_pin, LOW);
  delay(20);
  cli();
  digitalWrite(_pin, HIGH);
  delayMicroseconds(40);
  pinMode(_pin, INPUT);

  // read in timings
  for ( i=0; i< MAXTIMINGS; i++) {
    counter = 0;
    while (digitalRead(_pin) == laststate) {
      counter++;
      delayMicroseconds(1);
      if (counter == 255) {
        break;
      }
    }
    laststate = digitalRead(_pin);

    if (counter == 255) break;

    // ignore first 3 transitions
    if ((i >= 4) && (i%2 == 0)) {
      // shove each bit into the storage bytes
      data[j/8] <<= 1;
      if (counter > 6)
        data[j/8] |= 1;
      j++;
    }

  }

  sei();
  
  // check we read 40 bits and that the checksum matches
  if ((j >= 40) && 
      (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) ) {
    return true;
  }

  return false;
}

Просто, ничего лишнего. Видимо тогда Adafruit еще не заматерела. И файл примера DHTtester.ino

// Example testing sketch for various DHT humidity/temperature sensors
// Written by ladyada, public domain

#include "DHT.h"

#define DHTPIN 2     // what pin we're connected to

// Uncomment whatever type you're using!
//#define DHTTYPE DHT11   // DHT 11 
#define DHTTYPE DHT22   // DHT 22  (AM2302)
//#define DHTTYPE DHT21   // DHT 21 (AM2301)

// Connect pin 1 (on the left) of the sensor to +5V
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor

DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(9600); 
  Serial.println("DHTxx test!");
 
  dht.begin();
}

void loop() {
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  float t = dht.readTemperature();

  // check if returns are valid, if they are NaN (not a number) then something went wrong!
  if (isnan(t) || isnan(h)) {
    Serial.println("Failed to read from DHT");
  } else {
    Serial.print("Humidity: "); 
    Serial.print(h);
    Serial.print(" %\t");
    Serial.print("Temperature: "); 
    Serial.print(t);
    Serial.println(" *C");
  }
}

Повторю - останавливайтесь на той, которая работает.

pavel12
Offline
Зарегистрирован: 07.05.2016

Благодарю за помощь!

Удачного творчества

pavel12
Offline
Зарегистрирован: 07.05.2016

Простите. Ещё вопрос.
Как дёрганья 100 раз в сек отразятся на количестве зависаний программы?
Сбой программы приведёт к потери партии яиц. Вы можете подсказать чего в программе делать не желательно, что бы по возможности оградить её от сбоя?

dhog1
Offline
Зарегистрирован: 01.03.2016

Если программа - это объединение двух приведенных скетчей ("подруженных"), и пропуск нескольких zero_crosss_int() подряд некритичен, то никак не отразится. Динамическая индикация 4-х разрядного 7-индикатора "отжирает" 240 Гц, и с этим живут без особых проблем.

Все предыдущие посты суммируются (вырванной из контекста) фразой Стругацких из ТББ. "Марко было бы тукнуть по пестрякам. Да хохари облыго ружуют. На том и покалим сростень."

Но есть осадок. Прав был DIYMan, сразу же отреагировав на очевидное - временнЫе задержки в прерывании zero_crosss_int() нестерпимо режут глаз. Особенно в несколько миллисекунд. Понимаю, этот код всюду в Инете, но это очень, очень плохой код.

По приходу события zero_cross нужно запускать микросекундный таймер и его прерываниями (настраиваемыми текущим значением dimtime) управлять этим, как его... триаком. Код выложу позже, освобожусь только.

Тогда же покажу один из возможных и часто применяемых способов борьбы со сбоями программы - использование сторожевого таймера watchdog. Яйца нужно беречь.

dhog1
Offline
Зарегистрирован: 01.03.2016

1. Вот пример "правильной" работы с zero_cross().

Демо код, который вы прислали для диммера (повторю здесь).

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); }
}

Вот версия "без задержек", написанная поверх демо кода.


                            // просто макросы для удобного манипулирования битами
#define SETBIT(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
#define CLEARBIT(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
#define FLIPBIT(ADDRESS,BIT) (ADDRESS ^= (1<<BIT))

#define VARFROMCOMB(x, y) x
#define BITFROMCOMB(x, y) y

#define C_SETBIT(comb) SETBIT(VARFROMCOMB(comb), BITFROMCOMB(comb))
#define C_CLEARBIT(comb) CLEARBIT(VARFROMCOMB(comb), BITFROMCOMB(comb))
#define C_FLIPBIT(comb) FLIPBIT(VARFROMCOMB(comb), BITFROMCOMB(comb))

                            // для вывода 10 как в примере (это порт B, пин 2)
#define AC_LOAD_PRT   PORTB, PORTB2
#define AC_LOAD_DDR   DDRB,  DDB2
#define AC_LOAD_PIN   PINB,  PINB2

volatile unsigned int dimming = 128;  // Dimming level (0-128)  0 = ON, 128 = OFF

void setup() {
                            // то же, что и pinMode(AC_LOAD, OUTPUT);// Set AC Load pin as output
  C_SETBIT(AC_LOAD_DDR);    // AC_LOAD как OUTPUT
  C_CLEARBIT(AC_LOAD_PRT);  // и LOW
  
// Timer/Counter 1 initialization
// Clock value: 2000,000 kHz
// Mode: Normal top=0xFFFF
// Timer Period: 32,768 ms  tick value 0.5 us (0x14 ticks = 10 us)
// Timer1 Overflow Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: On
    TCCR1A = 0;
    TCCR1B = (0<<CS11);
    TCNT1H = 0x00;
    TCNT1L = 0x00;

// Timer/Counter 1 Interrupt(s) initialization
    TIMSK1 = (1<<OCIE1B) | (1<<OCIE1A);

// Watchdog Timer initialization                         // разрешить сторожевой таймер
// Watchdog Timer Prescaler: OSC/128k (=1 sec)           // в режиме сброса (reset)
// Watchdog timeout action: Reset                        // по истечении 1 сек
    WDTCSR = (1<<WDCE) | (1<<WDE);                       // с момента его запуска
    WDTCSR = (1<<WDIF) | (0<<WDIE) | (0<<WDCE) | (1<<WDE) | (0<<WDP3) | (1<<WDP2) | (1<<WDP1) | (0<<WDP0);
  
    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
                                          // сюда попадаем 100 раз в сек
unsigned int dimtime;                     // по сигналу zero cross

  // 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
    
    __asm__ __volatile__ ("wdr");         // сбросить сторожевой таймер

    dimtime = (75 * dimming) << 1;       // 1 тик таймера = 0.5 мкс, поэтому х2
    
    OCR1AH = dimtime >> 8;               // выставляем "метку" срабатывания таймера1 по
    OCR1AL = dimtime & 0x00FF;           // вычесленной задержке dimtime в мкс
    
    TCCR1B |= (1<<CS11);                 // запускаем таймер1
}


// Timer1 output compare A interrupt service routine
ISR (TIMER1_COMPA_vect) {
                                         // сюда попадаем после dimtime мкс
unsigned int temp;

    C_FLIPBIT(AC_LOAD_PIN);              // триак был LOW, выставляем в HIGH
                                         // выставляем небольшую задержку от текущего
    temp = (OCR1AL & 0x00FF) | (OCR1AH << 8);  // значения таймера1
    temp += 0x14;                        // примерно 10 мкс (на самом деле несколько больше)
    OCR1BH = temp >> 8;
    OCR1BL = temp & 0x00FF;
}


// Timer1 output compare B interrupt service routine
ISR (TIMER1_COMPB_vect) {
                                         // сюда попадаем примерно через 10 мкс
    C_FLIPBIT(AC_LOAD_PIN);              // триак был HIGH, выставляем в LOW
    TCCR1B &= ~(1<<CS11);                // отключаем таймер1
    TCNT1H = 0x00;                       // готовим значение счетчика к новому циклу
    TCNT1L = 0x00;
}

  
void loop()  {
  
  for (int i=5; i <= 128; i++){ cli(); dimming=i; sei(); delay(30); }
  for (int i=128; i >= 5; i--){ cli(); dimming=i; sei(); delay(30); }
}

Второй код должен компилироваться в 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).

pavel12
Offline
Зарегистрирован: 07.05.2016

Да... !
Слов нет. Ясно Почему в IDE вам тесно. Завтра попробую, должно работать красиво. Я почти закончил код, но за меню меня здесь расстреляют, сплошные if и delay. Оно вобщем подгоняется один раз перед началом работы - критические значения темп и влаги,калибровка датчиков,время переворотов. Требований.... удобство. А как я боролся с частотой морганий от считывания датчиков, это песня.Чем димминг больше, тем на программу времени меньше. Получилось конечно жуть,но р а б о т а е т и моргает при разном димминг почти одинаково через прим 10сек. Если хотите от души улыбнуться могу выложить "шедевр".

pavel12
Offline
Зарегистрирован: 07.05.2016

Спасибо за потраченное время!!! Код всё таки скину - улыбнётесь вечером, чур доброй улыбкой ,я всёж сильно старался и даже смачно покуривал сигаретку наблюдая за разговором датчика и лампы(вместо тена).

pavel12
Offline
Зарегистрирован: 07.05.2016

#include <Wire.h> // добавляем необходимые библиотеки
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
#include "DHT.h"
#define DHTPIN 2  
#define DHTPIN1 4
#define DHTTYPE DHT22   // DHT 22  (AM2302)
DHT dht(DHTPIN, DHTTYPE);
DHT dht1(DHTPIN1, DHTTYPE);
int AC_LOAD = 11;    // Output to Opto Triac pin
int dimming = 50;
unsigned long time,u=0,time1=0,time2;
float a,a1,b,b1,c,k=0,k1=0,k2=0,k3=-2.6,t=37,h,t1,h1;
int ledPin = 12;int ledPin2 = 13;
int y=100,x;

void setup()
{
  pinMode(AC_LOAD, OUTPUT);// Set AC Load pin as output
  lcd.begin(); a = 63; a1=40; b=38; b1=22;
  pinMode(ledPin,OUTPUT); 
  pinMode(ledPin2,OUTPUT);
  lcd.print("    P R I V E T "); 
  dht.begin();  
}
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()
{
  time2=dimming;
  time=millis();
  time1=map(time2,10,115,10000,2900);
  if ((time-u) >time1){
    u=time;
detachInterrupt(1);
   float hh = dht.readHumidity();
  float tt = dht.readTemperature();
  t=tt+k;h=hh+k1;
  float h2 = dht1.readHumidity();
  float t2= dht1.readTemperature();
  t1=t2+k2;h1=h2+k3;
 attachInterrupt(1, zero_crosss_int, RISING); 
  if (isnan(tt) || isnan(hh))
  {
    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(2,3);
    lcd.print("Vot Takie Pirogi");
    lcd.setCursor(0,1);
    lcd.print(" H1 ");
    lcd.print(h1);
    lcd.print("  ");
    lcd.print("T1 +");
    lcd.print(t1);
  }
  }
  attachInterrupt(1, zero_crosss_int, RISING);
  x=t*10;
  if (x<350){x=350;} 
  y=map(x,350,390,10,110);
  lcd.setCursor(9, 2);lcd.print(y);lcd.print("  ");
dimming=y;
         int buttonValue = analogRead(0); // считываем значения с аналогового входа(A0) 
    if( buttonValue <10)
   {
            lcd.clear();
            delay(1000);
            lcd.print("      M E N U ");
            buttonValue =800;
            lcd.setCursor(0, 2);
            lcd.print("  Temp <   > Vlaga ");
     do{
    if (buttonValue >460 && buttonValue <500)
          {
  
            lcd.clear();delay(1000);
            lcd.print("  Vlaga verx " );
            lcd.print(h);buttonValue=110;
             do{
                lcd.setCursor(7, 2);
                int buttonValue = analogRead(0);
                delay(200);
                if ( h >= a ){digitalWrite(ledPin,HIGH);} else {digitalWrite(ledPin,LOW);}
                if( buttonValue >390 && buttonValue <415){a=a+0.1;}
                if( buttonValue >300 && buttonValue <320){a=a-0.1;}
                lcd.print(a);
                if (buttonValue >460 && buttonValue <500)
                      {
                      lcd.clear();
                      delay(1000);
                      buttonValue=110;int buttonValue = analogRead(0);
                      lcd.print("  Vlaga niz ");
                      lcd.print(h);
                        do{
                     lcd.setCursor(7, 2);
                  int buttonValue = analogRead(0);
                  delay(200);
                  if ( h<=a1 ){digitalWrite(ledPin,HIGH);} else {digitalWrite(ledPin,LOW);}
                  if( buttonValue >390 && buttonValue <415){a1=a1+0.1;}
                  if( buttonValue >300 && buttonValue <320){a1=a1-0.1;}
                      lcd.print(a1);
                      
                        if (buttonValue >460 && buttonValue <500)
                      {lcd.clear();
                      delay(1000);
                      buttonValue=10;
                      buttonValue = analogRead(0);
                      lcd.print(" Kalibrovka Vlaga H");
                        do{
                     lcd.setCursor(4, 2);lcd.print("        ");lcd.setCursor(7, 2);
                  int buttonValue = analogRead(0);                                     
                  if( buttonValue >390 && buttonValue <415){k1=k1+0.1;}
                  if( buttonValue >300 && buttonValue <320){k1=k1-0.1;}
                      lcd.print(k1); delay(200);
                      
                        if (buttonValue >460 && buttonValue <500)
                      {lcd.clear();
                      delay(1000);
                      buttonValue=10;
                      buttonValue = analogRead(0);
                      lcd.print(" Kalibrovka Vlaga H1");
                        do{
                     lcd.setCursor(4, 2);lcd.print("        ");lcd.setCursor(7, 2);
                  int buttonValue = analogRead(0);                                     
                  if( buttonValue >390 && buttonValue <415){k3=k3+0.1;}
                  if( buttonValue >300 && buttonValue <320){k3=k3-0.1;}
                      lcd.print(k3); delay(200);
                       if( buttonValue <10){lcd.clear();delay(200);lcd.print(" Kalibrovka Vlaga H");break;}
                        }
                       while( buttonValue !=10);
                      }
                      if( buttonValue <10){lcd.clear();lcd.print("  Vlaga niz "); lcd.print(h);break;}
                        }
                       while( buttonValue !=10);
                      } 
                      if( buttonValue <10){lcd.clear();lcd.print("  Vlaga verx "); lcd.print(h);break;}
                          }
                           while( buttonValue !=10);
                      }
        if( buttonValue <10){ lcd.clear();delay(1000);lcd.print("      M E N U ");lcd.setCursor(0, 2);lcd.print("  Temp <   > Vlaga ");buttonValue=1000;break;}
               }
             while( buttonValue !=10);
          }
    else if (buttonValue > 160 && buttonValue < 200)
         {
                 
           lcd.clear();
           delay(1000);
           buttonValue=10;
           buttonValue = analogRead(0);
           lcd.print("  Temp verx ");
           lcd.print(t);
               do{
                  lcd.setCursor(7, 2);
                  int buttonValue = analogRead(0);
                  delay(200);
                  if ( t >= b ){digitalWrite(ledPin2,HIGH);} else {digitalWrite(ledPin2,LOW);}
                  if( buttonValue >390 && buttonValue <415){b=b+0.1;}
                  if( buttonValue >300 && buttonValue <320){b=b-0.1;}
                  lcd.print(b);
                  
                  if (buttonValue > 170 && buttonValue < 200)
                      {lcd.clear();
                      delay(1000);
                      buttonValue=10;
                      buttonValue = analogRead(0);
                      lcd.print("   Temp niz ");
                      lcd.print(t);
                        do{
                     lcd.setCursor(7, 2);
                  int buttonValue = analogRead(0);
                  delay(200);
                  if ( t <= b1 ){digitalWrite(ledPin2,HIGH);} else {digitalWrite(ledPin2,LOW);}
                  if( buttonValue >390 && buttonValue <415){b1=b1+0.1;}
                  if( buttonValue >300 && buttonValue <320){b1=b1-0.1;}
                      lcd.print(b1);
                      
                      if (buttonValue > 170 && buttonValue < 200)
                      {lcd.clear();
                      delay(1000);
                      buttonValue=10;
                      buttonValue = analogRead(0);
                      lcd.print(" Kalibrovka Temp T");
                        do{
                     lcd.setCursor(4, 2);lcd.print("        ");lcd.setCursor(7, 2);
                  int buttonValue = analogRead(0);
                  if( buttonValue >390 && buttonValue <415){k=k+0.1;}
                  if( buttonValue >300 && buttonValue <320){k=k-0.1;}
                      lcd.print(k);delay(200);
                       if (buttonValue > 170 && buttonValue < 200)
                      {lcd.clear();
                      delay(1000);
                      buttonValue=10;
                      buttonValue = analogRead(0);
                      lcd.print(" Kalibrovka Temp T1");
                        do{
                     lcd.setCursor(4, 2);lcd.print("        ");lcd.setCursor(7, 2);
                  int buttonValue = analogRead(0);
                  if( buttonValue >390 && buttonValue <415){k2=k2+0.1;}
                  if( buttonValue >300 && buttonValue <320){k2=k2-0.1;}
                      lcd.print(k2);delay(200);
                       if( buttonValue <10){lcd.clear();delay(200);lcd.print(" Kalibrovka Temp T");break;}
                        }
                       while( buttonValue !=10);
                      } 
                      if( buttonValue <10){lcd.clear();lcd.print("   Temp niz "); lcd.print(t);break;}
                        }
                       while( buttonValue !=10);
                      } 
                      if( buttonValue <10){lcd.clear();lcd.print("  Temp verx "); lcd.print(t);break;}
                          }
                           while( buttonValue !=10);
                      }
                 
        if( buttonValue <10){ lcd.clear();delay(1000);lcd.print("      M E N U ");lcd.setCursor(0, 2);lcd.print("  Temp <   > Vlaga ");buttonValue=1000;break;}
                 }
               while( buttonValue !=10);
          }
       buttonValue = analogRead(0);
   if( buttonValue <10){lcd.clear(); delay(1000);break;}
     }
while( buttonValue !=10);
  }
  if ( t >= b || t1>=b){digitalWrite(ledPin2,HIGH);} else {digitalWrite(ledPin2,LOW);}// здесь будет другое
  if ( t <= b1 || t1<=b1){digitalWrite(ledPin2,HIGH);} else {digitalWrite(ledPin2,LOW);}// здесь будет другое
  if ( h >= a || h1>=a){digitalWrite(ledPin,HIGH);} else {digitalWrite(ledPin,LOW);}// здесь будет другое
  if ( h <= a1 || h1<=a1){digitalWrite(ledPin,HIGH);} else {digitalWrite(ledPin,LOW);}// здесь будет другое
  
}

Если по "железу" нужна будет помощь,буду рад pavekat4@mail.ru

dhog1
Offline
Зарегистрирован: 01.03.2016

Вы правильно сделали, что выложили _работающий_ код. Не ошибается тот, кто... И мы не знаем, может кто-то читает тему и поможет критикой, советом. Работающий код не может вызвать улыбки. Усмешку вызывают хотелки и настоятельные просьбы их реализовать.

После наших разговоров конечно посмотрю с любопытством (без обязательств с моей стороны). Думаю, мы еще поговорим по теме.

dhog1
Offline
Зарегистрирован: 01.03.2016

Думаю, что долгое и нудное обсуждение кода лучше провести в личной переписке, неторопливо., не загромождая форум. Если тема этой ветки до конца не раскрыта, то хоть пообсуждалась.