历史上的今天
返回首页

历史上的今天

今天是:2025年07月23日(星期三)

正在发生

2021年07月23日 | STM32CubeMX | 29-使用硬件I2C读取甲醛传感器SGP30

2021-07-23 来源:eefocus

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


【STM32Cube_09】重定向printf函数到串口输出的多种方法。

https://github.com/Mculover666/HAL_Driver_Lib

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

宏定义SGP30器件地址

先来编写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;


枚举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 failrn");

        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 failrn");

        return -1;

    }

    

    /* 校验接收的测量数据 */

    if (CheckCrc8(&recv_buffer[0], 0xFF) != recv_buffer[2]) {

        printf("co2 recv data crc check failrn");

        return -1;

    }

    if (CheckCrc8(&recv_buffer[3], 0xFF) != recv_buffer[5]) {

        printf("tvoc recv data crc check failrn");

        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

#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 mculover666rn");

  

    if (-1 == sgp30_init()) {

        printf("sgp30 init failrn");

        

        /* 因为是裸机,所以直接进入死机 */

        while(1);

    }

    printf("sgp30 init successrn");

  /* USER CODE END 2 */


  while (1)

  {

/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */

if( -1 == spg30_read()) {

     printf("sgp30 read failrn");

}

else {

     printf("sgp30 read success, co2:%4d ppm, tvoc:%4d ppdrn", sgp30_data.co2, sgp30_data.tvoc);

}

 

HAL_Delay(2000);

}

/* USER CODE END 3 */

}


测试结果如图:


推荐阅读

史海拾趣

Dynachip Corp公司的发展小趣事

Dynachip Corp始终将创新作为公司发展的核心动力。他们不断投入研发资源,探索新的技术方向和应用场景。同时,他们还积极关注行业动态和市场趋势,及时调整产品策略和市场布局。这种持续创新的精神使Dynachip Corp能够保持在行业中的领先地位,并为未来的发展奠定了坚实的基础。展望未来,Dynachip Corp将继续秉承创新、品质、合作的理念,致力于成为全球领先的半导体企业。

Gamma Microelectronics ( APM )公司的发展小趣事

2007年10月,G24i在英国建立了DSSC的30MW试产线,这是全球范围内的重要里程碑。这条生产线具备高效的生产能力,能够在不到3小时的时间内制造出长达约800米的太阳能电池,生产速度高达每分钟4米以上。这一成就不仅展示了G24i在规模化生产方面的实力,也为后续的商业化应用奠定了产能基础。尽管初期商业化模组产品的转换效率仅为3%,但G24i通过不断优化生产工艺和降低成本,逐步提升了产品的市场竞争力。

长园维安(CYGWAYON)公司的发展小趣事

随着产品技术的成熟,长园维安开始积极拓展国际市场。公司与国际知名企业建立合作关系,共同开发新产品,拓展市场份额。同时,长园维安还积极参加国际展览,展示公司最新技术和产品,提高品牌知名度。这些努力使长园维安在全球电子行业中的影响力不断增强。

Fairchild公司的发展小趣事

1965年,Fairchild公司的创始人之一戈登·摩尔提出了著名的“摩尔定律”。该定律预测了集成电路上晶体管数量的增长速度,即每两年翻一番。这一预测在之后的几十年里得到了惊人的验证,并成为了电子行业的重要指导原则。摩尔定律的提出不仅推动了半导体技术的快速发展,也促进了计算机和其他电子设备的不断升级换代。

Altera (Intel)公司的发展小趣事

随着科技的不断进步和市场环境的变化,Fairchild公司也面临着转型和创新的挑战。为了保持竞争力和市场地位,Fairchild公司不断加大对新技术和新产品的研发投入。同时,公司也积极寻求与其他企业和研究机构的合作,共同推动半导体技术的创新和发展。通过这些努力,Fairchild公司成功实现了从传统半导体制造商向创新型科技企业的转型。

以上五个故事简要概述了Fairchild公司在电子行业发展的历程和成就。作为半导体行业的领军企业之一,Fairchild公司凭借其卓越的技术实力、创新能力和市场洞察力,为电子行业的发展做出了重要贡献。

Gem Asia Enterprise Co Ltd公司的发展小趣事

Gem Asia Enterprise最初是一家专注于电子元件生产的小型制造商。面对激烈的市场竞争,公司决定加大研发投入,专注于开发新型半导体材料。经过数年努力,Gem Asia成功研发出一种高效能、低功耗的半导体材料,并成功应用于智能手机和可穿戴设备中。这一创新不仅显著提升了产品的市场竞争力,还吸引了多家国际知名电子品牌的合作,使Gem Asia迅速在电子行业中崭露头角。

问答坊 | AI 解惑

电阻基出知识(上)

如标题,不多说了.…

查看全部问答>

设置dsp的wdkey=0x55和0xaa起什么作用?

书中说这是看门狗控制 是怎么控制看门狗的? 谢谢!!! 本人超级菜鸟,,,才开始看dsp,,, 谢谢!…

查看全部问答>

有人用TMS320VC5509A的么?请教:ioport的问题.

5509A的IO空间0x0000~0xffff. MOV #1, port(#01h) 此语句会改写中断标志寄存器IFR0么? 如果我想使用  IO空间 0000~0007的地址去 扩展地址线ADDR14,ADDR15,ADDR16.可行么? …

查看全部问答>

关于ARM方面的一个程序编写

有没有人可以告诉我这个程序怎么用ARM语言编写?        有一个地址区间,将指定数据如1-50放在地址开始区间内,再将1-50内被2整除的数放在另一个区间内.…

查看全部问答>

请问:要想构建一个祼机环境,要什么部件啊, 只有一块开发板行不行啊?

要想构建一个祼机环境,要什么部件啊, 只有一块开发板行不行啊?…

查看全部问答>

按摩器,按摩棒,震动器,震动棒方案

提供按摩器,按摩棒,震动器,震动棒方案开发及IC徐工:13713904933  QQ:104018792(技术交流)     我司是享誉电子产业界的义隆电子<EMC>的直接代理商,并专业从事电子产品研发,单片机开发,单片机解密。公司拥有数十名资 ...…

查看全部问答>

准备发礼品了,大家看看有没有在名单上

谢谢大家对我的支持,2011我会继续努力的。 现在我在做统计的工作,在回我贴的朋友里并明确告诉我投我的,我做了下统计,把名单列出来,大家看看还有没有遗漏?有出路的话请抓紧时间跟帖告诉我,你应该排在的顺序,那个压缩包的密码我先不公布,等 ...…

查看全部问答>

如何在ccs2.2里面实时打出一些程序运行的信息?或将信息保存?

如何在ccs2.2里面实时打出一些程序运行的信息?比如某个变量的值。或者如何将一个变量的一系列值保存到文件中阅读?谢谢! …

查看全部问答>

梦之旅同学松鼠1.0学习笔记(五)之1602

  最近比较忙,过段时间就要考期末了,所以半夜出来发代码,后面可能没时间了,发完代码睡觉,呵呵。   相信用过1602的人都知道,1602的相应操作,本文只想讲下4位数据的1602的驱动模式。    其实,4位的1602和8位的区别主要 ...…

查看全部问答>

求助 关于一个按键几个功能,程序出现问题

#include typedef unsigned char uchar  ; typedef unsigned int uint; uchar table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; uchar tt,dat; sbit button = P3^7; void delay_50us(uint t) {     &nbs ...…

查看全部问答>