【硬件模块】SGP30气体传感器

SGP30

这是SGP30官方文档里开头的介绍,简单来说就是SGP30是一个数字多像素气体传感器,然后具有长期稳定性和低漂移。

这些我们都不用管,我们只需要知道SGP30是通过I2C来通信的,并且可以采集的数据有CO2和TVOC的含量。TVOC是“Total Volatile Organic Compounds”,意思是总挥发性有机化合物。

可以来看一下它的参数。

TVOC的输出范围是0~60000ppb,而CO2的范围是400~60000ppm。一开始没注意范围,我看CO2一直都在400以上还以为出了啥问题。

对了,在SGP30上电初始化之后会有一段时间输出的CO2固定是400,而TVOC固定是0,是正常现象,等一会就可以正常采集数据了,后面会再说

接下来是电气规格,这边要注意电压不能超过1.98V!!!跟我们平时常用的3.3V和5V不一样。直接使用SGP30需要进行电平转换。

不过我用的是模块,已经把电平转换芯片加上去了,供电3.3V~5V都是可以的。

除了电气规则,还有一个就是物理环境,但是大家一般都不会处于这么极端的环境吧。

工作温度在-40℃~85℃之间,湿度在10%95%之间。

然后是通信时间,可以看到SGP30支持的I2C最大速率是400K。

了解完上面的内容之后就可以开始研究如何和SGP30用I2C通信了。

SGP30的七位从机地址是0x58,因此从机地址+读的地址就是0xB1,从机地址+写的地址就是0xB0,我们也可以写成 ( 0x58<<1 | 0x01) 和 ( 0x58<<1 | 0x00)

通信的时序就是I2C的标准,不一样的是SGP30的指令分两个字节发送,也就是说我们发送一个命令需要发送两次。

并且SGP30发来的数据,每俩字节就跟一个CRC校验位。

CRC校验多项式是0x31,我们可以直接搜索CRC在线校验计算器帮我们计算。当然,我们也可以忽略掉,但是还是要接收。

接下来看看指令。

虽然不多,但是我们用到的更少,我们基本上只用俩命令,第一个是0x2003初始化,第二个是0x2008获取采集数据。

我们在一开始的发送0x2003初始化一下,等待12ms(文档里说的,但我们最好多延时一会儿)

然后我们就可以发送0x2008采集数据了,等待10ms(我们最好多等一会),会返回给我们6个byte的数据,其中前俩字节是CO2的数据,第三个是CO2数据的CRC校验码,第四五个字节是TVOC的数据,最后一个字节是TVOC的CRC校验码。

根据文档里说的,在初始化(0x2003)的15s内,我们获取采集数据(0x2008)收到的结果会是400和0。并且我们需要每秒发送一次0x2008就可以保证SGP30内部的补偿算法生效,采集的数据会更精确。

至此我们就知道应该如何使用SGP了,接下来我会贴出示例代码,结合代码和注释以及上文,相信大家就都可以将SGP30这个模块移植到各自的板子上了。

软件I2C使用SGP30(以GD32为例)

虽然我这边演示的是GD32(因为最近在用的板子是GD32),但是其他板子也是一样的流程,不一样的只是操作GPIO的方式不一样,自己修改一下即可。

另外有个小坑需要注意一下,我们STM32模拟I2C的时候GPIO配置的是推挽输出模式(没试过开漏),然后在弄GD32的时候一开始我也配置的是推挽,结果连ACK都没收到,排查了好久才发现需要将GD32的GPIO配置为开漏才可以进行软件模拟I2C。

#include "board.h"
#include <stdio.h>
#include "Z_UART.h"#define SCL_Pin GPIO_PIN_8
#define SDA_Pin GPIO_PIN_9
#define IIC_PORT GPIOB//下面Z_I2C开头的是软件I2C,不是使用SGP30的重点
void Z_I2C_Init(void){rcu_periph_clock_enable(RCU_GPIOB);gpio_mode_set(IIC_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP,SCL_Pin|SDA_Pin);gpio_output_options_set(IIC_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ,SCL_Pin|SDA_Pin);gpio_bit_write(IIC_PORT,SCL_Pin,1);gpio_bit_write(IIC_PORT,SDA_Pin,1);
}void Z_I2C_SetSCL(uint8_t signal){if(signal==1) gpio_bit_write(IIC_PORT,SCL_Pin,1);else gpio_bit_write(IIC_PORT,SCL_Pin,0);delay_us(5);
}void Z_I2C_SetSDA(uint8_t signal){if(signal==1) gpio_bit_write(IIC_PORT,SDA_Pin,1);else gpio_bit_write(IIC_PORT,SDA_Pin,0);delay_us(5);
}uint8_t Z_I2C_GetSDA(void){return gpio_input_bit_get(IIC_PORT,SDA_Pin);
}void Z_I2C_Start(void){Z_I2C_SetSDA(1);Z_I2C_SetSCL(1);Z_I2C_SetSDA(0);Z_I2C_SetSCL(0);
}void Z_I2C_End(){Z_I2C_SetSDA(0);Z_I2C_SetSCL(1);Z_I2C_SetSDA(1);
}void Z_I2C_SendByte(uint8_t byte){Z_I2C_SetSCL(0);for(int i=0;i<8;++i){if((byte&0x80)==0) Z_I2C_SetSDA(0);else Z_I2C_SetSDA(1);byte<<=1;Z_I2C_SetSCL(1);Z_I2C_SetSCL(0);}
}uint8_t Z_I2C_ReveiceByte(){uint8_t data=0x00;Z_I2C_SetSDA(1);for(int i=0;i<8;++i){Z_I2C_SetSCL(1);if(Z_I2C_GetSDA()==1) data|=(0x80>>i);Z_I2C_SetSCL(0);}return data;
}void Z_I2C_SendACK(uint8_t ack){if(ack==0) Z_I2C_SetSDA(0);else Z_I2C_SetSDA(1);Z_I2C_SetSCL(1);Z_I2C_SetSCL(0);
}uint8_t Z_I2C_ReveiceACK(){Z_I2C_SetSDA(1);Z_I2C_SetSCL(1);uint8_t ack=Z_I2C_GetSDA();Z_I2C_SetSCL(0);return ack;
}//获取SGP30的数据并打印
void printfSGP30(void){Z_I2C_Start();                                          //I2C起始时序Z_I2C_SendByte(0x58<<1|0x00);                           //发送从机地址+写(0xB0)if(0 != Z_I2C_ReveiceACK()) printf("ACK error\r\n");    //接收ACKZ_I2C_SendByte(0x20);                                   //发送采集命令0x2008,需要分两次发送if(0 != Z_I2C_ReveiceACK()) printf("ACK error\r\n");Z_I2C_SendByte(0x08);if(0 != Z_I2C_ReveiceACK()) printf("ACK error\r\n");Z_I2C_End();                                            //结束I2Cdelay_ms(100);                                          //需要等待10ms,保险起见延时久一点uint16_t data[4] = {0};Z_I2C_Start();Z_I2C_SendByte(0x58<<1|0x01);                           //发送从机地址+读(0xB0)if(0 != Z_I2C_ReveiceACK()) printf("ACK error\r\n");    //接收ACKdata[0] = Z_I2C_ReveiceByte();                          //接收CO2的高8位Z_I2C_SendACK(0);                                       //发送ACKdata[1] = Z_I2C_ReveiceByte();                          //接收CO2的低八位Z_I2C_SendACK(0);printf("CRC is 0x%X\r\n",Z_I2C_ReveiceByte());          //获取并打印CO2的CRC,可以不处理,但是一定要读取Z_I2C_SendACK(0);data[2] = Z_I2C_ReveiceByte();                          //接收TVOC(16bit)Z_I2C_SendACK(0);data[3] = Z_I2C_ReveiceByte();Z_I2C_End();                                            //TVOC的CRC不接收了,直接结束I2C通信printf("%X\t%X\t%X\t%X\r\n",data[0],data[1],data[2],data[3]);               //打印一下原始数据printf("CO2 is %d,TVOC is %d\r\n",data[0]<<8|data[1],data[2]<<8|data[3]);   //打印一下CO2和TVOC}int main(void){board_init();//初始化串口,为了将结果打印到串口助手上,不懂怎么操作的小伙伴可以看看之前关于串口的文章Z_UART_Init();Z_I2C_Init();                                       //初始化软件I2C相关引脚Z_I2C_Start();                                      //I2C起始时序Z_I2C_SendByte(0xB0);                               //发送从机地址+写if(0 != Z_I2C_ReveiceACK()) printf("ACK error\r\n");Z_I2C_SendByte(0x20);                               //发送初始化命令0x2003if(0 != Z_I2C_ReveiceACK()) printf("ACK error\r\n");Z_I2C_SendByte(0x03);if(0 != Z_I2C_ReveiceACK()) printf("ACK error\r\n");Z_I2C_End();                                        //结束I2Cdelay_ms(100);                                      //初始化需要10ms,但我们还是延时久一点while (1){printfSGP30();delay_ms(1000);}
}

可以收到数据,并且前十几秒的数据固定是400和0是正常现象。

GD32硬件I2C

之前的文章讲了GD32的引脚IIC,那么我们也加上GD32引脚IIC的例子吧。没看过且感兴趣的小伙伴可以再回顾一下。

【GD32】08 - IIC(以SHT20为例)-CSDN博客文章浏览阅读550次,点赞26次,收藏14次。接下来是设置IIC通信的模式与地址,模式我们自然是选择I2C模式的,而地址可以选择7位或者是10位的(10位的参数截图没截上,因为卡在手册的下一页了),这个根据我们通信的模块的从机地址而定。今天来了解一下GD32中的硬件IIC,其实我个人是觉得软件IIC比较方便的,不过之前文章里用的都是软件IIC,今天就算是走出自己的舒适圈,我们来了解了解GD32中的硬件IIC。关于IIC以及本文中演示的SHT20,在之前的文章里都有,并且也不是本文的重点,因此这里就不介绍了,不了解且感兴趣的小伙伴可以去看看之前的文章。https://blog.csdn.net/m0_63235356/article/details/140020224?spm=1001.2014.3001.5501

#include "board.h"
#include <stdio.h>
#include "Z_UART.h"//获取SGP30的数据并打印
void printfSGP30(void){i2c_start_on_bus(I2C0);                                     //I2C起始时序while(!i2c_flag_get(I2C0,I2C_FLAG_SBSEND) );i2c_master_addressing(I2C0,0xB0,I2C_TRANSMITTER);           //发送从机地址+写while(!i2c_flag_get(I2C0,I2C_FLAG_ADDSEND) );               //等待从机发送完毕之后得到回应(即从机地址正确)i2c_flag_clear(I2C0,I2C_FLAG_ADDSEND);i2c_data_transmit(I2C0,0x20);while(!i2c_flag_get(I2C0,I2C_FLAG_BTC) ); i2c_data_transmit(I2C0,0x08);while(!i2c_flag_get(I2C0,I2C_FLAG_BTC) ); i2c_stop_on_bus(I2C0);                                       //结束I2Cdelay_ms(100);                                              //需要等待10ms,保险起见延时久一点i2c_start_on_bus(I2C0);                                     //I2C起始时序while(!i2c_flag_get(I2C0,I2C_FLAG_SBSEND) );i2c_master_addressing(I2C0,0xB0,I2C_RECEIVER);              //发送从机地址+读while(!i2c_flag_get(I2C0,I2C_FLAG_ADDSEND) );               //等待从机发送完毕之后得到回应(即从机地址正确)i2c_flag_clear(I2C0,I2C_FLAG_ADDSEND);i2c_ack_config(I2C0, I2C_ACK_ENABLE);   uint16_t data[4] = {0};while(!i2c_flag_get(I2C0,I2C_FLAG_RBNE) );          //等待接收缓冲区不为空data[0] = i2c_data_receive (I2C0); while(!i2c_flag_get(I2C0,I2C_FLAG_RBNE) );          //等待接收缓冲区不为空data[1] = i2c_data_receive (I2C0); while(!i2c_flag_get(I2C0,I2C_FLAG_RBNE) );          //等待接收缓冲区不为空uint8_t crc = i2c_data_receive (I2C0); printf("CRC is %X\r\n",crc);while(!i2c_flag_get(I2C0,I2C_FLAG_RBNE) );          //等待接收缓冲区不为空data[2] = i2c_data_receive (I2C0); i2c_ack_config(I2C0, I2C_ACK_DISABLE);while(!i2c_flag_get(I2C0,I2C_FLAG_RBNE) );          //等待接收缓冲区不为空data[3] = i2c_data_receive (I2C0); i2c_stop_on_bus(I2C0); printf("%X\t%X\t%X\t%X\r\n",data[0],data[1],data[2],data[3]);               //打印一下原始数据printf("CO2 is %d,TVOC is %d\r\n",data[0]<<8|data[1],data[2]<<8|data[3]);   //打印一下CO2和TVOC}int main(void){board_init();//初始化串口,为了将结果打印到串口助手上,不懂怎么操作的小伙伴可以看看之前关于串口的文章Z_UART_Init();//开启时钟rcu_periph_clock_enable(RCU_I2C0);rcu_periph_clock_enable(RCU_GPIOB);//初始化硬件IIC的引脚gpio_af_set(GPIOB, GPIO_AF_4,GPIO_PIN_8|GPIO_PIN_9);gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_8|GPIO_PIN_9);gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ,GPIO_PIN_8|GPIO_PIN_9);i2c_deinit(I2C0);                                           //复位IIC0i2c_clock_config(I2C0, 100000, I2C_DTCY_2);                 //设置IIC速率为100ki2c_ack_config(I2C0, I2C_ACK_ENABLE);                       //使能应答i2c_enable(I2C0);                                           //使能IICi2c_start_on_bus(I2C0);                                     //I2C起始时序while(!i2c_flag_get(I2C0,I2C_FLAG_SBSEND) );i2c_master_addressing(I2C0,0xB0,I2C_TRANSMITTER);           //发送从机地址+写while(!i2c_flag_get(I2C0,I2C_FLAG_ADDSEND));                //等待从机发送完毕之后得到回应(即从机地址正确)i2c_flag_clear(I2C0,I2C_FLAG_ADDSEND);i2c_data_transmit(I2C0,0x20);while(!i2c_flag_get(I2C0,I2C_FLAG_BTC) ); i2c_data_transmit(I2C0,0x03);while(!i2c_flag_get(I2C0,I2C_FLAG_BTC) ); i2c_stop_on_bus(I2C0);                                      //结束I2Cdelay_ms(100);                                              //初始化需要10ms,但我们还是延时久一点while (1){printfSGP30();delay_ms(1000);}
}

ESP32硬件I2C

这边也提供一下ESP32硬件I2C的代码吧,ESP32的硬件I2C方便好多,一下子就调通了。

顺便一提,因为没找到实习,于是决定暑假开始录制ESP32(ESP-IDF)的视频了,可以的话可以把今年服务外包的项目(省赛都没进)的硬件部分当个练手项目分享出来(基于ESP32),还有时间的话可以再录制一下GD32的视频。

ESP32已经在录了,相信没过多久就可以和大家见面了。可以关注一下b站的同名账号,微信视频号也会一起发。

#include <stdio.h>
#include "driver/i2c.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"// 获取SGP30的数据并打印
void printfSGP30(void) {i2c_cmd_handle_t cmd_handle = i2c_cmd_link_create();i2c_master_start(cmd_handle);i2c_master_write_byte(cmd_handle, 0xB0, true);i2c_master_write_byte(cmd_handle, 0x20, true);i2c_master_write_byte(cmd_handle, 0x08, true);i2c_master_stop(cmd_handle);i2c_master_cmd_begin(I2C_NUM_0, cmd_handle, 100 / portTICK_PERIOD_MS);i2c_cmd_link_delete(cmd_handle);vTaskDelay(100 / portTICK_PERIOD_MS);uint8_t data[6] = {0};cmd_handle = i2c_cmd_link_create();i2c_master_start(cmd_handle);i2c_master_write_byte(cmd_handle, 0xB1, true);i2c_master_read_byte(cmd_handle, &data[0], I2C_MASTER_ACK);i2c_master_read_byte(cmd_handle, &data[1], I2C_MASTER_ACK);i2c_master_read_byte(cmd_handle, &data[2], I2C_MASTER_ACK);i2c_master_read_byte(cmd_handle, &data[3], I2C_MASTER_ACK);i2c_master_read_byte(cmd_handle, &data[4], I2C_MASTER_ACK);i2c_master_read_byte(cmd_handle, &data[5], I2C_MASTER_ACK);i2c_master_stop(cmd_handle);i2c_master_cmd_begin(I2C_NUM_0, cmd_handle, 100 / portTICK_PERIOD_MS);i2c_cmd_link_delete(cmd_handle);printf("CO2 is %d,TVOC is %d\r\n", (uint16_t)data[0] << 8 | data[1],(uint16_t)data[3] << 8 | data[4]);  // 打印一下CO2和TVOC
}void app_main(void) {printf("hello world\r\n");i2c_config_t i2c_initer = {.clk_flags = 0,              // 选择默认时钟源.master.clk_speed = 100000,  // 指定速率为100Kbit,最大可以为400Kbit.mode = I2C_MODE_MASTER,  // 主机模式.scl_io_num = 7,          // 指定SCL的GPIO口.scl_pullup_en = true,    // SCL接上拉电阻.sda_io_num = 8,          // 指定SDA的GPIO口.sda_pullup_en = true,    // SDA接上拉电阻};if (i2c_param_config(I2C_NUM_0, &i2c_initer) == ESP_OK)printf("i2c parm config success\r\n");elseprintf("config fail\r\n");if (i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0) == ESP_OK)printf("i2c driver install success\r\n");elseprintf("driver fail\r\n");i2c_cmd_handle_t cmd_handle = i2c_cmd_link_create();i2c_master_start(cmd_handle);i2c_master_write_byte(cmd_handle, 0xB0, true);i2c_master_write_byte(cmd_handle, 0x20, true);i2c_master_write_byte(cmd_handle, 0x03, true);i2c_master_stop(cmd_handle);i2c_master_cmd_begin(I2C_NUM_0, cmd_handle, 100 / portTICK_PERIOD_MS);i2c_cmd_link_delete(cmd_handle);while (1) {printfSGP30();vTaskDelay(1000 / portTICK_PERIOD_MS);}
}

也可以正常打印出结果。 

文档原文包括译文,以及卖家发的资料我都打包好了,大家可以关注我的同名公众号“折途想要敲代码”,回复关键词“SGP30”即可免费下载啦。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/39669.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RPM包管理-rpm命令管理

1.RPM包命令原则 所有的rpm包都在光盘中 例&#xff1a;httpd-2.2.15-15.e16.centos.1.i686.rpm httpd 软件包名 2.2.15 软件版本 15 软件发布的次数 e16.centos 适合的Linux平台 i686 适合的硬件平台…

【Git 学习笔记】1.3 Git 的三个阶段

1.3 Git 的三个阶段 由于远程代码库后续存在新的提交&#xff0c;因此实操过程中的结果与书中并不完全一致。根据书中 HEAD 指向的 SHA-1&#xff1a;34acc370b4d6ae53f051255680feaefaf7f7850d&#xff0c;可通过以下命令切换到对应版本&#xff0c;并新建一个 newdemo 分支来…

Linux——shell原理和文件权限

1.shell原理 在我们使用云服务器时&#xff0c;需要通过shell进行使用&#xff0c;而shell则是一种外壳程序。 我们提到过&#xff0c;大部分的指令实际上就是文件&#xff0c;当用户需要执行某种功能时&#xff0c;由于用户不擅长和操作系统直接交互&#xff08;操作复杂&…

度量监控平台,研发的助手

背景 指标度量遥测数据准确、多维度和可观测统一管控台入口(SLS/ARMS日志查询&#xff0c;OpenTelemetry/SkyWalking&#xff0c;Grafana)Trace、Metric、Log (链路、指标、日志) 目标 快速排障&#xff0c;解决问题的助手整体联动&#xff0c;降低使用成本梳理排查路径&…

「PAI-ArtLab100 AIGC」设计普惠计划发布!与 100+ 高校共同探索 AIGC 教育新路径

随着人工智能技术的迅猛发展所带来的全新设计理念和工具&#xff0c;设计艺术教育正面临一场变革。AIGC&#xff08;AI生成内容&#xff09;技术不仅推动了设计领域的技术革新&#xff0c;还在教育模式、学习方法和创意实践展开全新的重塑。 6月28日&#xff0c;D20全球设计院长…

视频批量剪辑一键垂直翻转,轻松转换格式为mov,视频制作从此事半功倍!

在视频制作的海洋中&#xff0c;我们时常需要面对各种挑战&#xff0c;其中之一就是视频的翻转与调整。不论是出于创意需求还是格式转换的需要&#xff0c;视频翻转都是一个不可或缺的功能。今天&#xff0c;我要向大家介绍一款真正的批量视频翻转神器——视频剪辑高手&#xf…

如何选择易用性高的项目管理软件?

随着项目管理在各行各业的广泛应用&#xff0c;选择一款易用性高的项目管理软件变得越来越重要。易用性高的软件可以帮助企业提高工作效率&#xff0c;降低管理成本&#xff0c;同时还能提升团队之间的协作能力。那么&#xff0c;如何选择一款易用性高的项目管理软件呢&#xf…

港股通权限开通要求,交易时间与申报方式,港股通手续费详情

港股通权限开通要求 已开通上海或深圳A股证券账户 在申请权限开通前20个交易日内&#xff0c;证券账户以及资金账户&#xff08;包括证券市值和资金可用余额&#xff0c;含融资融券净资产&#xff09;的日均资产不低于人民币50万元。 投资者需要完成风险测评问卷&#xff0c;且…

详解HTTP:常用的密钥交换算法RSA与ECDHE

HTTPS 常用的密钥交换算法&#xff1a;RSA 与 ECDHE 在 HTTPS 中&#xff0c;密钥交换算法扮演了至关重要的角色&#xff0c;确保数据在传输过程中的安全性。目前常用的密钥交换算法主要有两种&#xff1a;RSA 和 ECDHE。相比于较为传统的 RSA&#xff0c;ECDHE 由于具备前向安…

Apache IoTDB 监控详解 | 分布式系统监控基础

IoTDB 分布式系统监控的基础“须知”&#xff01; 我这个环境的系统性能一直无法提升&#xff0c;能否帮我找到系统的瓶颈在哪里&#xff1f; 系统优化后&#xff0c;虽然写入性能有所提升&#xff0c;但查询延迟却增加了&#xff0c;下一步我该如何排查和优化呢&#xff1f; 请…

系留无人机+自组网+单兵图传:低空集群组网指挥系统技术详解

低空无人机集群的控制、调度、信息回传需要有高度可靠和稳定的无线通信链路来保障。我国发达的公网基础设施为上述应用创造了良好的条件&#xff0c;但低空应用必须要考虑到在极端情况下公网瘫痪造成的通信链路中断带来的影响&#xff0c;因此有必要在公网之外&#xff0c;寻求…

网络数据传输中的封装与解封装详解

注&#xff1a;机翻&#xff0c;未校对。 The goal of networks is to transmit data from one host to another. 网络的目标是将数据从一个主机传输到另一个主机。 Encapsulation 封装 To achieve this goal, each layer adds its own header to the data. A header contain…

Vue3的模板语法插值表达式用法

在template中输入“5 3” &#xff0c;是没有运算能力的&#xff0c;只会把字符直接显示出来&#xff0c;代码如下&#xff1a; <template><view>这是demo</view><view>5 3</view><navigator open-type"navigateBack"><vi…

【OpenSSH】立即检测 OpenSSH 的 regreSSHion 漏洞

OpenSSH regreSSHion 漏洞简介 OpenSSH 是一种广泛使用的网络协议&#xff0c;提供加密的数据通信和远程登录功能。然而&#xff0c;最近发现的一个漏洞&#xff08;CVE-2024-6387&#xff09;&#xff0c;被称为 regreSSHion&#xff0c;使得未经身份验证的攻击者能够在 Linu…

FlowUs新一代内容创作营销平台|FlowUs息流国产 好用 不限速

FlowUs 作为一个知识管理和协作平台&#xff0c;知识库功能可以被视为一个强大的学习工具&#xff01; 为什么FlowUs知识库可以成为学习利器呢&#xff1f;原因有以下几点 集中化知识存储&#xff1a;FlowUs允许我们将所有相关信息和资料集中在一个地方&#xff0c;便于访问和复…

zed_ros2_wapper colcon 报错

问题一&#xff1a; CMake Error at CMakeLists.txt:129 (find_package): By not providing “Findnmea_msgs.cmake” in CMAKE_MODULE_PATH this project has asked CMake to find a package configuration file provided by “nmea_msgs”, but CMake did not find one. Co…

不可忽视的安全防线:深入探讨安全阀检测时间的选择

在工业生产中&#xff0c;安全阀被誉为设备的“守护者”&#xff0c;它承担着防止压力过高导致设备损坏或事故发生的重要使命。然而&#xff0c;安全阀的性能并非永恒不变&#xff0c;其有效性需要通过定期检测来验证。 接下来&#xff0c;佰德将深入探讨安全阀检测的重要性、…

K8s 的最后一片拼图:dbPaaS

K8s 的发展使得私有云跟公共云之间的技术差不断的缩小&#xff0c;不管是在私有云还是公共云&#xff0c;大家今天都在基于 K8s 去开发 PaaS 系统。而 K8s 作为构建 PaaS 的基础&#xff0c;其全景图里还缺最后一块“拼图”——dbPaaS。作为一个云数据库行业干了十几年的资深从…

在uni-app使用vue3使用vuex

在uni-app使用vue3使用vuex 1.在项目目录中新建一个store目录&#xff0c;并且新建一个index.js文件 import { createStore } from vuex;export default createStore({//数据&#xff0c;相当于datastate: {count:1,list: [{name: 测试1, value: test1},{name: 测试2, value: …

LLM笔记:训练大模型之并行化

1 数据并行 最常见的并行化手段主要是把数据分成多个块&#xff0c;然后每个节点就可以在本地独立的跑各自的数据任务&#xff0c;最后再和其他节点通信&#xff0c;进而汇总最后的结果好处就是计算效率高&#xff0c;每个节点可以独自计算自己的任务且这种方法易于实现缺点就…