-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdht11_data.cpp
227 lines (197 loc) · 6.94 KB
/
dht11_data.cpp
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
215
216
217
218
219
220
221
222
223
224
225
226
227
/*
Code making use of gpiod-library to read
data from DHT11-sensor on a RaspberryPi5.
This code is largely based on:
https://github.com/adafruit/DHT-sensor-library/blob/master/DHT.cpp#L36
Adafruit published their library under MIT License.
This adaption is licensed GPLv3.
*/
#include <iostream>
#include <gpiod.hpp>
#include <chrono>
#include <thread>
// Uncomment for debug messages
//#define _DEBUG
// Define _DEBUG_PRINT
#ifdef _DEBUG
#define _DEBUG_PRINT(msg) std::cout << msg << std::endl
#define _DEBUG_RELEASE() gpiod_line_release(data_line);
#define _DEBUG_CLOSE() gpiod_chip_close(chip);
#else
#define _DEBUG_PRINT(msg)
#define _DEBUG_RELEASE()
#define _DEBUG_CLOSE()
#endif
// namespace declaration
using namespace std::chrono;
//gpiod variables
// GPIO connected to DHT11 data pin
const uint8_t data_pin = 26;
// Variable to store GPIO chip (pinctrl-RP1 = gpiochip4)
const char *chipname = "gpiochip4";
// Create instance of gpiod_chip
struct gpiod_chip *chip;
// Create instance of gpiod_line
struct gpiod_line *data_line;
// Array to store DHT11 data
std::uint8_t data[5];
// Variables
uint32_t _lastreadtime;
bool _lastresult;
// Function to map 1millisecond(ms) in microseconds(us) to clock ticks
uint64_t microsecondsToClockCycles(uint64_t ms) {
const time_point<high_resolution_clock> start = high_resolution_clock::now();
std::this_thread::sleep_for(microseconds(ms));
uint64_t us_hrc = duration_cast<microseconds>(high_resolution_clock::now()-start).count();
_DEBUG_PRINT(us_hrc);
return us_hrc;
}
// Count of cycles till timeout
uint32_t _maxcycles = microsecondsToClockCycles(1000);
// Used programmatically for timeout. \
// Not a timeout duration. Type: uint32_t
#define _TIMEOUT UINT32_MAX
// Function to measure duration of high(1) and low(0) signal
uint32_t expectPulse(bool level) {
uint32_t count = 0;
while (gpiod_line_get_value(data_line) == level) {
if (count++ >= _maxcycles) {
_DEBUG_PRINT("PULSE TIMEOUT");
return _TIMEOUT; // Exceeded timeout, fail.
}
}
return count;
}
// Function to read DHT data into data-array
bool readDHT() {
// Open GPIO chip
chip = gpiod_chip_open_by_name(chipname);
// Open GPIO line
data_line = gpiod_chip_get_line(chip, data_pin);
//Data Single-bus free status is at high voltage level
gpiod_line_request_input_flags(data_line, "DHT-data", GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP);
_DEBUG_PRINT("data_line:");
_DEBUG_PRINT(gpiod_line_get_value(data_line));
/*
When the communication between MCU and DHT11 begins,
the programme of MCU will set Data Single-bus voltage
level from high to low and this process must take at
least 18ms to ensure DHT's detection of MCU's signal,
then MCU will pull up voltage and wait 20-40us for
DHT's response.
*/
// START SIGNAL
// Release gpiod_line to change mode
gpiod_line_release(data_line);
// Set data_line from high to low
gpiod_line_request_output(data_line, "DHT-data", 0);
_DEBUG_PRINT("data_line:");
_DEBUG_PRINT(gpiod_line_get_value(data_line));
// Keep low signal for at least 18ms
std::this_thread::sleep_for(std::chrono::milliseconds(20));
// Release gpiod_line to change mode
gpiod_line_release(data_line);
// Use internal pull-up to set data_line from low to high
gpiod_line_request_input_flags(data_line, "DHT-data", GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP);
_DEBUG_PRINT("data_line:");
_DEBUG_PRINT(gpiod_line_get_value(data_line));
// Release gpiod_line to change mode
gpiod_line_release(data_line);
// Set data_line to input
gpiod_line_request_input(data_line, "DHT-data");
_DEBUG_PRINT("data_line:");
_DEBUG_PRINT(gpiod_line_get_value(data_line));
// Wait for DHT's response
if (expectPulse(0) == _TIMEOUT) {
_DEBUG_PRINT("DHT timeout waiting for start signal low pulse.");
_lastresult = false;
return _lastresult;
}
if (expectPulse(1) == _TIMEOUT) {
_DEBUG_PRINT("DHT timeout waiting for start signal high pulse.");
_lastresult = false;
return _lastresult;
}
// READ DATA
// Release data_line to change mode
gpiod_line_release(data_line);
// Set data_line to input with pull-down
gpiod_line_request_input(data_line, "DHT-data");
// When DHT is sending data to MCU, every bit of
// data begins with the 50us low-voltage-level and
// the length of the following high-voltage-level
// signal determines whether data bit is "0" or "1"
// Reset 40 bits of received data to zero.
data[0] = data[1] = data[2] = data[3] = data[4] = 0;
// Array to store 80-signal bits from DHT
uint32_t cycles[80];
// Assign signal bits from DHT to array
for (int i = 0; i < 80; i += 2) {
cycles[i] = expectPulse(0);
cycles[i + 1] = expectPulse(1);
}
// Release data_line and close chip
gpiod_line_release(data_line);
gpiod_chip_close(chip);
// Timing critical code is now complete.
// Inspect pulses and determine which ones are 0 (high state cycle count < low
// state cycle count), or 1 (high state cycle count > low state cycle count).
for (int i = 0; i < 40; ++i) {
uint64_t lowCycles = cycles[2 * i];
uint64_t highCycles = cycles[2 * i + 1];
if ((lowCycles == _TIMEOUT) || (highCycles == _TIMEOUT)) {
_DEBUG_PRINT("DHT timeout waiting for pulse.");
_lastresult = false;
return _lastresult;
}
data[i / 8] <<= 1;
// Now compare the low and high cycle times to see if the bit is a 0 or 1.
if (highCycles > lowCycles) {
// High cycles are greater than 50us low cycle count, must be a 1.
data[i / 8] |= 1;
}
// Else high cycles are less than (or equal to, a weird case) the 50us low
// cycle count so this must be a zero. Nothing needs to be changed in the
// stored data.
}
/* Uncomment for additional DEBUG info
// Prints data in binary
for (uint8_t i = 0; i < 5; i++) {
_DEBUG_PRINT(std::bitset<8> (data[i]));
}
*/
// Check we read 40 bits and that the checksum matches.
if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) {
_lastresult = true;
return _lastresult;
}
else {
_DEBUG_PRINT("DHT checksum failure!");
_lastresult = false;
return _lastresult;
}
_DEBUG_PRINT(_lastresult);
}
// Function to read temperature in degrees celcius
float readTemperature() {
float t;
t = data[2];
if (data[3] & 0x80) {
t = -1 - t;
}
t += (data[3] & 0x0f) * 0.1;
return t;
}
// Function to read relative humidity
float readHumidity() {
float rh;
rh = data[0] + data[1] * 0.1;
return rh;
}
int main() {
readDHT();
float temp = readTemperature();
std::cout << temp << "°C" << std::endl;
float relHumidity = readHumidity();
std::cout << relHumidity << "%" << std::endl;
}