使用STM32硬件I2C读取SGP30传感器数据
STM32硬件I2C读取SGP30传感器数据
配置
单片机:STM32F103C8T6
用的I2C1
代码
sgp30.h
// sgp30.h 文件,存放SGP30相关的宏定义和函数声明
#ifndef SGP30_H
#define SGP30_H
#include "stm32f1xx_hal.h"
// 定义SGP30的IIC从机地址
#define SGP30_ADDR 0x58
// 定义SGP30结构体,存储CO2和TVOC的值
typedef struct {
uint16_t co2;
uint16_t tvoc;
} sgp30_data_t;
// 声明SGP30初始化函数,发送初始化命令
void sgp30_init(void);
// 声明SGP30读取数据函数,返回CO2和TVOC的值
sgp30_data_t sgp30_read(void);
// 声明SGP30计算CRC校验值的函数,使用多项式x8 + x5 + x4 + x0
uint8_t sgp30_crc(uint8_t *data, uint8_t len);
#endif
sgp30.c
#include "sgp30.h"
#include "i2c.h"
// 定义SGP30初始化函数,发送初始化命令
void sgp30_init(void) {
uint8_t cmd[2] = {0x20, 0x03}; // 初始化命令为0x2003
HAL_I2C_Master_Transmit(&hi2c1, SGP30_ADDR << 1, cmd, 2, 100); // 发送初始化命令
HAL_Delay(20); // 等待10ms
}
// 定义SGP30读取数据函数,返回CO2和TVOC的值
sgp30_data_t sgp30_read(void) {
uint8_t cmd[2] = {0x20, 0x08}; // 读取命令为0x2008
uint8_t data[6]; // 存储返回的6个字节数据
uint8_t crc; // 存储CRC校验值
sgp30_data_t result; // 存储结果
HAL_I2C_Master_Transmit(&hi2c1, SGP30_ADDR << 1, cmd, 2, 100); // 发送读取命令
HAL_Delay(25); // 等待12ms
HAL_I2C_Master_Receive(&hi2c1, SGP30_ADDR << 1 | 0x01, data, 6, 100); // 接收6个字节数据
crc = sgp30_crc(data, 2); // 计算前两个字节的CRC校验值
if (crc == data[2]) { // 如果和第三个字节相同,说明CO2数据有效
result.co2 = (data[0] << 8) | data[1]; // 将前两个字节合并为CO2值
} else {
result.co2 = 0; // 否则,返回0表示无效
}
crc = sgp30_crc(data + 3, 2); // 计算第四和第五个字节的CRC校验值
if (crc == data[5]) { // 如果和第六个字节相同,说明TVOC数据有效
result.tvoc = (data[3] << 8) | data[4]; // 将第四和第五个字节合并为TVOC值
} else {
result.tvoc = 0; // 否则,返回0表示无效
}
return result; // 返回结果
}
// 定义SGP30计算CRC校验值的函数,使用多项式x8 + x5 + x4 + x0
uint8_t sgp30_crc(uint8_t *data, uint8_t len) {
uint8_t crc = 0xFF; // 初始值为0xFF
uint8_t bit; // 存储位掩码
for (uint8_t i = 0; i < len; i++) { // 遍历每个字节
crc ^= data[i]; // 异或当前字节
for (bit = 8; bit > 0; bit--) { // 遍历每个位
if (crc & 0x80) { // 如果最高位为1,就左移并异或0x31
crc = (crc << 1) ^ 0x31;
} else { // 否则,就左移
crc = (crc << 1);
}
}
}
return crc; // 返回CRC校验值
}
main.c
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
sgp30_init();
sgp30_data_t sgp30_data;
char co2_data[32];
char tvoc_data[32];
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
sgp30_data = sgp30_read();
sprintf(co2_data,"co2:%d\r\n",sgp30_data.co2);
sprintf(tvoc_data,"tvoc:%d\r\n",sgp30_data.tvoc);
HAL_UART_Transmit(&huart1,(uint8_t*)co2_data,strlen(co2_data),HAL_MAX_DELAY);
HAL_UART_Transmit(&huart1,(uint8_t*)tvoc_data,strlen(tvoc_data),HAL_MAX_DELAY);
HAL_Delay(1000); // 延时1秒
}
/* USER CODE END 3 */
}
注:sgp30需要上电初始化5秒左右,之后读出的数据就正常了
作者:weixin_53066478