简介
树莓派其实本身包含很多资源引脚, 合理利用其实可以自制智能家居的一部分,本身硬件和Linux系统等高级语言支持加生态, 不说了,
做就好了…
I2C 功能开启
参考之前的文章就可以了 Go实现树莓派读取bh1750光照强度
查看I2C总线上SHT30的设备地址
树莓派上两路i2c总线, 我们连接的是第一路,指令也是 -y 1, 如下
i2cdetect -y 1
为什么是0x44, 接着向下看, SHT3x默认地址就是0x44, 当Addr引脚接地则地址是0x44, 接VCC则是0x45, 电路图如下, 所以地址是0x44
代码
sht30.go
package sensorimport ("context""periph.io/x/conn/v3/gpio""periph.io/x/conn/v3/gpio/gpioreg""time"
)type SHT3xOption struct {I2COptionOnAlerted 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 SHT30TemperatureValuehumidity float32
}func (s *SHT30Value) setValues(temp int64, hum int64) {s.temperature.value = temps.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 SHT3xOptionalertPin gpio.PinIni2cDevicecancalFunc 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.Contextctx, 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 commandrecvBytes = make([]byte, 6)temp, hum int64)err = sensor.dev.Tx(sendBytes, recvBytes)if nil != err {return}if !sensor.checksumCompare(recvBytes[:2], recvBytes[2]) {err = CRCCheckFailedErrorreturn}if !sensor.checksumCompare(recvBytes[3:5], recvBytes[5]) {err = CRCCheckFailedErrorreturn}temp = int64(recvBytes[0])<<8 | int64(recvBytes[1])v.temperature.value = temphum = 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 ^= vfor 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():returncase <-time.After(time.Millisecond * 10):}}
}
使用代码
main.go
package mainimport ("IntelligentAgriculture/sensor""fmt""periph.io/x/conn/v3/i2c/i2creg""time"
)const (AlertPinNum = 27MotorPinNum = 17LEDPinNum = 22I2CSHT30Addr = 0x44I2CAt24C02Addr = 0x50I2CBH1750Addr = 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实现树莓派超声波测距