From 46f806b2826d2d7b2fe140b3e65464725444ad7c Mon Sep 17 00:00:00 2001 From: Oleksandr Voloshyn Date: Tue, 2 Mar 2021 09:13:46 +0100 Subject: [PATCH 01/12] Add dht driver Add dht package that implements driver for dht thermometer --- dht/constants.go | 69 ++++++++++++++++++++++++ dht/thermometer.go | 132 +++++++++++++++++++++++++++++++++++++++++++++ dht/util.go | 34 ++++++++++++ 3 files changed, 235 insertions(+) create mode 100644 dht/constants.go create mode 100644 dht/thermometer.go create mode 100644 dht/util.go diff --git a/dht/constants.go b/dht/constants.go new file mode 100644 index 000000000..a1b99dc44 --- /dev/null +++ b/dht/constants.go @@ -0,0 +1,69 @@ +package dht + +import ( + "encoding/binary" + "errors" + "machine" + "time" +) + +type DeviceType uint8 + +func (d DeviceType) extractData(buf []byte) (temp int16, hum uint16) { + if d == DHT11 { + temp = int16(buf[2]) + if buf[3]&0x80 > 0 { + temp = -1 - temp + } + temp *= 10 + temp += int16(buf[3] & 0x0f) + hum = 10*uint16(buf[0]) + uint16(buf[1]) + } else { + hum = binary.LittleEndian.Uint16(buf[0:2]) + temp = int16(buf[3])<<8 + int16(buf[2]&0x7f) + if buf[2]&0x80 > 0 { + temp = -temp + } + } + return +} + +type TemperatureScale uint8 + +func (t TemperatureScale) convertToFloat(temp int16) float32 { + if t == C { + return float32(temp) / 10 + } else { + // Fahrenheit + return float32(temp)*(9.0/50.) + 32. + } +} + +const ( + startTimeout = time.Millisecond * 200 + startingLow = time.Millisecond * 20 + + DHT11 DeviceType = iota + DHT22 + + C TemperatureScale = iota + F +) + +var ( + timeout uint16 + + checksumError = errors.New("checksum mismatch") + noSignalError = errors.New("no signal") + noDataError = errors.New("no data") +) + +func init() { + timeout = cyclesPerMillisecond() +} + +func cyclesPerMillisecond() uint16 { + freq := machine.CPUFrequency() + freq /= 1000 + return uint16(freq) +} diff --git a/dht/thermometer.go b/dht/thermometer.go new file mode 100644 index 000000000..352e8264f --- /dev/null +++ b/dht/thermometer.go @@ -0,0 +1,132 @@ +package dht + +import ( + "machine" + "time" +) + +type device struct { + pin machine.Pin + + measurements DeviceType + + temperature int16 + humidity uint16 +} + +func (t *device) Temperature() int16 { + return t.temperature +} + +func (t *device) TemperatureFloat(scale TemperatureScale) float32 { + return scale.convertToFloat(t.temperature) +} + +func (t *device) Humidity() uint16 { + return t.humidity +} + +func (t *device) HumidityFloat() float32 { + return float32(t.humidity) / 10. +} + +func initiateCommunication(p machine.Pin) { + // Send low signal to the device + p.Configure(machine.PinConfig{Mode: machine.PinOutput}) + p.Low() + time.Sleep(startingLow) + // Set pin to high and wait for reply + p.High() + p.Configure(machine.PinConfig{Mode: machine.PinInput}) +} + +func (t *device) ReadMeasurements() error { + // initial waiting + state := powerUp(t.pin) + defer t.pin.Set(state) + return t.read() +} + +func (t *device) read() error { + // initialize loop variables + bufferData := [5]byte{} + buf := bufferData[:] + signalsData := [80]uint16{} + signals := signalsData[:] + + initiateCommunication(t.pin) + err := waitForDataTransmission(t.pin) + if err != nil { + return err + } + t.receiveSignals(signals) + + err = t.extractData(signals[:], buf) + if err != nil { + return err + } + if !isValid(buf[:]) { + return checksumError + } + + t.temperature, t.humidity = t.measurements.extractData(buf) + return nil +} + +func (t *device) receiveSignals(result []uint16) { + i := uint8(0) + machine.UART1.Interrupt.Disable() + defer machine.UART1.Interrupt.Enable() + for ; i < 40; i++ { + result[i*2] = expectChange(t.pin, false) + result[i*2+1] = expectChange(t.pin, true) + } +} +func (t *device) extractData(signals []uint16, buf []uint8) error { + for i := uint8(0); i < 40; i++ { + lowCycle := signals[i*2] + highCycle := signals[i*2+1] + if lowCycle == timeout || highCycle == timeout { + return noDataError + } + byteN := i >> 3 + buf[byteN] <<= 1 + if highCycle > lowCycle { + buf[byteN] |= 1 + } + } + return nil +} + +func waitForDataTransmission(p machine.Pin) error { + // wait for thermometer to pull down + if expectChange(p, true) == timeout { + return noSignalError + } + //wait for thermometer to pull up + if expectChange(p, false) == timeout { + return noSignalError + } + // wait for thermometer to pull down and start sending the data + if expectChange(p, true) == timeout { + return noSignalError + } + return nil +} + +type Device interface { + ReadMeasurements() error + Temperature() int16 + TemperatureFloat(scale TemperatureScale) float32 + Humidity() uint16 + HumidityFloat() float32 +} + +func New(p machine.Pin, deviceType DeviceType) Device { + return &device{ + pin: p, + measurements: deviceType, + temperature: 0, + humidity: 0, + } +} diff --git a/dht/util.go b/dht/util.go new file mode 100644 index 000000000..d06e61721 --- /dev/null +++ b/dht/util.go @@ -0,0 +1,34 @@ +package dht + +import ( + "machine" + "time" +) + +// Check if the pin is disabled +func powerUp(p machine.Pin) bool { + state := p.Get() + if !state { + p.High() + time.Sleep(startTimeout) + } + return state +} + +func expectChange(p machine.Pin, oldState bool) uint16 { + counter := uint16(0) + for ; p.Get() == oldState && counter != timeout; counter++ { + } + return counter +} + +func checksum(buf []uint8) uint8 { + return buf[4] +} +func computeChecksum(buf []uint8) uint8 { + return buf[0] + buf[1] + buf[2] + buf[3] +} + +func isValid(buf []uint8) bool { + return checksum(buf) == computeChecksum(buf) +} From 775dd560a07b94998adcb631b570f79e1db5b521 Mon Sep 17 00:00:00 2001 From: Oleksandr Voloshyn Date: Tue, 2 Mar 2021 21:30:36 +0100 Subject: [PATCH 02/12] Add high and low frequency files Add high and low frequency definition of counter Change all code to use counter instead of fixed type uint16 --- dht/constants.go | 6 +++--- dht/highFreq.go | 5 +++++ dht/lowFreq.go | 5 +++++ dht/thermometer.go | 6 +++--- dht/util.go | 8 ++++---- 5 files changed, 20 insertions(+), 10 deletions(-) create mode 100644 dht/highFreq.go create mode 100644 dht/lowFreq.go diff --git a/dht/constants.go b/dht/constants.go index a1b99dc44..da2aaacaa 100644 --- a/dht/constants.go +++ b/dht/constants.go @@ -51,7 +51,7 @@ const ( ) var ( - timeout uint16 + timeout counter checksumError = errors.New("checksum mismatch") noSignalError = errors.New("no signal") @@ -62,8 +62,8 @@ func init() { timeout = cyclesPerMillisecond() } -func cyclesPerMillisecond() uint16 { +func cyclesPerMillisecond() counter { freq := machine.CPUFrequency() freq /= 1000 - return uint16(freq) + return counter(freq) } diff --git a/dht/highFreq.go b/dht/highFreq.go new file mode 100644 index 000000000..e30350d6a --- /dev/null +++ b/dht/highFreq.go @@ -0,0 +1,5 @@ +// +build mimxrt1062 stm32f405 atsamd51 stm32f103xx k210 stm32f407 + +package dht + +type counter uint32 diff --git a/dht/lowFreq.go b/dht/lowFreq.go new file mode 100644 index 000000000..6876f8ea5 --- /dev/null +++ b/dht/lowFreq.go @@ -0,0 +1,5 @@ +// +build arduino atmega1284p nrf52840 digispark nrf52 arduino_nano nrf51 atsamd21 fe310 arduino_nano33 circuitplay_express arduino_mega2560 + +package dht + +type counter uint16 diff --git a/dht/thermometer.go b/dht/thermometer.go index 352e8264f..7043109ae 100644 --- a/dht/thermometer.go +++ b/dht/thermometer.go @@ -51,7 +51,7 @@ func (t *device) read() error { // initialize loop variables bufferData := [5]byte{} buf := bufferData[:] - signalsData := [80]uint16{} + signalsData := [80]counter{} signals := signalsData[:] initiateCommunication(t.pin) @@ -73,7 +73,7 @@ func (t *device) read() error { return nil } -func (t *device) receiveSignals(result []uint16) { +func (t *device) receiveSignals(result []counter) { i := uint8(0) machine.UART1.Interrupt.Disable() defer machine.UART1.Interrupt.Enable() @@ -82,7 +82,7 @@ func (t *device) receiveSignals(result []uint16) { result[i*2+1] = expectChange(t.pin, true) } } -func (t *device) extractData(signals []uint16, buf []uint8) error { +func (t *device) extractData(signals []counter, buf []uint8) error { for i := uint8(0); i < 40; i++ { lowCycle := signals[i*2] highCycle := signals[i*2+1] diff --git a/dht/util.go b/dht/util.go index d06e61721..fd064ee9f 100644 --- a/dht/util.go +++ b/dht/util.go @@ -15,11 +15,11 @@ func powerUp(p machine.Pin) bool { return state } -func expectChange(p machine.Pin, oldState bool) uint16 { - counter := uint16(0) - for ; p.Get() == oldState && counter != timeout; counter++ { +func expectChange(p machine.Pin, oldState bool) counter { + cnt := counter(0) + for ; p.Get() == oldState && cnt != timeout; cnt++ { } - return counter + return cnt } func checksum(buf []uint8) uint8 { From 2443081ceb204154af251c0b2ee037390f5d31fc Mon Sep 17 00:00:00 2001 From: Oleksandr Voloshyn Date: Tue, 2 Mar 2021 22:55:42 +0100 Subject: [PATCH 03/12] Add time safe device class Add device class that performs update of the data if specified Add additional error outputs Add UpdatePolicy struct Add constructor with default and update settings --- dht/constants.go | 15 +++++-- dht/thermometer.go | 39 +++++++++++++----- dht/timeSafeThermometer.go | 81 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+), 13 deletions(-) create mode 100644 dht/timeSafeThermometer.go diff --git a/dht/constants.go b/dht/constants.go index da2aaacaa..1223deb4a 100644 --- a/dht/constants.go +++ b/dht/constants.go @@ -50,12 +50,21 @@ const ( F ) +// If update time is less than 2 seconds, thermometer will never update data automatically. +// It will require manual Update calls +type UpdatePolicy struct { + UpdateTime time.Duration + UpdateAutomatically bool +} + var ( timeout counter - checksumError = errors.New("checksum mismatch") - noSignalError = errors.New("no signal") - noDataError = errors.New("no data") + checksumError = errors.New("checksum mismatch") + noSignalError = errors.New("no signal") + noDataError = errors.New("no data") + updateError = errors.New("cannot update now") + uninitializedData = errors.New("no mesurements done") ) func init() { diff --git a/dht/thermometer.go b/dht/thermometer.go index 7043109ae..4b8fb604e 100644 --- a/dht/thermometer.go +++ b/dht/thermometer.go @@ -116,17 +116,36 @@ func waitForDataTransmission(p machine.Pin) error { type Device interface { ReadMeasurements() error - Temperature() int16 - TemperatureFloat(scale TemperatureScale) float32 - Humidity() uint16 - HumidityFloat() float32 + Measurements() (temperature int16, humidity uint16, err error) + Temperature() (int16, error) + TemperatureFloat(scale TemperatureScale) (float32, error) + Humidity() (uint16, error) + HumidityFloat() (float32, error) } -func New(p machine.Pin, deviceType DeviceType) Device { - return &device{ - pin: p, - measurements: deviceType, - temperature: 0, - humidity: 0, +func New(pin machine.Pin, deviceType DeviceType) Device { + return &managedDevice{ + t: device{ + pin: pin, + measurements: deviceType, + }, + lastUpdate: time.Time{}, + policy: UpdatePolicy{ + UpdateTime: time.Second * 2, + UpdateAutomatically: true, + }, + initialized: false, + } +} + +func NewWithPolicy(pin machine.Pin, deviceType DeviceType, updatePolicy UpdatePolicy) Device { + return &managedDevice{ + t: device{ + pin: pin, + measurements: deviceType, + }, + lastUpdate: time.Time{}, + policy: updatePolicy, + initialized: false, } } diff --git a/dht/timeSafeThermometer.go b/dht/timeSafeThermometer.go new file mode 100644 index 000000000..c56e40a14 --- /dev/null +++ b/dht/timeSafeThermometer.go @@ -0,0 +1,81 @@ +package dht + +import "time" + +type managedDevice struct { + t device + lastUpdate time.Time + policy UpdatePolicy + initialized bool +} + +func (m *managedDevice) Measurements() (temperature int16, humidity uint16, err error) { + err = m.checkForUpdateOnDataRequest() + if err != nil { + return 0, 0, err + } + return m.t.Temperature(), m.t.Humidity(), nil +} + +func (m *managedDevice) Temperature() (temp int16, err error) { + err = m.checkForUpdateOnDataRequest() + if err != nil { + return 0, err + } + temp = m.t.Temperature() + return +} + +func (m *managedDevice) checkForUpdateOnDataRequest() (err error) { + // update if necessary + if m.policy.UpdateAutomatically { + err = m.ReadMeasurements() + } + // ignore error if the data was updated recently + if err == updateError { + err = nil + } + // add error if the data is not initialized + if !m.initialized { + err = uninitializedData + } + return err +} + +func (m *managedDevice) TemperatureFloat(scale TemperatureScale) (float32, error) { + err := m.checkForUpdateOnDataRequest() + if err != nil { + return 0, err + } + return m.t.TemperatureFloat(scale), err +} + +func (m *managedDevice) Humidity() (hum uint16, err error) { + err = m.checkForUpdateOnDataRequest() + if err != nil { + return 0, err + } + return m.t.Humidity(), err +} + +func (m *managedDevice) HumidityFloat() (float32, error) { + err := m.checkForUpdateOnDataRequest() + if err != nil { + return 0, err + } + return m.t.HumidityFloat(), err +} + +func (m *managedDevice) ReadMeasurements() (err error) { + timestamp := time.Now() + if !m.initialized || timestamp.Sub(m.lastUpdate) > m.policy.UpdateTime { + err = m.t.ReadMeasurements() + } else { + err = updateError + } + if err == nil { + m.initialized = true + m.lastUpdate = timestamp + } + return +} From 622995d5023b6d3326b28368a57a121f6952675d Mon Sep 17 00:00:00 2001 From: Oleksandr Voloshyn Date: Wed, 3 Mar 2021 10:30:58 +0100 Subject: [PATCH 04/12] Add exported error type and constants Add exported error type and error constants for more efficient handling Make unmanaged device struct to implement Device interface --- dht/constants.go | 32 ++++++++++++++++++----- dht/thermometer.go | 53 +++++++++++++++++++++++++++----------- dht/timeSafeThermometer.go | 17 ++++++------ 3 files changed, 72 insertions(+), 30 deletions(-) diff --git a/dht/constants.go b/dht/constants.go index 1223deb4a..aec6144ee 100644 --- a/dht/constants.go +++ b/dht/constants.go @@ -2,7 +2,6 @@ package dht import ( "encoding/binary" - "errors" "machine" "time" ) @@ -39,6 +38,8 @@ func (t TemperatureScale) convertToFloat(temp int16) float32 { } } +type ErrorCode uint8 + const ( startTimeout = time.Millisecond * 200 startingLow = time.Millisecond * 20 @@ -48,8 +49,31 @@ const ( C TemperatureScale = iota F + + ChecksumError ErrorCode = iota + NoSignalError + NoDataError + UpdateError + UninitializedDataError ) +func (e ErrorCode) Error() string { + switch e { + case ChecksumError: + return "checksum mismatch" + case NoSignalError: + return "no signal" + case NoDataError: + return "no data" + case UpdateError: + return "cannot update now" + case UninitializedDataError: + return "no measurements done" + } + // should never be reached + return "unknown error" +} + // If update time is less than 2 seconds, thermometer will never update data automatically. // It will require manual Update calls type UpdatePolicy struct { @@ -59,12 +83,6 @@ type UpdatePolicy struct { var ( timeout counter - - checksumError = errors.New("checksum mismatch") - noSignalError = errors.New("no signal") - noDataError = errors.New("no data") - updateError = errors.New("cannot update now") - uninitializedData = errors.New("no mesurements done") ) func init() { diff --git a/dht/thermometer.go b/dht/thermometer.go index 4b8fb604e..0ba820cef 100644 --- a/dht/thermometer.go +++ b/dht/thermometer.go @@ -9,25 +9,43 @@ type device struct { pin machine.Pin measurements DeviceType + initialized bool temperature int16 humidity uint16 } -func (t *device) Temperature() int16 { - return t.temperature +func (t *device) ReadMeasurements() error { + _, _, err := t.Measurements() + return err } -func (t *device) TemperatureFloat(scale TemperatureScale) float32 { - return scale.convertToFloat(t.temperature) +func (t *device) Temperature() (int16, error) { + if !t.initialized { + return 0, UninitializedDataError + } + return t.temperature, nil +} + +func (t *device) TemperatureFloat(scale TemperatureScale) (float32, error) { + if !t.initialized { + return 0, UninitializedDataError + } + return scale.convertToFloat(t.temperature), nil } -func (t *device) Humidity() uint16 { - return t.humidity +func (t *device) Humidity() (uint16, error) { + if !t.initialized { + return 0, UninitializedDataError + } + return t.humidity, nil } -func (t *device) HumidityFloat() float32 { - return float32(t.humidity) / 10. +func (t *device) HumidityFloat() (float32, error) { + if !t.initialized { + return 0, UninitializedDataError + } + return float32(t.humidity) / 10., nil } func initiateCommunication(p machine.Pin) { @@ -40,11 +58,16 @@ func initiateCommunication(p machine.Pin) { p.Configure(machine.PinConfig{Mode: machine.PinInput}) } -func (t *device) ReadMeasurements() error { +func (t *device) Measurements() (temperature int16, humidity uint16, err error) { // initial waiting state := powerUp(t.pin) defer t.pin.Set(state) - return t.read() + err = t.read() + if err != nil { + temperature = t.temperature + humidity = t.humidity + } + return } func (t *device) read() error { @@ -66,7 +89,7 @@ func (t *device) read() error { return err } if !isValid(buf[:]) { - return checksumError + return ChecksumError } t.temperature, t.humidity = t.measurements.extractData(buf) @@ -87,7 +110,7 @@ func (t *device) extractData(signals []counter, buf []uint8) error { lowCycle := signals[i*2] highCycle := signals[i*2+1] if lowCycle == timeout || highCycle == timeout { - return noDataError + return NoDataError } byteN := i >> 3 buf[byteN] <<= 1 @@ -101,15 +124,15 @@ func (t *device) extractData(signals []counter, buf []uint8) error { func waitForDataTransmission(p machine.Pin) error { // wait for thermometer to pull down if expectChange(p, true) == timeout { - return noSignalError + return NoSignalError } //wait for thermometer to pull up if expectChange(p, false) == timeout { - return noSignalError + return NoSignalError } // wait for thermometer to pull down and start sending the data if expectChange(p, true) == timeout { - return noSignalError + return NoSignalError } return nil } diff --git a/dht/timeSafeThermometer.go b/dht/timeSafeThermometer.go index c56e40a14..c2abb572f 100644 --- a/dht/timeSafeThermometer.go +++ b/dht/timeSafeThermometer.go @@ -14,7 +14,7 @@ func (m *managedDevice) Measurements() (temperature int16, humidity uint16, err if err != nil { return 0, 0, err } - return m.t.Temperature(), m.t.Humidity(), nil + return m.t.Measurements() } func (m *managedDevice) Temperature() (temp int16, err error) { @@ -22,7 +22,7 @@ func (m *managedDevice) Temperature() (temp int16, err error) { if err != nil { return 0, err } - temp = m.t.Temperature() + temp, err = m.t.Temperature() return } @@ -32,12 +32,13 @@ func (m *managedDevice) checkForUpdateOnDataRequest() (err error) { err = m.ReadMeasurements() } // ignore error if the data was updated recently - if err == updateError { + // interface comparison does not work in tinygo. Therefore need to cast to explicit type + if code, ok := err.(ErrorCode); ok && code == UpdateError { err = nil } // add error if the data is not initialized if !m.initialized { - err = uninitializedData + err = UninitializedDataError } return err } @@ -47,7 +48,7 @@ func (m *managedDevice) TemperatureFloat(scale TemperatureScale) (float32, error if err != nil { return 0, err } - return m.t.TemperatureFloat(scale), err + return m.t.TemperatureFloat(scale) } func (m *managedDevice) Humidity() (hum uint16, err error) { @@ -55,7 +56,7 @@ func (m *managedDevice) Humidity() (hum uint16, err error) { if err != nil { return 0, err } - return m.t.Humidity(), err + return m.t.Humidity() } func (m *managedDevice) HumidityFloat() (float32, error) { @@ -63,7 +64,7 @@ func (m *managedDevice) HumidityFloat() (float32, error) { if err != nil { return 0, err } - return m.t.HumidityFloat(), err + return m.t.HumidityFloat() } func (m *managedDevice) ReadMeasurements() (err error) { @@ -71,7 +72,7 @@ func (m *managedDevice) ReadMeasurements() (err error) { if !m.initialized || timestamp.Sub(m.lastUpdate) > m.policy.UpdateTime { err = m.t.ReadMeasurements() } else { - err = updateError + err = UpdateError } if err == nil { m.initialized = true From 3e1bb5b01192acda10128f4ea685bcc6c6bb3b61 Mon Sep 17 00:00:00 2001 From: Oleksandr Voloshyn Date: Wed, 3 Mar 2021 10:34:31 +0100 Subject: [PATCH 05/12] Move initialized field to unmanaged device --- dht/thermometer.go | 9 +++++---- dht/timeSafeThermometer.go | 12 +++++------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/dht/thermometer.go b/dht/thermometer.go index 0ba820cef..7dd8fae57 100644 --- a/dht/thermometer.go +++ b/dht/thermometer.go @@ -66,6 +66,7 @@ func (t *device) Measurements() (temperature int16, humidity uint16, err error) if err != nil { temperature = t.temperature humidity = t.humidity + t.initialized = true } return } @@ -151,13 +152,13 @@ func New(pin machine.Pin, deviceType DeviceType) Device { t: device{ pin: pin, measurements: deviceType, + initialized: false, }, lastUpdate: time.Time{}, policy: UpdatePolicy{ UpdateTime: time.Second * 2, UpdateAutomatically: true, }, - initialized: false, } } @@ -166,9 +167,9 @@ func NewWithPolicy(pin machine.Pin, deviceType DeviceType, updatePolicy UpdatePo t: device{ pin: pin, measurements: deviceType, + initialized: false, }, - lastUpdate: time.Time{}, - policy: updatePolicy, - initialized: false, + lastUpdate: time.Time{}, + policy: updatePolicy, } } diff --git a/dht/timeSafeThermometer.go b/dht/timeSafeThermometer.go index c2abb572f..87c63d43a 100644 --- a/dht/timeSafeThermometer.go +++ b/dht/timeSafeThermometer.go @@ -3,10 +3,9 @@ package dht import "time" type managedDevice struct { - t device - lastUpdate time.Time - policy UpdatePolicy - initialized bool + t device + lastUpdate time.Time + policy UpdatePolicy } func (m *managedDevice) Measurements() (temperature int16, humidity uint16, err error) { @@ -37,7 +36,7 @@ func (m *managedDevice) checkForUpdateOnDataRequest() (err error) { err = nil } // add error if the data is not initialized - if !m.initialized { + if !m.t.initialized { err = UninitializedDataError } return err @@ -69,13 +68,12 @@ func (m *managedDevice) HumidityFloat() (float32, error) { func (m *managedDevice) ReadMeasurements() (err error) { timestamp := time.Now() - if !m.initialized || timestamp.Sub(m.lastUpdate) > m.policy.UpdateTime { + if !m.t.initialized || timestamp.Sub(m.lastUpdate) > m.policy.UpdateTime { err = m.t.ReadMeasurements() } else { err = UpdateError } if err == nil { - m.initialized = true m.lastUpdate = timestamp } return From 08e97729b9f1a271254e539c84b26a81f89e772f Mon Sep 17 00:00:00 2001 From: Oleksandr Voloshyn Date: Wed, 3 Mar 2021 10:59:26 +0100 Subject: [PATCH 06/12] Remove reading functionality from Measurements function Make Measurements function for dummy device no longer read measurements Now the function just returns stored measurements --- dht/thermometer.go | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/dht/thermometer.go b/dht/thermometer.go index 7dd8fae57..806a15c5b 100644 --- a/dht/thermometer.go +++ b/dht/thermometer.go @@ -16,7 +16,13 @@ type device struct { } func (t *device) ReadMeasurements() error { - _, _, err := t.Measurements() + // initial waiting + state := powerUp(t.pin) + defer t.pin.Set(state) + err := t.read() + if err != nil { + t.initialized = true + } return err } @@ -59,15 +65,12 @@ func initiateCommunication(p machine.Pin) { } func (t *device) Measurements() (temperature int16, humidity uint16, err error) { - // initial waiting - state := powerUp(t.pin) - defer t.pin.Set(state) - err = t.read() - if err != nil { - temperature = t.temperature - humidity = t.humidity - t.initialized = true + if !t.initialized { + return 0, 0, UninitializedDataError } + temperature = t.temperature + humidity = t.humidity + err = nil return } From 168ec28ca1adbbfecf9f765f92efeb44db9c6727 Mon Sep 17 00:00:00 2001 From: Oleksandr Voloshyn Date: Wed, 3 Mar 2021 12:07:49 +0100 Subject: [PATCH 07/12] Extract dummy device Add configure function to managed device --- dht/thermometer.go | 49 +++++++++++++------------------------- dht/timeSafeThermometer.go | 39 ++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 33 deletions(-) diff --git a/dht/thermometer.go b/dht/thermometer.go index 806a15c5b..95b4974f6 100644 --- a/dht/thermometer.go +++ b/dht/thermometer.go @@ -5,6 +5,15 @@ import ( "time" ) +type DummyDevice interface { + ReadMeasurements() error + Measurements() (temperature int16, humidity uint16, err error) + Temperature() (int16, error) + TemperatureFloat(scale TemperatureScale) (float32, error) + Humidity() (uint16, error) + HumidityFloat() (float32, error) +} + type device struct { pin machine.Pin @@ -141,38 +150,12 @@ func waitForDataTransmission(p machine.Pin) error { return nil } -type Device interface { - ReadMeasurements() error - Measurements() (temperature int16, humidity uint16, err error) - Temperature() (int16, error) - TemperatureFloat(scale TemperatureScale) (float32, error) - Humidity() (uint16, error) - HumidityFloat() (float32, error) -} - -func New(pin machine.Pin, deviceType DeviceType) Device { - return &managedDevice{ - t: device{ - pin: pin, - measurements: deviceType, - initialized: false, - }, - lastUpdate: time.Time{}, - policy: UpdatePolicy{ - UpdateTime: time.Second * 2, - UpdateAutomatically: true, - }, - } -} - -func NewWithPolicy(pin machine.Pin, deviceType DeviceType, updatePolicy UpdatePolicy) Device { - return &managedDevice{ - t: device{ - pin: pin, - measurements: deviceType, - initialized: false, - }, - lastUpdate: time.Time{}, - policy: updatePolicy, +func NewDummyDevice(pin machine.Pin, deviceType DeviceType) DummyDevice { + return &device{ + pin: pin, + measurements: deviceType, + initialized: false, + temperature: 0, + humidity: 0, } } diff --git a/dht/timeSafeThermometer.go b/dht/timeSafeThermometer.go index 87c63d43a..3054a6649 100644 --- a/dht/timeSafeThermometer.go +++ b/dht/timeSafeThermometer.go @@ -2,6 +2,11 @@ package dht import "time" +type Device interface { + DummyDevice + Configure(policy UpdatePolicy) +} + type managedDevice struct { t device lastUpdate time.Time @@ -78,3 +83,37 @@ func (m *managedDevice) ReadMeasurements() (err error) { } return } +func (m *managedDevice) Configure(policy UpdatePolicy) { + if policy.UpdateAutomatically && policy.UpdateTime < time.Second*2 { + policy.UpdateTime = time.Second * 2 + } + m.policy = policy +} + +func New(pin machine.Pin, deviceType DeviceType) Device { + return &managedDevice{ + t: device{ + pin: pin, + measurements: deviceType, + initialized: false, + }, + lastUpdate: time.Time{}, + policy: UpdatePolicy{ + UpdateTime: time.Second * 2, + UpdateAutomatically: true, + }, + } +} + +func NewWithPolicy(pin machine.Pin, deviceType DeviceType, updatePolicy UpdatePolicy) Device { + result := &managedDevice{ + t: device{ + pin: pin, + measurements: deviceType, + initialized: false, + }, + lastUpdate: time.Time{}, + } + result.Configure(updatePolicy) + return result +} From 56ef82b76de314b663352aae1c2b613dbc633dd2 Mon Sep 17 00:00:00 2001 From: Oleksandr Voloshyn Date: Wed, 3 Mar 2021 12:25:48 +0100 Subject: [PATCH 08/12] Fix missing import in managed device file Fix initialization flag for ReadMeasurements in dummy device --- dht/thermometer.go | 2 +- dht/timeSafeThermometer.go | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/dht/thermometer.go b/dht/thermometer.go index 95b4974f6..103cd38de 100644 --- a/dht/thermometer.go +++ b/dht/thermometer.go @@ -29,7 +29,7 @@ func (t *device) ReadMeasurements() error { state := powerUp(t.pin) defer t.pin.Set(state) err := t.read() - if err != nil { + if err == nil { t.initialized = true } return err diff --git a/dht/timeSafeThermometer.go b/dht/timeSafeThermometer.go index 3054a6649..5abafeebc 100644 --- a/dht/timeSafeThermometer.go +++ b/dht/timeSafeThermometer.go @@ -1,6 +1,9 @@ package dht -import "time" +import ( + "machine" + "time" +) type Device interface { DummyDevice From 0ffbc011ffce57e383763fe6db02ae09403bb37f Mon Sep 17 00:00:00 2001 From: Oleksandr Voloshyn Date: Wed, 3 Mar 2021 21:08:40 +0100 Subject: [PATCH 09/12] Add comments for dht driver --- dht/constants.go | 24 ++++++++++++-- dht/highFreq.go | 1 + dht/lowFreq.go | 1 + dht/thermometer.go | 65 +++++++++++++++++++++++++++++++++++--- dht/timeSafeThermometer.go | 32 +++++++++++++++++++ 5 files changed, 117 insertions(+), 6 deletions(-) diff --git a/dht/constants.go b/dht/constants.go index aec6144ee..30b5da871 100644 --- a/dht/constants.go +++ b/dht/constants.go @@ -1,3 +1,9 @@ +// Package dht provides a driver for dhtxx family temperature and humidity sensors. +// +// [1] Datasheet DHT11: https://www.mouser.com/datasheet/2/758/DHT11-Technical-Data-Sheet-Translated-Version-1143054.pdf +// [2] Datasheet DHT22: https://cdn-shop.adafruit.com/datasheets/Digital+humidity+and+temperature+sensor+AM2302.pdf +// Adafruit C++ driver: https://github.com/adafruit/DHT-sensor-library + package dht import ( @@ -6,8 +12,10 @@ import ( "time" ) +// enum type for device type type DeviceType uint8 +// DeviceType specific parsing of information received from the sensor func (d DeviceType) extractData(buf []byte) (temp int16, hum uint16) { if d == DHT11 { temp = int16(buf[2]) @@ -27,6 +35,7 @@ func (d DeviceType) extractData(buf []byte) (temp int16, hum uint16) { return } +// Celsius and Fahrenheit temperature scales type TemperatureScale uint8 func (t TemperatureScale) convertToFloat(temp int16) float32 { @@ -38,6 +47,7 @@ func (t TemperatureScale) convertToFloat(temp int16) float32 { } } +// All functions return ErrorCode instance as error. This class can be used for more efficient error processing type ErrorCode uint8 const ( @@ -57,31 +67,41 @@ const ( UninitializedDataError ) +// error interface implementation for ErrorCode func (e ErrorCode) Error() string { switch e { case ChecksumError: + // DHT returns ChecksumError if all the data from the sensor was received, but the checksum does not match. return "checksum mismatch" case NoSignalError: + // DHT returns NoSignalError if there was no reply from the sensor. Check sensor connection or the correct pin + // sis chosen, return "no signal" case NoDataError: + // DHT returns NoDataError if the connection was successfully initialized, but not all 40 bits from + // the sensor is received return "no data" case UpdateError: + // DHT returns UpdateError if ReadMeasurements function is called before time specified in UpdatePolicy or + // less than 2 seconds after past measurement return "cannot update now" case UninitializedDataError: + // DHT returns UninitializedDataError if user attempts to access data before first measurement return "no measurements done" } // should never be reached return "unknown error" } -// If update time is less than 2 seconds, thermometer will never update data automatically. -// It will require manual Update calls +// Update policy of the DHT device. UpdateTime cannot be shorter than 2 seconds. According to dht specification sensor +// will return undefined data if update requested less than 2 seconds before last usage type UpdatePolicy struct { UpdateTime time.Duration UpdateAutomatically bool } var ( + // timeout counter equal to number of ticks per 1 millisecond timeout counter ) diff --git a/dht/highFreq.go b/dht/highFreq.go index e30350d6a..1c4fb1803 100644 --- a/dht/highFreq.go +++ b/dht/highFreq.go @@ -2,4 +2,5 @@ package dht +// This file provides a definition of the counter for boards with frequency higher than 2^8 ticks per millisecond (>64MHz) type counter uint32 diff --git a/dht/lowFreq.go b/dht/lowFreq.go index 6876f8ea5..984e0bd41 100644 --- a/dht/lowFreq.go +++ b/dht/lowFreq.go @@ -2,4 +2,5 @@ package dht +// This file provides a definition of the counter for boards with frequency lower than 2^8 ticks per millisecond (<64MHz) type counter uint16 diff --git a/dht/thermometer.go b/dht/thermometer.go index 103cd38de..570bcd3c3 100644 --- a/dht/thermometer.go +++ b/dht/thermometer.go @@ -1,3 +1,9 @@ +// Package dht provides a driver for dhtxx family temperature and humidity sensors. +// +// [1] Datasheet DHT11: https://www.mouser.com/datasheet/2/758/DHT11-Technical-Data-Sheet-Translated-Version-1143054.pdf +// [2] Datasheet DHT22: https://cdn-shop.adafruit.com/datasheets/Digital+humidity+and+temperature+sensor+AM2302.pdf +// Adafruit C++ driver: https://github.com/adafruit/DHT-sensor-library + package dht import ( @@ -5,6 +11,7 @@ import ( "time" ) +// DummyDevice provides a basic interface for DHT devices. type DummyDevice interface { ReadMeasurements() error Measurements() (temperature int16, humidity uint16, err error) @@ -14,6 +21,11 @@ type DummyDevice interface { HumidityFloat() (float32, error) } +// Basic implementation of the DummyDevice +// This implementation takes measurements from sensor only with ReadMeasurements function +// and does not provide a protection from too frequent calls for measurements. +// Since taking measurements from the sensor is time consuming procedure and blocks interrupts, +// user can avoid any hidden calls to the sensor. type device struct { pin machine.Pin @@ -24,6 +36,8 @@ type device struct { humidity uint16 } +// ReadMeasurements reads data from the sensor. +// According to documentation pin should be always, but the t *device restores pin to the state before call. func (t *device) ReadMeasurements() error { // initial waiting state := powerUp(t.pin) @@ -35,6 +49,9 @@ func (t *device) ReadMeasurements() error { return err } +// Getter for temperature. Temperature method returns temperature as it is sent by device. +// The temperature is measured temperature in Celsius multiplied by 10. +// If no successful measurements for this device was performed, returns UninitializedDataError. func (t *device) Temperature() (int16, error) { if !t.initialized { return 0, UninitializedDataError @@ -42,6 +59,8 @@ func (t *device) Temperature() (int16, error) { return t.temperature, nil } +// Getter for temperature. TemperatureFloat returns temperature in a given scale. +// If no successful measurements for this device was performed, returns UninitializedDataError. func (t *device) TemperatureFloat(scale TemperatureScale) (float32, error) { if !t.initialized { return 0, UninitializedDataError @@ -49,6 +68,9 @@ func (t *device) TemperatureFloat(scale TemperatureScale) (float32, error) { return scale.convertToFloat(t.temperature), nil } +// Getter for humidity. Humidity returns humidity as it is sent by device. +// The humidity is measured in percentages multiplied by 10. +// If no successful measurements for this device was performed, returns UninitializedDataError. func (t *device) Humidity() (uint16, error) { if !t.initialized { return 0, UninitializedDataError @@ -56,6 +78,8 @@ func (t *device) Humidity() (uint16, error) { return t.humidity, nil } +// Getter for humidity. HumidityFloat returns humidity in percentages. +// If no successful measurements for this device was performed, returns UninitializedDataError. func (t *device) HumidityFloat() (float32, error) { if !t.initialized { return 0, UninitializedDataError @@ -63,6 +87,9 @@ func (t *device) HumidityFloat() (float32, error) { return float32(t.humidity) / 10., nil } +// Perform initialization of the communication protocol. +// Device lowers the voltage on pin for startingLow=20ms and starts listening for response +// Section 5.2 in [1] func initiateCommunication(p machine.Pin) { // Send low signal to the device p.Configure(machine.PinConfig{Mode: machine.PinOutput}) @@ -73,6 +100,8 @@ func initiateCommunication(p machine.Pin) { p.Configure(machine.PinConfig{Mode: machine.PinInput}) } +// Measurements returns both measurements: temperature and humidity as they sent by the device. +// If no successful measurements for this device was performed, returns UninitializedDataError. func (t *device) Measurements() (temperature int16, humidity uint16, err error) { if !t.initialized { return 0, 0, UninitializedDataError @@ -83,41 +112,61 @@ func (t *device) Measurements() (temperature int16, humidity uint16, err error) return } +// Main routine that performs communication with the sensor func (t *device) read() error { // initialize loop variables + + // buffer for the data sent by the sensor. Sensor sends 40 bits = 5 bytes bufferData := [5]byte{} buf := bufferData[:] + + // We perform measurements of the signal from the sensor by counting low and high cycles. + // The bit is determined by the relative length of the high signal to low signal. + // For 1, high signal will be longer than low, for 0---low is longer. + // See section 5.3 [1] signalsData := [80]counter{} signals := signalsData[:] + // Start communication protocol with sensor initiateCommunication(t.pin) + // Wait for sensor's response and abort if sensor does not reply err := waitForDataTransmission(t.pin) if err != nil { return err } - t.receiveSignals(signals) + // count low and high cycles for sensor's reply + receiveSignals(t.pin, signals) + // process received signals and store the result in the buffer. Abort if data transmission was interrupted and not + // all 40 bits were received err = t.extractData(signals[:], buf) if err != nil { return err } + // Compute checksum and compare it to the one in data. Abort if checksum is incorrect if !isValid(buf[:]) { return ChecksumError } + // Extract temperature and humidity data from buffer t.temperature, t.humidity = t.measurements.extractData(buf) return nil } -func (t *device) receiveSignals(result []counter) { +// receiveSignals counts number of low and high cycles. The execution is time critical, so the function disables +// interrupts +func receiveSignals(pin machine.Pin, result []counter) { i := uint8(0) machine.UART1.Interrupt.Disable() defer machine.UART1.Interrupt.Enable() for ; i < 40; i++ { - result[i*2] = expectChange(t.pin, false) - result[i*2+1] = expectChange(t.pin, true) + result[i*2] = expectChange(pin, false) + result[i*2+1] = expectChange(pin, true) } } + +// extractData process signal counters and transforms them into bits. +// if any of the bits were not received (timed-out), returns NoDataError func (t *device) extractData(signals []counter, buf []uint8) error { for i := uint8(0); i < 40; i++ { lowCycle := signals[i*2] @@ -134,6 +183,9 @@ func (t *device) extractData(signals []counter, buf []uint8) error { return nil } +// waitForDataTransmission waits for reply from the sensor. +// If no reply received, returns NoSignalError. +// For more details, see section 5.2 in [1] func waitForDataTransmission(p machine.Pin) error { // wait for thermometer to pull down if expectChange(p, true) == timeout { @@ -150,7 +202,12 @@ func waitForDataTransmission(p machine.Pin) error { return nil } +// Constructor function for a DummyDevice implementation. +// This device provides full control to the user. +// It does not do any hidden measurements calls and does not check +// for 2 seconds delay between measurements. func NewDummyDevice(pin machine.Pin, deviceType DeviceType) DummyDevice { + pin.High() return &device{ pin: pin, measurements: deviceType, diff --git a/dht/timeSafeThermometer.go b/dht/timeSafeThermometer.go index 5abafeebc..184ba788e 100644 --- a/dht/timeSafeThermometer.go +++ b/dht/timeSafeThermometer.go @@ -1,3 +1,9 @@ +// Package dht provides a driver for DHTXX family temperature and humidity sensors. +// +// [1] Datasheet DHT11: https://www.mouser.com/datasheet/2/758/DHT11-Technical-Data-Sheet-Translated-Version-1143054.pdf +// [2] Datasheet DHT22: https://cdn-shop.adafruit.com/datasheets/Digital+humidity+and+temperature+sensor+AM2302.pdf +// Adafruit C++ driver: https://github.com/adafruit/DHT-sensor-library + package dht import ( @@ -5,17 +11,22 @@ import ( "time" ) +// Device interface provides main functionality of the DHTXX sensors. type Device interface { DummyDevice Configure(policy UpdatePolicy) } +// managedDevice struct provides time control and optional automatic data retrieval from the sensor. +// It delegates all the functionality to device type managedDevice struct { t device lastUpdate time.Time policy UpdatePolicy } +// Measurements returns both measurements: temperature and humidity as they sent by the device. +// Depending on the UpdatePolicy of the device may update cached measurements. func (m *managedDevice) Measurements() (temperature int16, humidity uint16, err error) { err = m.checkForUpdateOnDataRequest() if err != nil { @@ -24,6 +35,9 @@ func (m *managedDevice) Measurements() (temperature int16, humidity uint16, err return m.t.Measurements() } +// Getter for temperature. Temperature method returns temperature as it is sent by device. +// The temperature is measured temperature in Celsius multiplied by 10. +// Depending on the UpdatePolicy of the device may update cached measurements. func (m *managedDevice) Temperature() (temp int16, err error) { err = m.checkForUpdateOnDataRequest() if err != nil { @@ -50,6 +64,8 @@ func (m *managedDevice) checkForUpdateOnDataRequest() (err error) { return err } +// Getter for temperature. TemperatureFloat returns temperature in a given scale. +// Depending on the UpdatePolicy of the device may update cached measurements. func (m *managedDevice) TemperatureFloat(scale TemperatureScale) (float32, error) { err := m.checkForUpdateOnDataRequest() if err != nil { @@ -58,6 +74,9 @@ func (m *managedDevice) TemperatureFloat(scale TemperatureScale) (float32, error return m.t.TemperatureFloat(scale) } +// Getter for humidity. Humidity returns humidity as it is sent by device. +// The humidity is measured in percentages multiplied by 10. +// Depending on the UpdatePolicy of the device may update cached measurements. func (m *managedDevice) Humidity() (hum uint16, err error) { err = m.checkForUpdateOnDataRequest() if err != nil { @@ -66,6 +85,8 @@ func (m *managedDevice) Humidity() (hum uint16, err error) { return m.t.Humidity() } +// Getter for humidity. HumidityFloat returns humidity in percentages. +// Depending on the UpdatePolicy of the device may update cached measurements. func (m *managedDevice) HumidityFloat() (float32, error) { err := m.checkForUpdateOnDataRequest() if err != nil { @@ -74,6 +95,8 @@ func (m *managedDevice) HumidityFloat() (float32, error) { return m.t.HumidityFloat() } +// ReadMeasurements reads data from the sensor. +// The function will return UpdateError if it is called more frequently than specified in UpdatePolicy func (m *managedDevice) ReadMeasurements() (err error) { timestamp := time.Now() if !m.t.initialized || timestamp.Sub(m.lastUpdate) > m.policy.UpdateTime { @@ -86,6 +109,10 @@ func (m *managedDevice) ReadMeasurements() (err error) { } return } + +// Configure configures UpdatePolicy for Device. +// Configure checks for policy.UpdateTime and prevent from updating more frequently than specified in [1][2] +// to prevent undefined behaviour of the sensor. func (m *managedDevice) Configure(policy UpdatePolicy) { if policy.UpdateAutomatically && policy.UpdateTime < time.Second*2 { policy.UpdateTime = time.Second * 2 @@ -93,7 +120,10 @@ func (m *managedDevice) Configure(policy UpdatePolicy) { m.policy = policy } +// Constructor of the Device implementation. +// This implementation updates data every 2 seconds during data access. func New(pin machine.Pin, deviceType DeviceType) Device { + pin.High() return &managedDevice{ t: device{ pin: pin, @@ -108,7 +138,9 @@ func New(pin machine.Pin, deviceType DeviceType) Device { } } +// Constructor of the Device implementation with given UpdatePolicy func NewWithPolicy(pin machine.Pin, deviceType DeviceType, updatePolicy UpdatePolicy) Device { + pin.High() result := &managedDevice{ t: device{ pin: pin, From b25b0fec31ac339064664676ddf2ed047f081841 Mon Sep 17 00:00:00 2001 From: Oleksandr Voloshyn Date: Wed, 3 Mar 2021 21:25:13 +0100 Subject: [PATCH 10/12] Add DHTXX information to makefile and readme Add import comment Exclude DHT from the test package --- Makefile | 2 +- README.md | 1 + dht/constants.go | 4 ++-- dht/highFreq.go | 2 +- dht/lowFreq.go | 2 +- dht/thermometer.go | 4 ++-- dht/timeSafeThermometer.go | 2 +- dht/util.go | 2 +- 8 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 50efd992f..5b355b704 100644 --- a/Makefile +++ b/Makefile @@ -169,7 +169,7 @@ endif DRIVERS = $(wildcard */) NOTESTS = build examples flash semihosting pcd8544 shiftregister st7789 microphone mcp3008 gps microbitmatrix \ hcsr04 ssd1331 ws2812 thermistor apa102 easystepper ssd1351 ili9341 wifinina shifter hub75 \ - hd44780 buzzer ssd1306 espat l9110x st7735 bmi160 l293x + hd44780 buzzer ssd1306 espat l9110x st7735 bmi160 l293x dht TESTS = $(filter-out $(addsuffix /%,$(NOTESTS)),$(DRIVERS)) unit-test: diff --git a/README.md b/README.md index 0bd1625f4..2a7b64129 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ The following 53 devices are supported. | [BMP180 barometer](https://cdn-shop.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf) | I2C | | [BMP280 temperature/barometer](https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp280-ds001.pdf) | I2C | | [Buzzer](https://en.wikipedia.org/wiki/Buzzer#Piezoelectric) | GPIO | +| [DHTXX thermometer and humidity sensor](https://cdn-shop.adafruit.com/datasheets/Digital+humidity+and+temperature+sensor+AM2302.pdf) | GPIO | | [DS1307 real time clock](https://datasheets.maximintegrated.com/en/ds/DS1307.pdf) | I2C | | [DS3231 real time clock](https://datasheets.maximintegrated.com/en/ds/DS3231.pdf) | I2C | | [ESP32 as WiFi Coprocessor with Arduino nina-fw](https://github.com/arduino/nina-fw) | SPI | diff --git a/dht/constants.go b/dht/constants.go index 30b5da871..8bed1a3c1 100644 --- a/dht/constants.go +++ b/dht/constants.go @@ -1,10 +1,10 @@ -// Package dht provides a driver for dhtxx family temperature and humidity sensors. +// Package dht provides a driver for DHTXX family temperature and humidity sensors. // // [1] Datasheet DHT11: https://www.mouser.com/datasheet/2/758/DHT11-Technical-Data-Sheet-Translated-Version-1143054.pdf // [2] Datasheet DHT22: https://cdn-shop.adafruit.com/datasheets/Digital+humidity+and+temperature+sensor+AM2302.pdf // Adafruit C++ driver: https://github.com/adafruit/DHT-sensor-library -package dht +package dht // import "tinygo.org/x/drivers/dht" import ( "encoding/binary" diff --git a/dht/highFreq.go b/dht/highFreq.go index 1c4fb1803..2eb9de38f 100644 --- a/dht/highFreq.go +++ b/dht/highFreq.go @@ -1,6 +1,6 @@ // +build mimxrt1062 stm32f405 atsamd51 stm32f103xx k210 stm32f407 -package dht +package dht // import "tinygo.org/x/drivers/dht" // This file provides a definition of the counter for boards with frequency higher than 2^8 ticks per millisecond (>64MHz) type counter uint32 diff --git a/dht/lowFreq.go b/dht/lowFreq.go index 984e0bd41..ea974680c 100644 --- a/dht/lowFreq.go +++ b/dht/lowFreq.go @@ -1,6 +1,6 @@ // +build arduino atmega1284p nrf52840 digispark nrf52 arduino_nano nrf51 atsamd21 fe310 arduino_nano33 circuitplay_express arduino_mega2560 -package dht +package dht // import "tinygo.org/x/drivers/dht" // This file provides a definition of the counter for boards with frequency lower than 2^8 ticks per millisecond (<64MHz) type counter uint16 diff --git a/dht/thermometer.go b/dht/thermometer.go index 570bcd3c3..2ee3d9339 100644 --- a/dht/thermometer.go +++ b/dht/thermometer.go @@ -1,10 +1,10 @@ -// Package dht provides a driver for dhtxx family temperature and humidity sensors. +// Package dht provides a driver for DHTXX family temperature and humidity sensors. // // [1] Datasheet DHT11: https://www.mouser.com/datasheet/2/758/DHT11-Technical-Data-Sheet-Translated-Version-1143054.pdf // [2] Datasheet DHT22: https://cdn-shop.adafruit.com/datasheets/Digital+humidity+and+temperature+sensor+AM2302.pdf // Adafruit C++ driver: https://github.com/adafruit/DHT-sensor-library -package dht +package dht // import "tinygo.org/x/drivers/dht" import ( "machine" diff --git a/dht/timeSafeThermometer.go b/dht/timeSafeThermometer.go index 184ba788e..3c4ff4761 100644 --- a/dht/timeSafeThermometer.go +++ b/dht/timeSafeThermometer.go @@ -4,7 +4,7 @@ // [2] Datasheet DHT22: https://cdn-shop.adafruit.com/datasheets/Digital+humidity+and+temperature+sensor+AM2302.pdf // Adafruit C++ driver: https://github.com/adafruit/DHT-sensor-library -package dht +package dht // import "tinygo.org/x/drivers/dht" import ( "machine" diff --git a/dht/util.go b/dht/util.go index fd064ee9f..0581c7376 100644 --- a/dht/util.go +++ b/dht/util.go @@ -1,4 +1,4 @@ -package dht +package dht // import "tinygo.org/x/drivers/dht" import ( "machine" From 2f89b3a8e32fb3f60e23bbe2ce3c2782d170575a Mon Sep 17 00:00:00 2001 From: Oleksandr Voloshyn Date: Thu, 4 Mar 2021 12:26:49 +0100 Subject: [PATCH 11/12] Add dht driver usage example Add smoke test for dht driver --- Makefile | 2 ++ examples/dht/main.go | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 examples/dht/main.go diff --git a/Makefile b/Makefile index 5b355b704..3d6459bf6 100644 --- a/Makefile +++ b/Makefile @@ -165,6 +165,8 @@ endif @md5sum ./build/test.hex tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/lis2mdl/main.go @md5sum ./build/test.hex + tinygo build -size short -o ./build/test.hex -target=feather-m0 ./examples/dht/main.go + @md5sum ./build/test.hex DRIVERS = $(wildcard */) NOTESTS = build examples flash semihosting pcd8544 shiftregister st7789 microphone mcp3008 gps microbitmatrix \ diff --git a/examples/dht/main.go b/examples/dht/main.go new file mode 100644 index 000000000..5600e6b10 --- /dev/null +++ b/examples/dht/main.go @@ -0,0 +1,23 @@ +package main + +import ( + "fmt" + "machine" + "time" + "tinygo.org/x/drivers/dht" +) + +func main() { + pin := machine.D6 + dhtSensor := dht.New(pin, dht.DHT11) + for { + temp, hum, err := dhtSensor.Measurements() + if err != nil { + fmt.Printf("Temperature: %02d.%d°C, Humidity: %02d.%d%%\n", temp/10, temp%10, hum/10, hum%10) + } else { + fmt.Printf("Could not take measurements from the sensor: %s\n", err.Error()) + } + // Measurements cannot be updated only 2 seconds. More frequent calls will return the same value + time.Sleep(time.Second * 2) + } +} From 897e9248d839f3cdc0767929e086ac3d5cf83e3f Mon Sep 17 00:00:00 2001 From: Oleksandr Voloshyn Date: Fri, 5 Mar 2021 04:56:44 +0100 Subject: [PATCH 12/12] Rename files names to all lower case --- dht/{highFreq.go => highfreq.go} | 0 dht/{lowFreq.go => lowfreq.go} | 0 dht/{timeSafeThermometer.go => timesafethermometer.go} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename dht/{highFreq.go => highfreq.go} (100%) rename dht/{lowFreq.go => lowfreq.go} (100%) rename dht/{timeSafeThermometer.go => timesafethermometer.go} (100%) diff --git a/dht/highFreq.go b/dht/highfreq.go similarity index 100% rename from dht/highFreq.go rename to dht/highfreq.go diff --git a/dht/lowFreq.go b/dht/lowfreq.go similarity index 100% rename from dht/lowFreq.go rename to dht/lowfreq.go diff --git a/dht/timeSafeThermometer.go b/dht/timesafethermometer.go similarity index 100% rename from dht/timeSafeThermometer.go rename to dht/timesafethermometer.go