Читаем показания DHT без библиотеки.
- Войдите на сайт для отправки комментариев
Втр, 14/07/2015 - 07:41
При опросе двух датчиков DHT21 с помощью библиотек заметил, что скетч "тормозится". Чтение одного DHT занимает до 250 мс. По даташиту опрос датчика должен уложиться примерно в 5 мс.
Как происходит общение МК с DHT21-DHT22. Для начинающих:)
Датчик молчит-на линии высокий уровень. МК прижимает линию к земле минимум на 800 мкс. Далее отпускает линию и подтягивающий резистор тянет её вверх. Заметьте, не МК тянет вверх!! МК переводит пин на ввод, а не устанавливает "1" на пине. В даташитах по этому поводу очень "скользко" . Здесь работает схемное "И": высокий уровень на линии если: И МК не тянет вниз ("1"), И DHT не тянет вниз ("1"). Низкий уровень на линии если: МК тянет вниз или DHT тянет вниз.
От импульса отрицательной полярности DHT "просыпается" и через 20-40 мкс (даже до 200 мкс) притягивает линию к земле на 80 мкс. Затем отпускает на 80 мкс. Снова прижимает на 50 мкс и отпускает.
Начинается первый импульс положительной полярности, несущий информацию "0" или "1". Длительность в 26 мкс соответствует "0", а 70 мкс - "1". Всё что нужно это прочитать 40 таких положительных импульсов различной длительности.
Скетч прилагаю.
// Mega
uint8_t data[5];
const byte DHT1_pin = 22;
const byte DHT2_pin = 24;
const unsigned int interval = 1000;
void setup(){
Serial.begin(9600);
}
void loop(){
int hum1 = 0, temp1 = 0;
int hum2 = 0, temp2 = 0;
static unsigned long prevMillis = 0;
if(millis() - prevMillis > interval){
prevMillis += 1000;
if(readingDHT(DHT1_pin)){ //если контрольная сумма верна
hum1 = (data[0] << 8) | data[1];//считаем Н и Т первого датчика
temp1 = ((data[2] & 0x7F) << 8) | data[3];
if(data[2] & 0x80) temp1 *= -1;
}else{
//ошибка DHT1
}
if(readingDHT(DHT2_pin)){
hum2 = (data[0] << 8) | data[1];
temp2 = ((data[2] & 0x7F) << 8) | data[3];
if(data[2] & 0x80) temp2 *= -1;
}else{
//ошибка DHT2
}
Serial.print("hum1 = "); Serial.print(hum1 /10);
Serial.print('.'); Serial.println(hum1 %10);
Serial.print("tem1 = ");Serial.print(temp1 /10);
Serial.print('.'); Serial.println(temp1 %10);
Serial.print("hum2 = ");Serial.print(hum2 /10);
Serial.print('.'); Serial.println(hum2 %10);
Serial.print("tem2 = ");Serial.print(temp2 /10);
Serial.print('.'); Serial.println(temp2 %10);
Serial.println();
}
}
//===============================================
boolean readingDHT(byte pin) {
boolean state = HIGH; //состояние линии
byte counter = 0, j = 0;
const byte count = 5;
for(byte i=0; i<5; i++){
data[i] = 0;
}
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
delay(1); //более 800mks нужно чтобы рабудить датчик DHT21-22
//delay(18); //для DHT11
//cli(); //отключить прерывания если нужно
pinMode(pin, INPUT); //начинаем слушать датчик
for(byte i = 0; i < 83; i++){//читаем 83 сост линии
counter = 0;
while (digitalRead(pin) == state) {//state==1 первый проход
counter++;
delayMicroseconds(4);//if 4 mkc count==3-7
if (counter > 20) break;
}//end while
state = !state;//digitalRead(_pin);
if (counter > 20) break;
if ((i > 3) && !(i & 1)) {//i%2 записать каждый бит в байты хранения
data[j >> 3] <<= 1; //читаем с 5(i=4) состояния(1,0,1,0,?,0,?,0,...?)
if (counter > count) data[j>>3] |= 1;//counter>3-10 дальше ошибки
j++;
}
}//end for
//sei(); //включить прерывания
uint8_t sum = data[0] + data[1] + data[2] + data[3];
if(sum == data[4]) return 1;
else return 0;
}
Да, по даташиту DHT21-22 нужно опрашивать не чаще раза в 2сек.
Поэтому в строке 5 нужно interval=2000; а в 16 - prevMillis +=2000; или понятней - prevMillis +=interval;
Но и при опросе каждую сек показания датчиков не повторяются при изменении температуры и влажности.
Я читаю данные с DHT22 при помощи функции pulseIn, все выглядит гораздо лучше, понятнее и никакой магии. Если нужно - могу свою переделанную библиотеку оно Adafruit дать, вытащите оттуда функцию.
SunX, выкладывайте свою библиотеку, раз уж лучше и понятней. Это замечательно, когда много примеров хороших и разных...
А про какую магию говорите?
Вот: https://github.com/SunAngel/DHT-sensor-library
Я вот про эту counter-магию:
counter = 0; while (digitalRead(pin) == state) {//state==1 первый проход counter++; delayMicroseconds(4);//if 4 mkc count==3-7 if (counter > 20) break; }//end while state = !state;//digitalRead(_pin); if (counter > 20) break; if ((i > 3) && !(i & 1)) {//i%2 записать каждый бит в байты хранения data[j >> 3] <<= 1; //читаем с 5(i=4) состояния(1,0,1,0,?,0,?,0,...?) if (counter > count) data[j>>3] |= 1;//counter>3-10 дальше ошибки j++; }Оно все работает и наверное даже правильно, но зато совершенно непонятно, почему все так.
PS: Примеры в моей измененной библиотеке естественно не работают, так как их я не переписывал. Так же в этой либе возвращаются температура и влажность умноженные на 10, что бы не использовать float и для других нужных мне вещей, но, думаю, Вы с этим спокойно справитесь.
Очень знакомая библиотека)) Если её ещё подправить, будет лучше, меньше тормозить. Все отличия в pulseIn и заключаются.
Про "магию" раскажу как время будет.
Ну не удивлюсь, если Adafruit ее в свою очередь где-то еще потырили %) Ну или кто-то потырил у них.
Как эта counter-магия работает я вполне понимаю, просто не понимаю, зачем так извращаться =).
Я вот про эту counter-магию:
counter = 0; while (digitalRead(pin) == state) {//state==1 первый проход counter++; delayMicroseconds(4);//if 4 mkc count==3-7 if (counter > 20) break; }//end while state = !state;//digitalRead(_pin); if (counter > 20) break; if ((i > 3) && !(i & 1)) {//i%2 записать каждый бит в байты хранения data[j >> 3] <<= 1; //читаем с 5(i=4) состояния(1,0,1,0,?,0,?,0,...?) if (counter > count) data[j>>3] |= 1;//counter>3-10 дальше ошибки j++; }Оно все работает и наверное даже правильно, но зато совершенно непонятно, почему все так.
В цикле while задержка складывается из delayMicrosecond(4) ==4mks (даже чуть больше) и чтение пина digitalRead(pin) == около 4-6 мкс, которые в сумме дают около 9мкс. За 6 проходов while получаем задержку около 50мкс. В это время положительный импульс 26мкс, соответствующий "0" уже закончился, а 70мкс импульс "1" ещё не закончился.
С pulseIn функция readingDHT(DHT_pin) выглядит попроще.
boolean readingDHT(byte pin) { byte duration = 0; byte j = 0; for(byte i = 0; i < 5; i++){ data[i] = 0; } pinMode(pin, OUTPUT); digitalWrite(pin, LOW); delay(1); //более 800mks нужно чтобы рабудить датчик DHT21-22 //delay(18); //для DHT11 //cli(); //отключить прерывания если нужно pinMode(pin, INPUT); //начинаем слушать датчик delayMicroseconds(50); for(byte i = 0; i < 41; i++){//читаем 41 положительный импульс (первый неинформативный) duration = pulseIn(pin, HIGH, 200); if(!duration) break; if (i){ //записываем сo 2 (i==1) импульса (1,?,?,...?) data[j/8] <<= 1; //пишем в младший бит "0" if(duration > 50) data[j/8] |= 1;//пишем в младший бит "1" j++; } }//end for //sei(); //включить прерывания uint8_t sum = data[0] + data[1] + data[2] + data[3]; if(sum == data[4]) return 1; else return 0; }Коммент в строке 18 читать как: сдвигаем влево на 1, а в младший бит пишется "0"
Попробовал оба варианта кода — со старой функцией readingDHT, с упрощённым вариантом с pulseIn. В обоих случаях hum1 и temp1 (у меня один датчик) равны нулю. Пробовал использовать также библиотеку (скетч), с ней всё работает корректно. Самое странное, что даже если добавить в этот код посылку сообщения об ошибке, оно никогда не будет послано — код считает, что всё в порядке. Помогите!
Если зарядить в блюпиле таймер
static void MX_TIM3_Init(void) { /* USER CODE BEGIN TIM3_Init 0 */ /* USER CODE END TIM3_Init 0 */ LL_TIM_InitTypeDef TIM_InitStruct = {0}; LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; /* Peripheral clock enable */ LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM3); LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOA); /**TIM3 GPIO Configuration PA7 ------> TIM3_CH2 */ GPIO_InitStruct.Pin = LL_GPIO_PIN_7; GPIO_InitStruct.Mode = LL_GPIO_MODE_FLOATING; LL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* TIM3 interrupt Init */ NVIC_SetPriority(TIM3_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0)); NVIC_EnableIRQ(TIM3_IRQn); /* USER CODE BEGIN TIM3_Init 1 */ /* USER CODE END TIM3_Init 1 */ TIM_InitStruct.Prescaler = 71; TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; TIM_InitStruct.Autoreload = 65535; TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; LL_TIM_Init(TIM3, &TIM_InitStruct); LL_TIM_DisableARRPreload(TIM3); LL_TIM_SetClockSource(TIM3, LL_TIM_CLOCKSOURCE_INTERNAL); LL_TIM_SetTriggerInput(TIM3, LL_TIM_TS_TI2FP2); LL_TIM_SetSlaveMode(TIM3, LL_TIM_SLAVEMODE_RESET); LL_TIM_CC_DisableChannel(TIM3, LL_TIM_CHANNEL_CH2); LL_TIM_IC_SetFilter(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV1); LL_TIM_IC_SetPolarity(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_FALLING); LL_TIM_DisableIT_TRIG(TIM3); LL_TIM_DisableDMAReq_TRIG(TIM3); LL_TIM_SetTriggerOutput(TIM3, LL_TIM_TRGO_RESET); LL_TIM_EnableMasterSlaveMode(TIM3); LL_TIM_IC_SetActiveInput(TIM3, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_INDIRECTTI); LL_TIM_IC_SetPrescaler(TIM3, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1); LL_TIM_IC_SetFilter(TIM3, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1); LL_TIM_IC_SetPolarity(TIM3, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_RISING); LL_TIM_IC_SetActiveInput(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_DIRECTTI); LL_TIM_IC_SetPrescaler(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1); /* USER CODE BEGIN TIM3_Init 2 */ /* USER CODE END TIM3_Init 2 */ }то можно получить аппаратно, без задержек вывод с датчика и его обработать.
void DHT11(void) { LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_7); LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_1); GPIO_InitStruct.Pin = GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);*/ GPIO_InitStruct.Pin = LL_GPIO_PIN_7 | LL_GPIO_PIN_1; GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT; GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; LL_GPIO_Init(GPIOA, &GPIO_InitStruct); HAL_Delay(20); GPIO_InitStruct.Mode = LL_GPIO_MODE_FLOATING; LL_GPIO_Init(GPIOA, &GPIO_InitStruct); // GPIO_InitStruct.Mode = GPIO_MODE_AF_INPUT; // HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); nt=0;nt2=0; LL_TIM_EnableIT_CC2(TIM3); //HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_2); LL_TIM_CC_EnableChannel(TIM3,LL_TIM_CHANNEL_CH1); //HAL_TIM_IC_Start(&htim3, TIM_CHANNEL_1); LL_TIM_CC_EnableChannel(TIM3,LL_TIM_CHANNEL_CH2); LL_TIM_EnableCounter(TIM3); LL_TIM_EnableIT_CC2(TIM2); //HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_2); LL_TIM_CC_EnableChannel(TIM2,LL_TIM_CHANNEL_CH2); LL_TIM_EnableCounter(TIM2); }; void TimerCaptureCompare_Callback(void) { period[nt] = LL_TIM_IC_GetCaptureCH2(TIM3); //HAL_TIM_ReadCapturedValue(htim3, TIM_CHANNEL_2); pulse[nt] = LL_TIM_IC_GetCaptureCH1(TIM3);// HAL_TIM_ReadCapturedValue(htim3, TIM_CHANNEL_1); nt++; if (nt >41) { LL_TIM_DisableCounter(TIM3); LL_TIM_SetCounter(TIM3,0); LL_TIM_DisableIT_CC2(TIM3);//HAL_TIM_IC_Stop_IT(htim3, TIM_CHANNEL_2); LL_TIM_CC_DisableChannel(TIM3,LL_TIM_CHANNEL_CH1);//HAL_TIM_IC_Stop(htim3, TIM_CHANNEL_1); LL_TIM_CC_DisableChannel(TIM3,LL_TIM_CHANNEL_CH2);//HAL_TIM_IC_Stop(htim3, TIM_CHANNEL_2); /* */ b1=0;for(i=0;i<8;i++) if ((period[9-i] / 100) > 0) b1|= (1 << i); b2=0;for(i=0;i<8;i++) if ((period[17-i] / 100) > 0) b2|= (1 << i); b3=0;for(i=0;i<8;i++) if ((period[25-i] / 100) > 0) b3|= (1 << i); b4=0;for(i=0;i<8;i++) if ((period[33-i] / 100) > 0) b4|= (1 << i); b5=0;for(i=0;i<8;i++) if ((period[41-i] / 100) > 0) b5|= (1 << i); /** / b1=0;for(i=0;i<8;i++) if ((period[i+1] / 100) > 0) b1|= (1 << i); b2=0;for(i=0;i<8;i++) if ((period[i+9] / 100) > 0) b2|= (1 << i); b3=0;for(i=0;i<8;i++) if ((period[i+17] / 100) > 0) b3|= (1 << i); b4=0;for(i=0;i<8;i++) if ((period[i+25] / 100) > 0) b4|= (1 << i); b5=0;for(i=0;i<8;i++) if ((period[i+33] / 100) > 0) b5|= (1 << i); */ float ft,fh; ft=(b3 & 0x80 ? -1 : 1)*0.1*(((uint16_t)(b3 & 0x7F)) << 8 | b4); fh=0.1*(((uint16_t)(b1 & 0x7F)) << 8 | b2); bs=b1+b2+b3+b4; if (bs==b5) {hum=(uint16_t)fh;tmp=(uint16_t)ft;} else {hum=0;tmp=0;}; }; };Про этом получение данных не зависит от типа 11 или 22. Различается только обработка. Одна проблема - нога входа таймера фиксирована РА7.
У меня появилась мысль, что, возможно, у Петра в скетче есть ошибка контрольной суммы, которая проявляется тем, что humidity и temperature равны нулю.
Мысль то откуда? Что выводить то если КС не сошлась? Некоторые выводят NaN.
Давно это было... С тех пор и не использую эти датчики. Может прерывания мешают? Пробовали запрещать перед опросом датчика?
Пробовал, не помогло...
#include <delay.h> #define DHT_PORT PORTD #define DHT_DDR DDRD #define DHT_PIN PIND #define DHT_BIT 5 unsigned int read_dht_hum() { int temp; unsigned char i,j; unsigned char data[5]; //=============MCU send START DHT_DDR|=(1<<DHT_BIT); //pin as output DHT_PORT&=~(1<<DHT_BIT); //0 delay_ms(18); DHT_PORT|=(1<<DHT_BIT); //1 DHT_DDR&=~(1<<DHT_BIT); //pin as input //=============check DHT11 response delay_us(50); if (DHT_PIN&(1<<DHT_BIT)) return 0; delay_us(80); if (!(DHT_PIN&(1<<DHT_BIT))) return 0; //===============receive 40 data bits while (DHT_PIN&(1<<DHT_BIT)); for (j=0; j<5; j++) { data[j]=0; for(i=0; i<8; i++) { while (!(DHT_PIN&(1<<DHT_BIT))); delay_us (30); if (DHT_PIN&(1<<DHT_BIT)) data[j]|=1<<(7-i); while (DHT_PIN&(1<<DHT_BIT)); } } if ((unsigned char)(data[0]+data[1]+data[2]+data[3])!=data[4]) //checksum return 0; temp = (data[0]<<8)+(data[2]); //data[0]-humidity, data[2]-temperature return temp; }Библиотека для CVAVR, но в принципе несложно перевести в Arduino
Интересно, что оно вот здесь возвращает? И почему так?
43temp = (data[0]<<8)+(data[2]);//data[0]-humidity, data[2]-temperaturereturn temp;если temp обьявлен как int
Интересно, что оно вот здесь возвращает? И почему так?
43temp = (data[0]<<8)+(data[2]);//data[0]-humidity, data[2]-temperatureЕсли ардуина оригинальная, то она сама разберется, а если китайская - то...
Давно работал, забыл уже. Это для DHT11, он дает только целую часть процента влажности , а дробная равно 0.
Процесс коммуникации
Формат данных DHT11/DHT22
Когда датчик влажности и температуры отправляет данные, он сначала отправляет MSb (Most Significant Bit) — старший значащий бит. Данные от датчика передаются в виде посылки, состоящих из 40 бит данных — это 5 байт из которых первых два влажность, следующие 2 температура и байт четности. Байт четности равен сумме предыдущих байт. 1 и 2 байт содержат соответственно целую и дробную часть информации о влажности, 3 и 4 байт содержат целую и дробную часть информации о температуре. Для датчика DHT11 2-й и 4-й байты всегда ноль. Значение этих байтов заключается в следующем:
Joog - как обычно...
К чему эти цитаты, вы сами головой думать умеете?
Вас спрашивают, что получится, если сложить влажность и температуру ? :)
Joog - как обычно...
К чему эти цитаты, вы сами головой думать умеете?
Вас спрашивают, что получится, если сложить влажность и температуру ? :)
Кому нужно разобраться, приведённого выше достаточно. Но вы из той породы кому надо на "пальцах" всё показывать и ещё и несколько раз.
unsigned char temp=0, hum=0;
int ca=0;
ca = read_dht_hum(); //читаем влажность и температуру c DHT11 из подпрограммы
hum = ((ca >>8) & 0xFF); // Разрезаем на байты старший байт влажность
temp = (ca & 0xFF); // Разрезаем на байты младший байт температура
Можете просто из подпрограммы забрать
chardata[5];если работаете с DHT22 и вам надо цифры после запятойТам не сложение температуры с влажностью, там возвращается двухбайтовая величина, в старшем байте которой находится однобайтная влажность, а в младшем - однобайтная температура. Непонятно только, почему переменная описана как знаковая величина.
Непонятно только, почему переменная описана как знаковая величина.
чтобы полной грудью ощутить разницу битового сдвига между знаковым и беззнаковым инт
Да ладно бы они в старшую часть температуру пхали, она тоже знаковая, потом её только выкусить и использовать, так нет жеж, там беззнаковая влажность.
Я также пробовал использовать эту библиотеку, и обсуждаю сейчас проблему с её разработчиком. Ни одна библиотека, которая читает DHT22 функцией, не работает.
Starter381 загрузите мой скетч, и посмотрите ошибки от датчика где происходят? Обязательно проверьте резистор от вывода Data к +5в, должен быть 10 килоом. Чем он меньше тем больше ошибок чтения. Data DHT на 5 пин Arduino/
unsigned char temp=0, hum=0; int ca=0; unsigned char data[5]; unsigned int read_dht_hum() //подпрограмма работы с DHT { #define DHT_PORT PORTD #define DHT_DDR DDRD #define DHT_PIN PIND #define DHT_BIT 5 //по ардуиновски D5 int temp; unsigned char i,j; ReLoad: //метка для ошибок //=============MCU send START DHT_DDR|=(1<<DHT_BIT); //выход DHT_PORT&=~(1<<DHT_BIT); //низкий уровень, подтягиваем линию, разбудим датчик delay(18); //18 мс по условиям документации. DHT_PORT|=(1<<DHT_BIT); //отпускаем линию DHT_DDR&=~(1<<DHT_BIT); //пин как выход //============= инциализация DHT delayMicroseconds(50); //задержка по условию if (DHT_PIN&(1<<DHT_BIT)){Serial.println("NO init "); goto ReLoad;} //датчик должен ответить 0 delayMicroseconds(80); if (!(DHT_PIN&(1<<DHT_BIT))){Serial.println("Creazy DHT ");goto ReLoad;} //по истечению 80 мкс, датчик должен отпустить шину //===============Приём 40 бит данных while (DHT_PIN&(1<<DHT_BIT)); //ждем пока на шине появится 1 for (j=0; j<5; j++) { data[j]=0; for(i=0; i<8; i++) { while (!(DHT_PIN&(1<<DHT_BIT))); //ждем когда датчик отпустит шину delayMicroseconds(30); //задержка высокого уровня при 0 30 мкс if (DHT_PIN&(1<<DHT_BIT)) //если по истечению времени сигнал на линии высокий, значит передается 1 data[j]|=1<<(7-i); //тогда i-й бит устанавливаем 1 while (DHT_PIN&(1<<DHT_BIT)); // ждем окончание 1 } } if ((unsigned char)(data[0]+data[1]+data[2]+data[3])!=data[4]) //checksum {Serial.println("checksum Error ");goto ReLoad;} temp = (data[0]<<8)+(data[2]); //data[0]-humidity, data[2]-temperature return temp; //двухбайтовая величина, в старшем байте которой находится однобайтная влажность, а в младшем - однобайтная температура. } //конец подрограммы void setup() { Serial.begin(9600); } void loop() { ca = read_dht_hum(); //читаем влажность и температуру c DHT11 из подпрограммы hum = ((ca >>8) & 0xFF); // Разрезаем на байты старший байт влажность temp = (ca & 0xFF); // Разрезаем на байты младший байт температура Serial.print(ca, HEX); //вывод полученного результата в шеснадцатеричном формате Serial.print(" "); Serial.print(data [0], HEX); //относительная влажность — целая часть в %; Serial.print(" "); Serial.print(data [1], HEX); //десятая часть относительной влажности в % (ноль для DHT11); Serial.print(" "); Serial.print(data [2], HEX); //целая часть температуры в °C; Serial.print(" "); Serial.print(data [3], HEX); //десятая часть температуры в °C (ноль для DHT11); Serial.print(" "); Serial.println(data [4], HEX); //контрольная сумма (последние 8 бит {1-й байт + 2-й байт + 3-й байт + 4-й байт}) delay(1000); //хватает задержки в 1 сек }Зачем клеить, а затем резать влажность и температуру, если она никуда не выводится?
"gotoReLoad"вообще за гранью моего понимания.Думаю, это Северныйветер в другой реинкарнации
со знаковыми и беззнаковыми стало еще интереснее...
Из функции с возвращаемым значением unsigned int
возвращаем знаковый int temp, который в loop() преобразуем в переменную опять же с именем temp, но уже типа байт :)
Но с точки зрения синтаксиса ошибок нет ... :)))) Хотя несоответвие типа функции и возвращаемого значения должно, по идее, подсвечиваться предупреждением
Вот что получил:
Значит датчик отвечает, работает. Он у вас на улице? Влажность 1,3% и температура +0,25. Контрольная сумма совпадает.
Это чрезвычайно странные показания датчика. У меня датчик расположен в тёплой комнате; другой скетч сообщает температуру 24.3°C, влажность 24.6%!
Starter381 Нашел в этой статье, оказывается всё таки они разные DHT11 и DHT22 в плане расчета конечных показаний. Немного переделал, у меня только DHT11, попробуйте.
unsigned char data[5]; float temperature, humidity; unsigned int read_dht_hum() //подпрограмма работы с DHT { #define DHT_PORT PORTD #define DHT_DDR DDRD #define DHT_PIN PIND #define DHT_BIT 5 //по ардуиновски D5 int temp; unsigned char i,j; ReLoad: //метка для ошибок //=============MCU send START DHT_DDR|=(1<<DHT_BIT); //выход DHT_PORT&=~(1<<DHT_BIT); //низкий уровень, подтягиваем линию, разбудим датчик delay(18); //18 мс по условиям документации. DHT_PORT|=(1<<DHT_BIT); //отпускаем линию DHT_DDR&=~(1<<DHT_BIT); //пин как выход //============= инциализация DHT delayMicroseconds(50); //задержка по условию if (DHT_PIN&(1<<DHT_BIT)){Serial.println("NO init "); goto ReLoad;} //датчик должен ответить 0 delayMicroseconds(80); if (!(DHT_PIN&(1<<DHT_BIT))){Serial.println("Creazy DHT ");goto ReLoad;} //по истечению 80 мкс, датчик должен отпустить шину //===============Приём 40 бит данных while (DHT_PIN&(1<<DHT_BIT)); //ждем пока на шине появится 1 for (j=0; j<5; j++) //цикл для 0-4 байт { data[j]=0; for(i=0; i<8; i++) //приём битов и укладка их в байты { while (!(DHT_PIN&(1<<DHT_BIT))); //ждем когда датчик отпустит шину delayMicroseconds(30); //задержка высокого уровня при 0 30 мкс if (DHT_PIN&(1<<DHT_BIT)) //если по истечению времени сигнал на линии высокий, значит передается 1 data[j]|=1<<(7-i); //тогда i-й бит устанавливаем 1 while (DHT_PIN&(1<<DHT_BIT)); // ждем окончание 1 } } if ((unsigned char)(data[0]+data[1]+data[2]+data[3])!=data[4]) //checksum {Serial.println("checksum Error ");goto ReLoad;} } //конец подрограммы void setup() { Serial.begin(9600); } void loop() { read_dht_hum(); //вызов подпрограммы DHT11 temperature= (data [3]*0.1) + ((data [2] & 0b01111111)*25.6); //нюанс расчета температуры для DHT22 if (data [2] & 0b10000000) temperature*= -1; //если отрицательная температура humidity= (data [1]*0.1) + (data [0]*25.6); //нюанс расчета влажности для DHT22 Serial.print(humidity); //относительная влажность в %; Serial.print("% "); Serial.print(temperature); //температура в °C; Serial.println("C"); delay(200); //хватает задержки в 1 сек , для этого скетча хватает скорости 180 }Starter381 Нашел в этой статье,
вместо того чтоб цитировать безграмотные статьи, может лучше в даташит заглянуть?
вот нахера эти гланды через жопу?
Температура и влажность выдаются в виде 16-битного целого, содержащего нужную величину, умноженную на 10. Старший бит температуры дополнительно несет знак.
И все!!
Пример
Влажность 00000010 10000100 = 644 = 64.4%
Я скажу так, Ваш код теперь работает, НО! Ваша логика в этом коде совершенно не понятна. Для начала, расскажите подробнее, зачем вам столько #define, которые ссылаются непонятно на что:
Во-вторых, что означают конкретно эти строки, и что это за ошибки, которые обрабатываются в этом месте:
if (DHT_PIN&(1<<DHT_BIT)){Serial.println("NO init "); goto ReLoad;} //датчик должен ответить 0 delayMicroseconds(80); if (!(DHT_PIN&(1<<DHT_BIT))){Serial.println("Creazy DHT ");goto ReLoad;} //по истечению 80 мкс, датчик должен отпустить шинуВаша логика в этом коде совершенно не понятна. Для начала, расскажите подробнее, зачем вам столько #define, которые ссылаются непонятно на что:
может стоит что-то почитать про микроконтроллеры, прежде чем задавать детские вопросы? А то беретесь работать с датчиком напрямую, без библиотек - а даже элементарные регистры МК ставят вас в тупик.
Напомните, что за цель у вас была изобретать велосипеды, чем не устроила готовая библиотека DHT.h ? Разобраться самому, как оно работает? - так разбирайтесь
Сейчас вы с Joog с грехом пополам повторили код стандартной библиотеки... если вы ничего не поняли, к чему была вся эта эпопея?
Я по специальности изначально фронтендист, так что не будь таким злым. Насчёт #define`ов вопрос снимаю.
Это же простые define, без наворотов.
А вот уже с такими у некоторых начинается непонимание:
Хотя всё тривиально. И использовалось ещё с тех пор, когда Ардуино ещё и в помине не было.)
Обнаружил проблему, что данный код возвращает неадекватные значения в диапазоне от -3200 до -3300 (чаще всего значения колеблются около -3275) при отрицательной температуре. При этом я проверил, что проблема лежит в коде, а не в самом датчике —с библиотекой DHT.h значения считаются нормально.