термореле для холодильника ds18b20+oled+nano

neid86@gmail.com
Offline
Зарегистрирован: 28.10.2014

Всем привет форумчане! Делаю потихоньку для своего холодильника термореле, т.к. оно скончалось, поискав нельколько проектов нашел у человека один подходящий и на его основе сделал под себя, поменял дисплей на oled 128*32 i2c(то что есть в наличии), и добавил меню для настройки некоторых параметров работы реле по заданной температуре(тоже взято у человека с этого форума), все это делается еще некоторых идей которые получат реализацию чуть позже, сейчас с этим бы разобраться. Столкнулся для меня не понятной ситуацией, являюсь новичком в программирование, суть в чем, при подключенном датчике температуры ds18b20, начинает тормозить окпрос кнопок ну и соотвественно вывод на экран. Как только его отключаю, сразу все летает, опрос  кнопок работает как надо. Но при подключеном датчика температуры , все выводится корректно и быстро, временные задежки работают корректно. Пересмотрел подключение темп.датчика, но для себя не выявил каких либо ощибок, на этом мои познания заканчиваются. помогите оптимизировать код без тормозов при подключенном датчике температуры. и опросе кнопок.

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <OneWire.h>
#include <DallasTemperature.h>

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

double f_tempC;                        // Текущая температура
double t_min,t_max;                    // переменне для установки макс.и мин. тепературы 
unsigned long ul_offTime;              // Время отключения компрессора
unsigned long ul_workTime;             // Время включения компрессора
unsigned long ul_newTime;              // Текущее время
unsigned long ul_deltaTime;            // Разница времени
//unsigned long ul_actHeartLedTime;    // Время светодиода активности
//boolean b_actLedOn;                  // Светодиод активности включён
boolean b_compressorOff;               // Компрессор выключен
boolean t_ok;                          // флаг исправности датчика температуры для вывода на oled ошибки

// Температура включения компрессора
#define TEMPERATURE_MAX t_max
// Температура отключения компрессора
#define TEMPERATURE_MIN t_min
// Пауза перед включением компрессора (600000 = 10 минут)
#define DELAY_COMPRESSOR 600000
// Максимальное время работы компрессора (3600000 = 1 час)
#define MAXTIME_COMPRESSOR 1200000
// Реле подключено к 3 пину
#define RELE 3
// Датчик температуры подключён к 2 пину
#define ONE_WIRE_BUS 2
// Светодиод активности подключён к 13 пину
//#define LED_ACTIVITY 13
// Свечение светодиода активности в мс
//#define LED_ACTIVITY_ON 50
// Пауза светодиода активности в мс
//#define LED_ACTIVITY_OFF 3950
// Светодиод ошибки датчика температуры подключён к 12 пину
//#define LED_ERROR 12
// Время работы компрессора при ошибке датчика температуры (1200000 = 20 минут)
#define ERROR_COMPRESSOR_ON 1200000
// Время паузы компрессора при ошибке датчика температуры (2400000 = 40 минут)
#define ERROR_COMPRESSOR_OFF 2400000

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

//массив надписей которые выводяться не на одном экране для экономии памяти
char* myLabel[]={//повторяющиеся надписи
  "Parametr","P1=","P2=","P3="};
int tt;
int m=0; //переменная для экранов меню
int p1=0; // переменная для примера 1
int p2=0; // переменная для примера 2
boolean p3=0; // переменная для примера 3
unsigned long PSTimer = 0;//таймер для обновления экрана
unsigned long KPTimer = 0;//таймер для опроса кнопок
unsigned long MSRTimer = 0;//таймер для автовозврата к MainScreen
#define MSRecovery 10000 //задержка автовозврата к MainScreen 10сек

#define nextPin 12 //кнопка "SET" на 12 входе
#define upPin 11 //кнопка "+"
#define downPin 10 //кнопка "-"
boolean f_key=0;//флаг для фиксации нажатия кнопки
#define bounce 100 //задержка антидребезга
#define ledPin 13 //Светодиод
#define eventLenght 10//длина очереди событий
byte eventList[eventLenght+1];//инициализация очереди событий + 1 пустое

//  |состояния|         события          | на пересечении действие
//  |---------+-+----+---+---+---+---+---|
//  |    v    |0| 1  | 2 | 3 | 4 | 5 | 6 | -расшифровка событий-
//  |         | |SET | + | - |   |   |   | 0-нет действий
//  |---------+-+----+---+---+---+---+---| 1-кнопка SET
//  |  0   m=0|0|m++ | 0 | 0 |PS | 0 |gk | 2-кнопка +
//  |  1   m=1|0|m++ |p1+|p1-|PS |m0 |gk | 3-кнопка -
//  |  2   m=2|0|m++ |p2+|p2-|PS |m0 |gk | 4-таймер обновления экрана
//  |  3   m=3|0|m++ |p3+|p3-|PS |m0 |gk | 5-таймер возврата к основному экрану
//  |---------+-+----+---+---+---+---+---| 6-таймер опроса кнопок

//коды действий
#define m_up 1// цифра - адрес команды в функции run(event)
#define p1_up 3
#define p1_dn 4
#define p2_up 5
#define p2_dn 6
#define led_on 7
#define led_off 8
#define PS 9
#define m0 10
#define gk 11

byte automat[4][7] = {         
  {    
    0, m_up, 0, 0, PS, 0, gk               }
  ,{   
    0, m_up, p1_up, p1_dn, PS, m0, gk                }
  ,{   
    0, m_up, p2_up, p2_dn, PS, m0, gk                }
  ,{   
    0, m_up, led_on, led_off, PS, m0, gk                } 
};





void setup() {
    // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x32)
  // init done
  display.display();
  display.clearDisplay();
  
  //Настройка входов
  pinMode(nextPin, INPUT);
  pinMode(upPin, INPUT);
  pinMode(downPin, INPUT);
  //Настройка выходов
  pinMode(ledPin, OUTPUT);
  pinMode(RELE, OUTPUT);
  digitalWrite(RELE, LOW); // При загрузке компрессор отключён
  
  b_compressorOff = true;
  sensors.begin();
  
  ul_offTime = millis();               // Запоминаем время начала работы программы
  //ul_actHeartLedTime = ul_offTime; 
}

// Функция вычисления разницы времени, в том числе и при длительной
// непрерывной работе более 49 суток
unsigned long deltamills(unsigned long t_old, unsigned long t_new) {
  unsigned long delta;
  if ( t_old <= t_new ) {        
    delta = t_new - t_old;
  } else {
    delta = (4294967295 - t_old) + t_new;
  }
  return delta;
}


//--------------функция изменения переменной-------------------
//х=var(переменная,минимум,максимум,шаг,циклически);
int var(int v, int mn, int mx, int stp, boolean c){
  v+=stp;
  switch (c){//c-1 циклически с-0 до пределов
  case 1://
    if (v<mn){
      v=mx;
    }
    if (v>mx){
      v=mn;
    }
    break;
  case 0:
    if (v<mn){
      v=mn;
    }
    if (v>mx){
      v=mx;
    }
    break;
  }
  return v;
}

//-------------ОПРОС КНОПОК------------
void getKey(){
  KPTimer=millis()+bounce;//сброс таймера
  switch (f_key){
  case 0:
    key_dn();//получаем события кнопок
    if (f_key==true){//если кнопка была нажата
      MSRTimer=millis();//сброс таймера автовозврата к главному экрану   
    }
    break;
  case 1:
    key_up();//проверка отпускания кнопки
    break;
  }
}

//--------------ПРОВВЕРКА НАЖАТИЯ------------
void key_dn(){
  //Обработка нажатия кнопки NEXT
  if (digitalRead(nextPin)== HIGH)
  {
    f_key=true;//устанавливаем флаг
    cludEvent(1);//сохраняем в очередь код события
  }
  //Обработка нажатия UP
  if (digitalRead(upPin)== HIGH)//если находимся на экране с переменной р1
  {
    f_key=true;//устанавливаем флаг
    cludEvent(2);//сохраняем в очередь код события
  }
  //Обработка нажатия DN
  if (digitalRead(downPin)== HIGH)//если находимся на экране с переменной р1
  {
    f_key=true;//устанавливаем флаг
    cludEvent(3);//сохраняем в очередь код события
  }
}
//проверка отпускания кнопки
void key_up(){
  if (digitalRead(nextPin)==0 && digitalRead(upPin)==0 && digitalRead(downPin)==0){
    f_key=false;//сброс флага
  }
}



//---------ФУНКЦИИ ОЧЕРЕДИ СОБЫТИЙ-------------
//положить задание
void cludEvent(byte e){
  if(eventList[0] !=0){//чтобы не потерять задание в очереди
    run(automat[m][getEvent()]);//выполнение действия из таблицы переходов
  }
  pushEvent();//сдвигаем очередь
  eventList[eventLenght-1]=e;//положить задание в очередь
}

//взять задание
byte getEvent(){
  return eventList[0];
}
//сдвинуть очередь
void pushEvent(){
  for (int i=0; i <= eventLenght-1; i++){
    eventList[i]=eventList[i+1];
  }
}

//количество заданий в очереди
byte getEventLenght(){
  byte el=0;
  for (int i=0; i <= eventLenght-1; i++){
    //для отладки
    //lcd.setCursor(5+i, 0);//выводит на дисплей очередь
    //lcd.print(eventList[i]);
    if(eventList[i] != 0){//подсчет заданий в очереди
      el++;
    } 
  }
  return el;//возвращает кол-во заданий в очереди
}


//выполнить действие согласно таблице переходов
//где переменная = var(переменная,минимум,максимум,шаг,циклически)
void run(int f){
  switch (f){
  case 0:
    break;
  case 1:
    m=var(m, 0, 3, 1, 1);//увеличиваем переменную уровня меню
    break;
  case 3:
    p1= var(p1, -5, 10, 1, 1);//то при нажатии кнопки + увеличиваем переменную р1 на единицу
    break;
  case 4:
    p1= var(p1,-5, 10, -1, 1);//то при нажатии кнопки - уменьшаем переменную р1 на единицу
    break;
  case 5:
    p2= var(p2, -5, 10, -1, 1);
    break;
  case 6:
    p2= var(p2, -5, 10, -1, 1);
    break;
  case 7:
    p3= var(p3, 0, 1, 1, 0);
    break;
  case 8:
    p3= var(p3, 0, 1, -1, 0);
    break;
  case 9:
    PreentScreen(m);//обновление экрана
    break;
  case 10:
    m=0;
    break;
  case 11:
    getKey();
    break;
  }
}


//--------Вывод экранов----------------------
void PreentScreen(int s){
  
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(30,0);
  display.println("ATLANT 130-3M");  //Выводи надпись название модели холодильника
 
  switch (s){
    
  case 0://Экран выводимый по умолчанию (не пункт меню)
    PrintLabel("Tempeture:",0,10);
    if (t_ok==0) {                              //если ds18b20 не исправен то выводим об ошибке подключения
        display.setTextColor(WHITE);
        display.setCursor(10,20);
        display.println("Tempsensor ERROR");
    } else {
        display.setCursor(60,10);              //если ds18b20 исправен то выводим текущую температуру
        display.print(f_tempC);
        display.println(" C");//выводим температуру    
    }
    break;

  case 1://экран изменения переменной 1
    PrintLabel(myLabel[0],0,10);
    PrintLabel(myLabel[1],0,20);
    display.setCursor(30,20);
    display.println(p1);
    break;

  case 2://экран изменения переменной 2
    PrintLabel(myLabel[0],0,10);
    PrintLabel(myLabel[2],0,20);
    display.setCursor(30,20);
    display.println(p2);
    break;

  case 3://экран изменения переменной 3
    PrintLabel("SCREEN 3",0,10);
    PrintLabel(myLabel[3],0,20);
    display.setCursor(30,20);
    display.println(p3);
    break;
  
  /*case 4://экран изменения переменной 4
    PrintLabel("SCREEN 4",0,10);
    PrintLabel(myLabel[3],0,20);
    display.setCursor(30,20);
    display.println(p3);
    break;*/
  }
display.display();
}

//---------вывод лейблов в указанном месте экрана-------------
void PrintLabel(char* t, byte x, byte y){//char* t - лейбл, x-столбец, y-строка
  display.setCursor(x,y);
  display.println(t);
}


void loop() {
  
  ul_newTime =  millis();              // Получаем текущее время
  
  //heartIndication(ul_newTime);         // Моргаем светодиодом активности

 run(automat[m][getEvent()]);//выполнение действия из таблицы переходов
  pushEvent();//сдвигаем очередь

  //------Опрос кнопок-----------------------
  if (millis()>KPTimer){//если пришло время
    cludEvent(6);//опрос кнопок - сохраняем в очередь код события
  }  
  digitalWrite(ledPin,p3);
  //-----Автовозврат к основному экрану---------------
  if (millis()-MSRTimer>=MSRecovery && m !=0 ){  //если пришло время и экран не основной
    MSRTimer=millis();
    cludEvent(5);//то отобразить главный экран - сохраняем в очередь код события                                    
  }
  //getEventLenght();//выводит очередь заданий на экран
  //-----------Обновление экрана--------------
  if (millis()-PSTimer>250){//вывод экрана каждые 250мсек 4р/сек
    PSTimer=millis();
    cludEvent(4);//обновление экрана - сохраняем в очередь код события
  }
  
  sensors.requestTemperatures();
  f_tempC = sensors.getTempCByIndex(0);  // Получаем температуру с датчика

// Проверяем работоспособность датчика температуры
if(( f_tempC > -30.0 ) && ( f_tempC < 50.0 )){ // Температурный датчик исправен
    t_ok=1;  //флаг исправности датчика температуры в 1 если исправен
    //digitalWrite(LED_ERROR, LOW);
  
    
    if ( b_compressorOff ) {                 // Если компрессор выключен
      ul_deltaTime = deltamills(ul_offTime, ul_newTime); // Разница времени простоя
      if (ul_deltaTime > DELAY_COMPRESSOR) {  // Если разница времени простоя больше разрешенной
        if ( f_tempC > TEMPERATURE_MAX ) {    // Если температура больше максимально допустимой
          digitalWrite(RELE, HIGH);           // Включаем компрессор
          b_compressorOff = false;
          ul_workTime = millis();             // Записываем время включения
        }
      }
    } else {                                  // Если компрессор включен
      ul_deltaTime = deltamills(ul_workTime, ul_newTime); // Разница времени работы
      // Если температура меньше минимально допустимой или время работы больше допустимого
      if ( ( f_tempC < TEMPERATURE_MIN ) || ( ul_deltaTime > MAXTIME_COMPRESSOR ) ) {
        digitalWrite(RELE, LOW);              // Выключаем компрессор
        b_compressorOff = true;
        ul_offTime = millis();                // Запоминаем время выключения компрессора
      }
    }
} else {                                    // Температурный датчик неисправен или оборван
    t_ok=0; //флаг исправности датчика температуры в ноль если не исправен

    if( b_compressorOff ){                    // Если компрессор выключен при неисправном датчике
        ul_deltaTime = deltamills(ul_offTime, ul_newTime); // Разница времени простоя
        if (ul_deltaTime > ERROR_COMPRESSOR_OFF) {  // Если разница времени простоя больше разрешенной
          digitalWrite(RELE, HIGH);           // Включаем компрессор
          b_compressorOff = false;
          ul_workTime = millis();             // Записываем время включения
        }
    } else {                                  // Если компрессор включен при неисправном датчике
      ul_deltaTime = deltamills(ul_workTime, ul_newTime);
      if ( ul_deltaTime > ERROR_COMPRESSOR_ON ) {
        digitalWrite(RELE, LOW);              // Выключаем компрессор
        b_compressorOff = true;
        ul_offTime = millis();                // Запоминаем время выключения компрессора
      }
    }
  }
  
}//end LOOP

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015
Поставьте печать millis перед строкой 380 и после строки 382 и посмотрите сколько времени эти строки работают. Вот Вам и тормоза. Пример неблокирующего вызова - http://arduino.ru/forum/programmirovanie/ds18b20-opredelenie-prisutstviya-datchika-na-shine#comment-245008
 
В строках 134-142 Вы, видимо, боретесь с переполнением millis? Это немного смешно. Этого не нужно делать, надо просто правильно работать с millis. Почитайте - http://arduino.ru/forum/programmirovanie/velikoe-perepolnenie-millis
 
neid86@gmail.com
Offline
Зарегистрирован: 28.10.2014

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

Поставьте печать millis перед строкой 380 и после строки 382 и посмотрите сколько времени эти строки работают. Вот Вам и тормоза. Пример неблокирующего вызова - http://arduino.ru/forum/programmirovanie/ds18b20-opredelenie-prisutstviya-datchika-na-shine#comment-245008
 
В строках 134-142 Вы, видимо, боретесь с переполнением millis? Это немного смешно. Этого не нужно делать, надо просто правильно работать с millis. Почитайте - http://arduino.ru/forum/programmirovanie/velikoe-perepolnenie-millis
 

пробую скомпилировать ваш код! ругается на sensors.isConversionAvailable(deviceAddress), такими словами Arduino: 1.8.5 (Windows 7), Плата:"Arduino Nano, ATmega328P"

 
C:\Users\Денис\Documents\Arduino\sketch_sep18a\sketch_sep18a.ino: In function 'void loop()':
 
sketch_sep18a:28: error: 'class DallasTemperature' has no member named 'isConversionAvailable'
 
exit status 1
'class DallasTemperature' has no member named 'isConversionAvailable'
 
дальше для меня темный лес пока, вы уж скажите что не так делаю, т.к. почитав несколько тем где вы предлагаете свой метод смотрю есть и кто поддержал вашу идею и много противников. С millis() таже ситуация, проблема в том что пока допрет, мне проще на примере показать чем задать направление. То что на температурный датчик тратися максимум около 750мс это я усвоил.  
template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; }

#include <OneWire.h>
#include <DallasTemperature.h>

#define SENSOR_PIN 6

OneWire oneWire(SENSOR_PIN);
DallasTemperature sensors(&oneWire);
DeviceAddress deviceAddress;


void setup(void) {
  Serial.begin(115200);
  Serial << "Non blocking Dallas Temperature Demo\n";
  sensors.begin();
  sensors.getAddress(deviceAddress, 0);
  sensors.setWaitForConversion(false);
}

void loop(void) {
	static bool didNotSendYet = true;
	static unsigned long start;
	if (didNotSendYet) {
		 start = millis();
		sensors.requestTemperaturesByAddress(deviceAddress); 
		didNotSendYet = false;
	} else if (sensors.isConversionAvailable(deviceAddress)) {
		const float temp = sensors.getTempC(deviceAddress);
		const unsigned long duration = millis() - start;
		Serial << "Temperature: " << temp << " (" << duration << " ms)\n"; 
		delay(2000);
		didNotSendYet = true;
	}
}

 

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

neid86@gmail.com пишет:

sketch_sep18a:28: error: 'class DallasTemperature' has no member named 'isConversionAvailable'

Значит, у Вас другая версия библиотеки DallasTemperature. Возмите вот эту - https://drive.google.com/open?id=1KaWWTHU3KcSg2R8Hcx6CyIyO1a9iSOt5

neid86@gmail.com
Offline
Зарегистрирован: 28.10.2014

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

neid86@gmail.com пишет:

sketch_sep18a:28: error: 'class DallasTemperature' has no member named 'isConversionAvailable'

Значит, у Вас другая версия библиотеки DallasTemperature. Возмите вот эту - https://drive.google.com/open?id=1KaWWTHU3KcSg2R8Hcx6CyIyO1a9iSOt5

С вашей заработал пример, до этого последняя была установлена версия dt 3,8,0

neid86@gmail.com
Offline
Зарегистрирован: 28.10.2014

Спасибо вам что направили меня! С этим примером код стал шустро работать ни каких затыков! опрос датчика около 43-44мс.

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

120% согласен. В температурной библиотеке оч много ненужных задержек.