GD32F470_GY-SHT31-D 数字温湿度传感器模块移植

news2025/1/15 10:44:37

2.11 SHT30温湿度传感器
2.11.1 模块来源
采购链接:
GY-SHT31-D 数字温湿度传感器模块
资料下载链接:
https://pan.baidu.com/s/1kisMJspcV6Qdr1ye9ElOlQ

2.11.2 规格参数
工作电压:2.4-5.5V
工作电流:0.2~1500uA
温度测量范围:-40~125℃
温度测量精度:±0.3℃
湿度测量范围:0~100%RH
湿度测量精度:±2%RH
输出方式: IIC
管脚数量:4 Pin
暂时无法在飞书文档外展示此内容
文件2.11.2-1 产品规格书

工作电流:0.2~1500uA
温度测量范围:-40~125℃
温度测量精度:±0.3℃
湿度测量范围:0~100%RH
湿度测量精度:±2%RH
输出方式: IIC
管脚数量:4 Pin

2.11.3 移植过程
我们的目标是在梁山派GD32F470上能够测量温湿度的功能。首先要获取资料,查看数据手册应如何实现,再移植至我们的工程。
2.11.3.1 查看资料
模块原理图
在这里插入图片描述
SHT30地址
数据手册上说明,当ADDR引脚接入VSS(接地)时,地址为0X44。而原理图上已经通过R14这个下拉电阻接地。不过需要注意的是,实际地址为0X44左移一位,因需要空出最低位给读写位,所以实际的地址是 0X44<<1。
在这里插入图片描述

测量模式
SHT30有两种测量模式,分别是单次测量模式和周期测量模式。
在单次测量模式下,发出一个测量命令就触发一次数据采集。每个数据都由一个16位的温度值和一个16位的湿度值(按此顺序)组成。在传输过程中,每个数据值后面总是跟着一个CRC校验和。但是在该模式下又分有时钟拉伸模式和时钟不拉伸模式,具体情况见下图。
在这里插入图片描述
并且在单次测量模式下,可以选择不同的测量命令。它们在可重复性(低、中、高)和时钟拉伸(启用或禁用)方面有所不同。这里的可重复性设置影响测量持续时间,从而影响传感器的总体能耗。
在这里插入图片描述
在周期测量模式下,时钟拉伸模式禁用,但是可以分为高中低的可重复性测量,测量周期为0.5、1、2、4、10(单位 次/秒)(这种模式下最快的测量速度是1秒10次)如果传感器在一种工作模式下正在测量数据,此时要发送其他命令(推荐先发送一次中断命令),让传感器停止当前的测量,进入单次测量模式,然后再发送命令。这里需要注意:如果测量频率过高,会导致传感器自热。
在这里插入图片描述
设置好周期测量模式的测量周期和可重复性强度后,随时可以进行测量读取数据,需要发送一个读取命令(0XE000)。一旦读取时序结束之后,寄存器中的数值就会清零,如果这时再一次读取数据将得到0。下一次测量结束后,寄存器的值就会重新写入。
在这里插入图片描述

2.11.3.2 引脚选择

SHT30立创·梁山派
VIN5V
GNDGND
SCLPB9
SDAPB8

在这里插入图片描述
2.11.3.3 移植至工程
移植步骤中的导入.c和.h文件与上一节相同,只是将.c和.h文件更改为bsp_sht30.c与bsp_sht30.h。见2.2.3.3 移植至工程。这里不再过多讲述。移植完成后面修改相关代码。
在文件bsp_sht30.c中,编写如下代码。

/********************************************************************************
  * 文 件 名: bsp_sht30.c
  * 版 本 号: 初版
  * 修改作者: LC
  * 修改日期: 2023年04月19日
  * 功能介绍:          
  ******************************************************************************
  * 注意事项:
*********************************************************************************/

#include "bsp_sht30.h"
#include "bsp_usart.h"
#include "stdio.h"
#include "systick.h"

//端口移植
#define RCU_SDA RCU_GPIOB
#define PORT_SDA GPIOB
#define GPIO_SDA GPIO_PIN_8

#define RCU_SCL RCU_GPIOB
#define PORT_SCL GPIOB
#define GPIO_SCL GPIO_PIN_9

//设置SDA输出模式
#define SDA_OUT()        gpio_mode_set(PORT_SDA,GPIO_MODE_OUTPUT,GPIO_MODE_OUTPUT,GPIO_SDA)
//设置SDA输入模式
#define SDA_IN()        gpio_mode_set(PORT_SDA,GPIO_MODE_INPUT,GPIO_MODE_OUTPUT,GPIO_SDA)
//获取SDA引脚的电平变化
#define SDA_GET()        gpio_input_bit_get(PORT_SDA,GPIO_SDA)
//SDA与SCL输出
#define SDA(x)          gpio_bit_write(PORT_SDA,GPIO_SDA, (x?SET:RESET))
#define SCL(x)          gpio_bit_write(PORT_SCL,GPIO_SCL, (x?SET:RESET))

double Temperature = 0.0, Humidity = 0.0;

/******************************************************************
 * 函 数 名 称:SHT30_GPIO_Init
 * 函 数 说 明:SHT30的引脚初始化
 * 函 数 形 参:无
 * 函 数 返 回:无
 * 作       者:LC
 * 备       注:无
******************************************************************/
void SHT30_GPIO_Init(void)
{
  /* 使能时钟 */
    rcu_periph_clock_enable(RCU_SCL);
        rcu_periph_clock_enable(RCU_SDA);
    
        /* 配置SCL为输出模式 */
        gpio_mode_set(PORT_SCL,GPIO_MODE_OUTPUT,GPIO_PUPD_NONE,GPIO_SCL);
        /* 配置为推挽输出 50MHZ */
        gpio_output_options_set(PORT_SCL,GPIO_OTYPE_PP,GPIO_OSPEED_50MHZ,GPIO_SCL);
        
        /* 配置SDA为输出模式 */
        gpio_mode_set(PORT_SDA,GPIO_MODE_OUTPUT,GPIO_PUPD_NONE,GPIO_SDA);
        /* 配置为推挽输出 50MHZ */
        gpio_output_options_set(PORT_SDA,GPIO_OTYPE_PP,GPIO_OSPEED_50MHZ,GPIO_SDA);
}


/******************************************************************
 * 函 数 名 称:IIC_Start
 * 函 数 说 明:IIC起始时序
 * 函 数 形 参:无
 * 函 数 返 回:无
 * 作       者:LC
 * 备       注:无
******************************************************************/
void IIC_Start(void)
{
        SDA_OUT();
        SCL(1); 
        SDA(0);
        
        SDA(1);
        delay_us(5);
        SDA(0);
        delay_us(5);
                       
        SCL(0);
}
/******************************************************************
 * 函 数 名 称:IIC_Stop
 * 函 数 说 明:IIC停止信号
 * 函 数 形 参:无
 * 函 数 返 回:无
 * 作       者:LC
 * 备       注:无
******************************************************************/
void IIC_Stop(void)
{
        SDA_OUT();
        SCL(0);
        SDA(0);
        
        SCL(1);
        delay_us(5);
        SDA(1);
        delay_us(5);
        
}

/******************************************************************
 * 函 数 名 称:IIC_Send_Ack
 * 函 数 说 明:主机发送应答或者非应答信号
 * 函 数 形 参:0发送应答  1发送非应答
 * 函 数 返 回:无
 * 作       者:LC
 * 备       注:无
******************************************************************/
void IIC_Send_Ack(unsigned char ack)
{
        SDA_OUT();
        SCL(0);
        SDA(0);
        delay_us(5);
        if(!ack) SDA(0);
        else         SDA(1);
        SCL(1);
        delay_us(5);
        SCL(0);
        SDA(1);
}


/******************************************************************
 * 函 数 名 称:I2C_WaitAck
 * 函 数 说 明:等待从机应答
 * 函 数 形 参:无
 * 函 数 返 回:0有应答  1超时无应答
 * 作       者:LC
 * 备       注:无
******************************************************************/
unsigned char I2C_WaitAck(void)
{
        
        char ack = 0;
        unsigned char ack_flag = 10;
        SCL(0);
        SDA(1);
        SDA_IN();
        
        SCL(1);
        while( (SDA_GET()==1) && ( ack_flag ) )
        {
                ack_flag--;
                delay_us(5);
        }
        
        if( ack_flag <= 0 )
        {
                IIC_Stop();
                return 1;
        }
        else
        {
                SCL(0);
                SDA_OUT();
        }
        return ack;
}

/******************************************************************
 * 函 数 名 称:Send_Byte
 * 函 数 说 明:写入一个字节
 * 函 数 形 参:dat要写人的数据
 * 函 数 返 回:无
 * 作       者:LC
 * 备       注:无
******************************************************************/
void Send_Byte(u8 dat)
{
        int i = 0;
        SDA_OUT();
        SCL(0);//拉低时钟开始数据传输
        
        for( i = 0; i < 8; i++ )
        {
                SDA( (dat & 0x80) >> 7 );
                __nop();
                SCL(1);
                delay_us(5);
                SCL(0);
                delay_us(5);
                dat<<=1;
        }        
}

/******************************************************************
 * 函 数 名 称:Read_Byte
 * 函 数 说 明:IIC读时序
 * 函 数 形 参:无
 * 函 数 返 回:读到的数据
 * 作       者:LC
 * 备       注:无
******************************************************************/
unsigned char Read_Byte(void)
{
        unsigned char i,receive=0;
        SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
        {
        SCL(0);
        delay_us(5);
        SCL(1);
        delay_us(5);
        receive<<=1;
        if( SDA_GET() )
        {        
            receive|=1;   
        }
        delay_us(5); 
    }                                         
        SCL(0); 
  return receive;
}

/******************************************************************
 * 函 数 名 称:SHT31_Write_mode
 * 函 数 说 明:在周期模式下设置测量周期与可重复性命令
 * 函 数 形 参:dat设置命令
                常用的有:每一秒采集0.5次  0x2024
                          每一秒采集1次    0x2126
                          每一秒采集2次    0x2220
                          每一秒采集4次    0x2334
                          每一秒采集10次   0x2721  
 * 函 数 返 回:
 * 作       者:LC
 * 备       注:
******************************************************************/
char SHT31_Write_mode(uint16_t dat)
{
        IIC_Start();
        
        // << 1 是将最后一位置0,设置为写命令
        Send_Byte((0X44 << 1) | 0 );
        //返回0为产生了应答,返回1说明通信失败
        if( I2C_WaitAck() == 1 )return 1;
        //发送命令的高8位
        Send_Byte((dat >> 8 ) );
        //返回0为产生了应答,返回1说明通信失败
        if( I2C_WaitAck() == 1 )return 2;
        //发送命令的低8位
        Send_Byte(dat & 0xff );
        //返回0为产生了应答,返回1说明通信失败
        if( I2C_WaitAck() == 1 )return 3;
//        IIC_Stop();
        return 0;
}

/******************************************************************
 * 函 数 名 称:crc8
 * 函 数 说 明:CRC校验
 * 函 数 形 参:data要校验的数据地址     len要校验的长度
 * 函 数 返 回:校验后的值
 * 作       者:LC
 * 备       注:无
******************************************************************/
unsigned char crc8(const unsigned char *data, int len)
{
        const unsigned char POLYNOMIAL = 0x31;
        unsigned char crc = 0xFF;
        int j, i;

        for (j=0; j<len; j++)
        {                  
                crc ^= *data++;
                for ( i = 0; i <8; i++ )
                {
                        crc = ( crc & 0x80 ) ? (crc << 1) ^ POLYNOMIAL : (crc << 1); 
                }                                                            
        }
        return crc;
}

/******************************************************************
 * 函 数 名 称:SHT30_Read
 * 函 数 说 明:读取温湿度值
 * 函 数 形 参:dat读取的命令
                周期模式命令为:0xe000
                单次模式命令为:0x2c06 or 0x2400
 * 函 数 返 回:0读取成功  其他失败
 * 作       者:LC
 * 备       注:当前为周期模式读取,如使用单次模式,则将
 *              【设置周期模式命令】下的命令注释即可。
******************************************************************/
char SHT30_Read(uint16_t dat)
{        
    uint16_t i = 0;
        unsigned char buff[6] = {0};
        uint16_t data_16 = 0;
        float temp = 0;
        float humi = 0;
    
    //设置周期模式命令
        SHT31_Write_mode(0x2130);//每1秒一次高重复测量(需要在周期模式下才有用)
    
        IIC_Start();
        Send_Byte( (0x44<<1) | 0);
        if( I2C_WaitAck() == 1 )return 1;
        Send_Byte((dat >> 8 ));
        if( I2C_WaitAck() == 1 )return 2;
        Send_Byte( dat & 0xff );
        if( I2C_WaitAck() == 1 )return 3;
    
    //如不使用超时判断,很容易数据错乱
        do
        {
                //超时判断
                i++;
                if( i > 20 ) return 4;
                delay_1ms(2);
                
                IIC_Start();
                Send_Byte((0X44 << 1) | 1 );//读
                
        }while(I2C_WaitAck() == 1);        //读取到温湿度数据则结束读命令

        
    //温度高8位
        buff[0] = Read_Byte();
        IIC_Send_Ack(0);
    //温度低8位
        buff[1] = Read_Byte();
        IIC_Send_Ack(0);        
        //温度CRC校验值
        buff[2] = Read_Byte();
        IIC_Send_Ack(0);
    //湿度高8位
        buff[3] = Read_Byte();
        IIC_Send_Ack(0);        
    //湿度低8位
        buff[4] = Read_Byte();
        IIC_Send_Ack(0);        
    //湿度CRC校验值
        buff[5] = Read_Byte();
        IIC_Send_Ack(1);        

        IIC_Stop();          
        
    //CRC校验(将要校验的数值带入,查看计算后的校验值是否和读取到的校验值一致)
    if( (crc8(buff,2) == buff[2]) && ( crc8(buff+3,2) == buff[5]) )
        {
        //计算温度值
        data_16 =(buff[0]<<8) | buff[1];
        Temperature = (data_16/65535.0)*175.0 - 45;
        //计算湿度值
        data_16 = 0;
        data_16 =(buff[3]<<8) | buff[4];
        Humidity = (data_16/65535.0) * 100.0;
        
        printf("temp = %.2f\r\n",Temperature);
        printf("humi = %.2f\r\n",Humidity);
        return 0;
    }
    else
        {
                printf("校验失败\r\n");   
        }
    return 5;
}


在文件bsp_sht30.h中,编写如下代码。

#ifndef _BSP_SHT30_H_
#define _BSP_SHT30_H_

#include "gd32f4xx.h"

extern double Temperature, Humidity;


#define u8 unsigned char

void SHT30_GPIO_Init(void);
char SHT30_Read(uint16_t dat);

#endif

2.11.4 移植验证
在自己工程中的main主函数中,编写如下。

/********************************************************************************
  * 文 件 名: main.c
  * 版 本 号: 初版
  * 修改作者: LC
  * 修改日期: 2022年04月19日
  * 功能介绍:          
  ******************************************************************************
  * 注意事项:
*********************************************************************************/

#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "bsp_led.h"
#include "sys.h"
#include "bsp_usart.h"
#include "bsp_key.h"
#include "bsp_basic_timer.h"
#include "bsp_pwm.h"
#include "stdlib.h"
#include "string.h"
#include "bsp_sht30.h"

/************************************************
函数名称 : main
功    能 : 主函数
参    数 : 无
返 回 值 : 无
作    者 : LC
*************************************************/
int main(void)
{

          nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);  // 优先级分组
        
    systick_config();                                                  // 滴答定时器初始化
        usart_gpio_config(9600U);                                          // 串口0初始化
        SHT30_GPIO_Init();
        
        printf("start\r\n");
    while(1) 
        {
                        SHT30_Read(0xe000);
                        delay_1ms(1000);
                
    }
}

移植现象:每隔1秒读取一次温湿度,并通过串口输出。
在这里插入图片描述
移植成功示例,见文件2.11.4-1 。
文件2.11.4-1

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

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

相关文章

微软文本转语音和语音转文本功能更新,效果显著!

今天我要和大家分享一个新功能更新——微软的文本转语音和语音转文本功能。最近&#xff0c;微软对其AI语音识别和语音合成技术进行了重大升级&#xff0c;效果非常好&#xff0c;现在我将分别为大家介绍这两个功能。 先来听下这个效果吧 微软文本转语音和语音转文本功能更新 …

CVPR24_ArGue: Attribute-Guided Prompt Tuning for Vision-Language Models

Abstract 尽管软提示微调在调整视觉语言模型以适应下游任务方面表现出色&#xff0c;但在处理分布偏移方面存在局限性&#xff0c;通过属性引导提示微调&#xff08;Attribute-Guided&#xff0c;ArGue&#xff09;来解决这个问题 Contributions 与直接在类名之前添加软提示…

浅析JavaWeb内存马基础原理与查杀思路

文章目录 前言Java内存马内存马分类&原理JavaWeb三大组件注入Servlet内存马注入Filter型内存马JAVA Agent内存马 哥斯拉木马0x01 WebShell0x02 MemShell0x03 FilterShell0x04 Arthas排查0x05 scanner查杀 总结 前言 几年前写过《Web安全-一句话木马》&#xff0c;主要介绍…

大意了MySQL关键字EXPLAIN

一、问题 然后explain带了单引号、以区别其关键字 二、报错如下 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near explain, us.nickname AS user_send_nickname, ua.nickname…

探索未来智慧酒店网项目接口架构

在数字化时代&#xff0c;智慧酒店已成为酒店业发展的重要趋势之一。智慧酒店网项目接口架构作为支撑智慧酒店运营的核心技术之一&#xff0c;其设计和优化对于提升用户体验、提高管理效率具有重要意义。本文将深入探讨智慧酒店网项目接口架构的设计理念和关键要素。 ### 智慧…

上位机图像处理和嵌入式模块部署(qmacvisual并发执行)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 类似于qmacvisual这样的软件&#xff0c;其实价格并不便宜。比如大家熟知的halcon、vision pro、vision master这样的软件&#xff0c;最便宜的版本…

练习实践-TLS02-会话恢复的两种形式-Session ID/SessionTicket

参考来源&#xff1a; 书籍&#xff1a;深入浅出https-从原理到实战&#xff08;作者&#xff1a;虞卫东&#xff09; 抓包分析文件可下载&#xff0c;来自github上的作者上传资源 会话恢复机制的背景 当客户端和服务器端握手成功&#xff0c;建立了一个完整的 TLS 连接&…

基于keepalived+gtid+双vip半同步主从复制的MySQL高性能集群

项目名称&#xff1a;基于keepalivedgtid双vip半同步主从复制的MySQL高性能集群 目录 项目名称&#xff1a;基于keepalivedgtid双vip半同步主从复制的MySQL高性能集群 项目规划图 1.配置4台MySQL服务器&#xff08;1台master&#xff0c;2台slave&#xff0c;1台backup&a…

【Django开发】0到1美多商城项目md教程第5篇:短信验证码,1. 避免频繁发送短信验证码逻辑分析【附代码文档】

美多商城完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;欢迎来到美多商城&#xff01;&#xff0c;项目准备。展示用户注册页面&#xff0c;创建用户模块子应用。用户注册业务实现&#xff0c;用户注册前端逻辑。图形验证码&#xff0c;图形验证码接口设…

江协STM32:定时器定时中断和定时器定时闹钟

定时器中断 新建文件 按这个图来编写程序 第一步&#xff1a;RCC开启时钟&#xff0c;定时器到基准时钟和整个外设到工作时钟就会同时打开 第二步&#xff1a;选择时基单元的时钟源&#xff0c;对于定时中断选择内部时钟源 第三步&#xff1a;配置时基单元&#xff0c;ARR,P…

CSS设置网页背景

目录 概述&#xff1a; 1.background-color: 2.background-image&#xff1a; 3.background-repeat&#xff1a; 4.background-position&#xff1a; 5.background-attachment&#xff1a; 6.background-size&#xff1a; 7.background-origin&#xff1a; 8.background-…

【Linux】Ubuntu 磁盘管理

准备一个U盘或者SD卡&#xff08;含读卡器&#xff09;&#xff0c;并将其格式化成 FAT32 格式&#xff0c;不要使用NTFS格式&#xff08;这是微软的专利&#xff0c;大部分Linux系统不支持&#xff09;和exFAT格式&#xff08;有的Linux系统也不支持&#xff09;。 如果Ubun…

Linux云计算之Linux基础2——Linux发行版本的安装

目录 一、彻底删除VMware 二、VMware-17虚拟机安装 三、MobaXterm 安装 四、Centos 发行版 7.9的安装 五、rockys 9.1的安装 六、ubuntu2204的安装 一、彻底删除VMware 在卸载VMware虚拟机之前&#xff0c;要先把与VMware相关的服务和进程终止 1. 在windows中按下【Windo…

【算法练习】28:选择排序学习笔记

一、选择排序的算法思想 弄懂选择排序算法&#xff0c;先得知道两个概念&#xff1a;未排序序列&#xff0c;已排序序列。 原理&#xff1a;以升序为例&#xff0c;选择排序算法的思想是&#xff0c;先将整个序列当做未排序的序列&#xff0c;以序列的第一个元素开始。然后从左…

Python快速入门系列-7(Python Web开发与框架介绍)

第七章:Python Web开发与框架介绍 7.1 Flask与Django简介7.1.1 Flask框架Flask的特点Flask的安装一个简单的Flask应用示例7.1.2 Django框架Django的特点Django的安装一个简单的Django应用示例7.2 前后端交互与数据传输7.2.1 前后端交互7.2.2 数据传输格式7.2.3 示例:使用Flas…

蓝桥杯23年第十四届省赛-异或和之和|拆位、贡献法

题目链接&#xff1a; 蓝桥杯2023年第十四届省赛真题-异或和之和 - C语言网 (dotcpp.com) 1.异或和之和 - 蓝桥云课 (lanqiao.cn) 参考题解&#xff1a; 蓝桥杯真题讲解&#xff1a;异或和之和 &#xff08;拆位、贡献法&#xff09;-CSDN博客 洛谷P9236 [蓝桥杯 2023 省 A]…

2024 年最新使用 Wechaty 开源框架搭建部署微信机器人(微信群智能客服案例)

读取联系人信息 获取当前机器人账号全部联系人信息 bot.on(ready, async () > {console.log("机器人准备完毕&#xff01;&#xff01;&#xff01;")let contactList await bot.Contact.findAll()for (let index 0; index < contactList.length; index) {…

STC89C51学习笔记(二)

STC89C51学习笔记&#xff08;二&#xff09; 综述&#xff1a;本文简要介绍了51单片机以及示例了如何成功运行一个程序&#xff08;点亮一个LED&#xff09;。 一、单片机介绍 单片机简称MCU&#xff0c;MCUCPURAMROM定时器中断系统通讯协议等单片机任务是信息采集、处理、…

Go 源码之互斥锁 Mutex

文章目录 一、总结二、源码&#xff08;一&#xff09;Mutex&#xff08;二&#xff09; Lock&#xff08;三&#xff09;Unlock 三、常见问题有劳各位看官 点赞、关注➕收藏 &#xff0c;你们的支持是我最大的动力&#xff01;&#xff01;&#xff01;接下来会不断更新 golan…

2.Swift基础控件:图标文字按钮

Swift图标标题按钮 一、自定义IconTitleButton类 import Foundation/* 枚举 设置 图片的位置 */ enum ButtonImagePosition : Int {case imageTop 0case imageLeftcase imageBottomcase imageRight } extension UIButton {/**type &#xff1a;image 的位置Space &#xff1…