Последние мои покупки у добрых китайцев (или швейцарцев?) были в магазине electrodragon, и одна из них — датчик температуры и влажности воздуха (относительной, прошу заметить!) dht21, он же — AM2301, существуют так же его вариации вроде DHT22 (AM2302), непонятно правда, чем отличается от dht21, при оказии можно будет попробовать и другой.

Описание датчика DHT21/DHT22:

3-проводное подключение;
1-wire интерфейс обмена данными;
пониженное энергопотребление;
не нужно никаких дополнительных компонентов;
Высокая долговременная термостабильность, заводская калибровка;
Цифровой выход;
Передача сигнала на большое расстояние
Измерение температуры и влажности воздуха


Характеристики:

Тип: AM2301/AM2302;

Разрешение данных: 0,1;

Диапазон измерения влажности 0-100% с точностью  ±3%;

Диапазон измерения температуры: -40℃ ~ +80℃ с точностью ±0.5℃.

Для тех, кто забыл, что такое влажность воздуха и почему иногда важно знать её величину, напомню вкратце, что от количества влаги (или пара, воды) в воздухе может зависеть как общее самочувствие человека, состояние его кожи, а то и различные заболевания в редких случаях; бывает, что нужно по другим причинам знать влажность воздуха в помещении (лаборатории, парники…).

Все конечно же, знают, что в воздухе всегда присутствует кроме газов, из которого он состоит, некоторое количество воды в виде пара, который появляется в воздухе в результате испарения воды (ваш К.О.). Но, при разной температуре воздуха в нём может содержаться разное количество воды, — это как в стакане с чаем можно растворить определённое количество сахара, после чего он перестанет растворяться, тогда говорят, что раствор насыщен, а если нагреть чай, то в нём можно будет растворить больше сахара. Охладив чай, мы можем увидеть как «лишний» сахар выпадает в осадок. Так и с воздухом — чем он теплее, тем больше в нём может содержаться воды (пара). Максимальное содержание воды в воздухе при определённой температуре даёт нам насыщенный паром воздух, и эта величина принимается за 100%.

Относительная же влажность воздуха — это то количество воды (пара) которое содержится в воздухе на данный момент относительно полностью насыщенного паром воздуха при заданной температуре. Вот так. Для человека комфортная влажность воздуха нормируется и в общем случае составляет от 30 до 50%, зимой при проветривании она может сильно снижаться (воздух, пришедший с улицы, нагрелся, но содержание воды в нём не изменилось, а значит относительная влажность упала).

Итак, будем измерять относительную влажность воздуха с помощью нашего датчика dht21/dht22. Программа взята с официального форума msp430, немного подкорректирована и добавлен вывод на дисплей hd44780. Ничего сложного:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/*
* This program will interface with the DHT22 Temperature and Humidity sensor using propriatory 1-wire
* interface on Pin P1.0 and Timer A1
* When MCU send start signal, RHT03 change from standby-status to running-status. When MCU finish sending the
* start signal, RHT03 will send response signal of 40-bit data that reflect the relative humidity and
* temperature to MCU.
* MCU will pull low data-bus and this process must beyond at least 1~10ms to ensure RHT03 could detect MCU's signal,
* then MCU will pulls up and wait 20-40us for RHT03's response.
* When RHT03 detect the start signal, RHT03 will pull low the bus 80us as response signal, then RHT03 pulls up
* 80us for preparation to send data.
*
* DHT22 is connected to P2.0 to read it through TA1.0 capture mode
* Data from DHT22 flow MSB to LSB, so the High byte (MSB) first then the Low byte of the 16 bit value of
* Humidity and heat.
* The information we need is represented in the high pulse durations.
* Accordingly, we only care about measuring the high pulses duration only
* -----------------------------------------------------------------------------
* | This code runs at 8Mhz to ensure capturing the DHT22 pulse width correctly |
* -----------------------------------------------------------------------------
*/


#include "msp430g2553.h"
#include "hd44780.h"

#define ISR_DELAY 0 // Timer A1 ISR modes
#define ISR_DHT22_READ 1

#define DHT22_DATA_SIZE 5 // Size of the DHT22 data received in bytes (Hum 2, Temp 2 and checksum 1)
#define DHT22_HIGH_DATA_THRESHOLD 50 // dht22 data high pulse duration threshold to decide on data being 0 or 1
// The ZERO bit high pulse width is 26us and the ONE bit high pulse width
// is 73us. So, the decision to decide if this is one or zero can be taken
// at thresold 50us
#define TRUE 1
#define FALSE 0

typedef enum {START_LOW, START_HIGH, DATA_LOW, DATA_HIGH} DHT22_STATES;
DHT22_STATES dht22_state = START_LOW;
DHT22_STATES previous_dht22_state; // Store previous DHT22 data parsing state

unsigned char dht22[5];
volatile unsigned int new_cap=0;
volatile unsigned int old_cap=0;
volatile unsigned char TimerA1_ISR_mode = ISR_DELAY;
volatile unsigned char bit_counter; // keeps track of the data pulses parsed (maximum 40 bits)
volatile unsigned char byte_counter; // keeps track of the data pulses parsed (maximum 5 bytes)
volatile unsigned char pulse_duration; // duration in uS of the DHT22 generated pulse data

unsigned char delay_in_progress=FALSE;

float Temp, Humidity;

void usdelay(unsigned int interval){
TimerA1_ISR_mode = ISR_DELAY;
// Setup TimerA
TA1CCTL0 = CCIE; // interrupt enabled
TA1CCR0 = TA1R + 8*interval;// micro secs @ 8Mhz Clock
TA1CTL = TASSEL_2 + MC_2; // SMCLK, continuous mode.
delay_in_progress = TRUE; // Indicate to other ISRs that they should not wake the CPU when triggered as the
// CPU is currently sleeping waiting for a delay to expire
//__bis_SR_register(CPUOFF + GIE); // suspend CPU
LPM0;
}

/*
* This Timer A1 interrupt handles two functions:
* - Generate uS delays
* - Read DHT22 sensor data stream in capture mode and store it in an array for later parsing
*/

#pragma vector=TIMER1_A0_VECTOR
__interrupt void Timer_A1_ISR (void)
{
if (TimerA1_ISR_mode == ISR_DELAY) {
TA1CTL = 0; // Stop Timer_A0
delay_in_progress = FALSE; // Indicate to other ISRs that they can wake the CPU now if needed
//__bic_SR_register_on_exit(CPUOFF);
LPM0_EXIT; // Return active
}

if (TimerA1_ISR_mode == ISR_DHT22_READ) {
switch (dht22_state) {
case START_LOW: // we receive a low pulse start from the DHT22
dht22_state = START_HIGH; // be ready to receive a high pulse start
// Initialize DHT22 readings array
for (byte_counter = 0; byte_counter < DHT22_DATA_SIZE; byte_counter++) {
dht22[byte_counter]=0;
}
bit_counter = 0; // reset DHT22 data bit counter within a byte
byte_counter = 0; // reset DHT22 data byte counter
break;

case START_HIGH:
previous_dht22_state = dht22_state;
dht22_state = DATA_LOW; // be ready to receive a low pulse data
break;

case DATA_LOW:
if (previous_dht22_state == DATA_HIGH){ // if we were previously in a dht22 high data pulse, then parse it
new_cap = TA1CCR0; // Store current time stamp (timer value)
// store the length of the previous high pulse
pulse_duration = (new_cap - old_cap)/8;
dht22[byte_counter]<<=1; // shift left to leave a space for the new bit if (pulse_duration > DHT22_HIGH_DATA_THRESHOLD){
dht22[byte_counter] |= BIT0; // This is a ONE bit
} else {
dht22[byte_counter] &= ~BIT0; // This is a ZERO bit
}
bit_counter++; // We passed one date bit, then increment counter
if (bit_counter == 8) { // Finished filling one byte, then move to next byte
byte_counter++;
bit_counter = 0;
if (byte_counter == DHT22_DATA_SIZE){
// disable interrupt and wake processor
TA1CTL = 0; // Stop Timer_A1
dht22_state = START_LOW;// rest to the initial state
LPM0_EXIT; // Return active
break;
}
}
}
dht22_state = DATA_HIGH; // move to the next state
break;

case DATA_HIGH:
old_cap=TA1CCR0; // Store the start of the high data pulse
previous_dht22_state = dht22_state; // As this is what contains the information we need
dht22_state = DATA_LOW;
break;

default:
break;
}
}
}

void read_DHT22(void){
unsigned int T,H;
P2OUT &= ~BIT0; // Issue start signal, P2.0 output low
usdelay(1000); // Wait 1ms to ensure that DHT22 has detected it

// Now listen to the data coming from the DHT22
TimerA1_ISR_mode = ISR_DHT22_READ; // Set ISR mode as parsing DHT22 data
P2SEL |= BIT0; // P2.0 option select Timer_A1
P2DIR &= ~BIT0; // P2.0 as input.
TA1CTL = TASSEL_2 + MC_2 + TAIE; // SMCLK, continuous mode, enable overflow interrupt
TA1CCTL0 = CM_3 + SCS + CCIS_0 + CAP + CCIE;
// Rising and falling edges, capture synchronize, capture mode.
// Interrupt enabled

LPM0; // Sleep CPU (LPM0 as the DHT22 parser is using SMCLK)
// and let the Timer A1 ISR parse the data coming to it in capture mode
// Once all data is read, the ISR will wakeup the CPU to present
usdelay(1000); // the collected data.
TimerA1_ISR_mode = ISR_DELAY;
TA1CTL = TACLR;
TA1CCTL0 = 0;
P2SEL &= ~BIT0;
// See if checksum is correct
if (dht22[4]=dht22[0]+dht22[1]+dht22[2]+dht22[3]) {
H=dht22[0]<<8;
Humidity = H + dht22[1];
T=dht22[2]<<8;
Temp = T + dht22[3];
}
}

void main(void){

WDTCTL = WDTPW + WDTHOLD;
// WDTCTL = WDTPW + WDTTMSEL; // WDT as interval timer,
// f = SMCLK / 32768
//Calibrate DCO for 8MHz operation
BCSCTL1 = CALBC1_1MHZ;
DCOCTL = CALDCO_1MHZ;

HD44780_Init();
HD44780_Clear_Screen();
__enable_interrupt(); // Enable global interrupt

while(1) {

BCSCTL1 = CALBC1_8MHZ;
DCOCTL = CALDCO_8MHZ;

P2OUT |= BIT0; // P2.0 output high
P2DIR |= BIT0; // P2.0 as output
read_DHT22();

BCSCTL1 = CALBC1_1MHZ;
DCOCTL = CALDCO_1MHZ;

HD44780_SetPosition(0,0);
HD44780_PrintStr("Temp:");
HD44780_SetPosition(1,0);
HD44780_PrintStr("Humidity:");

HD44780_SetPosition(0, 6);
HD44780_outdec(Temp, 1);
HD44780_SetPosition(1, 10);
HD44780_outdec(Humidity, 1);

HD44780_SetPosition(0,10);
HD44780_PrintStr("C");
HD44780_SetPosition(1,14);
HD44780_PrintStr("%");

usdelay(1000);
// read_DHT22(); // Breakpoint on debugger, return from call, never advance to next call.
// read_DHT22();
// LPM3; // Enter LPM3 w/ interrupt
}
}

К сожалению, обнаружилась проблема, которую я так и не смог пока побороть, — это зависание программы при повторном вызове функции чтения информации с датчика. Пока что программа работает за счёт «костыля» в виде увеличенной задержки при работе с hd44780, но это неправильно и надо разобраться, как её починить. Если у кого-то есть мысли по этому поводу, — прошу поделиться!

 файлы проекта

поделиться:
  • Добавить ВКонтакте заметку об этой странице
  • Мой Мир
  • Facebook
  • Twitter
  • LiveJournal
  • В закладки Google
  • Яндекс.Закладки
  • БобрДобр
  • Сто закладок
  • Blogger
  • Блог Я.ру
  • Одноклассники