-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDHT11.java
177 lines (139 loc) · 5.51 KB
/
DHT11.java
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
import java.util.ArrayList;
import java.util.List;
import com.pi4j.wiringpi.Gpio;
import com.pi4j.wiringpi.GpioUtil;
public class DHT11 {
// DHT11 sensor reader class for Raspberry Pi
private int pin; // GPIO pin number
private List<Integer> data = new ArrayList<>(10000);
private List<Integer> lengths = new ArrayList<>(40); // will contain the lengths of data pull up periods
public DHT11(int pin) {
// setup wiringPi
if (Gpio.wiringPiSetup() != 0) {
throw new RuntimeException("Initialization of the GPIO has failed.");
}
this.pin = pin;
GpioUtil.export(pin, GpioUtil.DIRECTION_OUT);
}
public DHT11Result read() {
data.clear();
lengths.clear();
// change to output, then send start signal
Gpio.pinMode(pin, Gpio.OUTPUT);
Gpio.digitalWrite(pin, Gpio.LOW);
Gpio.delay(18); // ms
Gpio.digitalWrite(pin, Gpio.HIGH);
// change to input
Gpio.pinMode(pin, Gpio.INPUT);
// collect data into a list
collectInput();
// parse lengths of all data pull up periods
parseDataPullUpLengths();
// if bit count mismatch, return error (4 byte data + 1 byte checksum)
if (lengths.size() != 40)
return new DHT11Result(DHT11Result.ERR_MISSING_DATA, 0.0, 0.0, data.size(), lengths.size());
// calculate bits from lengths of the pull up periods
boolean[] bits = calculateBits();
// we have the bits, calculate bytes
byte[] bytes = bitsToBytes(bits);
// calculate checksum and check
if (bytes[4] != calculateChecksum(bytes))
return new DHT11Result(DHT11Result.ERR_CRC, 0.0, 0.0, data.size(), lengths.size());
// ok, we have valid data, return it
return new DHT11Result(DHT11Result.ERR_NO_ERROR,
Double.parseDouble(bytes[2] + "." + bytes[3]),
Double.parseDouble(bytes[0] + "." + bytes[1]),
data.size(), lengths.size());
}
// this is used to determine where is the end of the data
private final int MAX_UNCHANGED_COUNT = 500;
private void collectInput() {
// collect the data while unchanged found
int unchangedCount = 0;
int last = -1;
while (true) {
int current = Gpio.digitalRead(pin);
data.add(current);
if (last != current) {
unchangedCount = 0;
last = current;
} else {
if (++unchangedCount > MAX_UNCHANGED_COUNT) break;
}
}
}
protected enum SignalTransition {
STATE_INIT_PULL_DOWN ,
STATE_INIT_PULL_UP ,
STATE_DATA_FIRST_PULL_DOWN,
STATE_DATA_PULL_UP ,
STATE_DATA_PULL_DOWN
};
private void parseDataPullUpLengths() {
SignalTransition state = SignalTransition.STATE_INIT_PULL_DOWN;
int currentLength = 0; // will contain the length of the previous period
for (int current : data) {
currentLength++;
switch (state) {
case STATE_INIT_PULL_DOWN:
if (current == Gpio.LOW) {
// ok, we got the initial pull down
state = SignalTransition.STATE_INIT_PULL_UP;
}
break;
case STATE_INIT_PULL_UP:
if (current == Gpio.HIGH) {
// ok, we got the initial pull up
state = SignalTransition.STATE_DATA_FIRST_PULL_DOWN;
}
break;
case STATE_DATA_FIRST_PULL_DOWN:
if (current == Gpio.LOW) {
// we have the initial pull down, the next will be the data pull up
state = SignalTransition.STATE_DATA_PULL_UP;
}
break;
case STATE_DATA_PULL_UP:
if (current == Gpio.HIGH) {
// data pulled up, the length of this pull up will determine whether it is 0 or 1
currentLength = 0;
state = SignalTransition.STATE_DATA_PULL_DOWN;
}
break;
case STATE_DATA_PULL_DOWN:
if (current == Gpio.LOW) {
// pulled down, we store the length of the previous pull up period
lengths.add(currentLength);
state = SignalTransition.STATE_DATA_PULL_UP;
}
break;
}
}
}
private boolean[] calculateBits() {
boolean[] bits = new boolean[40];
int longestPullUp = lengths.stream().mapToInt(Integer::intValue).max().getAsInt();
int shortestPullUp = lengths.stream().mapToInt(Integer::intValue).min().getAsInt();
// use the halfway to determine whether the period it is long or short
int halfway = shortestPullUp + (longestPullUp - shortestPullUp) / 2;
int i = 0;
for (int length : lengths) bits[i++] = length > halfway;
return bits;
}
private byte[] bitsToBytes(boolean[] bits) {
byte[] bytes = new byte[5];
byte value = 0;
for (int i = 0; i < bits.length; i ++) {
value <<= 1;
if (bits[i]) value |= 1;
if (i % 8 == 7) {
bytes[i / 8] = value;
value = 0;
}
}
return bytes;
}
private byte calculateChecksum(byte[] bytes) {
return (byte)(bytes[0] + bytes[1] + bytes[2] + bytes[3]);
}
}