Go实现树莓派I2C读取SHT30温度湿度传感器

简介

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/612481.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大米自动化生产线揭秘:包装设备选择与维护之道

在现代化的大米生产过程中&#xff0c;自动化生产线的应用已经越来越广泛。其中&#xff0c;包装设备作为生产线上的重要一环&#xff0c;其选择与维护直接关系到产品的质量和生产效率。与星派一起探讨大米自动化生产线中包装设备的选择与维护之道。 一、包装设备的选择 在选择…

寻找最大价值的矿堆 - 矩阵

系列文章目录 文章目录 系列文章目录前言一、题目描述二、输入描述三、输出描述四、Java代码五、测试用例 前言 本人最近再练习算法&#xff0c;所以会发布一些解题思路&#xff0c;希望大家多指教 一、题目描述 给你一个由’0’(空地)、‘1’(银矿)、‘2’(金矿)组成的地图…

Element快速上手!

Element是饿了么公司前端团队开发的一套基于Vue的组件库&#xff0c;用于快速构建网页~ 官网链接&#xff1a; Element - The worlds most popular Vue UI frameworkElement&#xff0c;一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库https://element.elem…

未授权访问:Memcached 未授权访问漏洞

目录 1、漏洞原理 2、环境搭建 3、未授权访问 防御手段 今天继续学习各种未授权访问的知识和相关的实操实验&#xff0c;一共有好多篇&#xff0c;内容主要是参考先知社区的一位大佬的关于未授权访问的好文章&#xff0c;还有其他大佬总结好的文章&#xff1a; 这里附上大…

求阶乘n!末尾0的个数溢出了怎么办

小林最近遇到一个问题&#xff1a;“对于任意给定的一个正整数n&#xff0c;统计其阶乘n&#xff01;的末尾中0的个数”&#xff0c;这个问题究竟该如何解决&#xff1f; 先用n5来解决这个问题。n的阶乘即n!5!5*4*3*2*1120&#xff0c;显然应该为2个数相乘等于10才能得到一个结…

AI大模型探索之路-训练篇20:大语言模型预训练-常见微调技术对比

系列篇章&#x1f4a5; AI大模型探索之路-训练篇1&#xff1a;大语言模型微调基础认知 AI大模型探索之路-训练篇2&#xff1a;大语言模型预训练基础认知 AI大模型探索之路-训练篇3&#xff1a;大语言模型全景解读 AI大模型探索之路-训练篇4&#xff1a;大语言模型训练数据集概…

Xilinx 千兆以太网TEMAC IP核简介

Xilinx 公司提供了千兆以太网MAC控制器的可参数化LogiCORET™IP解决方案&#xff0c;通过这个IPCore可以实现FPGA与外部网络物理层芯片的互连。基于Xilinx FPGA 的以太网设计&#xff0c;大大降低了工程的设计复杂度&#xff0c;缩短了开发周期&#xff0c;加快了产品的面市速度…

大数据Scala教程从入门到精通第六篇:Scala源文件编写和运行

一&#xff1a;Scala源文件编写和运行 1&#xff1a;源代码比较 public class HelloJava{public static void main(String[] args){System.out.println("hello scala")} } object HelloScala{//用于声明方法 入参是一个String类型的数组。返回值类型为空def main…

用云手机打造海外社媒矩阵

在全球经济一体化的大背景下&#xff0c;中国出海企业及B2B外贸公司正将海外社交媒体营销作为重要的市场拓展策略。为更好地触及不同受众群体&#xff0c;构建跨平台的社媒矩阵已成为企业营销的关键步骤。本文将探讨如何利用云手机技术&#xff0c;高效管理并运营多个海外社交媒…

泰迪智能科技携手新乡学院开展“泰迪智能双创工作室”共建交流会

为深化校企合作&#xff0c;实现应用型人才培养目标。5月8日&#xff0c;广东泰迪智能科技股份有限公司河南分公司市场总监张京瑞到访新乡学院数学与统计学院参观交流&#xff0c;数学与统计学院院长赵国喜、副院长皮磊、张秦&#xff0c;教研室主任许寿方、姚广出席本次交流会…

【研发日记】Matlab/Simulink避坑指南(十二)——Initialize Function执行Bug

文章目录 前言 背景介绍 问题描述 分析排查 解决方案 总结归纳 前言 见《研发日记&#xff0c;Matlab/Simulink避坑指南(七)——数据溢出钳位Bug》 见《研发日记&#xff0c;Matlab/Simulink避坑指南(八)——else if分支结构Bug》 见《研发日记&#xff0c;Matlab/Simuli…

【matlab基础知识代码】(十六)代数方程的图解法多项式型方程的准解析解方法

>> ezplot(exp(-3*t)*sin(4*t2)4*exp(-0.5*t)*cos(2*t)-0.5,[0 5]), line([0 5],[0 0]) 验证 >> t0.6738; >> exp(-3*t)*sin(4*t2)4*exp(-0.5*t)*cos(2*t)-0.5 ans -2.9852e-04 >> ezplot(x^2*exp(-x*y^2/2)exp(-x/2)*sin(x*y)) >> hold on; …

使用hdc TCP模式无线方式连接OpenHarmony设备

本文将介绍如何使用hdc工具 tcp模式以无线的方式连接OpenHarmony设备。 1. usb连接方式切换为tcp模式。 将usb线将OpenHarmony设备和电脑端连接&#xff0c;并且将两个连接至同一个局域网。 # 执行 tmode port port-number&#xff0c;port-number设置为端口号。 hdc tmode …

2024年首季:AGV项目大盘点,有过1亿的项目

导语 大家好&#xff0c;我是智能仓储物流技术研习社的社长&#xff0c;老K。专注分享智能仓储物流技术、智能制造等内容。 新书《智能物流系统构成与技术实践》 2024年第一季度&#xff0c;中国智慧物流行业迎来了一个重要的里程碑。 根据新战略移动机器人产业研究所的初步统计…

如何用python的Turtle绘画?

目录 一、画一个圆和正方形 二、简单的方式来画一个美女 三、Turtle是一个用于绘制图形的标准库 一、画一个圆和正方形 import turtle# 创建一个图形窗口 window turtle.Screen() window.bgcolor("white")# 创建一个海龟画笔 pen turtle.Turtle() pen.shape(&q…

鸿蒙内核源码分析(VFS篇) | 文件系统和谐共处的基础

基本概念 | 官方定义 VFS&#xff08;Virtual File System&#xff09;是文件系统的虚拟层&#xff0c;它不是一个实际的文件系统&#xff0c;而是一个异构文件系统之上的软件粘合层&#xff0c;为用户提供统一的类Unix文件操作接口。由于不同类型的文件系统接口不统一&#x…

nginx配置文件和配置命令详解案例

一.nginx.conf配置结构 1.1配置结构图 1.2 nginx中配置nginx.conf配置内容 #user nobody; user root; # 表示worker进程是有root用户去执行的 worker_processes 2; events {# 默认使用epolluse epoll;# 每个worker链接最大数据worker_connections 1024; } http {include …

PCIE协议-2-事务层规范-MEM/IO/CFG request rules

2.2.7 内存、I/O和配置请求规则 以下规则适用于所有内存、I/O和配置请求。每种类型的请求还有特定的额外规则。 所有内存、I/O和配置请求除了常见的头标字段外&#xff0c;还包括以下字段&#xff1a;requester ID[15:0]和Tag[9:0]&#xff0c;形成事务ID。Last DW BE[3:0] a…

uniapp百度地图聚合

// loadBMap.js ak 百度key export default function loadBMap(ak) {return new Promise((resolve, reject) > {//聚合API依赖基础库,因此先加载基础库再加载聚合APIasyncLoadBaiduJs(ak).then(() > {// 调用加载第三方组件js公共方法加载其他资源库// 加载聚合API// Ma…

定时任务执行 报错command not found 解决方案

目录 写在前面所需知识 问题复现解决方式方法1. 使用绝对路径的命令&#xff1a;方法2. 重新加载环境变量&#xff1a;成功解决截图 原理 写在前面 定时任务脚本出现command not found报错&#xff0c;解决方案。 所需知识 定时任务shell脚本环境变量 问题复现 编写了一个…