This repository has been archived by the owner on Sep 7, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
dht.c
214 lines (188 loc) · 6.39 KB
/
dht.c
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
211
212
213
214
/*
* Copyright (C) 2017, Denys Fedoryshchenko
* Contact: <nuclearcat@nuclearcat.com>
* Licensed under the GPLv2
* <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>
*
* DHT11/DHT22/AM2302/AM2320 driver for ESP8266 FreeRTOS SDK
* Driver made by more strictly following standards than random sources
*
* Driver can use much less mem (define LOWMEM), if instead of measuring number
* of cycles&storing them, we use Tlow with Thigh comparison, but it is more prone to errors
* due measurement jitter, as algoritm execution time varies and tiny code are
* in "time critical" part
*/
#include "esp_common.h"
#include <fcntl.h>
#include <stdio.h>
#include <gpio.h>
/*
Following list for PIN_FUNC_SELECT and PIN_PULLUP_DIS
GPIO0: PERIPHS_IO_MUX_GPIO0_U
GPIO1: PERIPHS_IO_MUX_U0TXD_U
GPIO2: PERIPHS_IO_MUX_GPIO2_U
GPIO3: PERIPHS_IO_MUX_U0RXD_U
GPIO4: PERIPHS_IO_MUX_GPIO4_U
GPIO5: PERIPHS_IO_MUX_GPIO5_U
GPIO6: PERIPHS_IO_MUX_SD_CLK_U
GPIO7: PERIPHS_IO_MUX_SD_DATA0_U
GPIO8: PERIPHS_IO_MUX_SD_DATA1_U
GPIO9: PERIPHS_IO_MUX_SD_DATA2_U
GPIO10: PERIPHS_IO_MUX_SD_DATA3_U
GPIO11: PERIPHS_IO_MUX_SD_CMD_U
GPIO12: PERIPHS_IO_MUX_MTDI_U
GPIO13: PERIPHS_IO_MUX_MTCK_U
GPIO14: PERIPHS_IO_MUX_MTMS_U
GPIO15: PERIPHS_IO_MUX_MTDO_U
*/
/*
* Define here your PIN and init for it
* WARNING: PIN4 and PIN5 swapped :( at most of ESP12 modules
*/
#define OW_PIN_NUM 4
#define OW_PIN_INIT() PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U, FUNC_GPIO4)
#define OW_PIN_NOPULLUP() PIN_PULLUP_DIS(PERIPHS_IO_MUX_GPIO4_U)
#define OW_GET_IN() GPIO_INPUT_GET(GPIO_ID_PIN(OW_PIN_NUM))
#define OW_OUT_LOW() ( GPIO_OUTPUT_SET(GPIO_ID_PIN(OW_PIN_NUM), 0) )
#define OW_OUT_HIGH() ( GPIO_OUTPUT_SET(GPIO_ID_PIN(OW_PIN_NUM), 1) )
#define OW_DIR_IN() ( GPIO_DIS_OUTPUT(GPIO_ID_PIN(OW_PIN_NUM)) )
#define MAXWAIT 1000000 /* Max waiting cycles in waittransition, approx 1s */
#define HIGH 1
#define LOW 0
/* Keep it for lower mem usage */
#define LOWMEM
void delay_ms(uint32_t ms) {
uint32_t i;
for (i = 0; i < ms; i++)
os_delay_us(1000);
}
/* Return number of cycles it waited for level, or 0 on failure */
int waittransition(uint level) {
int waittime = MAXWAIT-1;
while (waittime--) {
if (OW_GET_IN() == level) {
break;
}
}
if (waittime)
return(MAXWAIT-waittime);
else
return(0);
}
void dht_init(void) {
OW_PIN_INIT();
OW_PIN_NOPULLUP();
}
/*
* Important info from datasheet (AM2320)
* 3.3V - max 1m wire length, 5V max 30m. 5.1K pullup resistor for data line.
* Do not poll sensor more often than each 2S
* return 0 on success, 1 on failure(data invalid)
*/
int dht_read(int *temp, int *hum) {
uint8_t data[5];
int i;
memset(data, 0x0, 5);
/* Not in specs, but device should see transition from low to high
Might be reduced
*/
OW_OUT_HIGH();
delay_ms(25);
/* Tbe, you may adjust delay to 80us-20ms, esp. if you have
* high capacitance on data line, or its long. By specs at least 80us
*/
OW_OUT_LOW();
delay_ms(5);
/* Time critical part might introduce lag to your realtime functions
* Best (ideal) case lag 2950us, worst case 5370us, with non-critical
* section (but it is "schedulable") ~30ms
*/
#ifdef LOWMEM
portENTER_CRITICAL();
OW_DIR_IN();
/* Tbe, to Tgo, might be <= 1 */
if (!waittransition(HIGH))
goto bad;
/* Tgo, to Trel */
if (!waittransition(LOW))
goto bad;
/* Trel, to Treh */
if (!waittransition(HIGH))
goto bad;
/* Treh, to first byte Tlow */
if (!waittransition(LOW))
goto bad;
{
int lowcycles, highcycles;
for (i=0; i<40; ++i) {
lowcycles = waittransition(HIGH);
highcycles = waittransition(LOW);
data[i/8] <<= 1;
if (highcycles > lowcycles)
data[i/8] |= 1;
}
}
portEXIT_CRITICAL();
#else
/* Don't add anything here, time critical code */
portENTER_CRITICAL();
uint32_t cycles[80];
{
OW_DIR_IN();
/* Tbe, to Tgo, might be <= 1 */
if (!waittransition(HIGH))
goto bad;
/* Tgo, to Trel */
if (!waittransition(LOW))
goto bad;
/* Trel, to Treh */
if (!waittransition(HIGH))
goto bad;
/* Treh, to first byte Tlow */
if (!waittransition(LOW))
goto bad;
/* Each bit, [i] duration of low pulse, [i+1] - high pulse */
for (i=0; i<80; i+=2) {
cycles[i] = waittransition(HIGH);
cycles[i+1] = waittransition(LOW);
}
}
portEXIT_CRITICAL();
/*
// In case you want to debug received timing values
for (i=0;i<40;i++) { printf("[%d]%02X:",i,cycles[i]);}
*/
/* Time critical finished, processing data */
for (i=0; i<40; ++i) {
uint32_t lowCycles = cycles[2*i];
uint32_t highCycles = cycles[2*i+1];
/* On errors - quit */
if ((lowCycles == 0) || (highCycles == 0)) {
return(1);
}
/* Add bits for each byte if high cycle is more than low */
data[i/8] <<= 1;
if (highCycles > lowCycles) {
data[i/8] |= 1;
}
}
#endif
/* Verify checksum */
if (((data[0] + data[1] + data[2] + data[3]) & 0xFF) != data[4])
return(2);
*hum = ((data[0] << 8) + data[1]);
/* DHT11 specific */
if ( *hum > 1000 )
*hum = data[0];
*temp = (((data[2] & 0x7F) << 8) + data[3]);
/* DHT11 specific */
if ( *temp > 1250 )
*temp = data[2];
/* Negative temperature */
if ( data[2] & 0x80 )
*temp = -*temp;
return(0);
bad:
portEXIT_CRITICAL();
return(1);
}