使用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

物联沃分享整理
物联沃-IOTWORD物联网 » 使用STM32硬件I2C读取SGP30传感器数据

发表评论