Ви не увійшли.
Доброго здоров'я! По прикладам з інтернету написав скетч типу погодної станції з використанням 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)
Неактивний
На перший погляд явних помилок не видно.
Для початку рекомендую мінімізувати скетч, щоб він читав тільки цей сенсор і видавав результат dht22.readTemperature() в послідовний порт. Саме значення типу float, яке функція повертає. Якщо все ок, тоді додайте свою конвертацію в строку і виведіть строку. Якщо і з нею все ок, тоді проблема у виводі на LCD. Потестуйте вивод із різними фіксованими значеннями Temp, наприклад, -300, -125, -1, 0, 1, 125 - що для них відображається?
Неактивний
Доречі, -76.7 градусів буде показувати, якщо немає звʼязку з DHT22: 0xFFFF & ~0x8000 = 0x7FFF = 32767, у вас відображаються останні три цифри.
Якщо зібрати бібліотеку DHT з увімкненим DHT_DEBUG, вона має видати в Serial Port, що "DHT checksum failure!" та інші можливі помилки.
Остання редакція dimich (2024-07-27 03:51:29)
Неактивний
Або інший, більш ймовірний варіант: у вас не DHT22, а щось інше, що видає відʼємні значення у форматі доповнення до 2.
Для DHT22 бібліотека очікує відʼємні значення у прямому коді. Якщо девайс видає значення "-1" у форматі доповнення до 2, з точки зору бібліотеки це і буде -32767.
Неактивний
Залив стандартний приклад з бібліотеки 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)
Неактивний
Дякую, Ваш код допоміг мені. Але є маленька дивина, якщо я 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 беру в скобки, то на дисплеї одні нулі, а коли лишаю без них то все чітко показує...
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)
Неактивний
Я брав у скобки увесь цей шматок
{ 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';
...
Неактивний
Ага, точно так я вже і зробив. Просто пам'ятаю, що в Сі треба обгортати в скобки все, що має відноситись до else, хоча можу помилятися.
ааа, все, я зрозумів чому тільки temperature[0] = ' '; має бути в скобках. Дякую!!!
Остання редакція germansir (2024-07-27 12:49:01)
Неактивний
Просто пам'ятаю, що в Сі треба обгортати в скобки все, що має відноситись до else, хоча можу помилятися.
В C, як і в C++, і в багатьох інших мовах, до else відноситься той вираз, який за ним слідує безпосередньо. Якщо вираз складається з декількох операторів, вони мають бути в блоці {}.
Але для читабельності зазвичай в блок {} рекомендується обгортати навіть і один оператор, особливо якщо попередня частина в if теж в блоці {}. Хоча в різних організаціях і комʼюніті можуть бути різні вимоги до оформлення коду.
Остання редакція dimich (2024-07-27 13:07:16)
Неактивний
А що значить round?
Округлення до найближчого цілого. Без round() при приведенні float до int дробова частина просто відкидається. Вважаючи, що в самій бібліотеці float отримується із цілого числа множенням на 0.1, яке у двійковій формі не має точного представлення, то без round() може виникнути неточність.
Взагалі не розумію, навіщо вони в тій бібліотеці використовують float. Така точність там не потрібна, а 8-бітним мікроконтролерам доводиться програмно реалізовувати арифметику з плаваючою комою. Але то таке, не варто очікувати ефективного коду в ардуінівських бібліотеках. "Якось працює - і то добре"
Неактивний