简介
树莓派其实本身包含很多资源引脚, 合理利用其实可以自制智能家居的一部分,本身硬件和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实现树莓派超声波测距



















