Skip to content

Commit d1ace44

Browse files
kenbelldeadprogram
authored andcommitted
aht20: add device
1 parent 6b58fdc commit d1ace44

File tree

6 files changed

+260
-0
lines changed

6 files changed

+260
-0
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,8 @@ endif
187187
@md5sum ./build/test.hex
188188
tinygo build -size short -o ./build/test.hex -target=feather-m0 ./examples/ina260/main.go
189189
@md5sum ./build/test.hex
190+
tinygo build -size short -o ./build/test.hex -target=nucleo-l432kc ./examples/aht20/main.go
191+
@md5sum ./build/test.hex
190192

191193
DRIVERS = $(wildcard */)
192194
NOTESTS = build examples flash semihosting pcd8544 shiftregister st7789 microphone mcp3008 gps microbitmatrix \

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ The following 62 devices are supported.
5858
|----------|-------------|
5959
| [ADT7410 I2C Temperature Sensor](https://www.analog.com/media/en/technical-documentation/data-sheets/ADT7410.pdf) | I2C |
6060
| [ADXL345 accelerometer](http://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf) | I2C |
61+
| [AHT20 I2C Temperature and Humidity Sensor](http://www.aosong.com/userfiles/files/media/AHT20%20%E8%8B%B1%E6%96%87%E7%89%88%E8%AF%B4%E6%98%8E%E4%B9%A6%20A0%2020201222.pdf) | I2C |
6162
| [AMG88xx 8x8 Thermal camera sensor](https://cdn-learn.adafruit.com/assets/assets/000/043/261/original/Grid-EYE_SPECIFICATIONS%28Reference%29.pdf) | I2C |
6263
| [APA102 RGB LED](https://cdn-shop.adafruit.com/product-files/2343/APA102C.pdf) | SPI |
6364
| [AT24CX 2-wire serial EEPROM](https://www.openimpulse.com/blog/wp-content/uploads/wpsc/downloadables/24C32-Datasheet.pdf) | I2C |

aht20/aht20.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package aht20
2+
3+
import (
4+
"time"
5+
6+
"tinygo.org/x/drivers"
7+
)
8+
9+
// Device wraps an I2C connection to an AHT20 device.
10+
type Device struct {
11+
bus drivers.I2C
12+
Address uint16
13+
humidity uint32
14+
temp uint32
15+
}
16+
17+
// New creates a new AHT20 connection. The I2C bus must already be
18+
// configured.
19+
//
20+
// This function only creates the Device object, it does not touch the device.
21+
func New(bus drivers.I2C) Device {
22+
return Device{
23+
bus: bus,
24+
Address: Address,
25+
}
26+
}
27+
28+
// Configure the device
29+
func (d *Device) Configure() {
30+
// Check initialization state
31+
status := d.Status()
32+
if status&0x08 == 1 {
33+
// Device is initialized
34+
return
35+
}
36+
37+
// Force initialization
38+
d.bus.Tx(d.Address, []byte{CMD_INITIALIZE, 0x08, 0x00}, nil)
39+
time.Sleep(10 * time.Millisecond)
40+
}
41+
42+
// Reset the device
43+
func (d *Device) Reset() {
44+
d.bus.Tx(d.Address, []byte{CMD_SOFTRESET}, nil)
45+
}
46+
47+
// Status of the device
48+
func (d *Device) Status() byte {
49+
data := []byte{0}
50+
51+
d.bus.Tx(d.Address, []byte{CMD_STATUS}, data)
52+
53+
return data[0]
54+
}
55+
56+
// Read the temperature and humidity
57+
//
58+
// The actual temperature and humidity are stored
59+
// and can be accessed using `Temp` and `Humidity`.
60+
func (d *Device) Read() error {
61+
d.bus.Tx(d.Address, []byte{CMD_TRIGGER, 0x33, 0x00}, nil)
62+
63+
data := []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
64+
for retry := 0; retry < 3; retry++ {
65+
time.Sleep(80 * time.Millisecond)
66+
err := d.bus.Tx(d.Address, nil, data)
67+
if err != nil {
68+
return err
69+
}
70+
71+
// If measurement complete, store values
72+
if data[0]&0x04 != 0 && data[0]&0x80 == 0 {
73+
d.humidity = uint32(data[1])<<12 | uint32(data[2])<<4 | uint32(data[3])>>4
74+
d.temp = (uint32(data[3])&0xF)<<16 | uint32(data[4])<<8 | uint32(data[5])
75+
return nil
76+
}
77+
}
78+
79+
return ErrTimeout
80+
}
81+
82+
func (d *Device) RawHumidity() uint32 {
83+
return d.humidity
84+
}
85+
86+
func (d *Device) RawTemp() uint32 {
87+
return d.temp
88+
}
89+
90+
func (d *Device) RelHumidity() float32 {
91+
return (float32(d.humidity) * 100) / 0x100000
92+
}
93+
94+
func (d *Device) DeciRelHumidity() int32 {
95+
return (int32(d.humidity) * 1000) / 0x100000
96+
}
97+
98+
// Temperature in degrees celsius
99+
func (d *Device) Celsius() float32 {
100+
return (float32(d.temp*200.0) / 0x100000) - 50
101+
}
102+
103+
// Temperature in mutiples of one tenth of a degree celsius
104+
//
105+
// Using this method avoids floating point calculations.
106+
func (d *Device) DeciCelsius() int32 {
107+
return ((int32(d.temp) * 2000) / 0x100000) - 500
108+
}

aht20/aht20_test.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package aht20
2+
3+
import (
4+
"testing"
5+
6+
qt "github.com/frankban/quicktest"
7+
"tinygo.org/x/drivers/tester"
8+
)
9+
10+
func TestDefaultI2CAddress(t *testing.T) {
11+
c := qt.New(t)
12+
bus := tester.NewI2CBus(c)
13+
dev := New(bus)
14+
c.Assert(uint8(dev.Address), qt.Equals, uint8(Address))
15+
}
16+
17+
func TestInitialization(t *testing.T) {
18+
c := qt.New(t)
19+
bus := tester.NewI2CBus(c)
20+
fdev := tester.NewI2CDeviceCmd(c, Address)
21+
fdev.Commands = defaultCommands()
22+
bus.AddDevice(fdev)
23+
24+
// Set status to uninitialized to force initialization
25+
fdev.Commands[CMD_STATUS].Response[0] = 0x0C
26+
27+
dev := New(bus)
28+
dev.Configure()
29+
30+
// Check initialization command invoked
31+
c.Assert(fdev.Commands[CMD_INITIALIZE].Invocations > 0, qt.Equals, true)
32+
}
33+
34+
func TestRead(t *testing.T) {
35+
c := qt.New(t)
36+
bus := tester.NewI2CBus(c)
37+
fdev := tester.NewI2CDeviceCmd(c, Address)
38+
fdev.Commands = defaultCommands()
39+
bus.AddDevice(fdev)
40+
41+
dev := New(bus)
42+
dev.Read()
43+
44+
// Should be 25deg (250 decidegrees)
45+
c.Assert(dev.DeciCelsius(), qt.Equals, int32(250))
46+
47+
// Should be 36.3% (363 decipercent)
48+
c.Assert(dev.DeciRelHumidity(), qt.Equals, int32(363))
49+
}
50+
51+
func defaultCommands() map[uint8]*tester.Cmd {
52+
return map[uint8]*tester.Cmd{
53+
CMD_INITIALIZE: {
54+
Command: []byte{0xBE},
55+
Mask: []byte{0xFF},
56+
Response: []byte{},
57+
},
58+
CMD_TRIGGER: {
59+
Command: []byte{0xAC, 0x33, 0x00},
60+
Mask: []byte{0xFF, 0xFF, 0xFF},
61+
Response: []byte{0x1C, 0x5D, 0x10, 0x66, 0x01, 0xD2, 0x93},
62+
},
63+
CMD_SOFTRESET: {
64+
Command: []byte{0xBA},
65+
Mask: []byte{0xFF},
66+
Response: []byte{},
67+
},
68+
CMD_STATUS: {
69+
Command: []byte{0x71},
70+
Mask: []byte{0xFF},
71+
Response: []byte{0x1C},
72+
},
73+
}
74+
}

aht20/registers.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package aht20
2+
3+
import "errors"
4+
5+
const (
6+
Address = 0x38
7+
8+
CMD_INITIALIZE = 0xBE
9+
CMD_STATUS = 0x71
10+
CMD_TRIGGER = 0xAC
11+
CMD_SOFTRESET = 0xBA
12+
13+
STATUS_BUSY = 0x80
14+
STATUS_CALIBRATED = 0x08
15+
)
16+
17+
var (
18+
ErrBusy = errors.New("device busy")
19+
ErrTimeout = errors.New("timeout")
20+
)

examples/aht20/main.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package main
2+
3+
import (
4+
"machine"
5+
"time"
6+
7+
"tinygo.org/x/drivers/aht20"
8+
)
9+
10+
func main() {
11+
machine.I2C0.Configure(machine.I2CConfig{})
12+
13+
dev := aht20.New(machine.I2C0)
14+
dev.Configure()
15+
16+
dev.Reset()
17+
for {
18+
time.Sleep(500 * time.Millisecond)
19+
20+
err := dev.Read()
21+
if err != nil {
22+
println("Error", err)
23+
continue
24+
}
25+
26+
println("temp ", fmtD(dev.DeciCelsius(), 3, 1), "C")
27+
println("humidity", fmtD(dev.DeciRelHumidity(), 3, 1), "%")
28+
}
29+
}
30+
31+
func fmtD(val int32, i int, f int) string {
32+
result := make([]byte, i+f+1)
33+
neg := false
34+
35+
if val < 0 {
36+
val = -val
37+
neg = true
38+
}
39+
40+
for p := len(result) - 1; p >= 0; p-- {
41+
result[p] = byte(int32('0') + (val % 10))
42+
val = val / 10
43+
44+
if p == i+1 && p > 0 {
45+
p--
46+
result[p] = '.'
47+
}
48+
}
49+
50+
if neg {
51+
result[0] = '-'
52+
}
53+
54+
return string(result)
55+
}

0 commit comments

Comments
 (0)