Created
February 13, 2019 07:02
-
-
Save kokeiro001/1e3b9946fe113976904d0286db1c1969 to your computer and use it in GitHub Desktop.
DHT11からデータ取得するスクリプトの一部。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Threading.Tasks; | |
using Unosquare.RaspberryIO.Gpio; | |
namespace KokeiroPi.ConsoleApp.Devices | |
{ | |
enum DHTReadErrorState | |
{ | |
None, | |
MissingData, | |
CRC, | |
} | |
class DHT11ReadResult | |
{ | |
public DHTReadErrorState Error { get; set; } | |
public int Temperature { get; set; } | |
public int Humidity { get; set; } | |
public string ErrorMessage { get; set; } | |
} | |
class DHT11 | |
{ | |
private readonly GpioPin pin; | |
public DHT11(GpioPin pin) | |
{ | |
this.pin = pin; | |
} | |
public async Task<DHT11ReadResult> Read() | |
{ | |
pin.PinMode = GpioPinDriveMode.Output; | |
await pin.WriteAsync(GpioPinValue.High); | |
await Task.Delay(TimeSpan.FromMilliseconds(25)); | |
await pin.WriteAsync(GpioPinValue.Low); | |
await Task.Delay(TimeSpan.FromMilliseconds(11)); | |
pin.PinMode = GpioPinDriveMode.Input; | |
pin.InputPullMode = GpioPinResistorPullMode.PullUp; | |
var data = CollectInput(); | |
var pullUpLengths = ParseDataPullUpLengths(data); | |
if (pullUpLengths.Length != 40) | |
{ | |
return new DHT11ReadResult | |
{ | |
Error = DHTReadErrorState.MissingData, | |
ErrorMessage = $"data.Length={data.Length}, pullUpLengths.Length={pullUpLengths.Length}", | |
}; | |
} | |
var bits = CalculateBits(pullUpLengths); | |
var result = BitsToBytes(bits); | |
var checksum = CalculateChecksum(result); | |
if (result[4] != checksum) | |
{ | |
return new DHT11ReadResult | |
{ | |
Error = DHTReadErrorState.CRC | |
}; | |
} | |
return new DHT11ReadResult | |
{ | |
Temperature = result[2], | |
Humidity = result[0], | |
Error = DHTReadErrorState.None | |
}; | |
} | |
private GpioPinValue[] CollectInput() | |
{ | |
var unchangedCount = 0; | |
var maxUnchangedCount = 1000; | |
var last = default(GpioPinValue?); | |
var data = new List<GpioPinValue>(maxUnchangedCount * 2); | |
while (true) | |
{ | |
var current = pin.ReadValue(); | |
data.Add(current); | |
if (last != current) | |
{ | |
unchangedCount = 0; | |
last = current; | |
} | |
else | |
{ | |
unchangedCount++; | |
if (unchangedCount > maxUnchangedCount) | |
{ | |
break; | |
} | |
} | |
} | |
return data.ToArray(); | |
} | |
private int[] ParseDataPullUpLengths(GpioPinValue[] data) | |
{ | |
var state = State.InitPullDown; | |
var lengths = new List<int>(data.Length); | |
var currentLength = 0; | |
for (int i = 0; i < data.Length; i++) | |
{ | |
var current = data[i]; | |
currentLength++; | |
switch (state) | |
{ | |
case State.InitPullDown: | |
if (current == GpioPinValue.Low) | |
{ | |
state = State.InitPullUp; | |
} | |
break; | |
case State.InitPullUp: | |
if (current == GpioPinValue.High) | |
{ | |
state = State.DataFirstPullDown; | |
} | |
break; | |
case State.DataFirstPullDown: | |
if (current == GpioPinValue.Low) | |
{ | |
currentLength = 0; | |
state = State.DataPullUp; | |
} | |
break; | |
case State.DataPullUp: | |
if (current == GpioPinValue.High) | |
{ | |
currentLength = 0; | |
state = State.DataPullDown; | |
} | |
break; | |
case State.DataPullDown: | |
if (current == GpioPinValue.Low) | |
{ | |
lengths.Add(currentLength); | |
state = State.DataPullUp; | |
} | |
break; | |
default: | |
throw new InvalidOperationException(nameof(state)); | |
} | |
} | |
return lengths.ToArray(); | |
} | |
private bool[] CalculateBits(int[] pullUpLengths) | |
{ | |
var shortestPullUp = pullUpLengths.Min(); | |
var longestPullUp = pullUpLengths.Max(); | |
var halfway = shortestPullUp + (longestPullUp - shortestPullUp) / 2; | |
var bits = new bool[pullUpLengths.Length]; | |
for (int i = 0; i < pullUpLengths.Length; i++) | |
{ | |
bits[i] = pullUpLengths[i] > halfway; | |
} | |
return bits; | |
} | |
private byte[] BitsToBytes(bool[] bits) | |
{ | |
if (bits.Length % 8 != 0) | |
{ | |
throw new ArgumentException(nameof(bits)); | |
} | |
if (BitConverter.IsLittleEndian) | |
{ | |
bits = bits.Reverse().ToArray(); | |
} | |
var bitArray = new BitArray(bits); | |
var byteArray = new byte[bits.Length / 8]; | |
bitArray.CopyTo(byteArray, 0); | |
if (BitConverter.IsLittleEndian) | |
{ | |
byteArray = byteArray.Reverse().ToArray(); | |
} | |
return byteArray; | |
} | |
private byte CalculateChecksum(byte[] theBytes) | |
{ | |
return (byte)(theBytes[0] + theBytes[1] + theBytes[2] + (byte)(theBytes[3] & (byte)255)); | |
} | |
private enum State | |
{ | |
InitPullDown, | |
InitPullUp, | |
DataFirstPullDown, | |
DataPullUp, | |
DataPullDown, | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment