单片机高阶技能之动态链接库技术实现的讨论
演示用的CPU是STM32F407VET6,IDE请用MDK5.25,低版本的MDK打开可能会有问题。
可能有些童鞋看到这里,仍然以为我说的是用静态库的方式。请注意,静态库是不能省flash的,注意这里说的flash,是内存直接寻址的flash空间,不是指spi 的那种flash。如果这里用nand或nor,那种非常大,几乎不可能不够用了。
静态库只是为了屏蔽源码,保护源码。你有几个工程链接静态库,就会有几份拷贝,它不会省空间。此外,制作静态库,生成是*.a,或*.lib ,完全用编译器或IDE就可以搞定。但动态库,这里生成的是bin,或者是hex。而且也不是单纯的用编译器或IDE就能搞定。
如果你需要把代码加载到RAM中运行,且有多个线程需要用到这个代码,也可以用动态链接的方法,即使你需要这段代码支持可重入的特性,这也是可以做到的。
问题点:
一、一直不太明白的一点是,做静态变量重定向的R9寄存器,原则上是该填什么值?
以下贴出关键代码片段:
__global_reg(6) unsigned int *StaticVariableRelocate;
extern unsigned int *DynamicStaticVar=0;// Ö¸ÏòdllµÄ¾²Ì¬±äÁ¿
extern unsigned int HostStaticVar = 0x123455AA;
Fun DelayUs = 0;
TFun RunHostFun = 0;
NFun StaticVarInit = 0;
static unsigned int DLL_Len = 0;
static unsigned int DLL_Version = 0;
static unsigned int __attribute__((aligned(8))) DynamicRAM[SIZE_MEM_INT];
extern void DynamicLoader(unsigned int AddrDynamicLinkLib)
{
unsigned int *dst,*src;
unsigned int *RAM_ADDRESS_DLY = (unsigned int *)DynamicRAM;
unsigned int DLL_Static_len,DLL_Static_offset_addr;
unsigned int i;
DLL_Len = *((unsigned int *)AddrDynamicLinkLib);// 从DLL首地址获取文件长度
DLL_Version = *((unsigned int *)(AddrDynamicLinkLib + 4));// 获取DLL版本号
DLL_Static_offset_addr = *((unsigned int *)(AddrDynamicLinkLib + 8));// 获取动态库中静态变量区的首地址
DLL_Static_len = DLL_Len - DLL_Static_offset_addr;//动态链接库的静态区全长
//在RAM中为DLL分配静态变量区,或者说创建DLL的RW的运行域
for(i = 0,dst = RAM_ADDRESS_DLY,src = (unsigned int *)(AddrDynamicLinkLib + DLL_Static_offset_addr); i < ((DLL_Static_len / 4) + 1); i ++){
*dst ++= *src ++;
}
// 初始化宿主程序中需要用到的DLL函数地址
DelayUs = (Fun) (Name2Addr(AddrDynamicLinkLib,"DelayUs",7) + (unsigned int)AddrDynamicLinkLib);
RunHostFun = (TFun) (Name2Addr(AddrDynamicLinkLib,"RunHostFun",10) + (unsigned int)AddrDynamicLinkLib);
StaticVarInit = (NFun) (Name2Addr(AddrDynamicLinkLib,"StaticVarInit",13) + (unsigned int)AddrDynamicLinkLib);
StaticVariableRelocate = (unsigned int *)((unsigned int)RAM_ADDRESS_DLY); //重定向RW的地址,但地址值原则不明
StaticVarInit((unsigned int)LED_B_Control,&DynamicStaticVar,&HostStaticVar);
}
以上代码中StaticVariableRelocate = (unsigned int *)((unsigned int)RAM_ADDRESS_DLY);
目的是为了重定向动态库中静态变量的地址,StaticVariableRelocate 最后会关联到CPU寄存器的R9,也就是说用R9重定向的静态变量地址,但看了几本书也都没有给我说清楚这个填入的值,是怎么计算出来的。虽然这里看起来就是RAM_ADDRESS_DLY这么简单,也就是DynamicRAM这么规整的值,但实际上之前我每次改变DLL,这里都不是简单的RAM_ADDRESS_DLY的搞定了,是要有一些其他的运算式,我每次都是用仿真器反向跟踪和计算出这个值的,也没有发现规律,而且这样做也很麻烦。我觉得这个点是目前最妨碍这套动态链接库推广的地方。如果这个值能最终关联到某些由编译器更新和维护的标签,那就可以做到很傻瓜化了。不知道哪里还能找到合适的文档和书籍,解释这一点。
二、在动态库的汇编文件中,怎么样自动填充符号来保证DCD 特定值 在4倍地址处。
目前我用的是手动方式,比较笨,汇编也得也不是很多,不知道有没有更好的方法。
AREA FunctionArray, DATA, READONLY, ALIGN=0
Fun_Start
DCD 0x000000C4 ;//动态库的长度
DCD 0x00000007 ;//动态库版本
DCD 0x080040B4 - 0x08004000 ;// 静态变量的偏移地址
DCB "DelayUs"
DCB "%" ;注意要用%或&填充空缺,把下面的DCD指令顶到4倍地址处。如果是Thumb Code,用%。如果是ARM Code,用&
DCD 0x0800403C - 0x08004000 + 1 ;是Thumb Code的话,加1
DCB "RunHostFun"
DCB "%%" ;
DCD 0x08004054 - 0x08004000 + 1 ;
DCB "StaticVarInit"
DCB "%%%" ;
DCD 0x08004094 - 0x08004000 + 1 ;
END
对应的找dll的函数名和地址的函数是:
unsigned int Name2Addr(unsigned int addr,unsigned char *src,unsigned char len)
{
unsigned char *targ = (unsigned char *)(addr);
unsigned int i = 8,j;
FindHead:
for(j = 0; i < DLL_Len; i ++){//
if(src[j] == targ[i]){
j ++;
i ++;
break;
}
}
if((i + len) < DLL_Len){//
}else{
return 0;
}
for(; j < len; j ++,i++){
if(src[j] != targ[i]){
goto FindHead;
}
}
if(j == len){//
if('%' == targ[i]){ //
while(1){
if(targ[i]!= '%'){ ///
break;
}else{
i ++;
}
}
if((i+4)<DLL_Len){//
return ( (targ[i+0] << 8*0) |
(targ[i+1] << 8*1) |
(targ[i+2] << 8*2) |
(targ[i+3] << 8*3) );
}
}
}
return 0;
}
参数资料:
1.《ARM程序分析与设计》 ,其中最后一章有非常类似的实例。
2.《ARM体系结构与编程》 第二版
3. CM3权威指南
相关推荐
编译时无法生成所需的动态链接库(.so文件)问题解决方案
在使用这些库文件时,我们需要进行编译,生成对应的动态链接库(.so文件)。我们需要确保编译选项正确地指定了所需的库文件,并且包含了生成动态链接库的相关选项。错误信息可能指示了具体的问题,例如缺少的库文件、错误的编译选项或者依赖关系等。例如,编译器的版本是否支持生成动态链接库,以及是否正确设置了库文件的路径等。如果缺少依赖的库文件或者版本不兼容,编译时就无法生成所需的动态链接库。通过以上步骤,我们应该能够解决编译时无法生成动态链接库的问题,并成功生成所需的库文件,以供单片机开发使用。
加密芯片JNI支持的单片机开发
接下来,我们需要选用一款安全性能较高的加密芯片。该芯片支持AES-128加密算法,且能够提供多层安全措施,适用于各种场景的安全认证应用。首先,我们需要选用一款支持JNI技术的单片机。在这里,我们选择了ST公司的STM32系列单片机作为开发平台。本文将介绍如何在单片机中使用JNI技术实现加密芯片的支持。总的来说,利用JNI技术实现单片机对加密芯片的支持,可以为嵌入式系统提供更加优秀的安全性能。通过上述步骤,我们可以在单片机中实现对加密芯片的支持,从而提高系统的安全性能。加密芯片JNI支持的单片机开发。
电信运营基于分类模型的客户流失预警系统:数据挖掘驱动的精准挽留策略设计
内容概要:本文围绕电信客户流失预警与挽留策略,构建了一套从数据探索、预处理、特征工程、分类建模、模型评估与解释到业务落地的端到端数据挖掘实战方案。基于公开的 Telco Customer Churn 数据集,项目聚焦于识别高流失风险客户,并通过逻辑回归、随机森林和XGBoost等模型进行对比分析,结合ROC-AUC、精确率、召回率、F1等指标评估性能,利用SHAP等方法实现模型可解释性,最终将预测结果转化为可操作的客户分层与差异化挽留策略。文中强调了数据泄漏防范、类别不平衡处理、模型可复现性及A/B测试验证增量收益的重要性,并明确指出当前图表为示意性质,需通过附录代码运行真实数据生成结果。; 适合人群:具备一定数据分析与机器学习基础,从事数据科学、用户运营或客户留存相关工作的从业者,尤其是工作1-3年希望提升实战能力的研发与分析人员。; 使用场景及目标:①掌握客户流失预测的全流程方法论,包括数据清洗、特征工程、建模调参与模型解释;②学习如何将机器学习模型输出转化为可运营的客户触达策略;③理解模型评估与业务目标之间的衔接,如预算约束下的优先级排序与A/B测试设计; 阅读建议:此资源以实际业务场景驱动,不仅关注算法实现,更重视从业务定义到策略落地的闭环逻辑。建议结合附录提供的完整Python代码,在本地环境中下载数据集并复现分析流程,重点关注数据预处理防泄漏机制、模型管道构建、超参数调优策略及SHAP解释应用,避免将文中的示意图表误认为实测结果。
旋转高频信号注入法在PMSM零低速无位置控制中的仿真研究(Matlab代码实现)
内容概要:本文系统研究了旋转高频信号注入法在永磁同步电机(PMSM)零低速无位置传感器控制中的应用,并提供了基于Matlab/Simulink的完整仿真代码实现。针对PMSM在启动及低速运行时反电动势微弱导致传统观测器失效的问题,该方法通过在定子绕组中注入高频旋转电压信号,利用电机自身凸极效应产生的响应电流特征,实现对转子位置的高精度在线估计。文中详细阐述了该技术的理论基础、数学建模过程、仿真系统架构设计以及关键参数整定方法,全面验证了其在零速和低速工况下对转子初始位置辨识与动态跟踪的准确性、有效性及强鲁棒性。; 适合人群:具备电机控制理论基础知识和Matlab/Simulink仿真能力的电气工程、自动化、电力电子等相关专业的硕士研究生、博士研究生、科研人员以及从事高性能电机驱动系统研发的工程师。; 使用场景及目标:① 深入理解高频信号注入类无位置传感器控制技术的工作原理、信号处理机制与工程实现细节;② 掌握利用Matlab/Simulink搭建PMSM高性能矢量控制系统及高级观测器的仿真方法;③ 为开发高精度、低成本、全速度范围适用的PMSM无位置传感器驱动器提供坚实的理论依据和技术验证平台。; 阅读建议:建议读者结合文中详尽的理论推导与所提供的仿真代码进行对照学习,亲自动手运行、调试仿真模型,通过改变负载、转速、注入信号参数等工况,观察系统响应与控制效果的变化,从而深刻掌握旋转高频注入法的内在工作机制与设计要点。
Python小Demo实例源码爬取网易云音乐评论
Python小Demo实例源码爬取网易云音乐评论


单片机/工控
