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