CosyOS 发表于 2024-3-24 15:58:00

fjstcmcu 发表于 2024-3-24 15:54
是的,我是想我自己定义的函数希望成为可重入函数

我尽量简单回答一下吧。
首先要解答一下什么是“可重入函数”?

CosyOS 发表于 2024-3-24 16:43:04

本帖最后由 CosyOS 于 2024-3-24 17:59 编辑

fjstcmcu 发表于 2024-3-24 15:54
是的,我是想我自己定义的函数希望成为可重入函数
我尽量简单回答一下吧。
首先要解答一下什么是“可重入函数”?

可重入函数:未被设计用来访问特定的全局公共资源,并且所有形参和局部变量均分配在寄存器或可重入栈中。

C51下:
一、寄存器可重入函数
所有形参和局部变量均分配在寄存器中的可重入函数。
必要条件:代码优化等级最低不能低于4级,即必须开启寄存器变量优化。
判别方法:通过查看反汇编代码确认。调用处(传参)、函数入口、形参和局部变量的引用处均需查看,确认是否均为寄存器变量。

如不能生成寄存器可重入函数,可考虑可重入栈可重入函数。

二、可重入栈可重入函数
采用“reentrant”等关键字声明并定义的函数,未采用寄存器优先分配原则,所有形参和局部变量均分配在可重入栈中。
1、使用关键字“reentrant”声明并定义的函数,使用哪个可重入栈,由内存模型决定。
2、使用“small reentrant”等关键字声明并定义的函数,使用哪个可重入栈,由关键字决定(见下表)。



另需在启动文件中配置栈顶指针并启用相应的可重入栈。
C51的可重入栈效率较低,不建议采用。

C251下:
C251 Version 1:C251 Version 1 的可重入栈,与C51是相同的,仍为模拟栈,但取消了PBPSTACK。但现在不会再有人用 Version 1 了吧?所以 XXX。
C251 Version 2:自 C251 Version 2 开始,可重入栈采用与MDK-Arm相同的方式,即硬件栈、继承调用者栈,并同时采用寄存器优先分配原则。
可重入函数实现方案:
1、生成全局可重入函数(推荐方案)
C251标签页,“Generate reentrant functions”打勾,所有自定义函数都允许使用可重入栈,并试图生成可重入函数。
2、寄存器可重入函数 + 可重入栈可重入函数
寄存器可重入函数的生成必要条件:代码优化等级最低不能低于3级,即必须开启寄存器变量优化。但也未必能生成,必须反汇编验证,方法与C51相同。
可重入栈可重入函数:使用关键字“reentrant”声明并定义。

注意:251的可重入栈只能在edata中,因为硬件栈只能在edata中。

MDK-Arm下:
无需任何操作,直接便可以是可重入函数。

额外的注意:
1、即使一个函数可重入,也要注意它访问的资源是否为全局公共资源、是否可重入,是否需要对资源进行保护。
2、自定义函数内不要有局部的static变量,也不能对它有取址操作。实际上这一点已经被排除在可重入函数的定义之外。



fjstcmcu 发表于 2024-3-24 19:56:03

CosyOS 发表于 2024-3-24 16:43
我尽量简单回答一下吧。
首先要解答一下什么是“可重入函数”?



其实我需要的不是真正的可重入函数,我想把1602的显示内容更改操作放在定时器中断里,但在主程序的开始阶段调用1602内容更改操作显示一个开机内容,但keil不允许,有解决的办法(keil操作)

fjstcmcu 发表于 2024-3-24 20:06:31

CosyOS 发表于 2024-3-24 16:43
我尽量简单回答一下吧。
首先要解答一下什么是“可重入函数”?



有些理解,看来这个可重入函数实现挺麻烦的,还耗资源还不如重新定义一个函数,能说说这种形式有啥好处?

杨为民 发表于 2024-3-24 21:08:46

本帖最后由 杨为民 于 2024-3-24 21:11 编辑

fjstcmcu 发表于 2024-3-24 19:56
其实我需要的不是真正的可重入函数,我想把1602的显示内容更改操作放在定时器中断里,但在主程序的开始阶 ...

(1)首先对你现在的中断服务程序进行改造,把现在的中断服务程序“Old_ISR()”


void Old_ISR(void ) interruptx
{
.....
}

改为普通函数:
void Old_ISR(void )


{
.....
}





然后该写新的ISR为对旧ISR的调用:

void New_ISR(void ) interruptx
{
Old_ISR();
}


(2)如果你的意思是在main函数里、打开中断EA=1之前,想要执行一次中断来显示内容,现在就可以在main函数里、打开中断EA=1之前任意使用函数调用“Old_ISR();”语句了。
这时候由于中断没有打开,中断不会发生,不存在函数重入的问题,因此函数“Old_ISR()”是否可以重入没有关系。
(3)如果你的意思是在main函数里、打开中断EA=1之后,想要单独执行一次中断来显示内容,那么像上面一样地改造ISR,然后在本文前面给出的解答,在调用“Old_ISR()”的前后加临界区保护语句就可以了:
EA=0;
“Old_ISR()”

EA=1;

(4)在程序中直接调用中断服务函数是不被允许的,所以会编译出错。

王锦平 发表于 2025-4-8 15:15:26

是我的话我可能会考虑写自用的不可重入函数,在不清楚他库函数如何实现的情况下,我要什么就写什么,就是工作量有点大{:tuosai:}
页: 1 2 3 4 5 6 7 8 9 [10]
查看完整版本: STC单片机 uC/OS-II核心技术(12):关于临界区保护和函数可重入的测试题