CANoe入门——CANoe的诊断模块,调用CAPL进行uds诊断
目录
一、诊断窗口介绍
二、诊断数据库文件管理
三、添加基础诊断描述文件(若没有CDD/ODX/PDX文件)并使用对应的诊断功能进行UDS诊断
3.1、添加基础诊断描述文件
3.2、基于基础诊断,使用诊断控制台进行UDS诊断
3.2.1、生成基础诊断
3.2.2、添加诊断服务
3.2.3、发送诊断服务
3.2.4、使用基础诊断进行27服务安全解锁
3.2.5、添加安全解锁dll算法文件
3.2.6、其他uds服务
四、有诊断数据库文件(CDD、PDX、ODX)进行uds诊断
五、通过CAPL的仿真节点调用诊断库函数进行uds诊断
5.1、CAPL中使用进行uds诊断的基本步骤
5.2、CAPL中定义诊断请求
5.3、CAPL中发送诊断请求
5.3.1、通用诊断请求
5.3.2、发送诊断数据库中的诊断请求
5.4、CAPL中获取诊断响应
5.4.1、诊断响应回调函数(诊断响应事件)方式获取诊断响应
5.4.2、使用函数直接获取诊断响应(不借助事件回调)
5.5、CAPL中借助诊断描述文件中导入的seedKey.dll文件通过安全访问
5.6、CAPL发送其他诊断请求
CANoe的诊断功能支持解析多个总线的诊断信息,CANoe支持通过诊断控制台或者CAPL对诊断功能进行调用,通过模拟Tester(上位机)与ECU进行诊断测试,模拟ECU和其他ECU节点进行诊断等。
一、诊断窗口介绍
CANoe的诊断功能菜单如图所示,在这里采取从左往右的形式依次对这几个功能进行简要的介绍
1、Diagnostic/ISO TP:用于往CANoe工程中添加诊断描述文件,配置一些诊断参数,例如传输层,诊断层参数。
2、Basic Diagnostic:基础诊断,可在1中通过添加一个基础诊断文件后激活,可以自定义一些简单的诊断服务
3、Diagnostic Parameters:用于配置需要读取的诊断响应中的参数,可配置某一诊断请求为单次手动发送或者类似IG一样的自动发送功能
4、Diagnostic Console:数据库诊断窗口,用于发送诊断描述文件中定义的诊断服务,并在窗口内显示对应诊断请求的响应,需要导入诊断数据库(CDD、ODX、PDX)文件或添加基础诊断文件后激活使用
5、Fault Memory:访问ECU的故障码模块
6、Session Control:用于控制ECU的诊断会话和安全访问
7、OBD——II:车载OBD诊断功能
8、CANdelaStudio:CANoe自带的一个CDD查看、编辑器
9、ODXStudio:CANoe自带的一个PDX、ODX查看、编辑器
10~12:涉及BMS J1939传输协议的内容,由于本人没怎么接触过J1939,也不怎么使用,不做介绍。
二、诊断数据库文件管理
在CANoe中,要想能够使用CANoe的诊断功能,必须先为该CANoe工程配置一个诊断描述文件(基础诊断、CDD文件、ODX/PDX文件),诊断描述文件便是常说的诊断数据库,这个文件中往往包含着ECU支持的各种诊断服务和诊断参数等信息。
添加诊断描述文件:
点击如图所示图标,进入诊断描述文件配置界面。
在CAN(由于本工程是创建的CAN模板,故这里为CAN,LIN工程的话这里显示为LIN)处右击鼠标,选择添加一个诊断描述文件。
如图所示,可以选择添加四种类型的诊断描述文件。
如果有CDD或者PDX/ODX文件,可以选择第一个选项,添加对应的诊断数据库。
如果没有,可以选择第二个选项,添加一个基础诊断文件。(第三个和第四个我没用过)
三、添加基础诊断描述文件(若没有CDD/ODX/PDX文件)并使用对应的诊断功能进行UDS诊断
3.1、添加基础诊断描述文件
在上一步中选择第二个选项,Add Basic Diagnostic Description(UDS),
添加完成之后如图所示,在这里可以对传输层和诊断层以及附加的诊断描述文件进行配置。
如图是传输层参数配置界面:
Addressing:用于配置目标ECU的物理寻址、功能寻址、诊断响应的ID
Addition ISO TP:配置传输层参数
STmin:流控帧参数,用于告知发送方发送连续帧时的最短间隔时间。
Block Size:用于告知发送方在接收到下一条流控帧之前,本次可以发送的连续帧的数量,为0表示没有限制。
FC Delay:流控帧与FF CF之间的间隔时间
Max length:传输层支持的最大字节数,当接收到的长度大于该长度时,CANoe将会报错并结束传输。
Mixing of CAN 2.0 and CANFD Frames:
若配置为ignore,则忽略与配置不符的CAN报文,如:本工程配置为CAN工程,则会忽略CANFD的诊断报文;
若配置为accept,则可以接收与本工程配置不符的CAN报文,但仅接收;
若配置为adapt,则不仅可以接收与本工程配置不符的CAN报文,且在接收到之后会使用对应的报文类型进行发送。
到此,传输层配置就结束了,接着是诊断层的配置
如图是诊断层配置界面:
Tester Present Request:若勾选此选项,则CANoe会在发送完成一次诊断服务后会每隔S3 Client ms之后自动发送诊断仪在线请求(0x3E服务)
若勾选上方的From Description,则会默认发送诊断文件中的诊断仪在线命令,若勾选Manually,则可以自定义发送的诊断仪在线命令。
S3 Server Time:ECU离开非默认会话的超时时间,此时间必须大于S3 Client。
Timing:
P2 Client:CANoe发送请求后,需要在此时间内收到ECU给出的响应,否则抛出超时。
P2 Server:ECU收到诊断请求之后,需要在此时间以后给出对应的诊断响应
P2 extended client:当接收到NRC78之后,CANoe需要继续等待响应的时间
P2 extended server:当接收到NRC78之后,需要在此时间内给出下一次响应,否则判定为超时
Response code 0x21 supported:若勾选,则CANoe会在总线上收到0x21的NRC之后在Complete
within 时间内间隔repeat request after时间重复发送一次诊断请求
Seed and key DLL:安全访问算法动态链接库文件,导入此文件,CANoe会在27服务接收到种子之后自动调用此算法计算对应的秘钥。
Additional Descriptions:附加的诊断描述文件,这里可以添加一些当前诊断数据库文件中未定义的附加服务(由于这里使用的是基础诊断,就不再新增了)。
至此,基础诊断添加完毕,其实以上所提到的参数,如无特殊要求,使用默认值即可。
3.2、基于基础诊断,使用诊断控制台进行UDS诊断
3.2.1、生成基础诊断
我的诊断id配置如图。
配置基础诊断服务
在诊断菜单的左上角,打开Basic Diagnostic 基础诊断,可以看到,在基础诊断中已经有了CANoe预定的一些uds诊断服务,例如10服务 11服务等。
为了方便起见,我们使用CANoe自带的功能,先一键生成基础的诊断服务
点击上图中的edit处,选择Add All Services,添加所有诊断服务
添加完成之后,基础诊断界面的左侧就为每个诊断服务都生成了一个基本的诊断服务。
3.2.2、添加诊断服务
在对应的诊断服务处右击鼠标,即可新增一个对应的诊断服务
最上方的Service Name可以修改此服务的名称,红框中的value处可以修改对应的诊断子服务id
现在,我们就有了一个1001 默认会话服务,和一个1003拓展会话的诊断服务了。
3.2.3、发送诊断服务
运行工程,我们试着发送一下这两个诊断服务(此处的响应ECU是我使用同星智能的TsMaster软件模拟的ECU,大家如果有真实ECU可以接入真实ECU使用,如果没有真实的ECU,评论区我会提供一个使用使用CAPL模拟的ECU节点来进行使用)
双击对应的服务来发送此服务
可以看到,当我发送1001诊断之后,ECU回复了肯定响应5001,已经实现了通过基础诊断来完成uds诊断的功能。
但是,细心的朋友应该发现诊断控制台中抛出了红色的错误信息,这是因为我们没有给这个诊断请求设置对应的响应属性导致的,接下来,我们一起设置一下这个诊断请求的响应
在基础诊断配置界面,找到需要配置的服务,点击红框中的Response,即可配置其对应的响应,可以看到,我这个服务默认的响应是24个bit的(2个字节的50 01 加上一个字节的参数),而我的ECU实际回复了两个字节(50 01),没有参数,导致响应字节匹配错误而报出异常,这里我将响应参数删掉,即没有子参数。
在参数处点击对应的参数,右键鼠标选择delete,删除掉参数即可(删除就是0bit),此时对应的响应就是2字节了
修改完成之后,点击最上方的commit重新生成一下对应的诊断控制台,随后,我们重新点击这两个服务进行一下诊断服务的发送
可以看到,此时右下角已经不会抛出异常错误了(长度已经匹配正确)
看到这里,应该就已经掌握了添加一个基础诊断进行发送uds诊断的能力了。
3.2.4、使用基础诊断进行27服务安全解锁
此处我们再添加一个服务,用于对ECU进行安全访问控制
打开基础诊断配置界面,选择27服务,这里将安全会话等级设置为自己需要的等级,我就设置为level1了,请求参数根据自己的需要进行设置,我这边没有参数,就对参数进行了删除,然后响应参数的话,我这边会回复4字节的种子,于是我将响应参数长度设置为4 * 8 = 32bit
然后,再添加一个27 02服务,用于发送秘钥,并将参数长度设置为4字节(32bit),通常情况下种子与秘钥的长度是一样的,种子为4字节,秘钥也就是4字节
重新commit,就可以试一下我们刚刚添加的27服务了
3.2.5、添加安全解锁dll算法文件
由于安全访问需要用到安全访问算法,我们需要在诊断描述文件那里添加一个seedKey的dll算法。
(大家如果有,可以使用自己的dll算法,没有的话,我会在评论区提供一个我自己随便封装的一l算法文件dll,但使用我的dll就必须使用我的仿真代码来充当ECU了)
双击此处导入dll文件,导入完成后点击ok即可
随后来到诊断控制台,即可双击2701服务进行安全解锁了。
依次进入拓展会话(10 03),2701请求种子,2702发送秘钥,即可对ECU实现解锁~。
3.2.6、其他uds服务
对于其他的uds服务,添加方法和流程是一样的,这里不再一一进行配置了,大家掌握了配置方法之后自己进行配置尝试即可。
四、有诊断数据库文件(CDD、PDX、ODX)进行uds诊断
这种情况就比较简单了,当大家手里有现成的CDD文件或者pdx文件之后,直接进行导入即可使用。
同样的,打开诊断描述文件配置界面
在对应的总线处右击鼠标,选择第一个选项即可
随后在弹出的界面中选择自己的cdd文件就可以了。
添加完成之后,只需要配置一下对应的27服务seedkey.dll文件即可使用
配置完成后,就会出现刚刚导入的cdd诊断了
其余使用项基本与基础诊断一致,不再赘述。
五、通过CAPL的仿真节点调用诊断库函数进行uds诊断
大家可以根据自己的需求,将CAPL代码文件创建在对应的节点内。
在我的工程中,我就新建了一个空白节点,将代码写在此节点内
5.1、CAPL中使用进行uds诊断的基本步骤
在CAPL中要通过诊断库函数进行uds诊断,需要先设置对应的诊断目标ECU(通过匹配目标ECU,CAPL才能知道我们的诊断请求应该通过哪个ID来发送,哪个ID是诊断响应)
这个过程通过函数:diagSetTarget来实现
long diagSetTarget (char ecuName[]) |
在CAPL中,诊断请求和响应也是一种变量类型,我们要发送诊断请求,可以通过定义一个诊断请求变量,然后调用CAPL的诊断发送函数来进行发送
这个过程通过关键字:diagRequest来定义诊断请求
通过diagSendRequest函数来发送物理寻址的诊断请求
通过diagSendFunctional函数来发送功能寻址的诊断请求
long diagSendRequest (diagRequest obj) |
long diagSendFunctional( diagRequest request) |
发送诊断请求就这么两个步骤
5.2、CAPL中定义诊断请求
诊断请求的定义有好几种方式
diagRequest * diagReq;//方式1,定义一个通用的诊断请求,不限制诊断服务类型,不限制ECU
diagRequest BasicDiagnosticsEcu.* diagReq1;//方式2,定义一个名为"BasicDiagnosticsEcu"的ECU的通用诊断服务,不限制诊断服务类型,限制ECU
diagRequest BasicDiagnosticsEcu.SecurityAccess390 diagReq2;//方式3,定义一个名为"BasicDiagnosticsEcu"的ECU的通用诊断服务,限制诊断服务类型,限制ECU
其中,诊断ECU名称就是诊断描述文件的名称,即下图红框处的名称
诊断响应的定义与请求完全一致,仅关键字不同。
定义诊断响应使用关键字 diagResponse
5.3、CAPL中发送诊断请求
5.3.1、通用诊断请求
代码
on start
{char ECU_Name[32] = "BasicDiagnosticsEcu";//定义诊断ECU名称,此名称需要与诊断描述文件完全相同diagSetTarget(ECU_Name);
}on key'A'
{diagRequest * diagReq;//定义一个通用的诊断对象byte diagReqData[2] = {0x10,0x02};//定义请求内容diagReq.Resize(2);//重新设定诊断请求的长度diagReq.SetPrimitiveData(diagReqData,2);//设置诊断请求的原始数据,设置为数组中的内容,并设置数据长度diagSendRequest(diagReq);//发送诊断请求write("使用CAPL发送诊断请求");
}
在这段代码中,我使用按键A来发送一个1002请求,由于我定义的是一个通用的诊断请求,CAPL并不知道这个请求的内容和数据长度,所以需要人为调整这个请求的数据和长度
运行代码,按下按键看看
通过运行结果可以看到,当按下A之后,对应的事件代码被触发,发送了我们定义的10 02请求
5.3.2、发送诊断数据库中的诊断请求
发送诊断数据库中的诊断请求,并通用的请求简单一些,只需要定义完成之后调用发送函数即可,像这样
代码
on start
{char ECU_Name[32] = "BasicDiagnosticsEcu";//定义诊断ECU名称,此名称需要与诊断描述文件完全相同diagSetTarget(ECU_Name);
}on key'B'
{diagRequest BasicDiagnosticsEcu.ExtendedSession diagReq;//定义"BasicDiagnosticsEcu"内的拓展会话请求diagSendRequest(diagReq);
}
运行代码,按下B按键看看
可以看到,按下按键B之后,对应的诊断请求:BasicDiagnosticsEcu.ExtendedSession被发送了出去,这个请求就是我们在基础诊断数据库中定义的.ExtendedSession 1003服务
5.4、CAPL中获取诊断响应
CAPL提供了获取诊断响应的两种方式
5.4.1、诊断响应回调函数(诊断响应事件)方式获取诊断响应
CAPL提供了类似于键盘事件,on start事件的诊断响应事件,当用户设置了诊断对象的ECU之后,收到诊断响应ID的数据,会触发这个事件
代码
on start
{char ECU_Name[32] = "BasicDiagnosticsEcu";//定义诊断ECU名称,此名称需要与诊断描述文件完全相同diagSetTarget(ECU_Name);
}on key'B'
{diagRequest BasicDiagnosticsEcu.ExtendedSession diagReq;//定义"BasicDiagnosticsEcu"内的拓展会话请求diagSendRequest(diagReq);
}on diagResponse *//*号表示所有的,即所有的诊断响应都会触发该事件
{byte diagRespData[4096];//定义存储诊断响应的buff数组long diagRespDataLen;//诊断响应长度int i;this.GetPrimitiveData(diagRespData,4096);//将诊断响应的原始数据存储在此数组中diagRespDataLen=this.GetPrimitiveSize(); // 获取诊断响应的大小write("诊断响应长度为%d",diagRespDataLen);for(i=0;i<diagRespDataLen;i++){write("收到的诊断响应数据为%.2LX",diagRespData[i]);//打印诊断响应}
}
运行代码看看
如图所示,CAPL识别到了对应的诊断响应,并获取到了诊断响应的值。
5.4.2、使用函数直接获取诊断响应(不借助事件回调)
CAPL除了事件回调之外,还提供了一个函数用于直接获取对应的诊断响应
long diagGetLastResponse (diagRequest req, diagResponse respOut); | ||||
long diagGetLastResponse (diagResponse respOut); |
在需要的时刻调用此函数即可获取到对应的响应
代码
on start
{char ECU_Name[32] = "BasicDiagnosticsEcu";//定义诊断ECU名称,此名称需要与诊断描述文件完全相同diagSetTarget(ECU_Name);
}on key'B'
{diagRequest BasicDiagnosticsEcu.ExtendedSession diagReq;//定义"BasicDiagnosticsEcu"内的拓展会话请求diagSendRequest(diagReq);
}on key'C'
{diagResponse * resp;//定义一个诊断响应byte diagRespData[4096];//定义存储诊断响应的buff数组long diagRespDataLen;//诊断响应长度int i;diagGetLastResponse(resp);//将上一次的诊断响应赋值给刚刚定义的变量resp.GetPrimitiveData(diagRespData,4096);//将诊断响应的原始数据存储在此数组中diagRespDataLen=resp.GetPrimitiveSize(); // 获取诊断响应的大小write("诊断响应长度为%d",diagRespDataLen);for(i=0;i<diagRespDataLen;i++){write("收到的诊断响应数据为%.2LX",diagRespData[i]);//打印诊断响应}
}
在未按下C按键,即未调用获取响应的函数之前,write窗口没有诊断响应的信息
按下C按键之后,diagGetLastResponse函数被调用,成功获取到了上一次的响应。
以上,便是CAPL中获取诊断响应的两种方式,大家可以根据需要自行选择合适的方式。
5.5、CAPL中借助诊断描述文件中导入的seedKey.dll文件通过安全访问
在上面的文章中,我们已经知道了如何使用CAPL发送一个诊断请求,也知道了如何获取对应的诊断响应。
大家在使用CAPL进行诊断的过程中,免不了要经常进行27访问,那么如何在CAPL中通过安全访问呢?
这里可以直接调用诊断描述文件中导入的dll文件获取27秘钥
在CAPL中调用诊断描述文件中导入的dll文件获取27秘钥依靠函数diagGenerateKeyFromSeed
long diagGenerateKeyFromSeed ( byte seedArray[], dword seedArraySize, dword securityLevel, char variant[], char ipOption[], byte keyArray[], dword maxKeyArraySize, dword& keyActualSizeOut); // form 1 | |||
long DiagGenerateKeyFromSeed(char ecuQualifier[], byte seedArray[] , dword seedArraySize, dword securityLevel, char variant[], char option[] , byte keyArray[], dword maxKeyArraySize, dword& keyActualSizeOut); // form 2 |
通常情况下使用重载形式1即可
总共8个参数
seedArray:种子数组
seedArraySize:种子的长度
securityLevel:安全访问等级,2701则等级为0x1,2703则等级为0x3,2709则等级为0x9...
variant:诊断描述字符串,通常写一个空白字符串或者"Variant1"
ipOption:诊断描述字符串,通常写一个空白字符串或者"option"
keyArray:存放秘钥的数组
maxKeyArraySize:秘钥数组最大可能/最大允许的长度
keyActualSizeOut:秘钥数组中实际使用的字节/秘钥实际的长度。此参数在c++中是一个变量的引用,在CAPL中直接传变量即可
代码
variables
{diagRequest * diagReqSeed;//定义一个通用的诊断请求,用于请求种子diagRequest * diagReqKey;//定义通用的诊断请求,用于发送秘钥byte gSeedArray[4];//存储秘钥的数组,这里我由于我的种子长度为4,所以给4个字节dword gSeedArraySize = 4;//种子长度dword gSecurityLevel = 0x01;//安全等级char gVariant[200] = "Variant1";//诊断对象描述char gOption[200] = "option";//诊断对象描述byte gKeyArray[255];//存储种子的数组dword gMaxKeyArraySize = 255;//种子可能的最大长度dword gActualSizeOut;//种子的实际长度
}on start
{char ECU_Name[32] = "BasicDiagnosticsEcu";//定义诊断ECU名称,此名称需要与诊断描述文件完全相同diagSetTarget(ECU_Name);//设置诊断对象名称
}On key'B'
{byte reqData[2] = {0x27,0x01};//定义一个种子请求数组内容word reqDataLen;//种子请求的长度word i;reqDataLen = elcount(reqData);//计算种子请求的长度diagReqSeed.Resize(reqDataLen);//重置用于请求种子的诊断请求的长度diagReqSeed.SetPrimitiveData(reqData,reqDataLen);//将请求数组的数据设置给用于请求种子的诊断请求diagSendRequest(diagReqSeed);//发送诊断请求
}on diagResponse *
{byte respData[4096];//定义存放诊断响应的数组word respDataLen; //存放诊断响应的数组长度respDataLen = elcount(respData);//计算长度this.GetPrimitiveData(respData,respDataLen);//获取诊断响应到响应数组中if(respData[0] == 0x67 && respData[1] == 0x01)//如果回复的前面两个字节是67 01,即回复的是种子{byte keyReqData[6];//秘钥请求数组word keyReqLen;//秘钥请求数组长度keyReqLen = elcount(keyReqData);//计算长度memcpy_off(gSeedArray,0,respData,2,4);//将respdata的第2~6个字节拷贝放在gSeedArray中,即种子diagGenerateKeyFromSeed(gSeedArray,gSeedArraySize,gSecurityLevel,gVariant,gOption,gKeyArray,gMaxKeyArraySize,gActualSizeOut);//调用诊断描述文件中dll计算秘钥的函数//此时已经获得了秘钥,存在在keyArray中keyReqData[0] = 0x27;keyReqData[1] = gSecurityLevel + 1;//设置对应的秘钥请求前两个字节的内容,第一个字节为0x27,第二个字节为种子请求+1memcpy_off(keyReqData,2,gKeyArray,0,4);//将秘钥拷贝到秘钥请求数组中去diagReqKey.Resize(keyReqLen);//调节诊断请求大小diagReqKey.SetPrimitiveData(keyReqData,keyReqLen);//设置发送秘钥的诊断请求的数据diagSendRequest(diagReqKey);//发送秘钥诊断请求}
}
运行一下,看看
由于在诊断响应处理中,我使用的是回调方式,并且在获取完秘钥之后就发送出去了,所以就自动的通过了安全访问~
5.6、CAPL发送其他诊断请求
发送其他的诊断请求的方法与上述完全一致,如果是定义的通用型的,则需要调用resize函数先重新设置诊断请求的大小,再调用SetPrimitiveData函数设置诊断请求的数据,随后调用diagSendRequest或者diagSendFunctional函数进行发送诊断请求即可。
如果是定义的数据库中的诊断请求,就更简单了,定义完成之后,直接调用发送函数即可。
CAPL的诊断函数异常强大,由于是入门篇,本篇就介绍到这里。
相关文章:
CANoe入门——CANoe的诊断模块,调用CAPL进行uds诊断
目录 一、诊断窗口介绍 二、诊断数据库文件管理 三、添加基础诊断描述文件(若没有CDD/ODX/PDX文件)并使用对应的诊断功能进行UDS诊断 3.1、添加基础诊断描述文件 3.2、基于基础诊断,使用诊断控制台进行UDS诊断 3.2.1、生成基础诊断 3.…...
AI日报 - 2025年3月30日
🌟 今日概览(60秒速览) ▎🤖 模型进展 | Qwen2.5-Omni多模态实时交互,Gemini 2.5 Pro/GPT-4o低调升级,Claude内部思考过程揭秘。 新模型和升级持续涌现,多模态与内部机制理解成焦点。 ▎&#x…...
蓝桥刷题note11(好数)
1,好数 一个整数如果按从低位到高位的顺序,奇数位 (个位、百位、万位 ⋯⋯ ) 上的数字是奇数,偶数位 (十位、千位、十万位 ⋯⋯ ) 上的数字是偶数,我们就称之为 “好数”。 给定一个正整数 NN,请计算从 1 到 NN 一共…...
Go常用的设计模式
Go常用的设计模式 常见的设计模式,如 单例模式、工厂模式、策略模式、观察者模式、代理模式、装饰器模式 和 适配器模式 都可以在 Go 中实现,适用于不同的开发需求。 这些设计模式不仅能帮助你编写结构清晰、可维护的代码,还能让你更好地应…...
复现文献中的三维重建图像生成,包括训练、推理和可视化
要复现《One - 2 - 3 - 45 Fast Single Image to 3D Objects with Consistent Multi - View Generation and 3D Diffusion (CVPR)2024》文献中的三维重建图像生成,包括训练、推理和可视化,并且确保代码能正常运行,下面是基本的实现步骤和示例…...
day17 学习笔记
文章目录 前言一、数组的增删改查1.resize函数2.append函数3.insert函数4.delete函数5.argwhere函数6.unique函数 二、统计函数1.amax,amin函数2.ptp函数3.median函数4.mean函数5.average函数6.var,std函数 前言 通过今天的学习,我掌握了num…...
Mysql练习题
先创建对应数据表 #先创建表 #学生表 Student create table Student(SId varchar(10),Sname varchar(10),Sage datetime,Ssex varchar(10)); insert into Student values(01 , 赵雷 , 1990-01-01 , 男); insert into Student values(02 , 钱电 , 1990-12-21 , 男); insert int…...
torch不能使用cuda的解决方案
遇到了这样的报错,说明 torch不能使用cuda 反思 我频繁地尝试安装不同的 nvdia 驱动,浪费了很多时间。因为我的错误地认为nvidia会自带cuda,其实cuda需要单独安装。 还有我的torch是cpu版本的,即使nvidia cuda安装了࿰…...
Python 循环全解析:从语法到实战的进阶之路
一、问答题 (1)下面的循环体被重复了多少次?每次循环的输出结果是什么? i1 while i < 10:if i % 2 0:print(i)死循环,没有输出结果 i1 while i < 10:if i % 2 0:print(i)i l死循环,没有输出结果 i 1 while i< 10…...
代码随想录算法训练营--打卡day3
复习:标注感叹号的需要在电脑上重新做几遍 一.两两交换链表中的节点!! 1.题目链接 24. 两两交换链表中的节点 - 力扣(LeetCode) 2.思路 画图 3.代码 class Solution {public ListNode swapPairs(ListNode head) …...
ubuntu 安装mysql
在 Ubuntu 系统中安装 MySQL 的步骤如下: 步骤 1:更新软件包列表 sudo apt update步骤 2:安装 MySQL 服务器 sudo apt install mysql-server -yUbuntu 22.04/20.04 默认安装 MySQL 8.0,早期版本可能默认使用 MariaDB。 如果需要…...
用Python实现资本资产定价模型(CAPM)
使用 Python 计算资本资产定价模型(CAPM)并获取贝塔系数(β)。 步骤 1:导入必要的库 import pandas as pd import yfinance as yf import statsmodels.api as sm import matplotlib.pyplot as plt 步骤 2࿱…...
Conda配置Python环境
1. 安装 Conda 选择发行版: Anaconda:适合需要预装大量科学计算包的用户(体积较大)。 Miniconda:轻量版,仅包含 Conda 和 Python(推荐自行安装所需包)。 验证安装: co…...
Redisson延迟队列实战:分布式系统中的“时间管理者“
目录 引言:延迟队列的魅力与应用 什么是Redisson延迟队列? 技术原理与工作机制 应用场景 环境准备:搭建基础 Maven依赖配置 Redisson客户端配置 延迟队列实现:核心代码 工作原理深度解析 数据模型与存储结构 元素流转过…...
国产化适配 - YashanDB、达梦数据库与MySQL 的兼容性及技术选型对比分析
根据知识库信息,以下是 YashanDB、达梦数据库与MySQL 的兼容性及技术选型对比分析: 1. YashanDB 与 MySQL 兼容性 协议与语法兼容 : YashanDB 100%兼容 MySQL 5.7协议 的常用命令(如 SELECT、INSERT),但…...
从0开始——在PlatformIO下开展STM32单片机的HAL库函数编程指南
目录 前言 编写时钟初始化 实现Systicks_Handler,完成HAL库的时基更新 编写驱动测试 前言 笔者最开始的尝试是在2025年的寒假,准备向PlatformIO迁移HAL库,注意,截止到目前,PlatformIO对HAL库的支持已经非常完善了。…...
Python小练习系列 Vol.9:杨辉三角生成(数组构建 + 数学组合)
🧠 Python小练习系列 Vol.9:杨辉三角生成(数组构建 数学组合) 🔺 本期我们带来一道简洁却优雅的经典练习 —— 生成杨辉三角,是训练数组操作与组合思想的绝佳题目! 🧩 一、题目描述…...
Webview详解(下)
第三阶段:性能优化 加载速度优化 缓存策略 缓存策略可以显著减少网络请求,提升页面加载速度。常用的缓存策略包括 HTTP 缓存和本地资源预加载。 1. HTTP 缓存 HTTP 缓存利用 HTTP 协议中的缓存机制(如 Cache-Control、ETag 等࿰…...
scss基础用法
SCSS(Sassy CSS)是Sass的增强版本,作为CSS的预处理器,它提供了多种功能来提高代码的可维护性和效率。以下是SCSS的基础用法: 变量(Variables) 用于存储常用的值,如颜色、字体大小等。…...
知能行每日综测
题目1 自己的做法 答案 题目2 自己的 答案 题目3 注意:这道做错了,你们可以看看我哪里错了 题目4 我的 答案 题目5 没思路,不会做 已更改 题目6 答案 第七题 我的 不会 现在补综测最后一个...
c++ vs和g++下的string结构
话不多说进入正题.注:下述结构是在32位平台下进行验证,32位平台下指针占4个字节. vs下string的结构 string总共占28个字节,内部结构稍微复杂一点,先是有一个联合体,联合体用来定义 string中字符串的存储空间:(联合体的…...
海量数据处理
1.海量数据处理问题 给两个文件,分别有100亿个query,只有1G内存,如何找到两个文件交集? 解决方案一: 可以先用布隆过滤器,一个文件的query放进布隆过滤器,另一个文件依次查找,在的…...
洛谷题单1-P5706 【深基2.例8】再分肥宅水-python-流程图重构
题目描述 现在有 t t t 毫升肥宅快乐水,要均分给 n n n 名同学。每名同学需要 2 2 2 个杯子。现在想知道每名同学可以获得多少毫升饮料(严格精确到小数点后 3 3 3 位),以及一共需要多少个杯子。 输入格式 输入一个实数 t …...
【HarmonyOS 5】初学者如何高效的学习鸿蒙?
【HarmonyOS 5】初学者如何高效的学习鸿蒙? 一、前言 在全球科技格局风云变幻的当下,谷歌安卓系统的管控逐步收紧,加之国际形势愈发复杂,打造中国人自主的操作系统,已成为时代发展的必然要求,这不仅是突破…...
Java NIO之FileChannel 详解
关键点说明 文件打开选项: StandardOpenOption.CREATE - 文件不存在时创建 StandardOpenOption.READ/WRITE - 读写权限 StandardOpenOption.APPEND - 追加模式 StandardOpenOption.TRUNCATE_EXISTING - 清空已存在文件 缓冲区操作: ByteBuffer.wrap…...
数据可视化(matplotlib)-------图表样式美化
目录 一、图表样式概述 (一)、默认图表样式 (二)、图表样式修改 1、局部修改 2、全局修改 二、使用颜色 (一)、使用基础颜色 1、单词缩写或单词表示的颜色 2、十六进制/HTML模式表示的颜色 3、RGB…...
Go 语言中,关于客户端初始化的最佳实践
在 Go 语言中,关于客户端初始化的最佳实践确实需要注意以下几点: 全局单例模式是推荐做法,尤其对于需要保持长连接或需要复用资源的客户端(如数据库、Redis、HTTP 客户端等)并发安全是必须保证的,需要确保…...
MyBatis的第一天笔记
1. MyBatis 概述 1.1 什么是框架 框架是对通用代码的封装,提前写好了一堆接口和类,可以直接引入使用框架一般以jar包形式存在Java常用框架:SSM三大框架(Spring SpringMVC MyBatis)、SpringBoot、SpringCloud等 1.…...
区块链赋能,为木材货场 “智” 造未来
区块链赋能,为木材货场 “智” 造未来 在当今数字化浪潮席卷的时代,软件开发公司不断探索创新,为各行业带来高效、智能的解决方案。今天,让我们聚焦于一家软件开发公司的杰出成果 —— 区块链木材货场服务平台,深入了…...
IvorySQL:兼容Oracle数据库的开源PostgreSQL
今天给大家介绍一款基于 PostgreSQL 开发、兼容 Oracle 数据库的国产开源关系型数据库管理系统:IvorySQL。 IvorySQL 由商瀚高软件提供支持,主要的功能特性包括: 完全兼容 PostgreSQL:IvorySQL 基于 PostgreSQL 内核开发…...
Python 序列构成的数组(切片)
切片 在 Python 里,像列表(list)、元组(tuple)和字符串(str)这类 序列类型都支持切片操作,但是实际上切片操作比人们所想象的要强大 很多。 这一节主要讨论的是这些高级切片形式的…...
Pre-flash和Main flash
在相机拍照过程中,Pre-flash(预闪光) 和 Main flash(主闪光) 是常见的两种闪光灯使用模式,通常用于提高低光环境下的拍摄质量,尤其在自动曝光(AE)和自动对焦(…...
【区块链安全 | 第十篇】智能合约概述
部分内容与前文互补。 文章目录 一个简单的智能合约子货币(Subcurrency)示例区块链基础交易区块预编译合约 一个简单的智能合约 我们从一个基础示例开始,该示例用于设置变量的值,并允许其他合约访问它。 // SPDX-License-Identi…...
判断质数及其优化方法
判断质数(素数)及其优化方法 质数是指 大于1的自然数,且 只有1和它本身两个正约数。以下是几种判断方法及其优化策略。 目录 基础方法(试除法)优化1:仅检查到√n优化2:跳过偶数优化3ÿ…...
【源码阅读/Vue Flask前后端】简历数据查询功能
目录 一、Flask后端部分modelServiceroute 二、Vue前端部分index.js main.vue功能界面templatescriptstyle 一般就是三个层面,model层面用来建立数据库的字段,service用来对model进行操作,写一些数据库操作的代码,route就是具体的…...
R语言对偏态换数据进行转换(对数、平方根、立方根)
我们进行研究的时候经常会遇见偏态数据,数据转换是统计分析和数据预处理中的一项基本技术。使用 R 时,了解如何正确转换数据有助于满足统计假设、标准化分布并提高分析的准确性。在 R 中实现和可视化最常见的数据转换:对数、平方根和立方根转…...
链表(C++)
这是本人第二次学习链表,第一次学习链表是在大一上的C语言课上,首次接触,感到有些难;第二次是在大一下学习数据结构时(就是这次),使用C再次理解链表。同时,这也是开启数据结构学习写…...
算法-前缀和与差分
一、前缀和(Prefix Sum) 1. 核心思想 前缀和是一种预处理数组的方法,通过预先计算并存储数组的前缀和,使得后续的区间和查询可以在**O(1)**时间内完成。 2. 定义 给定数组 nums,前缀和数组 prefixSum 的每个元素 p…...
网关接口超时?用Java实现接口快速返回,后台继续执行的方法
网关接口超时?用Java实现接口快速返回,后台继续执行的方法 在开发过程中,我们经常会遇到网关接口由于超时限制而导致请求失败的情况。然而,有些接口本身就需要较长时间来执行任务,这时我们不能简单地增加超时时间&…...
HTTP---基础知识
天天开心!!! 文章目录 一、HTTP基本概念1. 什么是HTTP,又有什么用?2. 一次HTTP请求的过程3.HTTP的协议头4.POST和GET的区别5. HTTP状态码6.HTTP的优缺点 二、HTTP的版本演进1.各个版本的应用场景2、注意要点 三、HTTP与…...
python基础学习三(元组及字符串的使用)
文章目录 元组什么是元组元组的创建方式为什么要将元组设计成不可变序列元组的遍历集合集合的相关操作集合操作集合的数学操作集合生成式列表,字典,元组,集合总结 字符串字符串的驻留机制判断字符串的操作方法字符串的比较操作字符串的切片操…...
c#winform,倒鸭子字幕效果,typemonkey字幕效果,抖音瀑布流字幕效果
不废话 直接上效果图 C# winform 开发抖音的瀑布流字幕。 也是typemonkey插件字幕效果 或者咱再网上常说的倒鸭子字幕效果 主要功能 1,软件可以自定义添加字幕内容 2,软件可以添加字幕显示的时间区间 3,可以自定义字幕颜色,可以随…...
1、C51单片机(STC8G2K64S4)串口实验
一、串口1接线图 1、下面是单片机外接电路图,P30,P31分别用于RXD和TXD功能引脚 2、我们来查看单片机手册 串口1需要设置的寄存器 串口1的功能脚配置选择位,看电路图选择的是P3.0,P3.1。 3、串口1:SCON控制寄存器 设置为0x50:0101 0000。&a…...
ue材质学习感想总结笔记
2025 - 3 - 27 1.1 加法 对TexCoord上的每一个像素加上一个值,如果加上0.1,0.1, 那么左上角原来0,0的位置变成了0.1,0.1 右上角就变成了1.1,1.1,那么原来0,0的位置就去到了左上角左上边,所以图像往左上偏移。 总而言…...
MFC TRACE 宏的使用说明
书籍:《Visual C 2017从入门到精通》的2.7 字符串 环境:visual studio 2022 内容:几个字符串类型->(将单字节char*转换为宽字节wchar_t *)(将宽字节wchar_t* 转换为单字节char *) 问题&am…...
latex笔记
1、基本结构 \documentclass[a4paper, 12pt]{article} %文档类型 \begin{document}\title{My First Document}\author{My Name}\date{\today}\maketitleA sentence of text. \end{document}2、带有章、节、小节的结构 \documentclass[a4paper, 12pt]{article}\begin{document…...
Unity编辑器功能及拓展(3) —[Attribute]特性
在 Unity 中,[Attribute]格式的特性是用于扩展编辑器功能、控制序列化行为和调整 Inspector 显示,进行编辑器拓展的核心工具。 一.基础编辑器拓展 1.基础序列化控制 1.[SerializeField] 强制显示私有变量到Inspector 2.[HideInInspector] 隐藏该字段在Inspect…...
Rust基础语法
以下是 Rust 语言基础语法的核心要点,结合与 JavaScript 的对比,帮助前端开发者快速掌握核心概念: 一、变量与常量 1. 变量声明 Rust:变量默认不可变,需用 mut 显式声明可变性。let x 5; // 不可变变量 le…...
<tauri><rust><GUI>基于rust和tauri,实现一个大寰电爪PGHL(串口设备)定制化控制程序
前言 本文是基于rust和tauri,由于tauri是前、后端结合的GUI框架,既可以直接生成包含前端代码的文件,也可以在已有的前端项目上集成tauri框架,将前端页面化为桌面GUI。 环境配置 系统:windows 10平台:visual studio code语言:rust、javascript库:tauri2.0概述 本文是…...
Sentinel 相关知识点
Sentinel 实现原理? Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护等多个维度来帮助开发者保障微服务的稳定性。以下是 Sentinel 的实现原理: 核心概念 资源&…...