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秒左右,之后读出的数据就正常了

  • 1
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
由于SGP30气体传感器使用的是I2C通讯协议,因此在写代码之前需要确保已经正确初始化了I2C总线。以下为使用STM32标准库编写的SGP30气体传感器初始化和读取数据的代码: ```c #include "stm32f10x.h" #include "stm32f10x_i2c.h" #define SGP30_I2C_ADDR 0x58 // SGP30气体传感器I2C地址 // 初始化SGP30气体传感器 void SGP30_Init(void) { I2C_InitTypeDef i2c; GPIO_InitTypeDef gpio; // 使能I2C时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 配置I2C引脚 gpio.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; gpio.GPIO_Mode = GPIO_Mode_AF_OD; // 开漏输出,需要外接上拉电阻 gpio.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &gpio); // 配置I2C参数 i2c.I2C_Mode = I2C_Mode_I2C; i2c.I2C_DutyCycle = I2C_DutyCycle_2; i2c.I2C_OwnAddress1 = 0; i2c.I2C_Ack = I2C_Ack_Enable; i2c.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; i2c.I2C_ClockSpeed = 100000; // I2C总线速度为100KHz I2C_Init(I2C1, &i2c); I2C_Cmd(I2C1, ENABLE); } // 读取SGP30气体传感器数据 void SGP30_ReadData(uint16_t* tvoc, uint16_t* co2) { uint8_t data[6]; uint8_t cmd[2] = {0x20, 0x08}; // 读取TVOC和CO2浓度 // 发送读取数据的命令 I2C_GenerateSTART(I2C1, ENABLE); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(I2C1, SGP30_I2C_ADDR, I2C_Direction_Transmitter); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_SendData(I2C1, cmd[0]); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_SendData(I2C1, cmd[1]); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_GenerateSTOP(I2C1, ENABLE); // 读取返回的数据 I2C_GenerateSTART(I2C1, ENABLE); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(I2C1, SGP30_I2C_ADDR, I2C_Direction_Receiver); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); for (int i = 0; i < 5; i++) { while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); data[i] = I2C_ReceiveData(I2C1); } I2C_AcknowledgeConfig(I2C1, DISABLE); I2C_GenerateSTOP(I2C1, ENABLE); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); data[5] = I2C_ReceiveData(I2C1); // 将读取到的数据转换为TVOC和CO2浓度值 *tvoc = (data[0] << 8) | data[1]; *co2 = (data[3] << 8) | data[4]; } ``` 在使用该代码之前,需要先调用`SGP30_Init()`函数初始化SGP30气体传感器。然后,每次需要读取传感器数据时,调用`SGP30_ReadData()`函数即可。该函数会将读取到的TVOC和CO2浓度值存储在传入的指针变量中。需要注意的是,在读取数据之前需要等待一定时间,以便传感器可以完成数据的采集和处理。具体的等待时间可以参考SGP30气体传感器数据手册。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值