Skip to content

Commit eb7665a

Browse files
Ellerbachkrwq
authored andcommitted
Adding DHTxx support, software PWM and Servomotor (#154)
* Adding DHTxx support, software PWM and Servomotor * Fixing feedbacks from last PR * Correcting code and documentation based on PR feedbacks
1 parent 405acf6 commit eb7665a

27 files changed

+1391
-0
lines changed

src/devices/Dhtxx/DhtSensor.cs

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Device.Gpio;
7+
using System.Diagnostics;
8+
9+
namespace Iot.Device.DHTxx
10+
{
11+
public class DHTSensor : IDisposable
12+
{
13+
private const int MAX_TIME = 85;
14+
private const uint MAX_WAIT = 255;
15+
private byte[] _dht11Val = new byte[5];
16+
private int _pin;
17+
private DhtType _dhtType;
18+
19+
private GpioController _controller = new GpioController();
20+
21+
private Stopwatch _stopwatch = new Stopwatch();
22+
23+
/// <summary>
24+
/// Wait for a specific number of milliseconds
25+
///
26+
/// </summary>
27+
/// <param name="milliseconds">Number of milliseconds to wait</param>
28+
/// <remarks>
29+
/// This function doesn't work if you want to wait for less than 100 microseconds.
30+
/// </remarks>
31+
private void Wait(double milliseconds)
32+
{
33+
long initialTick = _stopwatch.ElapsedTicks;
34+
long initialElapsed = _stopwatch.ElapsedMilliseconds;
35+
double desiredTicks = milliseconds / 1000.0 * Stopwatch.Frequency;
36+
double finalTick = initialTick + desiredTicks;
37+
while (_stopwatch.ElapsedTicks < finalTick)
38+
{
39+
//nothing than waiting
40+
}
41+
}
42+
43+
/// <summary>
44+
/// How last read went, <c>true</c> for success, <c>false</c> for failure
45+
/// </summary>
46+
public bool IsLastReadSuccessful { get; internal set; }
47+
48+
/// <summary>
49+
/// Get the last read temperature in Celsius
50+
/// </summary>
51+
/// <remarks>
52+
/// If last read was not successfull, it returns double.MaxValue
53+
/// </remarks>
54+
public double Temperature => (_dhtType == DhtType.Dht11) ? GetTempDht11() : GetTempDht22();
55+
56+
/// <summary>
57+
/// Get the last read temperature in Farenheit
58+
/// </summary>
59+
/// <remarks>
60+
/// If last read was not successfull, it returns double.MaxValue
61+
/// </remarks>
62+
public double TemperatureInFarenheit => IsLastReadSuccessful ? (9.0 / 5.0 * Temperature + 32) : Double.MaxValue;
63+
64+
/// <summary>
65+
/// Get the temperature in Celsius
66+
/// </summary>
67+
/// <param name="temperatureInCelsius">The temperature in Celsius</param>
68+
/// <returns>Returns <c>true</c> if the read is successful</returns>
69+
/// <remarks>
70+
/// If last read was not successfull, it returns double.MaxValue
71+
/// </remarks>
72+
public bool TryGetTemperature(out double temperatureInCelsius)
73+
{
74+
var ret = ReadData();
75+
temperatureInCelsius = Temperature;
76+
return ret;
77+
}
78+
79+
/// <summary>
80+
/// Get the temperature in Farenheit
81+
/// </summary>
82+
/// <param name="temperatureInFarenheit">The temperature in Farenheit</param>
83+
/// <returns>Returns <c>true</c> if the read is successful</returns>
84+
/// <remarks>
85+
/// If last read was not successfull, it returns double.MaxValue
86+
/// </remarks>
87+
public bool TryGetTemperatureInFarenheit(out double temperatureInFarenheit)
88+
{
89+
var ret = ReadData();
90+
temperatureInFarenheit = TemperatureInFarenheit;
91+
return ret;
92+
}
93+
94+
/// <summary>
95+
/// Get the last read of relative humidity in percentage
96+
/// </summary>
97+
/// <remarks>
98+
/// If last read was not successfull, it returns double.MaxValue
99+
/// </remarks>
100+
public double Humidity => (_dhtType == DhtType.Dht11) ? GetHumidityDht11() : GetHumidityDht22();
101+
102+
/// <summary>
103+
/// Get the relative humidity in the air
104+
/// </summary>
105+
/// <param name="relativeHumidity">The percentage of relative humidity in the air</param>
106+
/// <returns>Returns <c>true</c> if the read is successful</returns>
107+
/// <remarks>
108+
/// If last read was not successfull, it returns double.MaxValue
109+
/// </remarks>
110+
public bool TryGetHumidity(out double relativeHumidity)
111+
{
112+
var ret = ReadData();
113+
relativeHumidity = Humidity;
114+
return ret;
115+
}
116+
117+
/// <summary>
118+
/// Get the temperature in Celsius and the relative humidity in the air
119+
/// </summary>
120+
/// <param name="temperatureInCelsius">The temperature in Celsius</param>
121+
/// <param name="relativeHumidity">The percentage of relative humidity in the air</param>
122+
/// <returns>Returns <c>true</c> if the read is successful</returns>
123+
/// <remarks>
124+
/// If last read was not successfull, it returns double.MaxValue
125+
/// </remarks>
126+
public bool TryGetTemperatureAndHumidity(out double temperatureInCelsius, out double relativeHumidity)
127+
{
128+
var ret = ReadData();
129+
temperatureInCelsius = Temperature;
130+
relativeHumidity = Humidity;
131+
return ret;
132+
}
133+
134+
/// <summary>
135+
/// Get the temperature in Farenheit and the relative humidity in the air
136+
/// </summary>
137+
/// <param name="temperatureInFarenheit">The temperature in Farenheit</param>
138+
/// <param name="relativeHumidity">The percentage of relative humidity in the air</param>
139+
/// <returns>Returns <c>true</c> if the read is successful</returns>
140+
/// <remarks>
141+
/// If last read was not successfull, it returns double.MaxValue
142+
/// </remarks>
143+
public bool TryGetTemperatureInFarenheitAndHumidity(out double temperatureInFarenheit, out double relativeHumidity)
144+
{
145+
var ret = ReadData();
146+
temperatureInFarenheit = TemperatureInFarenheit;
147+
relativeHumidity = Humidity;
148+
return ret;
149+
}
150+
151+
/// <summary>
152+
/// Create a DHT sensor
153+
/// </summary>
154+
/// <param name="pin">The pin number (GPIO number)</param>
155+
/// <param name="dhtType">The DHT Type, either Dht11 or Dht22</param>
156+
public DHTSensor(int pin, DhtType dhtType)
157+
{
158+
this._pin = pin;
159+
this._dhtType = dhtType;
160+
_controller.OpenPin(pin);
161+
}
162+
163+
/// <summary>
164+
/// Start a reading
165+
/// </summary>
166+
/// <returns>
167+
/// <c>true</c> if read is successfull, otherwise <c>false</c>.
168+
/// </returns>
169+
public bool ReadData()
170+
{
171+
// Set the max value for waiting micro second
172+
// 27 = debug
173+
// 99 = release
174+
byte waitMS = 99;
175+
#if DEBUG
176+
waitMS = 27;
177+
#endif
178+
_stopwatch.Start();
179+
PinValue lststate = PinValue.High;
180+
uint counter = 0;
181+
byte j = 0, i;
182+
for (i = 0; i < 5; i++)
183+
_dht11Val[i] = 0;
184+
185+
// write on the pin
186+
_controller.SetPinMode(_pin, PinMode.Output);
187+
_controller.Write(_pin, PinValue.Low);
188+
//wait 18 milliseconds
189+
Wait(18);
190+
_controller.Write(_pin, PinValue.High);
191+
// Wait about 40 microseconds
192+
Wait(0.03);
193+
_controller.SetPinMode(_pin, PinMode.Input);
194+
195+
for (i = 0; i < MAX_TIME; i++)
196+
{
197+
counter = 0;
198+
while (_controller.Read(_pin) == lststate)
199+
{
200+
counter++;
201+
// This wait about 1 microsecond
202+
// No other way to do it for such a precision
203+
for (byte wt = 0; wt < waitMS; wt++)
204+
;
205+
if (counter == MAX_WAIT)
206+
break;
207+
}
208+
209+
lststate = _controller.Read(_pin);
210+
if (counter == MAX_WAIT)
211+
break;
212+
213+
// top 3 transistions are ignored
214+
if ((i >= 4) && (i % 2 == 0))
215+
{
216+
_dht11Val[j / 8] <<= 1;
217+
if (counter > 16)
218+
_dht11Val[j / 8] |= 1;
219+
j++;
220+
}
221+
}
222+
223+
_stopwatch.Stop();
224+
if ((j >= 40) && (_dht11Val[4] == ((_dht11Val[0] + _dht11Val[1] + _dht11Val[2] + _dht11Val[3]) & 0xFF)))
225+
{
226+
IsLastReadSuccessful = (_dht11Val[0] != 0) || (_dht11Val[2] != 0);
227+
}
228+
else
229+
{
230+
IsLastReadSuccessful = false;
231+
}
232+
233+
return IsLastReadSuccessful;
234+
}
235+
236+
// Convertion for DHT11
237+
private double GetTempDht11() => IsLastReadSuccessful ? (double)(_dht11Val[2] + _dht11Val[3] / 10) : double.MaxValue;
238+
239+
private double GetHumidityDht11() => IsLastReadSuccessful ? (double)(_dht11Val[0] + _dht11Val[1] / 10) : double.MaxValue;
240+
241+
// convertion for DHT22
242+
private double GetTempDht22()
243+
{
244+
if (IsLastReadSuccessful)
245+
{
246+
var temp = (((_dht11Val[2] & 0x7F) << 8) | _dht11Val[3]) * 0.1F;
247+
// if MSB = 1 we have negative temperature
248+
return ((_dht11Val[2] & 0x80) == 0 ? temp : -temp);
249+
}
250+
else
251+
return (double.MaxValue);
252+
}
253+
254+
private double GetHumidityDht22() => IsLastReadSuccessful ? (double)((_dht11Val[0] << 8) | _dht11Val[1]) * 0.1F : double.MaxValue;
255+
256+
public void Dispose()
257+
{
258+
_controller.ClosePin(_pin);
259+
}
260+
}
261+
}

src/devices/Dhtxx/DhtType.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
namespace Iot.Device.DHTxx
6+
{
7+
/// <summary>
8+
/// The type of DHT sensor used
9+
/// </summary>
10+
public enum DhtType
11+
{
12+
Dht11,
13+
Dht22
14+
}
15+
}

src/devices/Dhtxx/Dhtxx.csproj

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netcoreapp2.1</TargetFramework>
5+
<EnableDefaultItems>false</EnableDefaultItems>
6+
<!--Disabling default items so samples source won't get build by the main library-->
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<Compile Include="DhtType.cs" />
11+
<Compile Include="DhtSensor.cs" />
12+
</ItemGroup>
13+
14+
<ItemGroup>
15+
<PackageReference Include="System.Device.Gpio" Version="0.1.0-prerelease*" />
16+
<None Include="README.md" />
17+
</ItemGroup>
18+
19+
</Project>

src/devices/Dhtxx/README.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# DHTxx Sensors
2+
3+
## Summary
4+
5+
The DHT temperature and humidity sensors are very popular. Most used sensors are DHT11 and DHT22. Both are supported by this library.
6+
7+
## Device Family
8+
9+
Device Family contains DHT11 and DHT22 which are very popular.
10+
11+
**DHT11** [datasheet in chineese](https://cdn-shop.adafruit.com/datasheets/DHT11-chinese.pdf)
12+
**DHT22** [datasheet](https://cdn-shop.adafruit.com/datasheets/DHT22.pdf)
13+
14+
Note: other DHT components are not supported but code can be adjusted to have them working
15+
16+
## Supported platforms
17+
18+
**Both DHT has been tested on a Raspberry Pi 3 Model B Rev 2**. Sensors has not yet been tested on other platforms. If you encounter issues running on other platforms, try to adjust the value ```waitMS``` in the ```DhtSensor.cs``` file.
19+
20+
```csharp
21+
byte waitMS = 99;
22+
#if DEBUG
23+
waitMS = 27;
24+
#endif
25+
```
26+
27+
This value is used to wait 1 microsecond in a for simple loop. This value is platform dependent.
28+
29+
```csharp
30+
for (byte wt = 0; wt < waitMS; wt++)
31+
;
32+
```
33+
34+
## Usage
35+
36+
Usage is straight forward and you will find more explanations in the [example](./samples/README.md).
37+
38+
You first need to create a sensor. First parameter is the GPIO pin you want to use and second the DHT type.
39+
40+
```csharp
41+
DHTSensor dht = new DHTSensor(26, DhtType.Dht22);
42+
```
43+
44+
You have 2 ways to read the temperature and humidity. Humidity is a value between 0.0 and 100.0. 100.0 represents 100% humidity in the air.
45+
46+
First one, once the sensor is created, you need to read first, make sure the read is successful and then you can get the Temperature and Humidity.
47+
48+
```csharp
49+
bool readret = dht.ReadData();
50+
if (readret)
51+
Console.WriteLine($"Temperature: {dht.Temperature.ToString("0.00")} °C, Humidity: {dht.Humidity.ToString("0.00")} %");
52+
else
53+
Console.WriteLine("Error reading the sensor");
54+
```
55+
Second way, is to use the ```TryGetTemperatureAndHumidity``` and the other ```TryGet``` functions. They will return true if the read has been successful and then as an output the temperature, either in Celsius or Fahrenheit and/or relative air humidity.
56+
57+
```csharp
58+
double Temp;
59+
double Hum;
60+
if (dht.TryGetTemperatureAndHumidity(out Temp, out Hum))
61+
Console.WriteLine($"Temperature: {Temp.ToString("0.00")} °C, Humidity: {Hum.ToString("0.00")} %");
62+
else
63+
Console.WriteLine("Error reading the sensor");
64+
```
65+
66+
Note that functions to read the temperature exist both in Celsius and Fahrenheit.
67+

0 commit comments

Comments
 (0)