本篇详细的记录了如何使用STM32CubeMX配置STM32L431RCT6的硬件I2C外设读取环境光强度传感器数据(BH1750)。
首先需要准备一个开发板,这里我准备的是STM32L4的开发板(BearPi)。
SGP30是一款单一芯片上具有多个传感元件的金属氧化物室内气体传感器,内集成4个气体传感元件,具有完全校准的空气质量输出信号,主要是对空气质量进行检测。TVOC(Total Volatile Organic Compounds,总挥发性有机物)是一项重要指标,一般我们可以用它来反映甲醛的浓度,所以SGP主要用于甲醛的检测,另外还可以用于监测CO2浓度。
二氧化碳浓度含量会影响人类的生活作息,整理出二氧化碳浓度含量与人体生理反应如下:
350~450ppm:同一般室外环境
350~1000ppm:空气清新,呼吸顺畅。
>1000ppm
:感觉空气浑浊,并开始觉得昏昏欲睡。
打开STM32CubeMX,打开MCU选择器:
搜索并选中芯片STM32L431RCT6
:
这里我都使用外部时钟:
小熊派开发板板载ST-Link并且虚拟了一个串口,原理图如下:
这里我将开关拨到AT-MCU
模式,使PC的串口与USART1之间连接。
接下来开始配置USART1
:
首先选择将SGP30传感器接在哪个I2C接口上,如图:
接下来开始配置I2C接口1:
STM32L4的最高主频到80M,所以配置PLL,最后使HCLK = 80Mhz
即可:
最后设置生成独立的初始化文件:
点击GENERATE CODE
即可生成MDK-V5工程:
参考:【STM32Cube_09】重定向printf函数到串口输出的多种方法。
驱动源码:https://github.com/Mculover666/HAL_Driver_Lib
参考Sensirion_Gas_Sensors_SGP30_Datasheet_EN.PDF.pdf进行编程。
先来编写sgp30.h
头文件,SGP30的器件地址在数据手册中已给出:
注意数据手册中给出了8位数据,只有低7位用作地址,结合原理图,可以定义如下:
#define SGP30_ADDR 0x58
#define SGP30_ADDR_WRITE SGP30_ADDR<<1 //0xb0
#define SGP30_ADDR_READ (SGP30_ADDR<<1)+1 //0xb1
typedef struct sgp30_data_st {
uint16_t co2;
uint16_t tvoc;
}sgp30_data_t;
参考数据手册,在sgp30.h
头文件中给出如下枚举定义:
typedef enum sgp30_cmd_en {
/* 初始化空气质量测量 */
INIT_AIR_QUALITY = 0x2003,
/* 开始空气质量测量 */
MEASURE_AIR_QUALITY = 0x2008
} sgp30_cmd_t;
/**
* @brief 向SGP30发送一条指令(16bit)
* @param cmd SGP30指令
* @retval 成功返回HAL_OK
*/
static uint8_t sgp30_send_cmd(sgp30_cmd_t cmd)
{
uint8_t cmd_buffer[2];
cmd_buffer[0] = cmd >> 8;
cmd_buffer[1] = cmd;
return HAL_I2C_Master_Transmit(&hi2c1, SGP30_ADDR_WRITE, (uint8_t*) cmd_buffer, 2, 0xFFFF);
}
/**
* @brief 软复位SGP30
* @param none
* @retval 成功返回HAL_OK
*/
static int sgp30_soft_reset(void)
{
uint8_t cmd = 0x06;
return HAL_I2C_Master_Transmit(&hi2c1, 0x00, &cmd, 1, 0xFFFF);
}
/**
* @brief 初始化SGP30空气质量测量模式
* @param none
* @retval 成功返回0,失败返回-1
*/
int sgp30_init(void)
{
int status;
status = sgp30_soft_reset();
if (status != HAL_OK) {
return -1;
}
HAL_Delay(100);
status = sgp30_send_cmd(INIT_AIR_QUALITY);
HAL_Delay(100);
return status == 0 ? 0 : -1;
}
/**
* @brief 初始化SGP30空气质量测量模式
* @param none
* @retval 成功返回HAL_OK
*/
static int sgp30_start(void)
{
return sgp30_send_cmd(MEASURE_AIR_QUALITY);
}
在数据手册中可知,SGP30分别在co2浓度之后和TVOC浓度数据之后发送了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;
}
接下来编写读取并校验数据的函数:
/**
* @brief 读取一次空气质量数据
* @param none
* @retval 成功返回0,失败返回-1
*/
int spg30_read(void)
{
int status;
uint8_t recv_buffer[6]={0};
/* 启动测量 */
status = sgp30_start();
if (status != 0) {
printf("sgp30 start fail\r\n");
return -1;
}
HAL_Delay(100);
/* 读取测量数据 */
status = HAL_I2C_Master_Receive(&hi2c1, SGP30_ADDR_READ, (uint8_t*)recv_buffer, 6, 0xFFFF);
if (status != HAL_OK) {
printf("I2C Master Receive fail\r\n");
return -1;
}
/* 校验接收的测量数据 */
if (CheckCrc8(&recv_buffer[0], 0xFF) != recv_buffer[2]) {
printf("co2 recv data crc check fail\r\n");
return -1;
}
if (CheckCrc8(&recv_buffer[3], 0xFF) != recv_buffer[5]) {
printf("tvoc recv data crc check fail\r\n");
return -1;
}
/* 转换测量数据 */
sgp30_data.co2 = recv_buffer[0] << 8 | recv_buffer[1];
sgp30_data.tvoc = recv_buffer[3] << 8 | recv_buffer[4];
return 0;
}
在main.c中包含头文件:
#include
#include "sgp30.h"
在main函数中对该驱动进行测试,修改main函数:
int main(void)
{
HAL_Init();
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
printf("SGP30 Test By mculover666\r\n");
if (-1 == sgp30_init()) {
printf("sgp30 init fail\r\n");
/* 因为是裸机,所以直接进入死机 */
while(1);
}
printf("sgp30 init success\r\n");
/* USER CODE END 2 */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if( -1 == spg30_read()) {
printf("sgp30 read fail\r\n");
}
else {
printf("sgp30 read success, co2:%4d ppm, tvoc:%4d ppd\r\n", sgp30_data.co2, sgp30_data.tvoc);
}
HAL_Delay(2000);
}
/* USER CODE END 3 */
}
更多精彩文章及资源,请关注我的微信公众号:『mculover666』。