历史上的今天
返回首页

历史上的今天

今天是:2025年07月22日(星期二)

正在发生

2021年07月22日 | 【STM32Cube_15】使用硬件I2C读取温湿度传感器数据(SHT30)

2021-07-22 来源:eefocus

本篇详细的记录了如何使用STM32CubeMX配置STM32L431RCT6的硬件I2C外设,读取SHT30温湿度传感器的数据并通过串口发送。


1. 准备工作

硬件准备

  • 开发板
    首先需要准备一个开发板,这里我准备的是STM32L4的开发板(BearPi):

mark

  • SHT30温湿度传感器
    SHT30温湿度传感器是一个完全校准的、现行的、带有温度补偿的数字输出型传感器,具有 2.4V-5.5V 的宽电压支持,使用IIC接口进行通信,最高速率可达1M并且有两个用户可选地址,除此之外,它还具有8个引脚的DFN超小封装,如图:

mark

SHT30的原理图如下:
mark

软件准备

  • 需要安装好Keil - MDK及芯片对应的包,以便编译和下载生成的代码;

  • 准备一个串口调试助手,这里我使用的是Serial Port Utility;

  

2.生成MDK工程

选择芯片型号

打开STM32CubeMX,打开MCU选择器:
mark

搜索并选中芯片STM32L431RCT6:
mark

配置时钟源

  • 如果选择使用外部高速时钟(HSE),则需要在System Core中配置RCC;

  • 如果使用默认内部时钟(HSI),这一步可以略过;

这里我都使用外部时钟:
mark

配置串口

小熊派开发板板载ST-Link并且虚拟了一个串口,原理图如下:

mark

这里我将开关拨到AT-MCU模式,使PC的串口与USART1之间连接。

接下来开始配置USART1:

mark

配置I2C接口

查看小熊派E53接口的原理图:
mark

接下来开始配置I2C接口1:
mark

配置时钟树

STM32L4的最高主频到80M,所以配置PLL,最后使HCLK = 80Mhz即可:
mark

生成工程设置

mark

代码生成设置

最后设置生成独立的初始化文件:
mark

生成代码

点击GENERATE CODE即可生成MDK-V5工程:
mark

3. 在MDK中编写、编译、下载用户代码

重定向printf( )函数

参考: 【STM32Cube_09】重定向printf函数到串口输出的多种方法。

修改I2C初始化代码的小BUG

mark

4. 编写SHT30驱动程序

参考 SHT30数据手册.pdf进行编程。

宏定义SHT30器件地址

先来编写sht30_i2c_drv.h头文件,SHT30的器件地址由ADDR端口的高低电平决定:

mark

注意数据手册中给出了8位数据,只有低7位用作地址,结合原理图,可以定义如下:


/* ADDR Pin Conect to VSS */


#define SHT30_ADDR_WRITE 0x44<<1 //10001000

#define SHT30_ADDR_READ (0x44<<1)+1 //10001011

枚举SHT30命令列表

参考数据手册,在sht30_i2c_drv.h头文件中给出如下枚举定义:


typedef enum

{

/* 软件复位命令 */


SOFT_RESET_CMD = 0x30A2,

/*

单次测量模式

命名格式:Repeatability_CS_CMD

CS: Clock stretching

*/

HIGH_ENABLED_CMD = 0x2C06,

MEDIUM_ENABLED_CMD = 0x2C0D,

LOW_ENABLED_CMD = 0x2C10,

HIGH_DISABLED_CMD = 0x2400,

MEDIUM_DISABLED_CMD = 0x240B,

LOW_DISABLED_CMD = 0x2416,


/*

周期测量模式

命名格式:Repeatability_MPS_CMD

MPS:measurement per second

*/

HIGH_0_5_CMD = 0x2032,

MEDIUM_0_5_CMD = 0x2024,

LOW_0_5_CMD = 0x202F,

HIGH_1_CMD = 0x2130,

MEDIUM_1_CMD = 0x2126,

LOW_1_CMD = 0x212D,

HIGH_2_CMD = 0x2236,

MEDIUM_2_CMD = 0x2220,

LOW_2_CMD = 0x222B,

HIGH_4_CMD = 0x2334,

MEDIUM_4_CMD = 0x2322,

LOW_4_CMD = 0x2329,

HIGH_10_CMD = 0x2737,

MEDIUM_10_CMD = 0x2721,

LOW_10_CMD = 0x272A,

/* 周期测量模式读取数据命令 */

READOUT_FOR_PERIODIC_MODE = 0xE000,

} SHT30_CMD;

发送命令函数

/**

* @brief 向SHT30发送一条指令(16bit)

* @param cmd —— SHT30指令(在SHT30_MODE中枚举定义)

* @retval 成功返回HAL_OK

*/

static uint8_t SHT30_Send_Cmd(SHT30_CMD cmd)

{

uint8_t cmd_buffer[2];

cmd_buffer[0] = cmd >> 8;

cmd_buffer[1] = cmd;

return HAL_I2C_Master_Transmit(&hi2c1, SHT30_ADDR_WRITE, (uint8_t* cmd_buffer, 2, 0xFFFF);

}

复位函数

/**

* @brief 复位SHT30

* @param none

* @retval none

*/

void SHT30_reset(void)

{

SHT30_Send_Cmd(SOFT_RESET_CMD);

HAL_Delay(20);

}


SHT30工作模式初始化函数(周期测量模式)

/**

* @brief 初始化SHT30

* @param none

* @retval 成功返回HAL_OK

* @note 周期测量模式

*/

uint8_t SHT30_Init(void)

{

return SHT30_Send_Cmd(MEDIUM_2_CMD);

}

从SHTY30读取一次数据(周期测量模式下)

从SHT30数据手册中可以得到在周期测量模式下读取一次数据的时序,如图:

mark

根据该时序可以看出,首先要发送读数据的命令,然后接收6个字节的数据,编写程序如下:


/**

* @brief 从SHT30读取一次数据

* @param dat —— 存储读取数据的地址(6个字节数组)

* @retval 成功 —— 返回HAL_OK

*/

uint8_t SHT30_Read_Dat(uint8_t* dat)

{

SHT30_Send_Cmd(READOUT_FOR_PERIODIC_MODE);

return HAL_I2C_Master_Receive(&hi2c1, SHT30_ADDR_READ, dat, 6, 0xFFFF);

}

从接收数据中校验并解析温度值和湿度值

在数据手册中可知,SHT30分别在温度数据和湿度数据之后发送了8-CRC校验码,确保了数据可靠性。


关于CRC校验请参考我的另一篇博客: 如何通俗的理解CRC校验并用C语言实现。


CRC-8校验程序如下:


#define CRC8_POLYNOMIAL 0x31


uint8_t CheckCrc8(uint8_t* const message, uint8_t initial_value)

{

uint8_t remainder; //余数

uint8_t i = 0, j = 0; //循环变量


/* 初始化 */

remainder = initial_value;


for(j = 0; j < 2;j++)

{

remainder ^= message[j];


/* 从最高位开始依次计算 */

for (i = 0; i < 8; i++)

{

if (remainder & 0x80)

{

remainder = (remainder << 1)^CRC8_POLYNOMIAL;

}

else

{

remainder = (remainder << 1);

}

}

}


/* 返回计算的CRC码 */

return remainder;

}


计算温度值和湿度值的公式在数据手册中已给出,如图:

mark

接下来编写解析数据的函数:


/**

* @brief 将SHT30接收的6个字节数据进行CRC校验,并转换为温度值和湿度值

* @param dat —— 存储接收数据的地址(6个字节数组)

* @retval 校验成功 —— 返回0

* 校验失败 —— 返回1,并设置温度值和湿度值为0

*/

uint8_t SHT30_Dat_To_Float(uint8_t* const dat, float* temperature, float* humidity)

{

uint16_t recv_temperature = 0;

uint16_t recv_humidity = 0;


/* 校验温度数据和湿度数据是否接收正确 */

if(CheckCrc8(dat, 0xFF) != dat[2] || CheckCrc8(&dat[3], 0xFF) != dat[5])

return 1;


/* 转换温度数据 */

recv_temperature = ((uint16_t)dat[0]<<8)|dat[1];

*temperature = -45 + 175*((float)recv_temperature/65535);


/* 转换湿度数据 */

recv_humidity = ((uint16_t)dat[3]<<8)|dat[4];

*humidity = 100 * ((float)recv_humidity / 65535);


return 0;

}

5. 测试SHT30驱动程序

在main函数中对该驱动进行测试,在main.c中添加如下代码:


#include

#include "sht30_i2c_drv.h"


int main(void)

{

/* USER CODE BEGIN 1 */

uint8_t recv_dat[6] = {0};

float temperature = 0.0;

float humidity = 0.0;

/* USER CODE END 1 */


HAL_Init();


SystemClock_Config();


MX_GPIO_Init();

MX_I2C1_Init();

MX_USART1_UART_Init();


/* USER CODE BEGIN 2 */

SHT30_Reset();

if(SHT30_Init() == HAL_OK)

printf("sht30 init ok.n");

else

printf("sht30 init fail.n");

/* USER CODE END 2 */


/* Infinite loop */

/* USER CODE BEGIN WHILE */

while (1)

{

/* USER CODE END WHILE */


/* USER CODE BEGIN 3 */

HAL_Delay(1000);

if(SHT30_Read_Dat(recv_dat) == HAL_OK)

{

if(SHT30_Dat_To_Float(recv_dat, &temperature, &humidity)==0)

{

printf("temperature = %f, humidity = %fn", temperature, humidity);

}

else

{

printf("crc check fail.n");

}

}

else

{

printf("read data from sht30 fail.n");

}

}

/* USER CODE END 3 */

}


测试结果如图:

mark

至此,我们已经学会如何使用硬件IIC接口读取温湿度传感器数据并使用软件CRC校验(SHT30),下一节将讲述如何使用硬件CRC校验SHT30的数据。

推荐阅读

史海拾趣

Global Mixed-Mode Technology Inc公司的发展小趣事
三相缺相报警灯电路在需要稳定三相电源供电的场合下非常重要。例如,在工业生产中,三相电动机、变压器等设备对电源的稳定性要求很高,一旦发生缺相,可能会导致设备损坏或生产事故。因此,在这些场合下需要安装三相缺相报警灯电路来及时监测并报警缺相情况。
康龙(CONCRAFT)公司的发展小趣事

随着公司实力的不断增强,康龙开始积极拓展国内外市场。公司先后在美国、欧洲等地设立了销售机构,与多家国际知名企业建立了长期稳定的合作关系。同时,康龙还积极参与国际展会和交流活动,提升品牌知名度和影响力。通过不懈的努力,康龙的产品已经成功打入国际市场,并赢得了客户的广泛赞誉。

西博臣(CYBERSEN)公司的发展小趣事

作为一家有社会责任感的企业,西博臣积极履行社会责任,关注环境保护和可持续发展。公司采用环保材料和生产工艺,减少生产过程中的能源消耗和废弃物排放。同时,公司还积极参与社会公益活动,为社会做出积极贡献。这些举措不仅体现了公司的社会责任感,也为其赢得了更多客户和合作伙伴的信任和支持。

Diamond SA公司的发展小趣事

在电子行业的初期,Diamond SA公司以其卓越的技术研发能力脱颖而出。公司创始人对半导体技术的深入研究,引领了一场技术革命。他们成功开发出一种新型的芯片设计,大大提高了电子设备的性能和效率。这一创新技术迅速在市场上获得了认可,Diamond SA公司也因此逐渐崭露头角。

Cicoil公司的发展小趣事

Cicoil公司的创立可以追溯到电子行业的快速发展时期。创始人看到了扁平电缆在电子设备中的巨大潜力,于是决定专注于这一领域的研究和开发。他们投入大量资源,研发出具有独特技术的柔性扁平电缆,为电子设备提供了更为灵活和可靠的连接方案。这一创新产品在市场上引起了轰动,为Cicoil公司赢得了良好的声誉和市场份额。

GSI Technology公司的发展小趣事

随着电子行业的快速发展,GSI Technology积极寻求新的市场机会。公司凭借其高性能存储器产品在军事、医疗、汽车等领域的应用优势,成功进军这些新兴市场。同时,GSI还积极与行业内其他企业建立战略合作关系,共同推动技术创新和市场拓展。例如,GSI与某知名汽车制造商合作,为其开发定制化的高性能存储器解决方案,有效提升了汽车智能化水平。

问答坊 | AI 解惑

携无线产品中的小天线设计

通常在进入设计周期末尾之前,天线设计不会引起太大注意。原因或许就是因为它们是无源器件,在RF信号通路中所起的作用看来不大。也可能是是因为设计师希望他们一直有能力在剩余空间内配置天线设计和进行元件选择。还有可能是因为天线不是摩尔定律的 ...…

查看全部问答>

申请LPC1343开发板

不涉及公司机密的分享…

查看全部问答>

求助:PLC与DSP无法通讯

我用得CJ1M,设计本身是用422口与DSP通讯,通讯9次,每包250个字节,每次是PCL申请数据,dsp在发送一包,现象是发送完第一包,dsp正确接收到后,就不发送第二包的神情数据了,采用软件监视模式发现程序停留在PMCR那一行,而不是捕捉PMCR完成标志下 ...…

查看全部问答>

求助无线发送接收

我毕业设计做一个无线接收检测温度和压力信号,可不知道无线模块怎么做,有大侠帮忙吗?…

查看全部问答>

诚恳请教各位前辈:mm我作嵌入式软件还是IC前端设计?

算下来小硕毕业后正好工作有三年了,可对于以后的发展方向却始终迷茫。 开始的一年半,主要做产品方案级的软件,感觉自己还比较喜欢也比较有自信。后来去了另外的部门,做音频格式的软件解码,大约一年的时间,做了两个格式的解码和一个格式的编 ...…

查看全部问答>

菜鸟求助:关于pci中断的使用

本人菜鸟,刚接触pci,用的是pci9054做一个运动控制卡 在中断部分遇到很多疑惑,求高人指点 1. pci本地中断,我在datasheet上看到的只有一个pin154为LINT#,可是在很多资料上看到写LINT#[2:1],我现在本地端有两个外部中断源,该怎么处理? 2.在 ...…

查看全部问答>

atmel网站上的资料使用问题

各位大侠,我是新手,问大家一个比较低级的问题, 我们公司准备做AT91sam9261ek板上的开发,我从atmel官方网上下载了一个资料包,at91lib_softpack_1.5,,这些资料可以用来做什么呢?readme内容如下: //-------------------------------------- ...…

查看全部问答>

vxworks串口问题

串口程序能接收,但是发送的话只能发送一次.第二次就发不了,必须重启之后才能发送. write函数返回的值一直都是正常的. 但是串口监控软件就是接收不到数据,只能接收第一次的数据. 是因为我的驱动有问题吗? 驱动是用的vxworks自带的,我没动过.…

查看全部问答>

请教genprint.dll安装问题

请问安装genprint.dll,还需要其它文件吗,应该怎么安装啊…

查看全部问答>