找回密码
 立即注册
楼主: 杨***

STC单片机 uC/OS-II核心技术(12):关于临界区保护和函数可重入的测试题

[复制链接]
  • TA的每日心情
    奋斗
    昨天 12:52
  • 签到天数: 175 天

    [LV.7]常住居民III

    5

    主题

    580

    回帖

    2355

    积分

    荣誉版主

    积分
    2355
    发表于 2024-3-24 15:58:00 | 显示全部楼层
    fjstcmcu 发表于 2024-3-24 15:54
    是的,我是想我自己定义的函数希望成为可重入函数

    我尽量简单回答一下吧。
    首先要解答一下什么是“可重入函数”?
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    奋斗
    昨天 12:52
  • 签到天数: 175 天

    [LV.7]常住居民III

    5

    主题

    580

    回帖

    2355

    积分

    荣誉版主

    积分
    2355
    发表于 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”等关键字声明并定义的函数,使用哪个可重入栈,由关键字决定(见下表)。

    截图202403241607458284.jpg

    另需在启动文件中配置栈顶指针并启用相应的可重入栈。
    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变量,也不能对它有取址操作。实际上这一点已经被排除在可重入函数的定义之外。



    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    慵懒
    昨天 09:02
  • 签到天数: 143 天

    [LV.7]常住居民III

    2

    主题

    53

    回帖

    378

    积分

    中级会员

    积分
    378
    发表于 2024-3-24 19:56:03 | 显示全部楼层
    CosyOS 发表于 2024-3-24 16:43
    我尽量简单回答一下吧。
    首先要解答一下什么是“可重入函数”?

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

    点评

    (1)首先对你现在的中断服务程序进行改造,把现在的中断服务程序“Old_ISR()” void Old_ISR(void ) interrupt x { ..... } 改为普通函数: void Old_ISR(void ) { ..... } 然后该写新的ISR为对旧  详情 回复 发表于 2024-3-24 21:08
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    慵懒
    昨天 09:02
  • 签到天数: 143 天

    [LV.7]常住居民III

    2

    主题

    53

    回帖

    378

    积分

    中级会员

    积分
    378
    发表于 2024-3-24 20:06:31 | 显示全部楼层
    CosyOS 发表于 2024-3-24 16:43
    我尽量简单回答一下吧。
    首先要解答一下什么是“可重入函数”?

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

    使用道具 举报

    该用户从未签到

    63

    主题

    703

    回帖

    1万

    积分

    荣誉版主

    积分
    10908
     楼主| 发表于 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 ) interrupt  x
    {
      .....
    }

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


    {
      .....
    }





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

    void New_ISR(void ) interrupt  x
    {
      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)在程序中直接调用中断服务函数是不被允许的,所以会编译出错。

    点评

    看了杨老师的解释,我才明白原来他是想主动调用一个中断函数!杨老师理解能力真好  发表于 2024-3-24 21:46
    回复 支持 反对 送花

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

    GMT+8, 2024-5-20 01:56 , Processed in 0.066318 second(s), 51 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

    快速回复 返回顶部 返回列表