资讯详情

STM32CubeMX | 29-使用硬件I2C读取甲醛传感器SGP30

本文详细记录了如何使用它STM32CubeMX配置STM32L431RCT6的硬件I2C环境光强环境光强度传感器数据(BH1750)。

1. 准备工作

开发板

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

SGP30传感器模块

SGP30是一种金属氧化物,单芯片上有多个传感元件,四个气体传感元件集成,空气质量输出信号完全校准,主要检测空气质量。TVOC(Total Volatile Organic Compounds,总挥发性有机物)是反映甲醛浓度的重要指标,因此,也可用于监测CO2浓度。

SGP引脚的定义如下: 典型应用电路如下: 电气特性如下:

二氧化碳浓度含量会影响人类的生活和休息,二氧化碳浓度含量与人体生理反应如下:

350~450ppm:室外环境一般 350~1000ppm:空气清新,呼吸顺畅。 >1000ppm:感觉空气浑浊,开始昏昏欲睡。

2.生成MDK工程

选择芯片型号

打开STM32CubeMX,打开MCU选择器:

搜索并选择芯片STM32L431RCT6:

配置时钟源

  • 如果选择使用外部高速时钟(HSE),则需要在System Core中配置RCC;
  • 如果使用默认内部时钟(HSI),这一步可以省略;

我在这里使用外部时钟:

配置串口

板载小熊派开发板ST-Link原理图如下:

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

然后开始配置USART1

配置硬件I2C

首先选择将SGP30传感器连接在哪里?I2C如图所示:

然后开始配置I2C接口1:

配置时钟树

STM32L最高主频为80M,所以配置PLL,最后使HCLK = 80Mhz即可:

生成工程设置

代码生成设置

最后,生成独立的初始化文件:

生成代码

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

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

重定向printf函数

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

4. 编写SGP30驱动程序

驱动源码:https://github.com/Mculover666/HAL_Driver_Lib

参考Sensirion_Gas_Sensors_SGP30_Datasheet_EN.PDF.pdf进行编程。

宏定义SGP30器件地址

先来编写sgp30.h头文件,SGP数据手册中已给出30个设备地址:

注意,结合原理图,可定义如下:

#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;

枚举SHT30命令列表

参考数据手册,在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);
}

SGP30初始化函数

/** * @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读取一次数据并校验解析

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

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

SGP30校验的参数已经在数据手册中给出:

编写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;
}

5. 测试SHT30驱动程序

在main.c中包含头文件:

#include <stdio.h>
#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 */
}

测试结果如图:

标签: 传感器ppdppd传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台