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

news2024/11/19 6:18:04

简介

树莓派其实本身包含很多资源引脚, 合理利用其实可以自制智能家居的一部分,本身硬件和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.coloradmin.cn/o/1662088.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux性能监控之top

说完了atop和htop&#xff0c;我们在来说说Linux自带的top&#xff0c;我们先看看命令效果&#xff1a; 可以看到是一个实时的系统监控工具&#xff0c;提供了一个动态的、交互式的实时视图&#xff0c;显示系统的整体性能信息以及正在运行的进程的相关信息。 我们先来解析下命…

重学java 35.API 6.包装类

心有所念&#xff0c;必有所灵 —— 24.5.10 一、基本数据类型对应的引用数据类型(包装类) 1概述 就是基本类型所对应的类&#xff08;包装类&#xff09;&#xff0c;我们需要将基本类型转为包装类&#xff0c;从而让基本类型拥有类的特性&#xff08;是基本类型可以使用包装类…

聊聊ChatGPT:智能语言模型背后的原理

目录 1. ChatGPT的基础&#xff1a;GPT模型 2. 预训练与微调&#xff1a;让模型更加智能 2.1 预训练 2.2 微调 3. 多样化的应用场景 4. 未来的展望 5. 结语 在当今的人工智能领域&#xff0c;OpenAI的ChatGPT无疑是一个炙手可热的话题。它不仅能流畅地进行对话&#xff…

Databend 开源周报第 143 期

Databend 是一款现代云数仓。专为弹性和高效设计&#xff0c;为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务&#xff1a;https://app.databend.cn 。 Whats On In Databend 探索 Databend 本周新进展&#xff0c;遇到更贴近你心意的 Databend 。 了解 Databend …

工控组态技术:实现工业自动化控制的重要手段

体验地址&#xff1a;by组态[web组态插件] 工控组态技术是一种应用于工业自动化控制领域的重要技术&#xff0c;它通过将各种不同的硬件设备和软件系统进行组合和配置&#xff0c;实现了工业生产过程的自动化控制和优化。 随着工业技术的不断发展和进步&#xff0c;工控组态技…

解锁Spring Cloud Gateway与Nginx最強配置,构建未来网络高速公路!(下)

文章目录 5. 监控与日志5.1 Nginx访问日志与错误日志配置访问日志配置错误日志配置 5.2 Spring Cloud Gateway的日志记录与监控集成日志记录监控集成微服务监控 6. 故障排查与常见问题6.1 配置错误常见原因与解决语法错误监听端口冲突路由规则不匹配 6.2 性能瓶颈识别与优化建议…

Navicat Data Modeler Ess for Mac:强大的数据库建模设计软件

Navicat Data Modeler Ess for Mac是一款专为Mac用户设计的数据库建模与设计工具&#xff0c;凭借其强大的功能和直观的界面&#xff0c;帮助用户轻松构建和管理复杂的数据库模型。 Navicat Data Modeler Ess for Mac v3.3.17中文直装版下载 这款软件支持多种数据库系统&#x…

OmniPlan Pro 4 for Mac中文激活版:项目管理的新选择

OmniPlan Pro 4 for Mac作为一款专为Mac用户设计的项目管理软件&#xff0c;为用户提供了全新的项目管理体验。其直观易用的界面和强大的功能特性&#xff0c;使用户能够轻松上手并快速掌握项目管理要点。 首先&#xff0c;OmniPlan Pro 4 for Mac支持自定义视图&#xff0c;用…

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

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

开源相机管理库Aravis例程学习(七)——chunk-parser

开源相机管理库Aravis例程学习&#xff08;七&#xff09;——chunk-parser 简介例程代码函数说明arv_camera_create_chunk_parserarv_camera_set_chunksarv_chunk_parser_get_integer_value 简介 本文针对官方例程中的&#xff1a;05-chunk-parser做简单的讲解。并介绍其中调…

钓场是怎么收费看时间的,钓鱼钓虾计时计费管理系统软件

钓场是怎么收费看时间的&#xff0c;钓鱼钓虾计时计费管理系统软件 一、前言 以下软件操作教程以&#xff0c;佳易王钓场计时计费管理软件为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 佳易王钓场计时计费管理软件&#xff0c;支持百人或千人…

sql-labs通关详解(1-10)

1.less-1 1.判断类型 由此判断是字符型漏洞由单引号闭合。 2.判断 字段个数 http://192.168.190.145/sqli-labs/Less-1/?id1 order by 3-- 3.获取数据库名 -1 union select 1,2,database()-- 4.获取表名 -1 union select 1,2,group_concat(table_name) from information_…

权限束缚术--权限提升你需要知道这些

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文主要对渗透测试中权限提升的一些基础知识进行整理 并不包含权限提升的具体操作 适合要入门权限提升的朋友 提权的重要性 我们在渗透网站时&#xff0c;我们往往会拿到一些权限&#xff0c;但是我们的权限有…

目标检测算法YOLOv7简介

YOLOv7由Chien-Yao Wang等人于2022年提出&#xff0c;论文名为&#xff1a;《YOLOv7: Trainable bag-of-freebies sets new state-of-the-art for real-time object detectors》&#xff0c;论文见&#xff1a;https://arxiv.org/pdf/2207.02696 &#xff0c;项目网页&#xff…

HC-05的简介与使用

蓝牙概述 蓝牙&#xff08;Bluetooth&#xff09;是一种用于无线通信的技术标准&#xff0c;允许设备在短距离内进行数据交换和通信。它是由爱立信&#xff08;Ericsson&#xff09;公司在1994年推出的&#xff0c;以取代传统的有线连接方式&#xff0c;使设备之间能够实现低功…

Ansible-Playbook通过role角色部署Lnmp架构

目录​​​​​​​ 一、配置Nginx的Roles角色 1.1编写files/default.conf 1.2编写files/nginx.repo 1.3编写handlers/main.yml 1.4编写tasks/main.yml文件 1.5编写vars/main.yml文件 1.6测试运行结果&#xff0c;并不是真的执行任务 二、配置Mysql的Roles角色 2.1编写…

vue-fontawesome-elementui-icon-picker选择icon框架

第一步&#xff1a;安装vue-fontawesome-elementui-icon-picker依赖 npm install vue-fontawesome-elementui-icon-picker --save-dev 第二步&#xff1a;main.js配置 (放在element ui引入之后) import iconPicker from vue-fontawesome-elementui-icon-picker; Vue.use(ico…

day2_greedyIntervalsLRU/LFU

二、贪心算法之区间调度问题 0.计算一个区间集合中无重复的区间的最大数量(模板) public int intervalSchedule(int[][] intvs) {if (intvs.length 0) return 0;// 按 end 升序排序Arrays.sort(intvs, (a, b) -> Integer.compare(a[1], b[1]));// 至少有一个区间不相交in…

Web3 Tools - Base58

Base58编码 Base58编码是一种用于表示数字的非常见的编码方法。它通常用于加密货币领域&#xff0c;例如比特币和其他加密货币的地址表示。 什么是Base58编码&#xff1f; Base58编码是一种将数字转换为人类可读形式的编码方法。与常见的Base64编码不同&#xff0c;Base58编码…

Docker常用镜像安装

1. mysql 1.1 安装 获取镜像 docker pull mysql:8.0.30创建文件挂载目录 创建容器并运行 docker run -p 3306:3306 --name mysql8 \ -v /home/docker/mysql8/log:/var/log/mysql \ -v /home/docker/mysql8/data:/var/lib/mysql \ -v /home/docker/mysql8/mysql-files:/va…