电池管理协议SMBus/I2C在STM32CubeMX配置使用-读取SN8765电池组

一、前言

目前有个电源组需要通过i2c进行读取,获取一些电池信息,采用SMBus协议进行读取,其可以看作i2c的子集,可以直接通过i2c的接口进行读写。
SMBus建立在被广泛采用的I2C总线之上,并定义了OSI(开放系统互连)模型的链路和网络层。PMBus™使用SMBus作为其物理层,并添加了命令定义和其他新特性。大多数新特性都属于OSI模型的中到高层次。
读取的电池组控制芯片为SN8765,属于定制的。
设备地址一般为0x16,需要联系厂家获取一些设备和软件读取信息和i2c读取的信息进行比对,确认i2c读取内容大小端问题及转换等问题,寄存器地址基本也是固定的,找厂家获取对应文档即可。
一般使用德州仪器TI的EV2300 HPA002设备和对应的bq Evaluation Software等软件进行读取,基本配置SMBus/I2C的SCL、SDA、GND进行读取即可,EV2300使用USB供电,对应USB驱动也在网上搜一下安装即可。
image.png

二、资料收集

SMBus介绍:https://www.eet-china.com/mp/a25851.html
STM32CubeMX HAL库SMBUS和PMBUS介绍:https://www.stmcu.com.cn/Designresource/design_resource_detail?file_name=AN4502_%E5%9F%BA%E4%BA%8ESTM32Cube%E5%BA%93%E7%9A%84SMBUS%E5%92%8CPMBUS%E4%BB%8B%E7%BB%8D&lang=EN&ver=4.0&cat=application_note
Alert mode:https://blog.csdn.net/weixin_49259827/article/details/128217687
EV2300驱动:https://www.laptopu.ro/wp-content/uploads/wpforo/attachments/103/2452-EV2300aDeviceDriverInstallerMultilanguage0-6.rar
SN8765规格书:https://download.csdn.net/download/weixin_41602413/10193698?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-download-2%7Edefault%7ECTRLIST%7ERate-1-10193698-blog-83178838.235%5Ev43%5Epc_blog_bottom_relevance_base3&depth_1-utm_source=distribute.pc_relevant.none-task-download-2%7Edefault%7ECTRLIST%7ERate-1-10193698-blog-83178838.235%5Ev43%5Epc_blog_bottom_relevance_base3&utm_relevant_index=2
对于F1\F4等不太适合X-CUBE-SMBUS,可以直接使用I2C:
image.png

三、CubeMX配置

1、方式1-X-CUBE-SMBUS(F1、F4等无法正常使用)

下载安装配置SMBUS中间件,基于i2c配置SMBus:(示例一下SMBUS配置,对于F1、F4等可以直接配置使用i2c,获取配置GPIO口软件模拟I2C)
image.png
配置开启SMBUS中间件:
第一次是没有的,需要登录下载安装:
image.png

2、HAL库方式i2c接口(不推荐,硬件i2c可能总是busy)

配置简单,接口也简单,但是调试时经常发现读写接口返回为HAL_BUSY,所以不是很推荐。
image.png

3、HAL库GPIO模拟i2c(推荐)

配置两个GPIO为SCL和SDA,然后增加us级别的延时,之后自行根据i2c协议模拟开始、结束、收、发、ack。
image.png

//
// Created by Administrator on 2024/3/5.
//#ifndef IIC_H
#define IIC_H#include <stdint.h>void IIC_Start(void);
void IIC_Stop(void);
void IIC_Send_Byte(uint8_t d);
uint8_t IIC_Wait_Ack(void);
uint8_t  IIC_Read_Byte(void);
void IIC_Ack(uint8_t ack);#endif //IIC_H
//
// Created by Administrator on 2024/3/5.
//#include "iic.h"#include "delay.h"
#include "gpio.h"/**********************************************************1.IIC软件模拟   使用HAL库时2.需要STM32CubeMX配置初始化的相关引脚为GPIO模式 SDA SCL初始状态下都是输出 推挽 上拉模式4.初始状态下SDA 与 SCL要给高电平 使用高低电平转换时之间要有明显的us级延时
**********************************************************/
static GPIO_InitTypeDef GPIO_InitStruct;
/**********************************************************
1.引脚配置 宏定义用IF语句
2.给引脚电平必须要给输出模式
3.SCL一直都是输出模式(输出时钟肯定是输出模式)
4.宏定义绑定引脚SDA与SCL   SDA PB5    SCL PB4
**********************************************************/
#define SCL_Type     GPIOB
#define SDA_Type     GPIOB#define SCL_GPIO    GPIO_PIN_4
#define SDA_GPIO    GPIO_PIN_5
//设置输出高低电平模式
#define SDA_OUT(X)   if(X) \HAL_GPIO_WritePin(SDA_Type, SDA_GPIO, GPIO_PIN_SET); \else  \HAL_GPIO_WritePin(SDA_Type, SDA_GPIO, GPIO_PIN_RESET);#define SCL_OUT(X)   if(X) \HAL_GPIO_WritePin(SCL_Type, SCL_GPIO, GPIO_PIN_SET); \else  \HAL_GPIO_WritePin(SCL_Type, SCL_GPIO, GPIO_PIN_RESET);#define SDA_IN         HAL_GPIO_ReadPin(SDA_Type,SDA_GPIO)//只有输入模式才能读取电平状态/*****************************************SDA引脚转变为 OUT输出模式(输出模式给停止 开始信号)
******************************************/
void IIC_SDA_Mode_OUT(void) {GPIO_InitStruct.Pin = SDA_GPIO;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(SDA_Type, &GPIO_InitStruct);
}/*****************************************SDA引脚转变为 输入模式(输入模式传输具体的数据)
******************************************/
void IIC_SDA_Mode_IN(void) {GPIO_InitStruct.Pin = SDA_GPIO;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(SDA_Type, &GPIO_InitStruct);
}/*****************************************IIC开始信号
******************************************/
void IIC_Start(void)//IIC开始信号
{//设置为输出模式IIC_SDA_Mode_OUT();//空闲状态两个引脚是高电平SDA_OUT(1);SCL_OUT(1);delay_us(5);//拉低数据线SDA_OUT(0);delay_us(5);//再拉低时钟线SCL_OUT(0);delay_us(5);
}//IIC停止信号
void IIC_Stop(void) {//设置为输出模式IIC_SDA_Mode_OUT();//拉低SDA_OUT(0);SCL_OUT(0);delay_us(5);//时钟线先拉高SCL_OUT(1);delay_us(5);//再把数据线拉高SDA_OUT(1);delay_us(5);
}void IIC_Send_Byte(uint8_t d)//主机发送8位数据给从机MSB 高位先发
{uint8_t i = 0;//设置为输出模式IIC_SDA_Mode_OUT();SDA_OUT(0);SCL_OUT(0);delay_us(5);for (i = 0; i < 8; i++) {if (d & (0x1 << (7 - i)))//表示数据是1SDA_OUT(1)else SDA_OUT(0);delay_us(5);SCL_OUT(1);//拉高时钟线,告诉对方你可以读了delay_us(5);SCL_OUT(0);//拉低时钟线,告诉对方你暂时别读,我在准备数据}}uint8_t IIC_Wait_Ack(void)//等待从机给主机应答或者不应答
{uint8_t ack = 0;//设置为输入模式IIC_SDA_Mode_IN();//时钟线拉高,时钟线为高电平期间,不管是数据还是ack都是有效的SCL_OUT(1);delay_us(5);if (SDA_IN == 1)ack = 1;//无效ACK,就是无效应答elseack = 0;//有效ACK,就是有效应答SCL_OUT(0);delay_us(5);return ack;
}uint8_t IIC_Read_Byte(void)//从机发送8位数据给主机
{uint8_t i = 0;uint8_t data = 0;//设置为输入模式IIC_SDA_Mode_IN();//先拉低时钟线,准备数据SCL_OUT(0);delay_us(5);for (i = 0; i < 8; i++) {SCL_OUT(1);//时钟线为高电平期间数据才是有效的delay_us(5);if (SDA_IN == 1)data |= (0x1 << (7 - i));//数据就是1elsedata &= ~(0x1 << (7 - i));//数据就是0SCL_OUT (0);//告诉对方此时准备数据,先别读写delay_us(5);}return data;
}//主机发送应答或者不应答给从机,1高电平不应答,反之应答
void IIC_Ack(uint8_t ack)
{//设置为输出模式IIC_SDA_Mode_OUT();SDA_OUT(0);SCL_OUT(0);delay_us(5);SDA_OUT(ack);//发送高/低电平--->发送不应答/应答delay_us(5);SCL_OUT(1);//告诉从机我已经准备好数据,你可以读取了delay_us(5);SCL_OUT (0);//拉低时钟线,发送ack结束delay_us(5);
}
void delay_us(uint32_t udelay)
{uint32_t startval,tickn,delays,wait;startval = SysTick->VAL;tickn = HAL_GetTick();//sysc = 72000;  //SystemCoreClock / (1000U / uwTickFreq);delays =udelay * 72; //sysc / 1000 * udelay;if(delays > startval){while(HAL_GetTick() == tickn){}wait = 72000 + startval - delays;while(wait < SysTick->VAL){}}else{wait = startval - delays;while(wait < SysTick->VAL && HAL_GetTick() == tickn){}}
}

四、示例代码

I2C需要确认方向、设备地址,寄存器地址,之后读写多个字节的流程就比较固定了,这里结合SN8765读取做了简单封装:

#include <stdio.h>
#include <string.h>
#include "battery.h"
//#include "i2c.h"
#include "iic.h"#define SN8765_DEVICE_ADDRESS 0x16
#define I2C_READ 1
#define I2C_WRITE 0typedef enum {BATTERY_SBS_CMD_TEMPERATURE = 0x08,BATTERY_SBS_CMD_VOLTAGE,BATTERY_SBS_CMD_CURRENT,BATTERY_SBS_CMD_RELATIVE_STATE_CHARGE = 0x0d,BATTERY_SBS_CMD_CYCLE_COUNT = 0x17,BATTERY_SBS_CMD_MANUFACTURER_DATE = 0x1b,BATTERY_SBS_CMD_SERIAL_NUMBER,BATTERY_SBS_CMD_MANUFACTURER_NAME = 0x20,BATTERY_SBS_CMD_DEVICE_NAME,
} BATTERY_SBS_CMD;uint8_t i2c_read_word(uint8_t cmd, uint8_t *res, uint8_t read_size) {//开始IIC_Start();//发送器件地址+写命令IIC_Send_Byte(SN8765_DEVICE_ADDRESS|I2C_WRITE);if(IIC_Wait_Ack()) {printf("wait ack failed1.\n");return 0;}//发送寄存器地址IIC_Send_Byte(cmd);if(IIC_Wait_Ack()) {printf("wait ack failed2.\n");return 0;}IIC_Start();//发送器件地址+读命令IIC_Send_Byte(SN8765_DEVICE_ADDRESS|I2C_READ);if (IIC_Wait_Ack()) {printf("wait ack failed3.\n");return 0;}//读单个或多个字节int i;for (i = 0; i < read_size; i++) {res[i] = IIC_Read_Byte();if (i != read_size - 1) {//应答IIC_Ack(0);} else {//最后一个字节读取后不应答IIC_Ack(1);}}//停止IIC_Stop();return i;
}void readAllBatteryInfo(T_BatteryInfo *batteryInfo) {uint8_t data[32] = {'\0'};memset(data, '\0', sizeof(data));i2c_read_word(BATTERY_SBS_CMD_TEMPERATURE, data, 2);batteryInfo->temperature = data[0] + (data[1] * 256);printf("data0:%02x,data1:%02x,temp:%d\n", data[0], data[1], batteryInfo->temperature);memset(data, '\0', sizeof(data));i2c_read_word(BATTERY_SBS_CMD_VOLTAGE, data, 2);batteryInfo->voltage = data[0] + (data[1] * 256);printf("data0:%02x,data1:%02x,voltage:%d\n", data[0], data[1], batteryInfo->voltage);memset(data, '\0', sizeof(data));i2c_read_word(BATTERY_SBS_CMD_CURRENT, data, 2);batteryInfo->current = (short)(data[0] + (data[1] * 256));printf("data0:%02x,data1:%02x,current:%d\n", data[0], data[1], batteryInfo->current);memset(data, '\0', sizeof(data));i2c_read_word(BATTERY_SBS_CMD_RELATIVE_STATE_CHARGE, data, 1);batteryInfo->relativeStateOfCharge = data[0];printf("data0:%02x,relativeStateOfCharge:%d\n", data[0], batteryInfo->relativeStateOfCharge);memset(data, '\0', sizeof(data));i2c_read_word(BATTERY_SBS_CMD_CYCLE_COUNT, data, 2);batteryInfo->cycleCount = data[0] + (data[1] * 256);printf("data0:%02x,data1:%02x,cycleCount:%d\n", data[0], data[1], batteryInfo->cycleCount);memset(data, '\0', sizeof(data));i2c_read_word(BATTERY_SBS_CMD_MANUFACTURER_DATE, data, 2);batteryInfo->manufactureDate = data[0] + (data[1] * 256);printf("data0:%02x,data1:%02x,manufactureDate:%d\n", data[0], data[1], batteryInfo->manufactureDate);memset(data, '\0', sizeof(data));i2c_read_word(BATTERY_SBS_CMD_SERIAL_NUMBER, data, 2);batteryInfo->serialNumber[1] = data[0];batteryInfo->serialNumber[0] = data[1];printf("data0:%02x,data1:%02x,serialNumber:%d,%d\n", data[0], data[1], batteryInfo->serialNumber[0], batteryInfo->serialNumber[1]);memset(data, '\0', sizeof(data));i2c_read_word(BATTERY_SBS_CMD_MANUFACTURER_NAME, data, 12);printf("manufacturer name:");for (int i = 0; i < 12; i++) {printf("%02x ", data[i]);}printf("\n");memset(data, '\0', sizeof(data));i2c_read_word(BATTERY_SBS_CMD_DEVICE_NAME, data, 8);printf("device name:");for (int i = 0; i < 8; i++) {printf("%02x ", data[i]);}printf("\n");
}
//
// Created by Administrator on 2024/3/5.
//#ifndef BATTERY_H
#define BATTERY_H
#include <stdint.h>typedef struct {uint16_t manufacturerAccess;uint16_t remainingCapacityAlarm;uint16_t remainingTimeAlarm;uint16_t batteryMode;uint16_t atRate;uint16_t atRateTimeToFull;uint16_t atRateTimeToEmpty;uint16_t atRateOK;uint16_t temperature;uint16_t voltage;int16_t current;uint16_t averageCurrent;uint8_t maxError;uint8_t relativeStateOfCharge;uint8_t absoluteStateOfCharge;uint16_t remainingCapacity;uint16_t fullChargeCapacity;uint16_t runTimeToEmpty;uint16_t averageTimeToEmpty;uint16_t averageTimeToFull;uint16_t chargingCurrent;uint16_t chargingVoltage;uint16_t batteryStatus;uint16_t cycleCount;uint16_t designCapacity;uint16_t designVoltage;uint16_t specificationInfo;uint16_t manufactureDate;uint8_t serialNumber[2];uint8_t manufacturerName[12];uint8_t deviceName[8];uint8_t deviceChemistry[5];uint8_t manufacturerDataOrCalibrationData[26];uint8_t authenticateOrManufacturerInput[32];uint16_t cellVoltage4;uint16_t cellVoltage3;uint16_t cellVoltage2;uint16_t cellVoltage1;
} T_BatteryInfo;void readAllBatteryInfo(T_BatteryInfo *batteryInfo);#endif //BATTERY_H

五、测试及比对结果

软件使用网图:

通过ti的软件结合EV2300 HPA002进行读取:
SMBUS_READ.png
一般常用读取的内容如下(出厂日期的计算比较特殊,需要按位分割计算,这在很多协议中比较常见):

  • 1、Cycle Count:充满一次电用完一次的循环次数,可用于充放电次数限制,强行报废电池;
  • 2、Temperature:温度(0.1K,0.1开尔文度数,需要转换为摄氏度)
  • 3、Voltage:电压(mV)
  • 4、Current:电流(mA)
  • 5、Relative State of Charge:相对电量值(百分比)
  • 6、Manufacturer Date:出厂日期(A.28 ManufactureDate (0x1b)

This read-word function returns the date the pack was manufactured in a packed integer. The date is
packed in the following fashion:
(year–1980) x 512 + month x 32 + day
The default value for this function is stored in Manuf Date.
When the SN8765 is in UNSEALED or higher security mode, this block is R/W.)
6259f3d7edc2e9e92e348b840b214a4.png
101010 1010 11101转换为2022年10月29日

  • 7、Manufacturer Name:厂家信息(有空格 16进制转ASCII:08 53 54 4c 2d 53 4f 4e 59 95 95 95)
  • 8、Device Name:设备名称(有空格,16进制转ASCII 06 54 54 4c 32 32 4d 59 )

在线进制转换:http://www.hiencode.com/jinzhi.html
I2C读取到的内容:
4e89d27d4319ffc72eaa79473fc5eda6.png

六、注意事项

  • 1、注意I2C读取多个字节问题:如果发现读取多个字节时第一个字节正确,后续字节为FF,那么大概率是ACK应答设置错误,导致后续字节未正常应答;
  • 2、小端结果,多字节转换时注意:多个字节时往往先读取到的是小端内容,但也要结合具体的配置,如果是大端先出则最终转换时计算结果会不同,最好结合测试工具和各字节内容先读取一个来确认一下字节序;
  • 3、如果软件模拟i2c发送寄存器地址一直ack超时,可以尝试切换使用HAL库的i2c接口;

七、最后

单组电池的供电时间毕竟有限,往往我们会有多个电池组来保证续航,对于多组电池我们stm32单片机的i2c可能是不够用的,这个时候会用到TCA9548A这样的芯片来扩展复用I2C,通过选择通道来读取不同通道I2C上连接的电池的信息。

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

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

相关文章

进行RLC防孤岛负载测试的步骤和规范

RLC防孤岛负载测试是用于检测并防止电力系统出现孤岛现象的测试方法&#xff0c;孤岛现象是指当电网因故障或停电而与主电网断开连接时&#xff0c;部分电力设备仍在运行&#xff0c;形成一个没有与主电网连接的独立电网。这种情况下&#xff0c;如果电力设备不能及时检测到孤岛…

职场人是如何被拉开差距的?

事实上&#xff0c;职场人的差距从第一天就拉开了。 心理学里有一个词&#xff0c;叫做“首因效应&#xff0c;说的是人们在第一次接触时形成的印象&#xff0c;将会决定后续认知的基调。 入职第一天&#xff0c;从自我介绍开始&#xff0c;展示自己的特长&#xff0c;给大家…

IOT病毒分析

前言&#xff1a; 最近审计报警日志&#xff0c;发现了一个IOT病毒&#xff0c;利用的是CVE-2023-1389漏洞扫描tplink&#xff0c;进行攻击&#xff0c;有点意思&#xff0c;拿出来分析下。 发现&#xff1a; 查看流量日志&#xff0c;发现了一个有问题的访问&#xff1a; 访…

【ArcGIS 疑难杂症】无法展开和读取xls、xlsx文件

xls、xlsx文件在ArcGIS中经常用来链接属性。 但是无论ArcMap还是ArcPro&#xff0c;打开xls、xlsx文件时候可能会出现报错。 比如&#xff0c;ArcMap可以打开xls&#xff0c;但是打开xlsx时会出现下面的报错。 而ArcPro就更逊了&#xff0c;xls、xlsx两种都打不开。 以上是小…

网工内推 | 网络工程师,CCIE认证优先,最高10k*13薪

01 广东丰德科技有限公司 招聘岗位&#xff1a;网络工程师 职责描述&#xff1a; 1、负责运营商机房的网络设备的运行维护、故障应急处理&#xff1b; 2、负责各类型网络设备或网络相关的故障的故障分析及诊断&#xff1b; 3、独立完成网络项目的方案设计编写并负责方案的验证…

STM32用HAL库函数实现硬件IIC

/*出处&#xff1a;【STM32入门教程-2024】第12集 IIC通信与温湿度传感器AHT20(DHT20)_哔哩哔哩_bilibili */ AHT20驱动 这篇笔记我主要介绍代码实现&#xff0c;想要了解原理的请自己看视频&#xff0c;我不过多赘述了。 AHT20通信数据帧格式&#xff1a; ①对照手册上的通…

IFM420-WRDUWZ电动机保护器EOCR-iFM420窗孔0.5-80A

韩国三和&#xff0c;EOCR&#xff0c;SAMWHA&#xff0c;Schneider&#xff0c;施耐德&#xff0c;电机保护器&#xff0c;电动机保护器&#xff0c;电子式电动机保护继电器&#xff0c;电子式过电流继电器&#xff0c;电子式欠电流继电器&#xff0c;电子式电压继电器&#x…

探索大数据混合分层架构:构建智能数据管理平台

随着大数据技术的发展和应用场景的不断拓展&#xff0c;传统的单一数据处理架构已经不能满足复杂多变的业务需求。在这样的背景下&#xff0c;大数据混合分层架构应运而生&#xff0c;成为了构建智能数据管理平台的关键。本文将深入探讨大数据混合分层架构的设计原则、核心组件…

JS事件循环、宏任务与微任务

在JavaScript中&#xff0c;事件循环&#xff08;Event Loop&#xff09;是处理异步操作的核心机制。它负责执行代码&#xff0c;处理事件&#xff0c;并在适当的时候调度回调。为了更好地理解JavaScript的执行模型&#xff0c;我们需要深入探讨事件循环、宏任务&#xff08;Ma…

从文本框限制字符输入,理解代码抽象过程(四次抽象到简单工厂到反射)

这里写目录标题 背景原因抽象过程第一次抽象第二次抽象第三次抽象第四次抽象简单工厂反射 背景 学生信息管理系统中有很多文本框的校验&#xff0c;其中有一点&#xff0c;就是不允许输入过长的信息。 原因 1、文本框校验限制输入长度确保用户内容不超出系统或数据库容量限制…

基于SpringBoot+Vue高校宣讲会管理系统设计与实现

项目介绍&#xff1a; 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装高校宣讲会管理系统软件来发挥其高效地信息…

2024五一劳动节活动策划方案

2024五一劳动节朋克国风养生局&#xff08;回春集主题&#xff09;活动策划方案-48P 方案页码&#xff1a;48页 文件格式&#xff1a;pptx 方案简介&#xff1a; 大健康线下活动屡屡出圈 近年来&#xff0c;随着健康意识和生活水平的提升 人们对于自身健康越发关注&#…

面试题:分布式消息中间件 MQ

MQ官网文档&#xff1a; RabbitMQ&#xff1a;https://www.rabbitmq.com/docs RocketMQ&#xff1a;https://rocketmq.apache.org/zh/docs/ Kafka&#xff1a;https://kafka.apache.org/documentation/ DDMQ&#xff1a;https://base.xiaojukeji.com/docs/ddmq 面试题&#xff…

【4103】基于小程序实现的老年人健康管理平台

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;spring…

CIA组织MikroTik软路由攻击场景复现及后门加解密剖析

概述 写文章还是有一段时间了&#xff0c;发布的文章也是获得了不少小伙伴的关注&#xff0c;同时也和圈子里面的小伙伴慢慢的建立起了联系&#xff0c;平时也会时不时的一起探讨一些技术问题。因此&#xff0c;在最近和小伙伴的交流学习过程中&#xff0c;有一个小伙伴提到了…

Java:SpringBoot如何优化启动速度

一、yml中设置懒加载 spring:main:lazy-initialization: true 二、SpringBoot启动类中添加注解 Indexed &#xff08;Spring5才有该注解&#xff09; Indexed EnableAsync RestController SpringBootApplication(exclude {WxMaAutoConfiguration.class}) EnableTransactionM…

面试:MYSQL(SQL优化、MYSQL事务)

目录 一、SQL优化 1、如何定位慢查询 &#xff08;1&#xff09;方案一&#xff1a;开源工具 &#xff08;2&#xff09;方案二&#xff1a;慢日志查询 2、定位到慢查询时&#xff0c;如何优化 3、什么是索引 &#xff08;1&#xff09;底层结构 4、聚簇索引&#xff0…

优秀博士学位论文分享:动态三维场景理解与重建

优秀博士学位论文代表了各学科领域博士研究生研究成果的最高水平&#xff0c;本公众号近期将推出“优秀博士学位论文分享”系列文章&#xff0c;对人工智能领域2023年优秀博士学位论文进行介绍和分享&#xff0c;方便广大读者了解人工智能领域最前沿的研究进展。 “博士学位论…

【数据结构初阶】时间复杂度和空间复杂度详解

今天我们来详细讲讲时间复杂度和空间复杂度&#xff0c;途中如果有不懂的地方可翻阅我之前文章。 个人主页&#xff1a;小八哥向前冲~-CSDN博客 数据结构专栏&#xff1a;数据结构【c语言版】_小八哥向前冲~的博客-CSDN博客 c语言专栏&#xff1a;c语言_小八哥向前冲~的博客-CS…

matlab新手快速上手6(引力搜索算法)

本文根据一个较为简单的matlab引力搜索算法框架详细分析蚁群算法的实现过程&#xff0c;对matlab新手友好&#xff0c;源码在文末给出。 引力搜索算法简介&#xff1a; 引力搜索算法是一种启发式优化算法&#xff0c;最初于2009年由伊朗的Esmat Rashedi、Hossein Nezamabadi-p…