简介
树莓派其实本身包含很多资源引脚, 合理利用其实可以自制智能家居的一部分,本身硬件和Linux系统等高级语言支持加生态, 不说了,
做就好了…
I2C 功能开启
参考之前的文章就可以了 Go实现树莓派读取bh1750光照强度
查看I2C总线上SHT30的设备地址
树莓派上两路i2c总线, 我们连接的是第一路,指令也是 -y 1, 如下
i2cdetect -y 1
为什么是0x44, 接着向下看, SHT3x默认地址就是0x44, 当Addr引脚接地则地址是0x44, 接VCC则是0x45, 电路图如下, 所以地址是0x44
代码
sht30.go
package sensor
import (
"context"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/gpio/gpioreg"
"time"
)
type SHT3xOption struct {
I2COption
OnAlerted func()
AlertPinNum PinNum
}
type SHT30TemperatureValue struct {
value int64
}
func (v SHT30TemperatureValue) Fahrenheit() float32 {
return -49.0 + (315.0 * float32(v.value) / 65535.0)
}
func (v SHT30TemperatureValue) Celsius() float32 {
return -49.0 + (175.0 * float32(v.value) / 65535.0)
}
type SHT30Value struct {
temperature SHT30TemperatureValue
humidity float32
}
func (s *SHT30Value) setValues(temp int64, hum int64) {
s.temperature.value = temp
s.humidity = 100.0 * (float32(hum) / 65535.0)
}
func (s *SHT30Value) Humidity() float32 {
return s.humidity
}
func (s *SHT30Value) Temperature() SHT30TemperatureValue {
return s.temperature
}
type SHT30Sensor struct {
opt SHT3xOption
alertPin gpio.PinIn
i2cDevice
cancalFunc context.CancelFunc
}
func NewSHT30Sensor(opt SHT3xOption) (*SHT30Sensor, error) {
var (
sensor = &SHT30Sensor{
opt: opt,
}
)
if opt.AlertPinNum > 0 {
sensor.alertPin = gpioreg.ByName(opt.AlertPinNum.String())
if nil == sensor.alertPin {
return nil, CantFindPinError
}
}
sensor.setDeviceInfo(opt.I2COption)
return sensor, nil
}
func (sensor *SHT30Sensor) Init() (err error) {
if err = sensor.init(); nil != err {
return err
}
if nil != sensor.opt.OnAlerted && nil != sensor.alertPin {
err = sensor.alertPin.In(gpio.PullNoChange, gpio.NoEdge)
if nil != err {
return err
}
var ctx context.Context
ctx, sensor.cancalFunc = context.WithCancel(context.Background())
go sensor.monitorAlertPin(ctx)
}
//if err = sensor.reset(); nil != err {
// return err
//}
return
}
func (sensor *SHT30Sensor) Destroy() error {
if nil != sensor.cancalFunc {
sensor.cancalFunc()
sensor.cancalFunc = nil
}
return nil
}
func (sensor *SHT30Sensor) GetValue() (v SHT30Value, err error) {
var (
sendBytes = []byte{0xE0, 0x00} // read command
recvBytes = make([]byte, 6)
temp, hum int64
)
err = sensor.dev.Tx(sendBytes, recvBytes)
if nil != err {
return
}
if !sensor.checksumCompare(recvBytes[:2], recvBytes[2]) {
err = CRCCheckFailedError
return
}
if !sensor.checksumCompare(recvBytes[3:5], recvBytes[5]) {
err = CRCCheckFailedError
return
}
temp = int64(recvBytes[0])<<8 | int64(recvBytes[1])
v.temperature.value = temp
hum = int64(recvBytes[3])<<8 | int64(recvBytes[4])
v.setValues(temp, hum)
return
}
/*
同硬件上nReset相同, 但这里是软件发送指令, 硬件是引脚触发, 不再响应指令
目前调用就会报错,所以直接返回
*/
func (sensor *SHT30Sensor) reset() error {
var (
sendBytes = []byte{0x30, 0xA2} // 软重置
)
_, err := sensor.dev.Write(sendBytes)
if nil != err {
return err
}
time.Sleep(time.Millisecond * (15 + 1)) // 软重置最长时间 1ms, 可能后续需要考虑指令取消, 最长15ms,目前先跟数据手册单个指令时间来
return err
}
/*
设置测量周期
mps 0.5, 指令 0x20, 0x32/0x24/0x2F(High/Medium/Low)
mps 1 , 指令 0x21, 0x30/0x26/0x2D(High/Medium/Low)
mps 2 , 指令 0x22, 0x36/0x20/0x2B(High/Medium/Low)
mps 4 , 指令 0x23, 0x34/0x22/0x29(High/Medium/Low)
mps 10 , 指令 0x27, 0x37/0x21/0x2A(High/Medium/Low)
*/
func (sensor *SHT30Sensor) init() error {
var (
sendBytes = []byte{0x22, 0x36}
)
_, err := sensor.dev.Write(sendBytes)
if nil != err {
return err
}
time.Sleep(time.Millisecond * 15)
return err
}
func (sensor *SHT30Sensor) checksumCompare(dat []byte, checksum byte) bool {
var crc = sensor.crc8(dat)
return crc == checksum
}
func (sensor *SHT30Sensor) crc8(dat []byte) byte {
var polynomial = byte(0x31) // 多项式值
var crc byte = 0xFF // 初始化值
for _, v := range dat {
crc ^= v
for i := 0; i < 8; i++ {
if (crc & 0x80) != 0 {
crc = (crc << 1) ^ polynomial
} else {
crc <<= 1
}
crc &= 0xFF // 保持 crc 为 8 位
}
}
return crc
}
func (sensor *SHT30Sensor) monitorAlertPin(ctx context.Context) {
var (
triggered bool // 用于确保不会反复提醒...
)
for {
if gpio.Low == sensor.alertPin.Read() {
if !triggered {
go sensor.opt.OnAlerted()
triggered = true
}
} else {
if triggered {
triggered = false
}
}
select {
case <-ctx.Done():
return
case <-time.After(time.Millisecond * 10):
}
}
}
使用代码
main.go
package main
import (
"IntelligentAgriculture/sensor"
"fmt"
"periph.io/x/conn/v3/i2c/i2creg"
"time"
)
const (
AlertPinNum = 27
MotorPinNum = 17
LEDPinNum = 22
I2CSHT30Addr = 0x44
I2CAt24C02Addr = 0x50
I2CBH1750Addr = 0x23
)
func main() {
i2cBus, err := i2creg.Open("")
if nil != err {
fmt.Println("i2creg.Open:", err)
return
}
defer i2cBus.Close()
s, err := sensor.NewSHT30Sensor(sensor.SHT3xOption{
OnAlerted: func() {
fmt.Println("alerted!!!")
},
AlertPinNum: AlertPinNum,
I2COption: sensor.I2COption{
I2CBus: i2cBus,
DeviceAddress: I2CSHT30Addr,
},
})
if nil != err {
fmt.Println("sensor.NewSHT30Sensor:", err)
return
}
defer s.Destroy()
err = s.Init()
if nil != err {
fmt.Println("sensor.Init:", err)
return
}
for {
v, err := s.GetValue()
if nil != err {
fmt.Println("sensor.GetValue: ", err)
continue
}
fmt.Printf("%0.2f℃, %0.2f℉, %0.2f(RH)\n", v.Temperature().Celsius(), v.Temperature().Fahrenheit(), v.Humidity())
time.Sleep(time.Second)
}
}
其他文章
Go实现树莓派读取bh1750光照强度
Go实现树莓派读取at24c02 eeprom读写数据
Go实现树莓派控制舵机
Go实现树莓派超声波测距