Скачки показателя температуры на дисплее

Тема в разделе "Arduino & Shields", создана пользователем Almeder, 22 мар 2017.

  1. Almeder

    Almeder Нерд

    Здравствуйте. Извините если открываю тему с ошибкой. Первый раз.
    В общем, собрал регулятор температуры. Arduino Uno, ЖКИ (16,2), DHT11, модуль реле. Подключен тепловой вентилятор.
    Проблема в том, что показатель температуры при каждом обновлении температуры (~2сек) показывает с разбегом в 2-3 градуса - 23, 25, 23, 27, не удерживается на одном уровне. Из-за этого реле очень часто срабатывает. Библиотеку DHT взял, которая шла вместе с книгой Петина. Датчик пришел еще со с стартовым набором Arduino.
    Все куплено на Алиэкспресс.
    Возможно датчик такого качества?
    Прошу помочь. Хотя бы словом.
    За ранее спасибо.
     
  2. Airbus

    Airbus Радиохулиган Модератор

    Скетч в студию!Датчики действительно не гуд.Я перешел на dht22Если нужна только температура то можно использовать ds18d20.И в скетче сделать гистерезис вкл при 25 град выкл при 27 например.И сделать задержку секунд30 или больше между опросами
     
  3. sslobodyan

    sslobodyan Гик

    Температура это достаточно медленный процесс, поэтому очень желательно сглаживать показания датчика. Хорошим вариантом будет temp=temp*k+value*(1-k) где temp это температура, k-коеффициент сглаживания от 0 до 1, причем чем он больше, тем больше сглаживание, но медленнее реакция, value - это новое значение температуры. Если вы опрашиваете датчик раз в секунду, то начните с k=0.3, если чаще то можете k увеличить и до 0.8. Очень желательно посмотреть в динамике в терминале какие идут value и результирующая температура temp для правильного подбора коеффициента.
     
  4. Almeder

    Almeder Нерд

    Гестерезис я сделал, он включается, когда температура выше заданной и выключается, когда ниже заданной. Но дело в том, что показания скачут с разницей в 3 градуса. Если например поставил 25, он может показать одну секунду 24, а потом сразу 27, а третью 25 (хотя никаких сквозняков 100%). Скетч я взял Джереми Блума, только там у него другой датчик и вентилятор вместо реле. Я просто поставил другой датчик, реле, и пару кнопок добавил. На счет опроса датчика, я думал об этом, хотел это сделать, но я весь интернет перерыл, но не нашел, как увеличить время опроса датчика, delay естественно не будет работать с кнопками, ставил mills на реле, тоже не работает. Я думаю, что все же дело в датчике, потому, что он периодически успокаивается и не так сильно скачет. Еще я подумал, что возможно дело в проводах. У меня Ардуино стоит в одной комнате, а датчик в другой. Я соединил их обычным 0,35 "волосатым" проводом. Может это помехи?
    форум1.jpg
    Screenshot 2017-03-23 19.52.33.jpg
    Screenshot 2017-03-23 19.53.11.jpg
    Screenshot 2017-03-23 19.54.28.jpg
    Screenshot 2017-03-23 19.55.15.jpg
     
  5. Almeder

    Almeder Нерд

    Я примерно понял, что вы имеете ввиду, но я еще не настолько силен в программировании Ардуино. Подскажите в какой раздел вставить эту формулу.
    Если я правильно понял то в void loop, после опроса датчика?
    111.jpg
     
  6. rkit

    rkit Гуру

    Датчики эти паршивые. Берите ds18b20.

    Странный вывод.
     
  7. sslobodyan

    sslobodyan Гик

    Хотите сказать, что эти датчики скоростные и меряют скоростные процессы? Удивлюсь, если это так.
     
  8. rkit

    rkit Гуру

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

    sslobodyan Гик

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

    sslobodyan Гик

    Научитесь правильно вставлять код - выше есть специальная кнопочка, так и называется "КОД". Потому что работать с вашим текстом просто не возможно.
    Вставить сглаживание надо сразу после получения значения с датчика. У вас там данные в t, значит следующая строка
    Код (C++):
    temp=temp*k+t*(1-k);
    причем temp должна быть статической или глобальной (объявленной вне главного цикла в самом верху скетча). Ну и выводить, естественно, temp а не t.
     
  11. Almeder

    Almeder Нерд

    Извините, я на форумах новичек.
    Вот сразу с формулой, static int temp поставил сразу после булинов.
    Вроде не ругается.
    Но пока не заливал. Решил подождать пока вы посмотрите.
    Кстати датчик у меня не работает с float. Точнее работает но выводит целые числа с двумя нулями. Это нормально?
    Я читал про DHT и DS, в дальнейшем конечно хочу взять DS, но пока устройство в работе, нет желания его отключать на долго. И подскажите пожалуйста, какие вообще лучшие датчики, для Arduino.
    И еще вспомнил, у меня либо что-то с дребезгом, либо с кнопками.
    Вроде как такового дребезга нет (одно нажатие - один показатель меняется), но кнопки не всегда срабатывают сразу. В дальнейшем поставлю Шмитта, но просто интересно, для общего образования так сказать.

    Код (C++):

    #include <Wire.h>
    #include <LiquidCrystal_I2C.h>
    #include <DHT.h>

    #define DHTPIN 2
    #define DHTTYPE DHT11

    DHT dht(DHTPIN, DHTTYPE);


    byte degree[8] = // кодируем символ градуса
    {
    B00111,
    B00101,
    B00111,
    B00000,
    B00000,
    B00000,
    B00000,
    };

    byte fan_on[8] = // лампа включена
    {
    B01110,
    B11111,
    B11111,
    B01110,
    B01110,
    B00100,
    B00000,
    };
    byte fan_off[8] = // лампа выключена
    {
    B01110,
    B10001,
    B10001,
    B01010,
    B01110,
    B00100,
    B00000,
    };
    const int Relay = 4;
    const int SPEAKER = 7;
    const int UP_BUTTON = 10;
    const int DOWN_BUTTON = 9;
    int switchPin = 5;

    boolean lastDownTempButton = LOW;
    boolean currentDownTempButton = LOW;
    boolean lastUpTempButton = LOW;
    boolean currentUpTempButton = LOW;
    boolean lastLedButton = LOW;
    boolean currentLedButton = LOW;
    int set_temp = 23;
    boolean one_time = false;
    boolean lcdOn = true;

    static int temp;

    LiquidCrystal_I2C lcd(0x3F,16,2);


    void setup() {


    pinMode(Relay, OUTPUT);



    lcd.init();
    lcd.backlight();

    lcd.createChar(0, degree);
    lcd.createChar(1, fan_off);
    lcd.createChar(2, fan_on);

    lcd.setCursor(0,0);
    lcd.print("Current:");
    lcd.setCursor(10,0);
    lcd.write((byte)0);
    lcd.setCursor(11,0);
    lcd.print("C");
    lcd.setCursor(0,1);
    lcd.print("Set:");
    lcd.setCursor(10,1);
    lcd.write((byte)0);
    lcd.setCursor(11,1);
    lcd.print("C");
    lcd.setCursor(15,1);
    lcd.write(1);
    }
    boolean debounce(boolean last, int pin)
    {
      boolean current = digitalRead(pin);
      if (last != current)
      {
        delay(5);
        current = digitalRead(pin);
      }
      return current;
    }


    void loop() {




    int t = dht.readTemperature();
    temp=temp*0.3+t*(1-0.3);
    lcd.setCursor(8,0);
    lcd.print(temp);

    currentDownTempButton = debounce(lastDownTempButton, DOWN_BUTTON);
    currentUpTempButton = debounce(lastUpTempButton, UP_BUTTON);
    currentLedButton = debounce(lastLedButton, switchPin);
      if (lastDownTempButton == LOW && currentDownTempButton == HIGH)
      {
        set_temp--;
      }
    else if (lastUpTempButton == LOW && currentUpTempButton == HIGH)
    {
      set_temp++;
    }
    lcd.setCursor(8,1);
    lcd.print(set_temp);

    lastDownTempButton = currentDownTempButton;
    lastUpTempButton = currentUpTempButton;

    if (lastLedButton == LOW && currentLedButton == HIGH)
      {
        if(lcdOn) lcdOn = false;
        else lcdOn = true;
       }

    lastLedButton = currentLedButton;
    if (lcdOn)
    {
      lcd.display();
      lcd.backlight();
    }
    else
    {
      lcd.noDisplay();
      lcd.noBacklight();
      }
    if (temp >set_temp)
    {
      if (!one_time)
      {
        tone(SPEAKER, 400);
        delay(500);
        one_time = true;
      }
      else
      {
       noTone(SPEAKER);
      }

      digitalWrite(Relay, LOW);
      lcd.setCursor(15,1);
      lcd.write(1);
    }
    if (temp <set_temp)
    {
    noTone(SPEAKER);
    one_time = false;
    digitalWrite(Relay, HIGH);
    lcd.setCursor(15,1);
    lcd.write(2);
    }
    }
     
    Последнее редактирование: 24 мар 2017
  12. sslobodyan

    sslobodyan Гик

    похоже, что должно работать.
    по датчикам - все зависит от требований, панацеи нет.
    по нолям - открываете библиотеку датчика и смотрите что она принимает и выдает, сравниваете с даташитом на датчик. в ардуине так всегда - сначала быстро как-нибудь, а потом вдумчиво разбираемся почему немножко не то, что хотелось.
    по кнопкам - такой алгоритм сами придумали, или где советовали? я б так не делал. для простых вариантов достаточно запоминать время (millis) последнего опроса клавиш и сравнивать с текущим в главном цикле. если текущее время больше запомненного на 50 (время антидребезга), то снова опрашиваем кнопки и запоминаем время. шмидта можно не ставить - это не аналоговая техника, здесь все через алгоритмы :)
     
    Almeder нравится это.
  13. rkit

    rkit Гуру

    В пинах ардуино триггер шмитта уже встроен.
     
  14. Almeder

    Almeder Нерд

    От Джерими Блума, правда видео 2014 года. Он показывал устранение дребезга через этот алгоритм и через триггер. И он больше склонялся к триггеру. Типа "зачем писать лишний код, когда можно устранить что-то аппаратно". Сей-час опробую новый скетч.
     
  15. Almeder

    Almeder Нерд

    Вроде работает, по крайней мере так не скачет, как бы перекатывается - на спиртовом градуснике 26, датчик показывает 26,25,24, 26, 25, 24 и т. д. меня пока устраивает, так как ниже заданной температуры он не падает резко. А потом, как аппарат освободится, буду другие датчики пробовать. Так что спасибо большое.
    Только скажите еще пожалуйста, я выше еще спрашивал, влияют ли провода на показания датчика, и вообще на Ардуино, я на датчик поставил обычный 0,35 провод (медный).
     
  16. rkit

    rkit Гуру

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

    Airbus Радиохулиган Модератор

    Тогда проще датчик и Арду в одном месте а исполнительное устройство в другом.И связь по радиоканалу. Тут походу датчик косячный я тут прикола ради погонял DHT11 ничего не меняется а если на него подышать то да!
    [​IMG]
    Возьмите даллас и не парьтесь.Можно классные вещи делать.Вот когда то под этот шилд был у меня терморегулятор на 2 датчика
    Код (C++):
    //  v 0.1 beta

    #include <EEPROM.h>
    #include <OneWire.h>
    #include <LiquidCrystal.h>

    #define OUT1 2 // выходы для реле
    #define OUT2 3

    byte tempOUT1, tempOUT2;

    LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
    OneWire  ds(11); // 11 вход датчика 18b20

    byte gradus[8] = {
      0b00110,
      0b01001,
      0b01001,
      0b00110,
      0b00000,
      0b00000,
      0b00000,
      0b00000
    };


    void erorr(){ // останавливает работу программы и сигнализирует ошибку
      digitalWrite(OUT1, LOW); // выключаем реле
      digitalWrite(OUT2, LOW);
        while(1){ // крутим бесконечный цикл
          digitalWrite(13, !digitalRead(13));
          delay(500);
        }
    }
    ////

    byte key(){ //// для кнопок ЛСДшилда
      int val = analogRead(0);
        if (val < 50) return 5;
        else if (val < 150) return 3;
        else if (val < 350) return 4;
        else if (val < 500) return 2;
        else if (val < 800) return 1;
        else return 0;
    }
    ////

    void setMenu(){ // установка температуры
      byte pos;  
      digitalWrite(OUT1, LOW); // выключаем реле
      digitalWrite(OUT2, LOW);

      lcd.clear();
      lcd.setCursor(0, 0); // что нужно отрисовать один раз
      lcd.print("OUT1: ");
      lcd.setCursor(0, 1);
      lcd.print("OUT2: ");
      lcd.blink();
     
      while(1){ // крутим бесконечный цикл    
        byte KEY = key(); // читаем состояние кнопок
       
        lcd.setCursor(6, 0); // выводим на экран
        lcd.print(tempOUT1);
        lcd.write(1);
        lcd.print("C  ");
        lcd.setCursor(6, 1);
        lcd.print(tempOUT2);  
        lcd.write(1);
        lcd.print("C  ");
       
         ////// обработка кнопок
        if (pos == 0){  // если в первой позиции
          lcd.setCursor(5, 0); // устанавливаем курсор
          if (KEY == 2) { // если нажата кнопка
            tempOUT1--;   // изменяем значение
            EEPROM.write(1, tempOUT1); // сохраняем в еепром
          }
          else if (KEY == 5){
            tempOUT1++;
            EEPROM.write(1, tempOUT1);    
          }  
        }
        if (pos == 1){
          lcd.setCursor(5, 1);
          if (KEY == 2) {
            tempOUT2--;
            EEPROM.write(2, tempOUT2);
          }
          else if (KEY == 5){
            tempOUT2++;
            EEPROM.write(2, tempOUT2);    
          }  
        }
       
        if (KEY == 3) pos--; // крутим позицию
        else if (KEY == 4) pos++;  
        if (pos > 1) pos = 0;
       delay(200);
      }
    }

    float getTemp(){   // возвращает температуру с датчика
      byte data[12];   // и останавливает программу на секунду
      byte addr[8];
     
      if (!ds.search(addr)) {
        lcd.clear();
        lcd.print("No sensor.");
        erorr();
      }
     
      ds.reset_search();
      if (OneWire::crc8(addr, 7) != addr[7]) {
        lcd.clear();
        lcd.print("Sensor CRC erorr");
        erorr();  
      }
     
      ds.reset();          
      ds.select(addr);      
      ds.write(0x44);    
      delay(1000);  
     
      ds.reset();
      ds.select(addr);  
      ds.write(0xBE);        

      for (int i = 0; i < 9; i++) data[i] = ds.read();
      int raw = (data[1] << 8) | data[0]; // Переводим в температуру  
      if (data[7] == 0x10) raw = (raw & 0xFFF0) + 12 - data[6];
     
      return raw / 16.0;
    }

    void setup() {
    //  Serial.begin(9600);
      lcd.createChar(1, gradus);
      lcd.begin(16, 2);
      lcd.clear();
     
      pinMode(13, OUTPUT);
      pinMode(OUT1, OUTPUT);
      pinMode(OUT2, OUTPUT);
     
      tempOUT1 = EEPROM.read(1); // читаем настройки
      tempOUT2 = EEPROM.read(2); // из еепром
    }

    void loop() {
      if (key() == 1) setMenu(); // если нажата селект, уходим в меню
      else if (key() == 4) analogWrite(10, 20); // если вниз, глушим подсветку
      else if (key() == 3) digitalWrite(10, HIGH);
     
      float temperature = getTemp(); // читаем температуру
      if (temperature < tempOUT1) digitalWrite(OUT1, HIGH); // сверяем температуру
      else digitalWrite(OUT1, LOW);                         // и управляем выходами
      if (temperature < tempOUT2) digitalWrite(OUT2, HIGH);
      else digitalWrite(OUT2, LOW);
         
      lcd.setCursor(0, 0); /// вывод инфы на экран
      lcd.print("1:");
      lcd.print(tempOUT1);
      lcd.write(1);
    //  lcd.print("C");
        if (digitalRead(OUT1)) lcd.print(" ON "); // показываем состояние выхода
        else lcd.print(" OFF");
      lcd.setCursor(0, 1);
      lcd.print("2:");
      lcd.print(tempOUT2);
      lcd.write(1);
        if (digitalRead(OUT2)) lcd.print(" ON ");
        else lcd.print(" OFF");  
       
      lcd.setCursor(9, 0); // показываем температуру с датчика
      lcd.print("|");
      lcd.print(temperature, 1);
      lcd.write(1);
      lcd.print("C");
      lcd.setCursor(9, 1);    
      lcd.print("|");
    }


     
     
    Последнее редактирование: 24 мар 2017
  18. Almeder

    Almeder Нерд

    Да спасибо, я так и планирую, сейчас пока устройство в работе. Как освободится. Буду менять датчик.
    И за скетч тоже спасибо большое. Будем изучать.)
     
  19. sslobodyan

    sslobodyan Гик

    Поиграйте с коэффициентом, может станет получше.
     
  20. Onkel

    Onkel Гуру

    вам надо принять силовое решение и перейти на рабочие датчики ds18b20. В противном случае в любой момент можно словить казус.