【STM32Cube_15】使用硬件I2C读取温湿度传感器数据(SHT30)

发布者:数字梦想最新更新时间:2021-07-22 来源: eefocus关键字:STM32Cube  硬件I2C  SHT30 手机看文章 扫描二维码
随时随地手机看文章

本篇详细的记录了如何使用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的数据。

关键字:STM32Cube  硬件I2C  SHT30 引用地址:【STM32Cube_15】使用硬件I2C读取温湿度传感器数据(SHT30)

上一篇:【STM32Cube_14】使用硬件I2C读写环境光强度传感器(BH1750)
下一篇:【STM32Cube_16】使用硬件CRC校验数据(以SHT30为例)

推荐阅读最新更新时间:2024-11-17 01:08

浅谈 STM32 硬件I2C的使用 (中断方式 无DMA 无最高优先级)
引子 STM32的硬件I2C很多人都对它望而却步。因为很多电工都说,STM32 硬件 I2C有BUG、不稳定、死机等等……最后都使用GPIO模拟I2C。 的确,模拟I2C好用。但是在我看来在一个72M的Cortex-M3的MCU上这样做非常不妥。一般来说I2C是一种慢速总线,就算工作在400kHz的快速模式上,I2C传送每个字节仍需要至少23us——还没有计算地址、起始信号和结束信号的发送。如果使用GPIO模拟的I2C,这23us的CPU时间都在空转中浪费了,而这23us已经可以做不少的事情了,所以在STM32上I2C还是使用硬件为佳——虽然它多多少少有点缺陷。 这篇文章不是给完全没有接触过STM32 硬件I2C的新手看的,看这篇
[单片机]
浅谈 STM32 <font color='red'>硬件</font><font color='red'>I2C</font>的使用 (中断方式 无DMA 无最高优先级)
基于 STM32 的硬件 I2C 读取 MPU6050 数据
MPU6050其实就是一个 I2C 器件,里面有很多寄存器(但是我们用到的只有几个),我们通过读写寄存器来操作这个芯片。所以首要问题就是 STM32 和 MPU6050 的 I2C 通信。 1、配置 STM32 (用I2C1:PB6——SCL;PB7——SDA) 1)时钟 RCC RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1 , ENABLE); 2)GPIO 配置 GPIO_InitStructure.GPIO_Pin = GPIO
[单片机]
基于 STM32 的<font color='red'>硬件</font> <font color='red'>I2C</font> 读取 MPU6050 <font color='red'>数据</font>
使用STM8L的硬件I2C(四)硬件I2C的使用注意
其他系列文章请参见: (一)硬件I2C的简介 (二)硬件I2C的事件和检测 (三)硬件I2C中断读写(流程及代码) 使用STM8L的硬件I2C时,有几个点要注意: I2C的初始化 时钟的使能操作必须在其他I2C设置之前,否则设置不生效 CLK_PeripheralClockConfig(CLK_Peripheral_I2C1, ENABLE); Slave地址的设置 这一点让人困扰,花了不少时间才搞清楚。 是因为标准库函数I2C_Send7bitAddress()并不会帮助你左移。 这个左移动作必须由用户完成,如下: I2C_Send7bitAddress(I2C1, _i2c_dev.addr 1, I2C
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved