#1 2024-07-26 22:40:12

germansir
Учасник
Зареєстрований: 2024-07-26
Повідомлень: 7

dht22 не показує мінусову температуру

Доброго здоров'я! По прикладам з інтернету написав скетч типу погодної станції з використанням DHT22, бібліотеку взяв від Adafruit. Все працює добре, але коли температура становиться нижче 0 то показує -76 градусів. Я вже замахався шукати причину.

#include <DHT.h>
#include <DHT_U.h>
#include <stdio.h>
#include <Wire.h>
#include <SPI.h>  // include SPI library
#include <virtuabotixRTC.h>
#include <Adafruit_Sensor.h>
//#include <Adafruit_BME280.h>
//#define SEALEVELPRESSURE_HPA (1013.25)

//Adafruit_BME280 bme;
virtuabotixRTC myRTC(6, 7, 8);
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);  // Устанавливаем дисплей
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
#define DHTPIN 3             // DHT22 data pin is connected to Arduino analog pin 0
#define DHTTYPE DHT22        // DHT22 sensor is used
DHT dht22(DHTPIN, DHTTYPE);  // configure DHT library

char temperature[] = "000.0";
char humidity[] = "000.0%";

void setup() {
  //myRTC.setDS1302Time(40, 52, 19, 6, 26, 7, 2024); //сек,хв,год,день,число,місяць,рік
  myRTC.updateTime();
  sensors.begin();
  dht22.begin();
  lcd.init();
  lcd.backlight();  // Включаем подсветку дисплея
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);
  delay(1000);  // wait 1 second

  byte drop[8] = {
    0b00100,
    0b01010,
    0b11011,
    0b10011,
    0b10001,
    0b11011,
    0b01110,
    0b00000
  };

  byte cel[8] = {
    0b00110,
    0b01001,
    0b01001,
    0b00110,
    0b00000,
    0b00000,
    0b00000,
    0b00000
  };
  lcd.createChar(1, drop);
  lcd.createChar(2, cel);
}

// main loop
void loop() {
  float tempC = sensors.getTempCByIndex(0);
  lcd.setCursor(10, 2);
  lcd.print(tempC, 1);
  lcd.write(2);
  lcd.print("C");

  /*lcd.setCursor(0, 3);
  lcd.print(bme.readPressure() / 133.32F,0);
  lcd.print("mmHg");

  lcd.setCursor(10, 3);
  lcd.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
  lcd.print("m");*/
  sensors.requestTemperatures();
  // read humidity
  int RH = dht22.readHumidity() * 10;
  // read temperature in degree Celsius
  int Temp = dht22.readTemperature() * 10;

  // update temperature and humidity arrays
  if (Temp < 0) {
    temperature[0] = '-';
    Temp = abs(Temp);
  } else
    temperature[0] = ' ';
    temperature[1] = (Temp / 100) % 10 + '0';
    temperature[2] = (Temp / 10) % 10 + '0';
    temperature[4] = Temp % 10 + '0';

  if (RH >= 1000)
    humidity[0] = '1';
  else
    humidity[0] = ' ';
  humidity[1] = (RH / 100) % 10 + '0';
  humidity[2] = (RH / 10) % 10 + '0';
  humidity[4] = RH % 10 + '0';
  delay(500);  // wait 1 second
  lcd.setCursor(0, 1);
  lcd.print(temperature);
  lcd.write(2);
  lcd.print('C');
  lcd.setCursor(0, 2);
  lcd.print(humidity);
  lcd.write(1);

  lcd.setCursor(10, 0);
  lcd.print(myRTC.dayofmonth);
  lcd.print(".");
  if (myRTC.month < 10) lcd.print(0);
  lcd.print(myRTC.month);

  lcd.print(".");
  lcd.print(myRTC.year);
  lcd.setCursor(0, 0);
  myRTC.updateTime();
  lcd.print(myRTC.hours, DEC);
  lcd.print(":");
  if (myRTC.minutes < 10) lcd.print(0);
  lcd.print(myRTC.minutes, DEC);
  lcd.print(":");
  if (myRTC.seconds < 10) lcd.print(0);

  lcd.print(myRTC.seconds, DEC);
  lcd.setCursor(10, 1);
  if (myRTC.dayofweek == 1) lcd.print("SUNDAY");
  else if (myRTC.dayofweek == 2) lcd.print("MONDAY");
  else if (myRTC.dayofweek == 3) lcd.print("TUESDAY");
  else if (myRTC.dayofweek == 4) lcd.print("WEDNESDAY");
  else if (myRTC.dayofweek == 5) lcd.print("THURSDAY");
  else if (myRTC.dayofweek == 6) lcd.print("FRIDAY");
  else if (myRTC.dayofweek == 7) lcd.print("SATURDAY");
}
// end of code.

Остання редакція germansir (2024-07-26 22:41:00)

Неактивний

#2 2024-07-27 02:58:01

dimich
Учасник
Зареєстрований: 2023-12-01
Повідомлень: 172

Re: dht22 не показує мінусову температуру

На перший погляд явних помилок не видно.
Для початку рекомендую мінімізувати скетч, щоб він читав тільки цей сенсор і видавав результат dht22.readTemperature() в послідовний порт. Саме значення типу float, яке функція повертає. Якщо все ок, тоді додайте свою конвертацію в строку і виведіть строку. Якщо і з нею все ок, тоді проблема у виводі на LCD. Потестуйте вивод із різними фіксованими значеннями Temp, наприклад, -300, -125, -1, 0, 1, 125 - що для них відображається?

Неактивний

#3 2024-07-27 03:41:27

dimich
Учасник
Зареєстрований: 2023-12-01
Повідомлень: 172

Re: dht22 не показує мінусову температуру

Доречі, -76.7 градусів буде показувати, якщо немає звʼязку з DHT22: 0xFFFF & ~0x8000 = 0x7FFF = 32767, у вас відображаються останні три цифри.
Якщо зібрати бібліотеку DHT з увімкненим DHT_DEBUG, вона має видати в Serial Port, що "DHT checksum failure!" та інші можливі помилки.

Остання редакція dimich (2024-07-27 03:51:29)

Неактивний

#4 2024-07-27 04:06:34

dimich
Учасник
Зареєстрований: 2023-12-01
Повідомлень: 172

Re: dht22 не показує мінусову температуру

Або інший, більш ймовірний варіант: у вас не DHT22, а щось інше, що видає відʼємні значення у форматі доповнення до 2.
Для DHT22 бібліотека очікує відʼємні значення у прямому коді. Якщо девайс видає значення "-1" у форматі доповнення до 2, з точки зору бібліотеки це і буде -32767.

Неактивний

#5 2024-07-27 08:29:34

germansir
Учасник
Зареєстрований: 2024-07-26
Повідомлень: 7

Re: dht22 не показує мінусову температуру

Залив стандартний приклад з бібліотеки DHT Adafruit dht test, то в терміналі взагалі почав показувати -3276.5.

Неактивний

#6 2024-07-27 09:40:08

dimich
Учасник
Зареєстрований: 2023-12-01
Повідомлень: 172

Re: dht22 не показує мінусову температуру

germansir пише:

Залив стандартний приклад з бібліотеки DHT Adafruit dht test, то в терміналі взагалі почав показувати -3276.5.

Ви ж цю бібліотеку використовуєте: https://github.com/adafruit/DHT-sensor-library? Ось її код, який конвертує сире значення в градуси Цельсія: DHT.cpp:112

Для DHT22 вона повертає значення -3276.5, якщо девайс видає сире значення 0xFFFD. В доповненному до 2 коді це якраз -3.

Значить у вас не DHT22. Як мінімум, не така DHT22, яку очікує бібліотека. Може репліка, і китайці помилились із форматом даних. На дані від DHT11 або DHT12 теж наче б то не схоже.

Можете спробувати такий воркераунд:

int Temp = round(dht22.readTemperature() * 10);
if (Temp < 0) {
    temperature[0] = '-';
    Temp &= 0x7FFF;
} else {
    temperature[0] = ' ';
}
...

Але не маючи точного опису формату даних, що видає ваш сенсор, за коректність не ручаюсь. Потрібно перевіряти на різних температурах.

Остання редакція dimich (2024-07-27 09:49:46)

Неактивний

#7 2024-07-27 12:11:49

germansir
Учасник
Зареєстрований: 2024-07-26
Повідомлень: 7

Re: dht22 не показує мінусову температуру

Дякую, Ваш код допоміг мені. Але є маленька дивина, якщо я else беру в скобки, то на дисплеї одні нулі, а коли лишаю без них то все чітко показує...

if (Temp < 0) {
    temperature[0] = '-';
    Temp &= 0x7FFF;
    Temp = abs(Temp);
  } else
    temperature[0] = ' ';
    temperature[1] = (Temp / 100) % 10 + '0';
    temperature[2] = (Temp / 10) % 10 + '0';
    temperature[4] = Temp % 10 + '0';

Неактивний

#8 2024-07-27 12:27:49

dimich
Учасник
Зареєстрований: 2023-12-01
Повідомлень: 172

Re: dht22 не показує мінусову температуру

germansir пише:

якщо я else беру в скобки, то на дисплеї одні нулі, а коли лишаю без них то все чітко показує...

if (Temp < 0) {
    temperature[0] = '-';
    Temp &= 0x7FFF;
    Temp = abs(Temp);
  } else
    temperature[0] = ' ';
    temperature[1] = (Temp / 100) % 10 + '0';
    temperature[2] = (Temp / 10) % 10 + '0';
    temperature[4] = Temp % 10 + '0';

Які саме рядки берете в скобки? В вищеприведеному коді без скобок до else відноситься тільки `temperature[0] = ' ';`. Це те ж саме, що

if (Temp < 0) {
    temperature[0] = '-';
    Temp &= 0x7FFF;
  } else {
    temperature[0] = ' ';
  }
  temperature[1] = (Temp / 100) % 10 + '0';
  temperature[2] = (Temp / 10) % 10 + '0';
  temperature[4] = Temp % 10 + '0';

В своєму прикладі я взяв `temperature[0] = ' ';` в скобки, бо без них код погано читабельний, і здається, що всі рядки з temperature[.. відносяться до else. А в else має виконуватись тільки `temperature[0] = ' ';`, решта - незалежно від знаку Temp.

UPD: `Temp = abs(Temp)` там зайве. Після `Temp &= 0x7FFF` Temp уже і так додатнє.

Остання редакція dimich (2024-07-27 12:29:47)

Неактивний

#9 2024-07-27 12:34:09

germansir
Учасник
Зареєстрований: 2024-07-26
Повідомлень: 7

Re: dht22 не показує мінусову температуру

Я брав у скобки увесь цей шматок

  {  
    temperature[0] = ' ';
    temperature[1] = (Temp / 100) % 10 + '0';
    temperature[2] = (Temp / 10) % 10 + '0';
    temperature[4] = Temp % 10 + '0';
}

Неактивний

#10 2024-07-27 12:44:00

dimich
Учасник
Зареєстрований: 2023-12-01
Повідомлень: 172

Re: dht22 не показує мінусову температуру

germansir пише:

Я брав у скобки увесь цей шматок

  {  
    temperature[0] = ' ';
    temperature[1] = (Temp / 100) % 10 + '0';
    temperature[2] = (Temp / 10) % 10 + '0';
    temperature[4] = Temp % 10 + '0';
}

А, ну звісно, тоді temperature[1..4] заповнюється тільки в else, тобто при невідʼємному значенні Temp.
Щоб було зрозуміліше, у своєму коді замініть "Temp = abs(Temp)" на "Temp &= 0x7FFF" - це функціональна зміна.
А обгортання "temperature[0] = ' '" у скобки - стилістична правка, не обовʼязкова, просто для зручності читання коду. Весь готовий шматок коду має бути таким.

...
int Temp = round(dht22.readTemperature() * 10);
if (Temp < 0) {
    temperature[0] = '-';
    Temp &= 0x7FFF;
} else {
    temperature[0] = ' ';
}
temperature[1] = (Temp / 100) % 10 + '0';
temperature[2] = (Temp / 10) % 10 + '0';
temperature[4] = Temp % 10 + '0';
...

Неактивний

#11 2024-07-27 12:47:04

germansir
Учасник
Зареєстрований: 2024-07-26
Повідомлень: 7

Re: dht22 не показує мінусову температуру

Ага, точно так я вже і зробив. Просто пам'ятаю, що в Сі треба обгортати в скобки все, що має відноситись до else, хоча можу помилятися.
ааа, все, я зрозумів чому тільки temperature[0] = ' '; має бути в скобках. Дякую!!!

Остання редакція germansir (2024-07-27 12:49:01)

Неактивний

#12 2024-07-27 13:06:39

dimich
Учасник
Зареєстрований: 2023-12-01
Повідомлень: 172

Re: dht22 не показує мінусову температуру

germansir пише:

Просто пам'ятаю, що в Сі треба обгортати в скобки все, що має відноситись до else, хоча можу помилятися.

В C, як і в C++, і в багатьох інших мовах, до else відноситься той вираз, який за ним слідує безпосередньо. Якщо вираз складається з декількох операторів, вони мають бути в блоці {}.
Але для читабельності зазвичай в блок {} рекомендується обгортати навіть і один оператор, особливо якщо попередня частина в if теж в блоці {}. Хоча в різних організаціях і комʼюніті можуть бути різні вимоги до оформлення коду.

Остання редакція dimich (2024-07-27 13:07:16)

Неактивний

#13 2024-07-27 13:21:02

germansir
Учасник
Зареєстрований: 2024-07-26
Повідомлень: 7

Re: dht22 не показує мінусову температуру

А що значить round?

Неактивний

#14 2024-07-27 13:54:46

dimich
Учасник
Зареєстрований: 2023-12-01
Повідомлень: 172

Re: dht22 не показує мінусову температуру

germansir пише:

А що значить round?

Округлення до найближчого цілого. Без round() при приведенні float до int дробова частина просто відкидається. Вважаючи, що в самій бібліотеці float отримується із цілого числа множенням на 0.1, яке у двійковій формі не має точного представлення, то без round() може виникнути неточність.

Взагалі не розумію, навіщо вони в тій бібліотеці використовують float. Така точність там не потрібна, а 8-бітним мікроконтролерам доводиться програмно реалізовувати арифметику з плаваючою комою. Але то таке, не варто очікувати ефективного коду в ардуінівських бібліотеках. "Якось працює - і то добре" smile

Неактивний

#15 2024-07-27 13:56:12

germansir
Учасник
Зареєстрований: 2024-07-26
Повідомлень: 7

Re: dht22 не показує мінусову температуру

Ага, зрозумів. Щиро дякую!!

Неактивний

Швидке повідомлення

Введіть повідомлення і натисніть Надіслати

Підвал форуму