c语言延时函数_子牙篇(2)多任务程序设计中的函数重入问题

weixin_39559333 2020-11-29 09:07:44  39  收藏

文章标签: c语言延时函数 c语言延时函数delay c语言延时函数delay延时一秒 中断函数中调用延时会影响其他中断?

中断是单片机最重要的功能,对多任务程序设计中的函数重入问题必须要给予足够的重视,下面给出了一个Keil的C51编译器的翻车现场。

(一) 函数重入问题

如果一个函数如果不受函数递归时或者被中断时被重新执行过的影响,还能继续正常运行下去,称这个函数是“可重入的”,否则称为“不可重入的”。

(1)函数的递归调用。递归是一种很重要的计算方法。当一个函数进行递归时,函数从递归点开始又从头开始执行一次本函数,当函数从递归点退回时,函数递归前的变量值是否还保持原来的值,是否能够再正常执行下去,这是个问题。能够正确递归的函数称为“可递归的”,可递归的意味着可重入的。

(2)多任务中断重入。如果一个函数正在执行的过程中,被另一个任务中断了,然后该任务也调用了这个函数,导致这个函数的代码又被从头开始执行,其中使用过的变量的值都被改变了。然后等中断任务结束后,被中断的函数继续执行。

这时存在一个极大的问题,虽然编译器将中断的寄存器现场恢复了,但是被中断的函数使用的,那些被中断任务改变了的变量,如何恢复?这个问题称为函数重入问题。

(3)根据中断现场的保存和恢复机制,如果一个函数不使用任何变量(单片机的公共端口一般不含在内,因为这些端口寄存器的值本身就是在不断变化,不存在保存与恢复),只使用了通用寄存器,则该函数是“中断可重入的”。因为所有的寄存器在中断完成后都被恢复了。

(二)函数不可重入范例

Keil的C51编译器缺省是函数不可重入的,当然不是所有不可重入函数在后台和中断中同时调用都会发生问题。下图的程序给出了一个精心策划的例子,演示了Keil翻车的现场。

图1 不可重入函数翻车的程序

(1)本范例有前后台两个任务,端口P2连接8个下拉的LED。第39行到到第49行是后台任务,P25~P27三个LED按照间隔1秒钟全暗、P27亮、P27P26亮和P27P26P25亮的方式发光。第55行到到第61行是中断前台任务,定时器0每50毫秒产生一次中断,每中断20次(1秒钟)P20P21P22三个LED闪烁一次,闪光时间30毫秒。

(2)在前后台任务中都采用同一个延时函数“Delay_MS”作为软件延时用,该函数完全会碰到函数重入的问题。

(3)本项目对Keil的设置为大模式和不优化,因此所有的变量均实际存储在XRAM空间,都是静态变量,因此延时函数“Delay_MS”是不可重入的。

使用Keil生成HEX文件,烧录到实验箱单片机上,可以观察到后台任务的P27P26P25三个LED闪烁一轮后就不再闪烁了,但前台任务的P20P21P22三个LED仍然正常连续闪烁。

根据程序可以判断,中断是正常工作的,在中断里的Delay_MS()函数是正常工作的,但是在主循环中的Delay_MS()函数却死在那里退不出来了,因此证明这个函数是不可重入的,并且导致了系统工作不正常。

(4)根据Delay_MS()函数定义的第17到23行,可以看到中断中延时函数正常退出时,静态变量j和i的值为0,静态变量k的值为30。因此每次中断任务完成后,这三个变量的值未必会恢复到它们在主函数中的值。

(5)假如中断发生时后台任务的延时函数正准备执行第21行或者第22行程序,等中断退出后,i和j的值为0。这时无论做--j或者做--i,其值将变为0xFFFF,不为0,因此要继续做减一循环,程序原地踏步。但是要把一个16位的长整数减为0,要花不止1秒的时间,这时中断任务又来了,变量值又被清0,周而复始,后台程序就停留在那里循环,不会退出延迟函数,所以后台任务的LED就死在那里不再闪烁了。

同样中断退出后k的值为30,对于第17行程序,后台任务的k值一次次被清为30,很难达到循环的上限1000。

下图是用8通道逻辑分析仪对P2端口的测量时序图。

图2 翻车现场的逻辑分析仪截屏

图中T0时刻单片机加电,全部位端口为高电平,所有的LED均不亮。T1时刻程序执行到第42行,通道7开始低电平发光,然后是通道6开始低电平发光,然后通道5开始低电平发光。

T2时刻(图中垂直红线)中断第20次时,通道0、1和2开始低电平发光。然后中断完成后,可以看到让通道5持续低电平发光的第47行程序调用的延时函数被强行终止,程序又从第40行开始重新循环。但轮循环更不走运,在T3时刻,第45行后台任务调用的延时函数再无出头之日,后台任务被永远阻塞在那里,后台的LED不再闪动了。具体的效果看与本文对应的小视频。

图3是Keil翻车后的现场图。

图3 翻车后的运行情况

(三)Keil的C51程序中断重入问题的解决方法

解决Keil的C51程序中断重入问题有两个方法:

(1)按照Keil的规范对函数添加关键字“reentrant”,将函数定义为可重入的

void Delay_MS(unsigned int n) reentrant

Keil编译器会设置一个“?C_XBP”函数指针变量,然后按照标准C语言函数帧模型来操作。

(2)将涉及有中断重入问题的函数重复写成多个同样的函数,取不同的函数名,每个调用的中断任务和后台任务分别用一个。这样不同的任务对应不同的函数实体,自然不存在函数重入问题了。

(四)假设用缺省是函数可重入的8位单片机C语言编译器就没有这个问题了,正常运行时8通道逻辑分析仪的期望结果见图4,期望的效果看与本文对应的小视频。

图4 克服中断重入问题正常运行的效果

相关资源:四史答题软件安装包exe

https://blog.csdn.net/weixin_39559333/article/details/110617431

递归重入c语言延时函数多任务程序设计中的函数重入问题按照Keil的规范对函数添加关键字“reentrant”,将函数定义为可重入的 void Delay_MS(x) reentrant相关推荐

  1. c51语言1秒延时程序,KeilC51程序设计中几种精确延时方法

    实现延时通常有两种方法: 一种是硬件延时,要用到定时器/计数器,这种方法可以提高CPU的工作效率,也能做到精确延时:另一种是软件延时,这种方法主要采用循环体进行. 1 使用定时器/计数器实现精确延时 ...

  2. C语言 —— 关键字(C语言标准定义的32个关键字:auto、register、static、sizeof、signed、unsigned 、break 、 continue 、void)

    C语言标准定义的32个关键字:(列出每个关键字的意义) 关键字 意 义 auto 声明自动变量,缺省时编译器一般默认为 auto int 声明整型变量 double 声明双精度变量 long 声明长整 ...

  3. c语言程序设计 实验五数组6,c语言实验五数组程序设计解答.doc

    c语言实验五数组程序设计解答.doc 实验五数组应用(二)一.实验目的1(掌握二维数组的定义和初始化.2(掌握二维数组元素的引用及其应用.3(掌握字符数组的定义和初始化.4(掌握字符数组元素的引用及其 ...

  4. c语言延时函数delay_STM32中精确延时函数的实现

    在与传感器或者模块的总线进行通信的时候,常常需要使用到精确延时,一般我们会封装几个常用延时函数,下面我们以STM32F103芯片为例,详细介绍一下STM32下一种精确延时函数的实现: 时钟树 下图中紫 ...

  5. 51c语言延时作用,51单片机C语言延时函数怎么定义和使用

    描述 51单片机C语言延时函数怎么定义 C语言定义延时函数主要通过无意义指令的执行来达到延时的目的.C程序中可使用不同类型的变量来进行延时设计.经实验测试,使用unsigned char类型具有比un ...

  6. 延时作用是什么意思c语言,单片机中C语言延时函数

    原标题:单片机中C语言延时函数 延时程序计算2009-11-02 22:15单片机C语言延时程序用C语言写出来程序非常的简练,它是一种模块化的语言,一种比汇编更高级的语言,但是就是这样一种语言也还是有 ...

  7. c语言延时函数_介召几个frida在安卓逆向中使用的脚本以及延时Hook手法

    0x00 frida简介 frida是近几年才推出的一款全平台的逆向神器.功能上主要采用动态hook的方式,加入log,修改逻辑等.可以对java,native等hook. 具体使用情况,谁用谁知道. ...

  8. 单片机中C语言延时函数

    单片机C语言延时程序计算2009-11-02 22:15单片机C语言延时程序用C语言写出来程序非常的简练,它是一种模块化的语言,一种比汇编更高级的语言,但是就是这样一种语言也还是有它不足之处:它的延时 ...

  9. 单片机c语言中延时函数的作用,单片机中C语言延时函数

    单片机C语言延时程序计算2009-11-02 22:15单片机C语言延时程序用C语言写出来程序非常的简练,它是一种模块化的语言,一种比汇编更高级的语言,但是就是这样一种语言也还是有它不足之处:它的延时 ...

最新文章

  1. Hibernate 之父:是时候升级到 Java EE 6 了!
  2. 报表需求源源不断?手把手教你提升报表通用性
  3. HBuilder的快捷操作
  4. Android UI 备忘:DrawerLayout
  5. C# Task 循环任务_聊聊 JavaScript 的并发、异步和事件循环
  6. C# 静态类的构造函数
  7. bzoj 4131: 并行博弈(博弈)
  8. AcWing 829. 模拟队列
  9. mysql 双1设置_2020-10-15:mysql的双1设置是什么?
  10. 扇贝有道180923每日一句
  11. 【瑕疵检测】基于matlab瓶盖瑕疵检测【含Matlab源码 730期】
  12. linux注册节点报错,Linux 运维4月17日 5.102-5.103
  13. html 长度太长截断,HTML CSS 表格换行禁止 超出指定长度自动截断
  14. EasyUI 中 Combobox里的onChange和onSelect事件的区别
  15. ANN之乘积量化PQ
  16. [JsHtml]全面清除前端缓存
  17. 谈谈B端、C端、G端的产品区别
  18. 因计算机丢失d3dx9-30,Win10玩仙剑5提示“丢失d3dx9_30.dll”怎么解决?
  19. Typo: In word 拼写检查
  20. 大厂10年经验,我对Java高并发问题方案的总结,堪称教科书级

热门文章

  1. windows 脚本taskkill强制关闭进程报拒绝访问
  2. [转载](家常菜系列)教你几道八大菜系中的佳肴做法
  3. 手机端定位获取用户位置信息
  4. 达梦数据库支持的数据类型
  5. Nginx(十八)mime.types的作用
  6. JS禁止输入特殊符号,只能输入中文,英文和数字
  7. 加密潮流:时尚向元宇宙的进阶
  8. springboot中@Valid使用
  9. oracle数据文件全部丢失,oracle 数据文件,控制文件和参数文件全部丢失恢复
  10. CDB(ContainerDatabase)与PDB(PluggableDatabase)