Публикация репозитория
This commit is contained in:
commit
eeb6ec46be
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
go.sum
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Chapvic
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
1
README.md
Normal file
1
README.md
Normal file
@ -0,0 +1 @@
|
||||
# Библиотека Go для чтения показаний датчиков DHT-11/22
|
9
cmd/check/main.go
Normal file
9
cmd/check/main.go
Normal file
@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"gitfox.ru/victor/go-dht"
|
||||
)
|
||||
|
||||
func main() {
|
||||
dht.ReadDHT_check(dht.GPIO_4)
|
||||
}
|
15
cmd/example/main.go
Normal file
15
cmd/example/main.go
Normal file
@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gitfox.ru/victor/go-dht"
|
||||
"gitfox.ru/victor/go-wiringpi"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if temp, hum, err := dht.ReadDHT(wiringpi.GPIO_4); err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
fmt.Printf("Temperature: %.1f\nHumidity: %.1f\n", temp, hum)
|
||||
}
|
||||
}
|
99
dht.go
Normal file
99
dht.go
Normal file
@ -0,0 +1,99 @@
|
||||
// Read temperature and humidity data from a DHT11/22 sensors on a Raspberry PI
|
||||
package dht
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"gitfox.ru/victor/go-wiringpi"
|
||||
)
|
||||
|
||||
const (
|
||||
ERR_SETUP_FAILED = "WiringPi setup failed!"
|
||||
ERR_BAD_VALUE = "Bad value!"
|
||||
|
||||
MAX_TIMINGS = 85
|
||||
BAD_VALUE = 999
|
||||
|
||||
DATA_SIZE = 5
|
||||
DATA_BITS = DATA_SIZE * 8
|
||||
)
|
||||
|
||||
|
||||
var (
|
||||
IterationCount = 10
|
||||
QueryTimeout = uint(500)
|
||||
)
|
||||
|
||||
|
||||
/*
|
||||
* Signal Sensor we're ready to read by pulling pin UP for 10 milliseconds,
|
||||
* pulling pin down for 18 milliseconds and then back up for 40 microseconds
|
||||
*/
|
||||
func initDHT(pin int) {
|
||||
/* Initialize sensor */
|
||||
wiringpi.PinMode(pin, wiringpi.OUTPUT)
|
||||
wiringpi.DigitalWrite(pin, wiringpi.HIGH)
|
||||
wiringpi.Delay(10)
|
||||
wiringpi.DigitalWrite(pin, wiringpi.LOW)
|
||||
wiringpi.Delay(18)
|
||||
wiringpi.DigitalWrite(pin, wiringpi.HIGH)
|
||||
wiringpi.DelayMicroseconds(40)
|
||||
|
||||
/* Read data from pin. Look for a change in state. */
|
||||
wiringpi.PinMode(pin, wiringpi.INPUT)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check we read 40 bits (8bit x 5) + verify checksum in the last byte.
|
||||
* Return it if data is good
|
||||
*/
|
||||
func decodeData(data [DATA_SIZE]int, bits int) (temperature float64, humidity float64, err error) {
|
||||
if ((bits >= DATA_BITS) && (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF))) {
|
||||
humidity = float64(((data[0] << 8) + data[1])) / 10
|
||||
if (humidity > 100) {
|
||||
humidity = float64(data[0]) // for DHT11
|
||||
}
|
||||
temperature = float64((((data[2] & 0x7F) << 8) + data[3])) / 10
|
||||
if (temperature > 125) {
|
||||
temperature = float64(data[2]) // for DHT11
|
||||
}
|
||||
if (data[2] & 0x80 == 0x80) {
|
||||
temperature *= -1
|
||||
}
|
||||
return
|
||||
}
|
||||
return BAD_VALUE, BAD_VALUE, errors.New(ERR_BAD_VALUE)
|
||||
}
|
||||
|
||||
|
||||
func ReadDHT(pin int) (temperature float64, humidity float64, err error) {
|
||||
/*
|
||||
* Initialize WiringPi
|
||||
*/
|
||||
if err = wiringpi.Setup(); err != nil {
|
||||
return 0, 0, errors.New(ERR_SETUP_FAILED)
|
||||
}
|
||||
|
||||
data := [DATA_SIZE]int{} // Sensor data
|
||||
bits := 0 // Bits read from sensor
|
||||
|
||||
/*
|
||||
* Calling sequentially two algorithms with a repeat call if an error occurs.
|
||||
* The maximum number of call iterations is 10 (IterationCount) with a delay of 100 ms (QueryTimeout)
|
||||
*/
|
||||
for n := 0; n < IterationCount; n++ {
|
||||
if data, bits, err = read_dht_1(pin); err == nil {
|
||||
if temperature, humidity, err = decodeData(data, bits); err == nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
wiringpi.Delay(QueryTimeout)
|
||||
if data, bits, err = read_dht_2(pin); err == nil {
|
||||
if temperature, humidity, err = decodeData(data, bits); err == nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
wiringpi.Delay(QueryTimeout)
|
||||
}
|
||||
return decodeData(data, bits)
|
||||
}
|
44
dht_1.go
Normal file
44
dht_1.go
Normal file
@ -0,0 +1,44 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"gitfox.ru/victor/go-wiringpi"
|
||||
)
|
||||
|
||||
func read_dht_1(pin int) (data [DATA_SIZE]int, bits int, err error) {
|
||||
laststate := wiringpi.HIGH
|
||||
counter := 0
|
||||
|
||||
initDHT(pin)
|
||||
|
||||
/* detect change and read data */
|
||||
for i := 0; i < MAX_TIMINGS; i++ {
|
||||
counter = 0
|
||||
for (wiringpi.DigitalRead(pin) == laststate) {
|
||||
counter++
|
||||
wiringpi.DelayMicroseconds(2)
|
||||
if (counter == 255) {
|
||||
break
|
||||
}
|
||||
}
|
||||
laststate = wiringpi.DigitalRead(pin)
|
||||
if (counter == 255) {
|
||||
break
|
||||
}
|
||||
|
||||
/* ignore first 3 transitions */
|
||||
if ((i >= 4) && (i % 2 == 0)) {
|
||||
/* shove each bit into the storage bytes */
|
||||
data[bits / 8] <<= 1
|
||||
if (counter > 16) {
|
||||
data[bits / 8] |= 1
|
||||
}
|
||||
bits++
|
||||
}
|
||||
}
|
||||
|
||||
if ((bits >= DATA_BITS) && (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF))) {
|
||||
return
|
||||
}
|
||||
return data, bits, errors.New(ERR_BAD_VALUE)
|
||||
}
|
136
dht_2.go
Normal file
136
dht_2.go
Normal file
@ -0,0 +1,136 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"gitfox.ru/victor/go-wiringpi"
|
||||
)
|
||||
|
||||
func btoi(b bool) int {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func abs(n int) int {
|
||||
if n < 0 {
|
||||
n *= -1
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func decode_signals(duration [DATA_BITS]int) (result [DATA_BITS]bool) {
|
||||
// The initial values for the centroids are the minimum and maximum
|
||||
min := 0
|
||||
max := 0
|
||||
for i := range duration {
|
||||
if (duration[i] < min) {
|
||||
min = duration[i]
|
||||
}
|
||||
if (duration[i] > max) {
|
||||
max = duration[i]
|
||||
}
|
||||
}
|
||||
|
||||
// This will always converge, so won't run infinitely
|
||||
// Assignment step: assign each observation to the nearest centroid
|
||||
for true {
|
||||
nMap := [DATA_BITS]bool{}
|
||||
for j := range nMap {
|
||||
if ((abs(min - duration[j]) > abs(max - duration[j]))) {
|
||||
nMap[j] = true
|
||||
} else {
|
||||
nMap[j] = false
|
||||
}
|
||||
}
|
||||
|
||||
// Update step: update the centroid location with the mean of the assigned observations
|
||||
nMin := 0
|
||||
nMax := 0
|
||||
observations := 0
|
||||
for j := range nMap {
|
||||
observations += btoi(nMap[j])
|
||||
if (nMap[j]) {
|
||||
nMax += duration[j]
|
||||
} else {
|
||||
nMin += duration[j]
|
||||
}
|
||||
}
|
||||
|
||||
// Check for devision by zero
|
||||
if observations == 0 {
|
||||
nMax = 0
|
||||
} else {
|
||||
nMax /= observations
|
||||
}
|
||||
if (DATA_BITS - observations) == 0 {
|
||||
nMin = 0
|
||||
} else {
|
||||
nMin /= DATA_BITS - observations
|
||||
}
|
||||
|
||||
// Check convergence: k-means has converged if no assignments have changed
|
||||
if nMap == result {
|
||||
break
|
||||
}
|
||||
|
||||
// Iterate: new values are now old
|
||||
min = nMin
|
||||
max = nMax
|
||||
result = nMap
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
func read_dht_2(pin int) (data [DATA_SIZE]int, bits int, err error) {
|
||||
lastState := wiringpi.HIGH
|
||||
stateDuration := 0
|
||||
stateChanges := 0
|
||||
|
||||
// Saved state duration
|
||||
signalState := [DATA_BITS]int{}
|
||||
|
||||
initDHT(pin)
|
||||
|
||||
for stateChanges = 0; (stateChanges < MAX_TIMINGS) && (stateDuration < 255) && (bits < DATA_BITS); stateChanges++ {
|
||||
stateDuration = 0
|
||||
for true {
|
||||
if ((wiringpi.DigitalRead(pin) == lastState) && (stateDuration < 255)) {
|
||||
stateDuration++
|
||||
wiringpi.DelayMicroseconds(1)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
lastState = wiringpi.DigitalRead(pin)
|
||||
|
||||
// First 2 state changes are sensor signaling ready to send, ignore
|
||||
// them. Each bit is preceeded by a state change to mark its
|
||||
// beginning, ignore it too.
|
||||
if ((stateChanges > 2) && (stateChanges % 2 == 0)) {
|
||||
signalState[bits] = stateDuration
|
||||
bits++
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure if all 40 bits are read, otherwise return with a bad read
|
||||
if (bits >= DATA_BITS) {
|
||||
// Use the k-means decoder instead of the split one, as it's slightly more robust with neglible
|
||||
// runtime increase
|
||||
signalData := decode_signals(signalState)
|
||||
for j := range signalData {
|
||||
data[j / 8] <<= 1 // Each array element has 8 bits. Shift Left 1 bit.
|
||||
if (signalData[j]) { // A state with a duration assigned to an upper cluster is a '1'
|
||||
data[j / 8] |= 1
|
||||
}
|
||||
}
|
||||
|
||||
if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return data, bits, errors.New(ERR_BAD_VALUE)
|
||||
}
|
47
dht_check.go
Normal file
47
dht_check.go
Normal file
@ -0,0 +1,47 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"gitfox.ru/victor/go-wiringpi"
|
||||
)
|
||||
|
||||
func ReadDHT_check(pin int) {
|
||||
/*
|
||||
* Initialize WiringPi
|
||||
*/
|
||||
if err := wiringpi.Setup(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data := [DATA_SIZE]int{} // Sensor data
|
||||
bits := 0 // Bits read from sensor
|
||||
|
||||
temperature := float64(0)
|
||||
humidity := float64(0)
|
||||
err := error(nil)
|
||||
|
||||
/*
|
||||
* Calling sequentially two algorithms with a repeat call if an error occurs.
|
||||
* The maximum number of call iterations is 10 (IterationCount) with a delay of 100 ms (QueryTimeout)
|
||||
*/
|
||||
fmt.Printf("BEGIN\n")
|
||||
for n := 1; n <= IterationCount; n++ {
|
||||
data, bits, err = read_dht_1(pin)
|
||||
temperature, humidity, err = decodeData(data, bits)
|
||||
if err == nil {
|
||||
err = errors.New("OK")
|
||||
}
|
||||
fmt.Printf("ITER: %d of %d, FN: 1 -> T: %.1f, H: %.1f (bits: %02d, error: %s)\n", n, IterationCount, temperature, humidity, bits, err)
|
||||
wiringpi.Delay(QueryTimeout)
|
||||
|
||||
data, bits, err = read_dht_2(pin)
|
||||
temperature, humidity, err = decodeData(data, bits)
|
||||
if err == nil {
|
||||
err = errors.New("OK")
|
||||
}
|
||||
fmt.Printf("ITER: %d of %d, FN: 2 -> T: %.1f, H: %.1f (bits: %02d, error: %s)\n", n, IterationCount, temperature, humidity, bits, err)
|
||||
wiringpi.Delay(QueryTimeout)
|
||||
}
|
||||
fmt.Printf("END\n")
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user