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

Ze-pp
Offline
Зарегистрирован: 20.12.2018

Приветствую всех форумчан!

Собираю автоматику для курятника. Комплектация6 Ардуино Про мини, ЕСП-12 (для передачи данных на смартфон), ДХТ22 - конроль температуры и влажности, TM1637 - отображение температуры и влажности в самом помещении, 2-х канальный (самодельный) семисторный диммер с отслеживанием ноля, по классической схеме. Один канал (без диммирования) на включение вентилятора, второй(с диммированием) - для плавного включения красной обогревательной лампы. 

Для диммирования был взят, доработан под себя и отдельно обкатан такой код:

[code]
#include <CyberLib.h> //Библиотека от Cyber-Place.ru
volatile uint8_t tic, Dimmer1, Dimmer2, Dimmer3;
uint8_t data;
int DimRandom=10; //Переменная для хранения максимального значения яркости Диммера (0 макс/200-мин, 255-выключено)
int DimRandomOld = 255; //Переменная для хранения минимального значения яркости Диммера 
 
void setup() 
  D11_Out; //Настраиваем порты на выход
  D11_Low; //установить на выходах низкий уровень сигнала
  D2_In; //настраиваем порт на вход для отслеживания прохождения сигнала через ноль  
    attachInterrupt(0, detect_up, LOW);  // настроить срабатывание прерывания interrupt0 на pin 2 на низкий уровень
    StartTimer1(halfcycle, 40); //время для одного разряда ШИМ
    StopTimer1(); //остановить таймер
    UART_Init(115200); //инициализация порта
}
//********************обработчики прерываний*******************************
void halfcycle()  //прерывания таймера
  tic++;  //счетчик  
  if(Dimmer1 < tic ) D11_High; //управляем выходом
}
 
void  detect_up()  // обработка внешнего прерывания. Сработает по переднему фронту
{  
 tic=0;             //обнулить счетчик
 ResumeTimer1();   //запустить таймер
 attachInterrupt(0, detect_down, HIGH);  //перепрограммировать прерывание на другой обработчик
}  
 
void  detect_down()  // обработка внешнего прерывания. Сработает по заднему фронту
{   
 StopTimer1(); //остановить таймер
 D11_Low; //логический ноль на выходы
 tic=0;       //обнулить счетчик
 attachInterrupt(0, detect_up, LOW); //перепрограммировать прерывание на другой обработчик
//*************************************************************************
void loop() 
{ Start
//DimRandom = random(15, 200); 
//if (DimRandom > DimRandomOld) 
//{ 
//for (int i = DimRandomOld; i < DimRandom+1; i++) 
//{ 
//Dimmer1 = i; 
//delay (10); 
//} 
//} 
if (DimRandom < DimRandomOld) 
for (int i = DimRandomOld; i > DimRandom-1; i--) 
Dimmer1 = i; 
//delay (10); 
//DimRandomOld = DimRandom; 
End
}
[/code]
 
 
 
Здесь все работает. я даже смирился с функцией delay в обработчике увеличения яркости.
sadman41
Offline
Зарегистрирован: 19.10.2016

У attachInterrupt уровень может быть не только LOW/HIGH , но и CHANGE.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

И?

Ze-pp
Offline
Зарегистрирован: 20.12.2018

Потом я разместил этот код в уже рабочую, отлаженную программу автоматики (вместо симисторов раньше я использовал реле).

Скетч компилируется без ошибок, но устройство не работает. Даже индикатор ТМ1637 не загорается. Но если закоментировать эту строчку

// attachInterrupt(0, detect_up, FALLING);  // настроить срабатывание прерывания interrupt0 на pin 2 на низкий уровень

то устройство запускается и работает. Естественно плавного пуска подогрева не происходит. Помогите разобраться в чем дело. Уже пять вечеров и ночей пытаюсь разобраться - не получается. Вот сам код:

[code]
//////////////////////////////////////////////
//        RemoteXY include library          //
//////////////////////////////////////////////
 
// определение режима соединения и подключение библиотеки RemoteXY 
#define REMOTEXY_MODE__ESP8266_HARDSERIAL_POINT
#include <CyberLib.h>// шустрая библиотека для таймера
#include <RemoteXY.h>
#include <Average.h> // Источник - https://github.com/MajenkoLibraries/Average 
#include <DHT.h>
#include <OneWire.h>
#include "TM1637.h"
#define CLK  4            // номер пина семисегмента TM1637
#define DIO  5            // номер пина семисегмента TM1637
#define dht22pin 8        // номер пина датчика DHT22
#define ZERO_PIN 2        // вход контроля перехода через 0 (ZERO, Z-C)только пин 2 !!!
#define DIM_PIN 11        // выход на симистор PWM (DIM)
#define fanPin 17         // номер пина семистора вентилятора (А3)
TM1637 tm1637(CLK,DIO);
DHT dht(dht22pin, DHT22);
unsigned long currentTime=0; // таймер с момента запуска программы
unsigned long tTime  =0; //таймер опроса датчика DHT22
uint32_t ms1        = 0;
uint32_t ms2        = 0; // таймер опроса датчика DHT22
uint32_t ms3        = 0; // таймер переключения дисплея 
int fanState = LOW; // состояние пина семистора  вентилятора
unsigned long previousMillis = 0;// последний момент времени, когда состояние пина семистора вентилятора изменялось
long OnTime = 1200000; // длительность работы вентилятора 20 минут (в миллисекундах)
long OffTime = 120000; // выключено 2 минуты(в миллисекундах)
byte coldTemp = 3; // Температура, ниже которой вентилятор не включится
byte treshold = 68; // Процент влажности, по достижению которого включаем вентилятор
byte hotTemp = 26; // Температура, ниже которой включается обогрев
Average<float> ave_t(10); // Для усреднения последних значений температуры с датчика создаём массив на 10 шт.
Average<float> ave_h(10); // Для усреднения последних значений влажности с датчика создаём массив на 10 шт.
uint8_t disp_mode   = 0;
int DimMax= 10; //Переменная для хранения максимального значения яркости Диммера 
int DimMin = 254; //Переменная для хранения минимального значения яркости Диммера
volatile uint8_t tic, Dimmer1;
 
 
// настройки соединения 
#define REMOTEXY_SERIAL Serial
#define REMOTEXY_SERIAL_SPEED 115200
#define REMOTEXY_WIFI_SSID "Hen_"
#define REMOTEXY_WIFI_PASSWORD ""
#define REMOTEXY_SERVER_PORT 6377
 
 
// конфигурация интерфейса   
#pragma pack(push, 1) 
uint8_t RemoteXY_CONF[] = 
  { 255,1,0,16,0,131,0,8,13,1,
  67,4,36,17,20,5,2,26,7,67,
  4,36,6,20,5,2,26,7,65,4,
  25,39,9,9,65,1,25,63,9,9,
  129,0,4,6,18,6,17,208,162,208,
  181,208,188,208,191,46,0,129,0,4,
  17,18,6,17,208,146,208,187,208,176,
  208,182,208,189,46,0,129,0,16,28,
  29,6,17,208,159,208,190,208,180,208,
  190,208,179,209,128,208,181,208,178,0,
  129,0,12,52,36,6,17,208,146,208,
  181,208,189,209,130,208,184,208,187,209,
  143,209,130,208,190,209,128,0,1,0,
  24,79,12,12,2,31,82,0 }; 
   
// структура определяет все переменные вашего интерфейса управления  
struct { 
     // input variable
  uint8_t reset_Button; // =1 если кнопка нажата, иначе =0 
 
    // output variable
  char hum_Text[7];  // =строка UTF8 оканчивающаяся нулем 
  char temp_Text[7];  // =строка UTF8 оканчивающаяся нулем 
  uint8_t hot_Led_r; // =0..255 яркость красного цвета индикатора 
  uint8_t fan_Led_b; // =0..255 яркость синего цвета индикатора 
 
    // other variable
  uint8_t connect_flag;  // =1 if wire connected, else =0 
 
} RemoteXY; 
#pragma pack(pop) 
 
/////////////////////////////////////////////
//           END RemoteXY include          //
/////////////////////////////////////////////
 
 
 
void setup() 
{
  RemoteXY_Init (); 
 Serial.begin(115200);
  currentTime = millis();  //запускаем счетчик 
   dht.begin();
  // Инициализация дисплея
  tm1637.init();
// Установка яркости дисплея  
  tm1637.set(7);
   delay(50);
   pinMode(fanPin, OUTPUT);
   digitalWrite(fanPin, fanState); // изначально семистор вентилятора выключен 
//   pinMode(hotPin, OUTPUT);
//   digitalWrite(hotPin, LOW); // изначально реле ИК-лампы выключено
   pinMode(DIM_PIN, OUTPUT); // выход диммера для подогрева
   digitalWrite(DIM_PIN, LOW); // изначально выход диммера выключен
   pinMode(ZERO_PIN, INPUT);
 
// attachInterrupt(0, detect_up, FALLING);  // настроить срабатывание прерывания interrupt0 на pin 2 на низкий уровень 
   StartTimer1(halfcycle, 40); //время для одного разряда ШИМ
   StopTimer1(); //остановить таймер
            
}
 
   void(* resetFunc) (void) = 0; // объявляем функцию reset
   
 
void loop() 
{
   
   if(currentTime>=(tTime+500))// Опрашиваем датчик каждые 0,5 сек. 
   {
   tTime=currentTime;
   float t = dht.readTemperature(); 
   float h = dht.readHumidity();
   if (isnan(h) || isnan(t)) {
    strcpy (RemoteXY.temp_Text, "Ошибка");
    strcpy (RemoteXY.hum_Text, "Ошибка");
    
//    return;
  } else {
   ave_t.push(t); // Кладём результат измерения температуры в массив. В массиве помещается 10 измерений, новоприбывшее выталкивает самое старое.
   RemoteXY_Handler ();
   ave_h.push(h); // Кладём результат измерения влажности в массив. В массиве помещается 10 измерений, новоприбывшее выталкивает самое старое.
   RemoteXY_Handler ();
   double val = t; 
   dtostrf(val, 0, 2, RemoteXY.temp_Text); // выводим значение температуры в приложении
   double mas = h; 
   dtostrf(mas, 0, 2, RemoteXY.hum_Text); // выводим значение влажности в приложении
   }
   }
/*************************************ДИСПЛЕЙ******************************************/
   
   if(currentTime < ms1 || (currentTime - ms1) > 500 ){
      ms1 = currentTime;
   int  Temp = ave_t.mean();
   int Hum = ave_h.mean();
 
   switch( disp_mode ){
//        case 0:
// Отображение времени таймера
//               tm1637.clearDisplay();
//               tm1637.point(true);
//               tm1637.display(0,mins/10);
//               tm1637.display(1,mins%10);
//               tm1637.display(2,sec/10);
//               tm1637.display(3,sec%10);              
//            break;
// Отображение влажности
        case 0: 
              tm1637.clearDisplay();
              tm1637.point(false);
              tm1637.display(0,Hum/10);
              tm1637.display(1,Hum%10);
              DisplaySpecialChar(3,0x24);
            break;
        case 1:
// Отображение температуры
            
               tm1637.clearDisplay();
               tm1637.point(false);
               tm1637.display(0,Temp/10);
               tm1637.display(1,Temp%10);
               DisplaySpecialChar(2,0x63);
               tm1637.display(3,0x0C);
            
            break;
   }
   }                    
   // Переключение режимов отображения
   if(currentTime < ms3 || (currentTime - ms3) > 3000  ){
      ms3 = currentTime;
      switch( disp_mode ){
         case 0 : disp_mode = 1; break;
         case 1 : disp_mode = 0; break;
   //     default: disp_mode = 0;
      }
   }
 /****************************************ПОДОГРЕВ**********************************/  
   RemoteXY_Handler ();
   if (ave_t.mean()< hotTemp) // Вычисляем "скользящее среднее" по последним 10 замерам, сравниваем его со значением температуры включения обогрева
   {
//   digitalWrite(DIM_PIN,1);
   for (int i = DimMin; i > DimMax-1; i--) 
   {
   Dimmer1 = i; 
   delay (12);
   } 
   DimMin = DimMax;
 
   RemoteXY.hot_Led_r= 255;  // включаем индикатор подогрева в приложении
   }
    else  
    {
    digitalWrite(DIM_PIN,LOW);   // вырубить ток на всякий случай
//   DimMin = 255;
//    DimMax = 10;
    RemoteXY.hot_Led_r= 0;  // выключаем индикатор в приложении
    }
 /******************************ВЕНТИЛЯТОР********************************/
 
   // выясняем не настал ли момент сменить состояние реле вентилятора
   unsigned long currentMillis = millis(); // таймер для работы ветилятора в миллисекундах
   RemoteXY_Handler ();
   if ((fanState == LOW)&& (ave_t.mean()> coldTemp)&& (ave_h.mean()> treshold) && (currentMillis - previousMillis >= OffTime))
  {
    fanState = HIGH; // включаем вентилятор
    previousMillis = currentMillis ; // запоминаем момент времени
    digitalWrite(fanPin, fanState); // реализуем новое состояние
    RemoteXY.fan_Led_b= 255;  // включаем индикатор в приложении
 
 //       Serial.println("Вентилятор включен");
 //   Serial.println(ave_h.mean());
      } 
  // если вентилятор включен и работает больше чем надо
  if((fanState == HIGH) && (currentMillis - previousMillis >= OnTime)||(ave_t.mean()<= coldTemp) || (fanState == HIGH) && (ave_h.mean()< treshold) )
  {
    fanState = LOW; // выключаем
    previousMillis = currentMillis; // запоминаем момент времени
// TimerDisplayOff();
    digitalWrite(fanPin, fanState); // реализуем новое состояние
    RemoteXY.fan_Led_b= 0;  // выключаем индикатор в приложении
//    Serial.println("Вентилятор выключен");
 
    void     flushData(); // После того, как мы остудили мотор, надо "прочистить" массив с замерами влажности актуальными замерами. Иначе мотор будет врубаться снова и снова.
//    Serial.println("Вентилятор выключен");
 
    }
 
/********************************************СБРОС****************************************************/
  RemoteXY_Handler ();
    if (RemoteXY.reset_Button!=0) {
  resetFunc();
  }
}
 
/*****************************Вывести спец-символ на дисплей***************************************/
 
 
void DisplaySpecialChar(uint8_t BitAddr,int8_t SpecChar)
{
  tm1637.start();          //start signal sent to TM1637 from MCU
  tm1637.writeByte(ADDR_FIXED);//
 
  tm1637.stop();           //
  tm1637.start();          //
  tm1637.writeByte(BitAddr|0xc0);//
  
  tm1637.writeByte(SpecChar);//
  tm1637.stop();            //
  tm1637.start();          //
  
  tm1637.writeByte(tm1637.Cmd_DispCtrl);//
  tm1637.stop();           //
}
 
 void flushData() {
  int k = 0;
  unsigned long currentMillis = millis(); // запуск таймера 
  while (k < 10) {
    float t = dht.readTemperature(); // Опрашиваем датчик
    float h = dht.readHumidity();
    if (isnan(h) || isnan(t)) {
//      Serial.println("Sensor error!");
//      delay(interval);
      return;
    } else {
      ave_h.push(h); // Кладём результат измерения влажности в массив. В массиве помещается 10 измерений, новоприбывшее выталкивает самое старое.
      ave_t.push(t);
    }
  if(currentMillis>=(ms2+5000)) 
   {
    k++;
    ms2 = currentMillis; // запоминаем время
  }
  }
}
//********************обработчик и прерываний******************** *********** 
void halfcycle() //прерывания таймера 
tic++; //счетчик 
if(Dimmer1 < tic ) digitalWrite(DIM_PIN , HIGH); //управляем выходом 
 
void detect_up() // обработка внешнего прерывания. Сработает по переднему фронту синусоиды 
tic=0; //обнулить счетчик 
ResumeTimer1(); //запустить таймер 
attachInterrupt(0, detect_down, RISING); //перепрограммировать прерывание на другой обработчик 
 
void detect_down() // обработка внешнего прерывания. Сработает по заднему фронту синусоиды 
StopTimer1(); //остановить таймер 
digitalWrite(DIM_PIN,LOW); //логический ноль на выходы 
tic=0; //обнулить счетчик 
attachInterrupt(0, detect_up, FALLING); //перепрограммировать прерывание на другой обработчик 
 
[/code]
Ze-pp
Offline
Зарегистрирован: 20.12.2018

не успел дописать пост

Ze-pp
Offline
Зарегистрирован: 20.12.2018

sadman41 пишет:

У attachInterrupt уровень может быть не только LOW/HIGH , но и CHANGE.

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

sadman41
Offline
Зарегистрирован: 19.10.2016

Я вам просто сообщаю. А то вы в обработчике начинаете вытворять странные вещи. К добру такой подход не приводит.

Ze-pp
Offline
Зарегистрирован: 20.12.2018

sadman41 пишет:

Я вам просто сообщаю. А то вы в обработчике начинаете вытворять странные вещи. К добру такой подход не приводит.

Какие именно вещи? Ткните носом.

sadman41
Offline
Зарегистрирован: 19.10.2016

Переназначать прерывания, например.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ze-pp пишет:

Ткните носом.

Тыкаю. Ошибки в строках №№ ХЗ, ХЗ и ХЗ.

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

Вот, блин, ведь в окне сообщения есть красная иконка с надписью code. Неужели она ни о чём не говорит?

Ze-pp
Offline
Зарегистрирован: 20.12.2018

sadman41 пишет:

Переназначать прерывания, например.

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

Ze-pp
Offline
Зарегистрирован: 20.12.2018
//////////////////////////////////////////////
//        RemoteXY include library          //
//////////////////////////////////////////////
 
// определение режима соединения и подключение библиотеки RemoteXY 
#define REMOTEXY_MODE__ESP8266_HARDSERIAL_POINT
#include <CyberLib.h>// шустрая библиотека для таймера
#include <RemoteXY.h>
#include <Average.h> // Источник - https://github.com/MajenkoLibraries/Average 
#include <DHT.h>
#include <OneWire.h>
#include "TM1637.h"
#define CLK  4            // номер пина семисегмента TM1637
#define DIO  5            // номер пина семисегмента TM1637
#define dht22pin 8        // номер пина датчика DHT22
#define ZERO_PIN 2        // вход контроля перехода через 0 (ZERO, Z-C)только пин 2 !!!
#define DIM_PIN 11        // выход на симистор PWM (DIM)
#define fanPin 17         // номер пина семистора вентилятора (А3)
TM1637 tm1637(CLK,DIO);
DHT dht(dht22pin, DHT22);
unsigned long currentTime=0; // таймер с момента запуска программы
unsigned long tTime  =0; //таймер опроса датчика DHT22
uint32_t ms1        = 0;
uint32_t ms2        = 0; // таймер опроса датчика DHT22
uint32_t ms3        = 0; // таймер переключения дисплея 
int fanState = LOW; // состояние пина семистора  вентилятора
unsigned long previousMillis = 0;// последний момент времени, когда состояние пина семистора вентилятора изменялось
long OnTime = 1200000; // длительность работы вентилятора 20 минут (в миллисекундах)
long OffTime = 120000; // выключено 2 минуты(в миллисекундах)
byte coldTemp = 3; // Температура, ниже которой вентилятор не включится
byte treshold = 68; // Процент влажности, по достижению которого включаем вентилятор
byte hotTemp = 26; // Температура, ниже которой включается обогрев
Average<float> ave_t(10); // Для усреднения последних значений температуры с датчика создаём массив на 10 шт.
Average<float> ave_h(10); // Для усреднения последних значений влажности с датчика создаём массив на 10 шт.
uint8_t disp_mode   = 0;
int DimMax= 10; //Переменная для хранения максимального значения яркости Диммера 
int DimMin = 254; //Переменная для хранения минимального значения яркости Диммера
volatile uint8_t tic, Dimmer1;
 
 
// настройки соединения 
#define REMOTEXY_SERIAL Serial
#define REMOTEXY_SERIAL_SPEED 115200
#define REMOTEXY_WIFI_SSID "Hen_"
#define REMOTEXY_WIFI_PASSWORD ""
#define REMOTEXY_SERVER_PORT 6377
 
 
// конфигурация интерфейса   
#pragma pack(push, 1) 
uint8_t RemoteXY_CONF[] = 
  { 255,1,0,16,0,131,0,8,13,1,
  67,4,36,17,20,5,2,26,7,67,
  4,36,6,20,5,2,26,7,65,4,
  25,39,9,9,65,1,25,63,9,9,
  129,0,4,6,18,6,17,208,162,208,
  181,208,188,208,191,46,0,129,0,4,
  17,18,6,17,208,146,208,187,208,176,
  208,182,208,189,46,0,129,0,16,28,
  29,6,17,208,159,208,190,208,180,208,
  190,208,179,209,128,208,181,208,178,0,
  129,0,12,52,36,6,17,208,146,208,
  181,208,189,209,130,208,184,208,187,209,
  143,209,130,208,190,209,128,0,1,0,
  24,79,12,12,2,31,82,0 }; 
   
// структура определяет все переменные вашего интерфейса управления  
struct { 
     // input variable
  uint8_t reset_Button; // =1 если кнопка нажата, иначе =0 
 
    // output variable
  char hum_Text[7];  // =строка UTF8 оканчивающаяся нулем 
  char temp_Text[7];  // =строка UTF8 оканчивающаяся нулем 
  uint8_t hot_Led_r; // =0..255 яркость красного цвета индикатора 
  uint8_t fan_Led_b; // =0..255 яркость синего цвета индикатора 
 
    // other variable
  uint8_t connect_flag;  // =1 if wire connected, else =0 
 
} RemoteXY; 
#pragma pack(pop) 
 
/////////////////////////////////////////////
//           END RemoteXY include          //
/////////////////////////////////////////////
 
 
 
void setup() 
{
  RemoteXY_Init (); 
 Serial.begin(115200);
  currentTime = millis();  //запускаем счетчик 
   dht.begin();
  // Инициализация дисплея
  tm1637.init();
// Установка яркости дисплея  
  tm1637.set(7);
   delay(50);
   pinMode(fanPin, OUTPUT);
   digitalWrite(fanPin, fanState); // изначально семистор вентилятора выключен 
//   pinMode(hotPin, OUTPUT);
//   digitalWrite(hotPin, LOW); // изначально реле ИК-лампы выключено
   pinMode(DIM_PIN, OUTPUT); // выход диммера для подогрева
   digitalWrite(DIM_PIN, LOW); // изначально выход диммера выключен
   pinMode(ZERO_PIN, INPUT);
 
// attachInterrupt(0, detect_up, FALLING);  // настроить срабатывание прерывания interrupt0 на pin 2 на низкий уровень 
   StartTimer1(halfcycle, 40); //время для одного разряда ШИМ
   StopTimer1(); //остановить таймер
            
}
 
   void(* resetFunc) (void) = 0; // объявляем функцию reset
   
 
void loop() 
{
   
   if(currentTime>=(tTime+500))// Опрашиваем датчик каждые 0,5 сек. 
   {
   tTime=currentTime;
   float t = dht.readTemperature(); 
   float h = dht.readHumidity();
   if (isnan(h) || isnan(t)) {
    strcpy (RemoteXY.temp_Text, "Ошибка");
    strcpy (RemoteXY.hum_Text, "Ошибка");
    
//    return;
  } else {
   ave_t.push(t); // Кладём результат измерения температуры в массив. В массиве помещается 10 измерений, новоприбывшее выталкивает самое старое.
   RemoteXY_Handler ();
   ave_h.push(h); // Кладём результат измерения влажности в массив. В массиве помещается 10 измерений, новоприбывшее выталкивает самое старое.
   RemoteXY_Handler ();
   double val = t; 
   dtostrf(val, 0, 2, RemoteXY.temp_Text); // выводим значение температуры в приложении
   double mas = h; 
   dtostrf(mas, 0, 2, RemoteXY.hum_Text); // выводим значение влажности в приложении
   }
   }
/*************************************ДИСПЛЕЙ******************************************/
   
   if(currentTime < ms1 || (currentTime - ms1) > 500 ){
      ms1 = currentTime;
   int  Temp = ave_t.mean();
   int Hum = ave_h.mean();
 
   switch( disp_mode ){
//        case 0:
// Отображение времени таймера
//               tm1637.clearDisplay();
//               tm1637.point(true);
//               tm1637.display(0,mins/10);
//               tm1637.display(1,mins%10);
//               tm1637.display(2,sec/10);
//               tm1637.display(3,sec%10);              
//            break;
// Отображение влажности
        case 0: 
              tm1637.clearDisplay();
              tm1637.point(false);
              tm1637.display(0,Hum/10);
              tm1637.display(1,Hum%10);
              DisplaySpecialChar(3,0x24);
            break;
        case 1:
// Отображение температуры
            
               tm1637.clearDisplay();
               tm1637.point(false);
               tm1637.display(0,Temp/10);
               tm1637.display(1,Temp%10);
               DisplaySpecialChar(2,0x63);
               tm1637.display(3,0x0C);
            
            break;
   }
   }                    
   // Переключение режимов отображения
   if(currentTime < ms3 || (currentTime - ms3) > 3000  ){
      ms3 = currentTime;
      switch( disp_mode ){
         case 0 : disp_mode = 1; break;
         case 1 : disp_mode = 0; break;
   //     default: disp_mode = 0;
      }
   }
 /****************************************ПОДОГРЕВ**********************************/  
   RemoteXY_Handler ();
   if (ave_t.mean()< hotTemp) // Вычисляем "скользящее среднее" по последним 10 замерам, сравниваем его со значением температуры включения обогрева
   {
//   digitalWrite(DIM_PIN,1);
   for (int i = DimMin; i > DimMax-1; i--) 
   {
   Dimmer1 = i; 
   delay (12);
   } 
   DimMin = DimMax;
 
   RemoteXY.hot_Led_r= 255;  // включаем индикатор подогрева в приложении
   }
    else  
    {
    digitalWrite(DIM_PIN,LOW);   // вырубить ток на всякий случай
//   DimMin = 255;
//    DimMax = 10;
    RemoteXY.hot_Led_r= 0;  // выключаем индикатор в приложении
    }
 /******************************ВЕНТИЛЯТОР********************************/
 
   // выясняем не настал ли момент сменить состояние реле вентилятора
   unsigned long currentMillis = millis(); // таймер для работы ветилятора в миллисекундах
   RemoteXY_Handler ();
   if ((fanState == LOW)&& (ave_t.mean()> coldTemp)&& (ave_h.mean()> treshold) && (currentMillis - previousMillis >= OffTime))
  {
    fanState = HIGH; // включаем вентилятор
    previousMillis = currentMillis ; // запоминаем момент времени
    digitalWrite(fanPin, fanState); // реализуем новое состояние
    RemoteXY.fan_Led_b= 255;  // включаем индикатор в приложении
 
 //       Serial.println("Вентилятор включен");
 //   Serial.println(ave_h.mean());
      } 
  // если вентилятор включен и работает больше чем надо
  if((fanState == HIGH) && (currentMillis - previousMillis >= OnTime)||(ave_t.mean()<= coldTemp) || (fanState == HIGH) && (ave_h.mean()< treshold) )
  {
    fanState = LOW; // выключаем
    previousMillis = currentMillis; // запоминаем момент времени
// TimerDisplayOff();
    digitalWrite(fanPin, fanState); // реализуем новое состояние
    RemoteXY.fan_Led_b= 0;  // выключаем индикатор в приложении
//    Serial.println("Вентилятор выключен");
 
    void     flushData(); // После того, как мы остудили мотор, надо "прочистить" массив с замерами влажности актуальными замерами. Иначе мотор будет врубаться снова и снова.
//    Serial.println("Вентилятор выключен");
 
    }
 
/********************************************СБРОС****************************************************/
  RemoteXY_Handler ();
    if (RemoteXY.reset_Button!=0) {
  resetFunc();
  }
}
 
/*****************************Вывести спец-символ на дисплей***************************************/
 
 
void DisplaySpecialChar(uint8_t BitAddr,int8_t SpecChar)
{
  tm1637.start();          //start signal sent to TM1637 from MCU
  tm1637.writeByte(ADDR_FIXED);//
 
  tm1637.stop();           //
  tm1637.start();          //
  tm1637.writeByte(BitAddr|0xc0);//
  
  tm1637.writeByte(SpecChar);//
  tm1637.stop();            //
  tm1637.start();          //
  
  tm1637.writeByte(tm1637.Cmd_DispCtrl);//
  tm1637.stop();           //
}
 
 void flushData() {
  int k = 0;
  unsigned long currentMillis = millis(); // запуск таймера 
  while (k < 10) {
    float t = dht.readTemperature(); // Опрашиваем датчик
    float h = dht.readHumidity();
    if (isnan(h) || isnan(t)) {
//      Serial.println("Sensor error!");
//      delay(interval);
      return;
    } else {
      ave_h.push(h); // Кладём результат измерения влажности в массив. В массиве помещается 10 измерений, новоприбывшее выталкивает самое старое.
      ave_t.push(t);
    }
  if(currentMillis>=(ms2+5000)) 
   {
    k++;
    ms2 = currentMillis; // запоминаем время
  }
  }
}
//********************обработчик и прерываний******************** *********** 
void halfcycle() //прерывания таймера 
{ 
tic++; //счетчик 
if(Dimmer1 < tic ) digitalWrite(DIM_PIN , HIGH); //управляем выходом 
} 
 
void detect_up() // обработка внешнего прерывания. Сработает по переднему фронту синусоиды 
{ 
tic=0; //обнулить счетчик 
ResumeTimer1(); //запустить таймер 
attachInterrupt(0, detect_down, RISING); //перепрограммировать прерывание на другой обработчик 
} 
 
void detect_down() // обработка внешнего прерывания. Сработает по заднему фронту синусоиды 
{ 
StopTimer1(); //остановить таймер 
digitalWrite(DIM_PIN,LOW); //логический ноль на выходы 
tic=0; //обнулить счетчик 
attachInterrupt(0, detect_up, FALLING); //перепрограммировать прерывание на другой обработчик 
} 

 

Ze-pp
Offline
Зарегистрирован: 20.12.2018

ЕвгенийП пишет:

Ze-pp пишет:

Ткните носом.

Тыкаю. Ошибки в строках №№ ХЗ, ХЗ и ХЗ.

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

Вот, блин, ведь в окне сообщения есть красная иконка с надписью code. Неужели она ни о чём не говорит?

Извините, не разобрался с интерфейсом.

sadman41
Offline
Зарегистрирован: 19.10.2016

Ze-pp пишет:

sadman41 пишет:

Переназначать прерывания, например.

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

Вы меня уж извинте, но курятники - не мой конек. Тем более под Новый Год. И в таких объемах кода. Просто можно два обработчика в одном сделать, а не ставить себе ловушки. Вот и все, что я хотел написать. 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, вот, теперь хоть обсуждать можно, а то ведь без номеров строк как разговаривать-то

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

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

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

И перезалейте ваш  код согласно правилам форума. Если вы хотите что бы вам помогли - не усложняйте задачу помогающим.

 

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

курятник это хорошо, пожалуй подскажу что знаю:

1. научитесь вставлять код правильно, так читать его никто не будет (в верхнейчати окошка есть две скобки красные , жмем туда и вставляем код)

2. я тоже пользуюсь библиотекой киберлиб, меня она устраивает. но у нее есть свои недостатки

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

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

Ze-pp
Offline
Зарегистрирован: 20.12.2018

Так основной код программы я перезалил. Или опять что-то не правильно?

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

так правильно, я пока писал меня опередили))

Ze-pp
Offline
Зарегистрирован: 20.12.2018

Baks пишет:

курятник это хорошо, пожалуй подскажу что знаю:

1. научитесь вставлять код правильно, так читать его никто не будет (в верхнейчати окошка есть две скобки красные , жмем туда и вставляем код)

2. я тоже пользуюсь библиотекой киберлиб, меня она устраивает. но у нее есть свои недостатки

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

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

Для управления вентилятором, у меня в канале управления тиристором стоит птрон МОС3041, со встроенным детектором ноля. Ина нем прерывания не нужны. Такой же оптрон я могу поставить на нагревательную лампу - это обеспечит минимальную защиту нити накала и продлит срок службы. Я только по этой причине и хочу сделать плавный пуск лампы, потому, что когда она управлялась реле -за сезон вышли из строя 2 лампы.

Ze-pp
Offline
Зарегистрирован: 20.12.2018

За код - буду благодарен. Может когда пригодится.

Ze-pp
Offline
Зарегистрирован: 20.12.2018

Тогда поставим вопрос так - если в канале диммера использовать оптрон МОС3041( со встроенным детектором ноля), избавить код от прерываний - пусть этим занимается оптрон. Можно будет реализовать подобие плавного пуска?

bwn
Offline
Зарегистрирован: 25.08.2014

С зависшей программой, при включении прерывания, проблема была. Вытащил из setup (109 строка) и перенес в конец loop, запускается ессно один раз через флаг. Все работает. Почему помогло, не знаю, чессно, может старшие товарищи объяснят. 

sadman41
Offline
Зарегистрирован: 19.10.2016

Интересные эффекты бывают если не сделать INPUT_PULLUP и забыть подтянуть штаны.

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

код для двух димеров

один можно выбросить или просто игнорить


// Slave DIMMER 2 kanal +I2C
//http://geekmatic.in.ua/Arduino_Nano_i2c_chapter2
//http://cyber-place.ru/showthread.php?t=525&page=3

#include <Wire.h>
#define SLAVE_ADDRESS 8

#include <TimerOne.h> //использует Timer1 
volatile uint8_t tic, Dimmer1, Dimmer2;

#define PIN_Dim_1 4
#define PIN_Dim_2 5
#define PIN_zero 2 //(Interrupt = 0)
#define PIN_Blink 13

boolean Flag = true;
boolean Old_Flag = true;
void setup()
{
  Wire.begin(SLAVE_ADDRESS);
  Wire.onReceive(receiveEvent);
// Serial.begin(9600);
// Serial.println("readi 1");  
  pinMode(PIN_Dim_1, OUTPUT);  // PIN_ как выход
  pinMode(PIN_Dim_2, OUTPUT);    // PIN_ как выход
  digitalWrite(PIN_Dim_1, 0);    // выключает  
  digitalWrite(PIN_Dim_2, 0);    // выключает  
  pinMode(PIN_zero, INPUT);    // PIN_ как выход
  
// CHANGE – прерывание вызывается при любом изменении значения на входе; 
// RISING – вызов прерывания при изменении уровня напряжения с низкого (Low) на высокий(HIGH) 
// FALLING – вызов прерывания при изменении уровня напряжения с высокого (HIGH) на низкий (Low) 
    attachInterrupt(PIN_zero -2, detect_up, FALLING);  // настроить срабатывание прерывания interrupt0 на pin 2 на низкий уровень
// StartTimer1(halfcycle, 40); //время для одного разряда ШИМ
// StopTimer1(); //остановить таймер
   Timer1.initialize(40);              // Интервал срабатывания таймера в мкс  
   Timer1.attachInterrupt(halfcycle);   //будет вызыватся каждый раз при отсчете заданого времени 
   Timer1.stop();  
}
void loop()
{
	if(Flag != Old_Flag){
	digitalWrite(PIN_Blink, Flag);
     Old_Flag = Flag;	
	}
 //Serial.print("Dimmer1= "); Serial.print((int)Dimmer1); 
 //Serial.print(" Dimmer2= "); Serial.println((int)Dimmer2);  
 //delay(500);   
}

void receiveEvent(int i)
{
  while (Wire.available()) {
  Dimmer1 = Wire.read();
  Dimmer2 = Wire.read();
  }
  Flag = !Flag;
}

//********************обработчики прерываний*******************************
void halfcycle()  //прерывания таймера
{ 
 tic++;  //счетчик  
 if(Dimmer1 < tic ) digitalWrite(PIN_Dim_1, 1);    // выключает  ; //управляем выходом
 if(Dimmer2 < tic ) digitalWrite(PIN_Dim_2, 1);    // выключает  ;  //управляем выходом
}

void  detect_up()  // обработка внешнего прерывания. Сработает по переднему фронту
{  
 tic=0;             //обнулить счетчик
 Timer1.resume();   //запустить таймер 
 attachInterrupt(PIN_zero -2, detect_down, RISING);  //перепрограммировать прерывание на другой обработчик
}  

void  detect_down()  // обработка внешнего прерывания. Сработает по заднему фронту
{   
 Timer1.stop(); //остановить таймер 
 digitalWrite(PIN_Dim_1, 0);    // выключает  
 digitalWrite(PIN_Dim_2, 0);    // выключает//логический ноль на выходы
 tic=0;       //обнулить счетчик
 attachInterrupt(PIN_zero -2, detect_up, FALLING); //перепрограммировать прерывание на другой обработчик
} 
//*************************************************************************

контроллер должен отслеживать сам переход через 0, по другому не получится
Ze-pp
Offline
Зарегистрирован: 20.12.2018

sadman41 пишет:

Интересные эффекты бывают если не сделать INPUT_PULLUP и забыть подтянуть штаны.

2 пин подтянут к +5В резистором на плате с диммером

Ze-pp
Offline
Зарегистрирован: 20.12.2018

bwn пишет:

С зависшей программой, при включении прерывания, проблема была. Вытащил из setup (109 строка) и перенес в конец loop, запускается ессно один раз через флаг. Все работает. Почему помогло, не знаю, чессно, может старшие товарищи объяснят. 

Перенес строку 109 на 245. Залил скетч. Схема запустилась - лампа зажглась без диммирования, Индикатор завис на показаниях влажности, точка вай фай поднялась, но приложение на смартфоне подключиться не может.

bwn
Offline
Зарегистрирован: 25.08.2014

Вы ее от повторных обращений заблокировали? 

Ze-pp
Offline
Зарегистрирован: 20.12.2018

bwn пишет:

Вы ее от повторных обращений заблокировали? 

Как это сделать?

bwn
Offline
Зарегистрирован: 25.08.2014

Примерно так:

static boolean attFlag = true;
if (attFlag) {
  здесь 109 строка
  attFlag = false;
}

 

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

я не понял что и куда вы перенесли в коде, но похоже что не заработает диммер и какая разница где прервание будет задаваться

Ze-pp
Offline
Зарегистрирован: 20.12.2018

bwn пишет:

Примерно так:

static boolean attFlag = true;
if (attFlag) {
  здесь 109 строка
  attFlag = false;
}

 

Сделал так ( это стоит в конце loop)

/********************************************СБРОС****************************************************/
  RemoteXY_Handler ();
    if (RemoteXY.reset_Button!=0) {
  resetFunc();
  }
  static boolean attFlag = true;
if (attFlag) {
  attachInterrupt(0, detect_up, FALLING);  // настроить срабатывание прерывания interrupt0 на pin 2 на низкий уровень
  attFlag = false;
}
  
}

/*****************************Вывести спец-символ на дисплей***************************************/

Не помогло. Все как в предыдущий раз.

 

bwn
Offline
Зарегистрирован: 25.08.2014

Значит не судьба.(((( 

Ze-pp
Offline
Зарегистрирован: 20.12.2018

Спасибо.

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

тут незнаю что вы ходели но похоже на бред

   if (ave_t.mean()< hotTemp) // Вычисляем "скользящее среднее" по последним 10 замерам, сравниваем его со значением температуры включения обогрева
   {
//   digitalWrite(DIM_PIN,1);
   for (int i = DimMin; i > DimMax-1; i--)
   {
   Dimmer1 = i;
   delay (12);
   }
   DimMin = DimMax;
  

 

Ze-pp
Offline
Зарегистрирован: 20.12.2018

Baks пишет:

тут незнаю что вы ходели но похоже на бред

   if (ave_t.mean()< hotTemp) // Вычисляем "скользящее среднее" по последним 10 замерам, сравниваем его со значением температуры включения обогрева
   {
//   digitalWrite(DIM_PIN,1);
   for (int i = DimMin; i > DimMax-1; i--)
   {
   Dimmer1 = i;
   delay (12);
   }
   DimMin = DimMax;
  

 

Почему бред?

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

Ze-pp
Offline
Зарегистрирован: 20.12.2018

Вэтом коде все работало как надо.

#include <CyberLib.h> //Библиотека от Cyber-Place.ru
volatile uint8_t tic, Dimmer1, Dimmer2, Dimmer3;
uint8_t data;
int DimRandom=10; //Переменная для хранения максимального значения яркости Диммера (0 макс/200-мин, 255-выключено)
int DimRandomOld = 255; //Переменная для хранения минимального значения яркости Диммера 
 
void setup() 
{ 
  D11_Out; //Настраиваем порты на выход
  D11_Low; //установить на выходах низкий уровень сигнала
  D2_In; //настраиваем порт на вход для отслеживания прохождения сигнала через ноль  
    attachInterrupt(0, detect_up, LOW);  // настроить срабатывание прерывания interrupt0 на pin 2 на низкий уровень
    StartTimer1(halfcycle, 40); //время для одного разряда ШИМ
    StopTimer1(); //остановить таймер
    UART_Init(115200); //инициализация порта
}
//********************обработчики прерываний*******************************
void halfcycle()  //прерывания таймера
{ 
  tic++;  //счетчик  
  if(Dimmer1 < tic ) D11_High; //управляем выходом
}
 
void  detect_up()  // обработка внешнего прерывания. Сработает по переднему фронту
{  
 tic=0;             //обнулить счетчик
 ResumeTimer1();   //запустить таймер
 attachInterrupt(0, detect_down, HIGH);  //перепрограммировать прерывание на другой обработчик
}  
 
void  detect_down()  // обработка внешнего прерывания. Сработает по заднему фронту
{   
 StopTimer1(); //остановить таймер
 D11_Low; //логический ноль на выходы
 tic=0;       //обнулить счетчик
 attachInterrupt(0, detect_up, LOW); //перепрограммировать прерывание на другой обработчик
} 
//*************************************************************************
void loop() 
{ Start
//DimRandom = random(15, 200); 
//if (DimRandom > DimRandomOld) 
//{ 
//for (int i = DimRandomOld; i < DimRandom+1; i++) 
//{ 
//Dimmer1 = i; 
//delay (10); 
//} 
//} 
if (DimRandom < DimRandomOld) 
{ 
for (int i = DimRandomOld; i > DimRandom-1; i--) 
{ 
Dimmer1 = i; 
//delay (10); 
} 
} 
//DimRandomOld = DimRandom; 
End
}

 

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

апотом что тут происходит?

 DimMin = DimMax;

и что произойдет при второс заходе в эту функцию?

Ze-pp
Offline
Зарегистрирован: 20.12.2018

Baks пишет:

апотом что тут происходит?

 DimMin = DimMax;

и что произойдет при второс заходе в эту функцию?

если не будет этой строчки, лампа циклично плавно зажигается и резко гаснет. А с этой строчкой - просто продолжает светиться.

SLKH
Offline
Зарегистрирован: 17.08.2015

Ze-pp пишет:

Тогда поставим вопрос так - если в канале диммера использовать оптрон МОС3041( со встроенным детектором ноля), избавить код от прерываний - пусть этим занимается оптрон. Можно будет реализовать подобие плавного пуска?

можно, пропуском полупериодов.

 

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

можно вот так сделать, добавить флаг, в верху обьявить как       boolean flag = true;

   RemoteXY_Handler ();
   if (ave_t.mean()< hotTemp) // Вычисляем "скользящее среднее" по последним 10 замерам, сравниваем его со значением температуры включения обогрева
   {
//   digitalWrite(DIM_PIN,1);
   if (flag == true)
	   flag = false;
    for (int i = DimMin; i > DimMax-1; i--) 
    {
     Dimmer1 = i; 
     delay (12);
    } 
     DimMin = DimMax; 
     RemoteXY.hot_Led_r= 255;  // включаем индикатор подогрева в приложении	   
   }
    else  
    {
	 flag == true
     digitalWrite(DIM_PIN,LOW);   // вырубить ток на всякий случай
//   DimMin = 255;
//    DimMax = 10;
     RemoteXY.hot_Led_r= 0;  // выключаем индикатор в приложении
    }

 

Ze-pp
Offline
Зарегистрирован: 20.12.2018

Baks пишет:

можно вот так сделать, добавить флаг, в верху обьявить как       boolean flag = true;

   RemoteXY_Handler ();
   if (ave_t.mean()< hotTemp) // Вычисляем "скользящее среднее" по последним 10 замерам, сравниваем его со значением температуры включения обогрева
   {
//   digitalWrite(DIM_PIN,1);
   if (flag == true)
	   flag = false;
    for (int i = DimMin; i > DimMax-1; i--) 
    {
     Dimmer1 = i; 
     delay (12);
    } 
     DimMin = DimMax; 
     RemoteXY.hot_Led_r= 255;  // включаем индикатор подогрева в приложении	   
   }
    else  
    {
	 flag == true
     digitalWrite(DIM_PIN,LOW);   // вырубить ток на всякий случай
//   DimMin = 255;
//    DimMax = 10;
     RemoteXY.hot_Led_r= 0;  // выключаем индикатор в приложении
    }

 

это с учетом установки оптрона МОС3041?

Ze-pp
Offline
Зарегистрирован: 20.12.2018

SLKH пишет:

Ze-pp пишет:

Тогда поставим вопрос так - если в канале диммера использовать оптрон МОС3041( со встроенным детектором ноля), избавить код от прерываний - пусть этим занимается оптрон. Можно будет реализовать подобие плавного пуска?

можно, пропуском полупериодов.

 

Каким образом это сделать?

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

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

в верху обьявить как       boolean flag = true;

   RemoteXY_Handler ();
   if (ave_t.mean()< hotTemp) // Вычисляем "скользящее среднее" по последним 10 замерам, сравниваем его со значением температуры включения обогрева
   {
//   digitalWrite(DIM_PIN,1);
   if (flag == true)
	   flag = false;
    for (int i = DimMin; i > DimMax-1; i--) 
    {
     Dimmer1 = i; 
     delay (12);
    } 
  //   DimMin = DimMax;  <_______________________________________________________________________________
     RemoteXY.hot_Led_r= 255;  // включаем индикатор подогрева в приложении	   
   }
    else  
    {
	 flag == true
     digitalWrite(DIM_PIN,LOW);   // вырубить ток на всякий случай
//   DimMin = 255;
//    DimMax = 10;
     RemoteXY.hot_Led_r= 0;  // выключаем индикатор в приложении
    }
 
Ze-pp
Offline
Зарегистрирован: 20.12.2018

Baks пишет:

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

в верху обьявить как       boolean flag = true;

   RemoteXY_Handler ();
   if (ave_t.mean()< hotTemp) // Вычисляем "скользящее среднее" по последним 10 замерам, сравниваем его со значением температуры включения обогрева
   {
//   digitalWrite(DIM_PIN,1);
   if (flag == true)
	   flag = false;
    for (int i = DimMin; i > DimMax-1; i--) 
    {
     Dimmer1 = i; 
     delay (12);
    } 
  //   DimMin = DimMax;  <_______________________________________________________________________________
     RemoteXY.hot_Led_r= 255;  // включаем индикатор подогрева в приложении	   
   }
    else  
    {
	 flag == true
     digitalWrite(DIM_PIN,LOW);   // вырубить ток на всякий случай
//   DimMin = 255;
//    DimMax = 10;
     RemoteXY.hot_Led_r= 0;  // выключаем индикатор в приложении
    }
 

Происходит следующее:

Сначала лампа включается резко, горит секунд 5, потом гаснет. Потом плавно зажигается, секунды 3 и гаснет на это же время. Индикатор висит на показаниях влажности.

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

Делать диммер по такому алгоритму как у вас это изваращение. Вот нормальная реализация - https://playground.arduino.cc/Main/ACPhaseControl

Для линейной регулировки мощности обогрева в  OCR1A надо заносить не напрямую, а использую заранее рассчтанную таблицу. Но можно и без этого обойтись

Ze-pp
Offline
Зарегистрирован: 20.12.2018

asam пишет:

Делать диммер по такому алгоритму как у вас это изваращение. Вот нормальная реализация - https://playground.arduino.cc/Main/ACPhaseControl

Для линейной регулировки мощности обогрева в  OCR1A надо заносить не напрямую, а использую заранее рассчтанную таблицу. Но можно и без этого обойтись

Я попробую использовать код из вашего примера у себя в программе. но он очень похож на код из первого поста. И схема диммера такая-же. Суть в том (повторю), что скетч только диммера (из первого поста) работает без замечаний. Но стоит его внедрить в программу автоматики, и эта программа зависает.

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016
//////////////////////////////////////////////
//        RemoteXY include library          //
//////////////////////////////////////////////
 
// определение режима соединения и подключение библиотеки RemoteXY 
#define REMOTEXY_MODE__ESP8266_HARDSERIAL_POINT
#include <CyberLib.h>// шустрая библиотека для таймера
#include <RemoteXY.h>
#include <Average.h> // Источник - <a href="https://github.com/MajenkoLibraries/Average" title="https://github.com/MajenkoLibraries/Average" rel="nofollow">https://github.com/MajenkoLibraries/Average</a> 
#include <DHT.h>
#include <OneWire.h>
#include "TM1637.h"
#define CLK  4            // номер пина семисегмента TM1637
#define DIO  5            // номер пина семисегмента TM1637
#define dht22pin 8        // номер пина датчика DHT22
#define ZERO_PIN 2        // вход контроля перехода через 0 (ZERO, Z-C)только пин 2 !!!
#define DIM_PIN 11        // выход на симистор PWM (DIM)
#define fanPin 17         // номер пина семистора вентилятора (А3)
TM1637 tm1637(CLK,DIO);
DHT dht(dht22pin, DHT22);
unsigned long currentTime=0; // таймер с момента запуска программы
unsigned long tTime  =0; //таймер опроса датчика DHT22
uint32_t ms1        = 0;
uint32_t ms2        = 0; // таймер опроса датчика DHT22
uint32_t ms3        = 0; // таймер переключения дисплея 
int fanState = LOW; // состояние пина семистора  вентилятора
unsigned long previousMillis = 0;// последний момент времени, когда состояние пина семистора вентилятора изменялось
long OnTime = 1200000; // длительность работы вентилятора 20 минут (в миллисекундах)
long OffTime = 120000; // выключено 2 минуты(в миллисекундах)
byte coldTemp = 3; // Температура, ниже которой вентилятор не включится
byte treshold = 68; // Процент влажности, по достижению которого включаем вентилятор
byte hotTemp = 26; // Температура, ниже которой включается обогрев
Average<float> ave_t(10); // Для усреднения последних значений температуры с датчика создаём массив на 10 шт.
Average<float> ave_h(10); // Для усреднения последних значений влажности с датчика создаём массив на 10 шт.
uint8_t disp_mode   = 0;
int DimMax= 10; //Переменная для хранения максимального значения яркости Диммера 
int DimMin = 254; //Переменная для хранения минимального значения яркости Диммера
volatile uint8_t tic =0;
 volatile uint8_t Dimmer1=255;
 
// настройки соединения 
#define REMOTEXY_SERIAL Serial
#define REMOTEXY_SERIAL_SPEED 115200
#define REMOTEXY_WIFI_SSID "Hen_"
#define REMOTEXY_WIFI_PASSWORD ""
#define REMOTEXY_SERVER_PORT 6377
 
 
// конфигурация интерфейса   
#pragma pack(push, 1) 
uint8_t RemoteXY_CONF[] = 
  { 255,1,0,16,0,131,0,8,13,1,
  67,4,36,17,20,5,2,26,7,67,
  4,36,6,20,5,2,26,7,65,4,
  25,39,9,9,65,1,25,63,9,9,
  129,0,4,6,18,6,17,208,162,208,
  181,208,188,208,191,46,0,129,0,4,
  17,18,6,17,208,146,208,187,208,176,
  208,182,208,189,46,0,129,0,16,28,
  29,6,17,208,159,208,190,208,180,208,
  190,208,179,209,128,208,181,208,178,0,
  129,0,12,52,36,6,17,208,146,208,
  181,208,189,209,130,208,184,208,187,209,
  143,209,130,208,190,209,128,0,1,0,
  24,79,12,12,2,31,82,0 }; 
   
// структура определяет все переменные вашего интерфейса управления  
struct { 
     // input variable
  uint8_t reset_Button; // =1 если кнопка нажата, иначе =0 
 
    // output variable
  char hum_Text[7];  // =строка UTF8 оканчивающаяся нулем 
  char temp_Text[7];  // =строка UTF8 оканчивающаяся нулем 
  uint8_t hot_Led_r; // =0..255 яркость красного цвета индикатора 
  uint8_t fan_Led_b; // =0..255 яркость синего цвета индикатора 
 
    // other variable
  uint8_t connect_flag;  // =1 if wire connected, else =0 
 
} RemoteXY; 
#pragma pack(pop) 
 
/////////////////////////////////////////////
//           END RemoteXY include          //
/////////////////////////////////////////////
 
 
 
void setup() 
{
  RemoteXY_Init (); 
 Serial.begin(115200);
  currentTime = millis();  //запускаем счетчик 
   dht.begin();
  // Инициализация дисплея
  tm1637.init();
// Установка яркости дисплея  
  tm1637.set(7);
   delay(50);
   pinMode(fanPin, OUTPUT);
   digitalWrite(fanPin, fanState); // изначально семистор вентилятора выключен 
//   pinMode(hotPin, OUTPUT);
//   digitalWrite(hotPin, LOW); // изначально реле ИК-лампы выключено
   pinMode(DIM_PIN, OUTPUT); // выход диммера для подогрева
   digitalWrite(DIM_PIN, LOW); // изначально выход диммера выключен
   pinMode(ZERO_PIN, INPUT);
 
 attachInterrupt(0, detect_up, FALLING);  // настроить срабатывание прерывания interrupt0 на pin 2 на низкий уровень 
   StartTimer1(halfcycle, 40); //время для одного разряда ШИМ
   StopTimer1(); //остановить таймер
            
}
 
   void(* resetFunc) (void) = 0; // объявляем функцию reset
   
 
void loop() 
{
   
   if(currentTime>=(tTime+500))// Опрашиваем датчик каждые 0,5 сек. 
   {
   tTime=currentTime;
   float t = dht.readTemperature(); 
   float h = dht.readHumidity();
   if (isnan(h) || isnan(t)) {
    strcpy (RemoteXY.temp_Text, "Ошибка");
    strcpy (RemoteXY.hum_Text, "Ошибка");
    
//    return;
  } else {
   ave_t.push(t); // Кладём результат измерения температуры в массив. В массиве помещается 10 измерений, новоприбывшее выталкивает самое старое.
   RemoteXY_Handler ();
   ave_h.push(h); // Кладём результат измерения влажности в массив. В массиве помещается 10 измерений, новоприбывшее выталкивает самое старое.
   RemoteXY_Handler ();
   double val = t; 
   dtostrf(val, 0, 2, RemoteXY.temp_Text); // выводим значение температуры в приложении
   double mas = h; 
   dtostrf(mas, 0, 2, RemoteXY.hum_Text); // выводим значение влажности в приложении
   }
   }
/*************************************ДИСПЛЕЙ******************************************/
   
   if(currentTime < ms1 || (currentTime - ms1) > 500 ){
      ms1 = currentTime;
   int  Temp = ave_t.mean();
   int Hum = ave_h.mean();
 
   switch( disp_mode ){
//        case 0:
// Отображение времени таймера
//               tm1637.clearDisplay();
//               tm1637.point(true);
//               tm1637.display(0,mins/10);
//               tm1637.display(1,mins%10);
//               tm1637.display(2,sec/10);
//               tm1637.display(3,sec%10);              
//            break;
// Отображение влажности
        case 0: 
              tm1637.clearDisplay();
              tm1637.point(false);
              tm1637.display(0,Hum/10);
              tm1637.display(1,Hum%10);
              DisplaySpecialChar(3,0x24);
            break;
        case 1:
// Отображение температуры
            
               tm1637.clearDisplay();
               tm1637.point(false);
               tm1637.display(0,Temp/10);
               tm1637.display(1,Temp%10);
               DisplaySpecialChar(2,0x63);
               tm1637.display(3,0x0C);
            
            break;
   }
   }                    
   // Переключение режимов отображения
   if(currentTime < ms3 || (currentTime - ms3) > 3000  ){
      ms3 = currentTime;
      switch( disp_mode ){
         case 0 : disp_mode = 1; break;
         case 1 : disp_mode = 0; break;
   //     default: disp_mode = 0;
      }
   }
 /****************************************ПОДОГРЕВ**********************************/  
   RemoteXY_Handler ();
   if (ave_t.mean()< hotTemp) // Вычисляем "скользящее среднее" по последним 10 замерам, сравниваем его со значением температуры включения обогрева
   {
//   digitalWrite(DIM_PIN,1);
   if (flag == true)
	   flag = false;
    for (int i = DimMin; i > DimMax-1; i--) 
    {
     Dimmer1 = i; 
     delay (12);
    } 
     DimMin = DimMax; 
     RemoteXY.hot_Led_r= 255;  // включаем индикатор подогрева в приложении	   
   }
    else  if (ave_t.mean()> hotTemp +1)
    {
	 Dimmer1 = 255; 
	 flag == true
     digitalWrite(DIM_PIN,LOW);   // вырубить ток на всякий случай
//   DimMin = 255;
//    DimMax = 10;
     RemoteXY.hot_Led_r= 0;  // выключаем индикатор в приложении
    }
 /******************************ВЕНТИЛЯТОР********************************/
 
   // выясняем не настал ли момент сменить состояние реле вентилятора
   unsigned long currentMillis = millis(); // таймер для работы ветилятора в миллисекундах
   RemoteXY_Handler ();
   if ((fanState == LOW)&& (ave_t.mean()> coldTemp)&& (ave_h.mean()> treshold) && (currentMillis - previousMillis >= OffTime))
  {
    fanState = HIGH; // включаем вентилятор
    previousMillis = currentMillis ; // запоминаем момент времени
    digitalWrite(fanPin, fanState); // реализуем новое состояние
    RemoteXY.fan_Led_b= 255;  // включаем индикатор в приложении
 
 //       Serial.println("Вентилятор включен");
 //   Serial.println(ave_h.mean());
      } 
  // если вентилятор включен и работает больше чем надо
  if((fanState == HIGH) && (currentMillis - previousMillis >= OnTime)||(ave_t.mean()<= coldTemp) || (fanState == HIGH) && (ave_h.mean()< treshold) )
  {
    fanState = LOW; // выключаем
    previousMillis = currentMillis; // запоминаем момент времени
// TimerDisplayOff();
    digitalWrite(fanPin, fanState); // реализуем новое состояние
    RemoteXY.fan_Led_b= 0;  // выключаем индикатор в приложении
//    Serial.println("Вентилятор выключен");
 
    void     flushData(); // После того, как мы остудили мотор, надо "прочистить" массив с замерами влажности актуальными замерами. Иначе мотор будет врубаться снова и снова.
//    Serial.println("Вентилятор выключен");
 
    }
 
/********************************************СБРОС****************************************************/
  RemoteXY_Handler ();
    if (RemoteXY.reset_Button!=0) {
  resetFunc();
  }
}
 
/*****************************Вывести спец-символ на дисплей***************************************/
 
 
void DisplaySpecialChar(uint8_t BitAddr,int8_t SpecChar)
{
  tm1637.start();          //start signal sent to TM1637 from MCU
  tm1637.writeByte(ADDR_FIXED);//
 
  tm1637.stop();           //
  tm1637.start();          //
  tm1637.writeByte(BitAddr|0xc0);//
  
  tm1637.writeByte(SpecChar);//
  tm1637.stop();            //
  tm1637.start();          //
  
  tm1637.writeByte(tm1637.Cmd_DispCtrl);//
  tm1637.stop();           //
}
 
 void flushData() {
  int k = 0;
  unsigned long currentMillis = millis(); // запуск таймера 
  while (k < 10) {
    float t = dht.readTemperature(); // Опрашиваем датчик
    float h = dht.readHumidity();
    if (isnan(h) || isnan(t)) {
//      Serial.println("Sensor error!");
//      delay(interval);
      return;
    } else {
      ave_h.push(h); // Кладём результат измерения влажности в массив. В массиве помещается 10 измерений, новоприбывшее выталкивает самое старое.
      ave_t.push(t);
    }
  if(currentMillis>=(ms2+5000)) 
   {
    k++;
    ms2 = currentMillis; // запоминаем время
  }
  }
}
//********************обработчик и прерываний******************** *********** 
void halfcycle() //прерывания таймера 
{ 
tic++; //счетчик 
if(Dimmer1 < tic ) digitalWrite(DIM_PIN , HIGH); //управляем выходом 
} 
 
void detect_up() // обработка внешнего прерывания. Сработает по переднему фронту синусоиды 
{ 
tic=0; //обнулить счетчик 
ResumeTimer1(); //запустить таймер 
attachInterrupt(0, detect_down, RISING); //перепрограммировать прерывание на другой обработчик 
} 
 
void detect_down() // обработка внешнего прерывания. Сработает по заднему фронту синусоиды 
{ 
StopTimer1(); //остановить таймер 
digitalWrite(DIM_PIN,LOW); //логический ноль на выходы 
tic=0; //обнулить счетчик 
attachInterrupt(0, detect_up, FALLING); //перепрограммировать прерывание на другой обработчик 
} 

пробуем так, должно работать

я ошибся в условии должно быть так     else  if (ave_t.mean()> hotTemp +1)

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

Ze-pp
Offline
Зарегистрирован: 20.12.2018

Без изменений.

Ze-pp
Offline
Зарегистрирован: 20.12.2018

На сегодня эксперементов хватит. Всем спаибо! До завтра.

sadman41
Offline
Зарегистрирован: 19.10.2016

Отладка методом тыканья палкой в сено. Интересно даже - как долго продолжится и чем закончится.