Compare commits

...

4 Commits

Author SHA1 Message Date
sago35 3c1aaa9a9f Add error check for d.bus.Tx() 2024-07-18 08:35:57 +09:00
sago35 3f4a9d82f7 Add check for which 2024-07-16 09:00:34 +09:00
sago35 19c9fe6db3 Add error handling 2024-07-14 13:37:13 +09:00
sago35 315dbef694 dht20: add I2C driver for DHT20 temperature and humidity sensor 2024-07-13 10:48:33 +09:00
4 changed files with 187 additions and 0 deletions
+144
View File
@@ -0,0 +1,144 @@
// Package dht20 implements a driver for the DHT20 temperature and humidity sensor.
//
// Datasheet: https://cdn-shop.adafruit.com/product-files/5183/5193_DHT20.pdf
package dht20
import (
"errors"
"time"
"tinygo.org/x/drivers"
)
var (
errUpdateCalledTooSoon = errors.New("Update() called within 80ms is invalid")
)
// Device wraps an I2C connection to a DHT20 device.
type Device struct {
bus drivers.I2C
Address uint16
data [8]uint8
temperature float32
humidity float32
prevAccessTime time.Time
}
// New creates a new DHT20 connection. The I2C bus must already be
// configured.
//
// This function only creates the Device object, it does not touch the device.
func New(bus drivers.I2C) Device {
return Device{
bus: bus,
Address: defaultAddress, // Using the address defined in registers.go
}
}
// Configure sets up the device for communication and initializes the registers if needed.
func (d *Device) Configure() error {
// Get the status word
d.data[0] = 0x71
err := d.bus.Tx(d.Address, d.data[:1], d.data[:1])
if err != nil {
return err
}
if d.data[0] != 0x18 {
// Initialize registers
err := d.initRegisters()
if err != nil {
return err
}
}
// Set the previous access time to the current time
d.prevAccessTime = time.Now()
return nil
}
// initRegisters initializes the registers 0x1B, 0x1C, and 0x1E to 0x00.
func (d *Device) initRegisters() error {
// Initialize register 0x1B
d.data[0] = 0x1B
d.data[1] = 0x00
err := d.bus.Tx(d.Address, d.data[:2], nil)
if err != nil {
return err
}
// Initialize register 0x1C
d.data[0] = 0x1C
d.data[1] = 0x00
err = d.bus.Tx(d.Address, d.data[:2], nil)
if err != nil {
return err
}
// Initialize register 0x1E
d.data[0] = 0x1E
d.data[1] = 0x00
err = d.bus.Tx(d.Address, d.data[:2], nil)
if err != nil {
return err
}
return nil
}
// Update reads data from the sensor and updates the temperature and humidity values.
// Note that the values obtained by this function are from the previous call to Update.
// If you want to use the most recent values, shorten the interval at which Update is called.
func (d *Device) Update(which drivers.Measurement) error {
if which&drivers.Temperature == 0 && which&drivers.Humidity == 0 {
return nil
}
// Check if 80ms have passed since the last access
if time.Since(d.prevAccessTime) < 80*time.Millisecond {
return errUpdateCalledTooSoon
}
// Check the status word Bit[7]
d.data[0] = 0x71
err := d.bus.Tx(d.Address, d.data[:1], d.data[:1])
if err != nil {
return err
}
if (d.data[0] & 0x80) == 0 {
// Read 7 bytes of data from the sensor
err := d.bus.Tx(d.Address, nil, d.data[:7])
if err != nil {
return err
}
rawHumidity := uint32(d.data[1])<<12 | uint32(d.data[2])<<4 | uint32(d.data[3])>>4
rawTemperature := uint32(d.data[3]&0x0F)<<16 | uint32(d.data[4])<<8 | uint32(d.data[5])
// Convert raw values to human-readable values
d.humidity = float32(rawHumidity) / 1048576.0 * 100
d.temperature = float32(rawTemperature)/1048576.0*200 - 50
// Trigger the next measurement
d.data[0] = 0xAC
d.data[1] = 0x33
d.data[2] = 0x00
err = d.bus.Tx(d.Address, d.data[:3], nil)
if err != nil {
return err
}
// Update the previous access time to the current time
d.prevAccessTime = time.Now()
}
return nil
}
// Temperature returns the last measured temperature.
func (d *Device) Temperature() float32 {
return d.temperature
}
// Humidity returns the last measured humidity.
func (d *Device) Humidity() float32 {
return d.humidity
}
+6
View File
@@ -0,0 +1,6 @@
package dht20
// Constants/addresses used for I2C.
// The I2C address which this device listens to.
const defaultAddress = 0x38
+36
View File
@@ -0,0 +1,36 @@
package main
import (
"machine"
"strconv"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/dht20"
)
var (
i2c = machine.I2C0
)
func main() {
i2c.Configure(machine.I2CConfig{})
sensor := dht20.New(i2c)
sensor.Configure()
// Trigger the first measurement
sensor.Update(drivers.AllMeasurements)
for {
time.Sleep(1 * time.Second)
// Update sensor dasta
sensor.Update(drivers.AllMeasurements)
temp := sensor.Temperature()
hum := sensor.Humidity()
// Note: The sensor values are from the previous measurement (1 second ago)
println("Temperature:", strconv.FormatFloat(float64(temp), 'f', 2, 64), "°C")
println("Humidity:", strconv.FormatFloat(float64(hum), 'f', 2, 64), "%")
}
}
+1
View File
@@ -99,6 +99,7 @@ tinygo build -size short -o ./build/test.hex -target=hifive1b ./examples/ssd1351
tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/lis2mdl/main.go
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/max72xx/main.go
tinygo build -size short -o ./build/test.hex -target=feather-m0 ./examples/dht/main.go
tinygo build -size short -o ./build/test.hex -target=feather-m0 ./examples/dht20/main.go
# tinygo build -size short -o ./build/test.hex -target=arduino ./examples/keypad4x4/main.go
tinygo build -size short -o ./build/test.hex -target=feather-rp2040 ./examples/pcf8523/
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/alarm/