杨为民 发表于 2023-10-14 19:22:16

STC单片机 uC/OS-II核心技术(11):uC/OS-II系统对用户程序打开/关闭总中断的响应

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

一、引言(1)笔者在论坛中提出了对RTOS系统的基本测试方法和测试程序,引起了很大的反响和争议,包括对任务切换速度的测试、临界区保护方法为空(方法0)时的任务调度测试、对于临界区保护方法1(关闭总中断的方法)在临界区保护嵌套中进行任务调度的测试、对于临界区保护方法2(对任务调度加锁/解锁的方法)在临界区保护嵌套中进行任务调度的测试、以及对于临界区保护方法3(不关闭任何中断的方法,见前文)的测试。本文将介绍笔者对RTOS系统的下一个基本测试方法和测试程序——单片机RTOS系统对用户程序打开/关闭总中断的响应。(2)对于裸机编程应用,用户可以自由地打开和关闭总中断。对于一个具体的单片机RTOS系统,在RTOS程序中用户是否可以自由地(或者多大程度地)使用非系统中断(包括打开和关闭总中断EA)是衡量单片机RTOS重要的一项指标,这项指标影响着用户的编程方法和应用领域。通常RTOS系统都包括定时器节拍等系统中断,因此运行时总中断总是打开的EA=1。但是系统运行的时候允不允许用户自由地写EA=0关闭所有中断,以及长时间关闭总中断会对系统产生什么影响对于不同的RTOS系统却是不同的。(3)为了测试挑战者x51移植版V3.30是否允许用户自由地关闭打开总中断EA,本文提供了三个范例:第一个范例是三个实时任务同时执行,第二个范例是观察关闭和打开总中断的影响,第三个是任务交替执行。(4)通常给用户进行测试的产品都采用“黑箱”模型,挑战者x51-RTOS产品测试版也是以库函数的封装方式提供的,产品测试版以封装的方式提供的最大优点是容易确定是产品内部的问题还是测试程序的问题。二、范例一:实时多任务同时执行(5)本文范例一的任务A是一个P0端口的LED灯闪烁,任务的程序如下图:
其中第72行和第79行是P0端口的8个LED灯一起闪烁的视觉效果,第74行到第77行和第81行到第84行是供逻辑分析仪显示的通道2信号,信号是一个连续的40毫秒周期的方波。
(6)本文范例的任务B是一个P1端口的LED灯闪烁,任务的程序如下图:
其中第96行和第101行是P1端口的左右各4个LED灯交替闪烁的视觉效果,第97行到第100行(100毫秒方波)和第102行到第105行(30毫秒方波)是供逻辑分析仪显示的通道4信号。
(7)本文范例的任务C是一个P3端口的LED灯闪烁,任务的程序如下图:
其中第119行和第120行是P3端口的6个LED跑马灯的视觉效果,第121行到第124行是供逻辑分析仪显示的通道5信号,信号是一个连续的40毫秒周期的方波。
(8)本文范例均使用定时器0作为系统节拍中断源,使用定时器3作为对比中断源,观察总中断EA的关闭对它们的影响。下图是相关的程序:
其中第74行到第77行将定时器0补充设置为不可屏蔽中断的模式3,在第91行到第97行的定时器0中断的ISR中第95行是RTOS的系统节拍函数调用,第93行和第96行在逻辑分析仪的0通道产生1毫秒周期的正脉冲。图中的第113行到第116行的定时器3中断的ISR是在逻辑分析仪6通道上产生5KHz的方波。定时器3的中断是否发生依赖于总中断EA是否打开。
(9)下图是范例一运行时的逻辑分析仪截图:
通道0和通道6的中断信号是连续的,通道2的任务A信号、通道4的任务B信号和通道5的任务C信号也都是连续的。由于范例一任务中所有控制LED灯闪烁的延时函数都采用了RTOS的休眠函数“OSTimeDly()”,在延时期间对挂起当前任务,将CPU执行权留给其他就绪任务去执行,从图中可以看出任务A、任务B和任务C是同时执行的。三、范例二:关闭和打开总中断的影响
(10)本文范例二的任务A与任务B与范例1的相同,只是在任务B的主循环中加上关闭和打开总中断EA的语句,以观察EA对RTOS系统运行的影响。任务B的程序如下图:
其中第95行和第103行分别为关闭和打开总中断EA,第94行和第102行是将EA的状态显示逻辑分析仪的第1通道上,高电平为EA=1,低电平EA=0。
(11)下图是范例二运行时的逻辑分析仪截图:
其中通道1周期地显示出高低电平信号,代表总中断EA交替地关闭和打开。(12)从上图中可以得出以下结果,在一个任务中关闭和打开总中断EA:对不可屏蔽中断定时器0中断(系统中断)通道0没有影响。对三个实时任务的连续执行通道2、通道4和通道5没有影响。对于一般定时器3中断通道6,EA=0(低电平)期间中断被关闭。(13)结论:对于挑战者x51移植版V3.30,用户可以在同一个任务里自由地关闭和打开总中断,对非系统中断进行控制,不影响任务的执行。四、范例三:任务交替执行
(14)本文范例三的任务A与范例1的相同,只是在任务B的主循环中加上关闭总中断EA和在任务C中打开总中断EA的语句,以观察EA对RTOS系统任务调度的影响。其中任务B的程序如下图:
其中第100行和第101行在任务B中断关闭总中断。任务C的程序如下图:
范例三任务C将6个跑马灯程序分为两半,在其中第132行到133行打开总中断EA。图中第131行休眠延时程序是为了在逻辑分析仪上产生一个打开EA的时间信号。
(15)下图是范例三运行时的逻辑分析仪截图:
对比范例二,可以看出在任务C中打开总中断EA并不影响任务C的执行和任务调度。在任务B循环中关闭总中断EA,导致任务B要循环三次关闭三次总中断EA才能挂起自己,将任务控制权交给任务C去执行,因此也不影响任务B的执行和任务调度。(16)结论:对于挑战者x51移植版V3.30,用户可以在不同的任务里自由地关闭和打开总中断,对非系统中断进行控制,不影响任务的执行和任务的调度。五、微山x51-uCOSII移植版V1.10范例二测试(17)微山x51-uCOSII移植版V1.10是笔者为uC/OS-II教学开发的一个教学版本,该版本的临界区保护方法为直接关闭总中断的不可嵌套的方法1:#defineOS_ENTER_CRITICAL() EA=0 /* 直接禁止中断 */#defineOS_EXIT_CRITICAL()EA=1 /* 直接允许中断 */
下图是该版本对本文范例二的测试结果:
其中由于通道1被中断内任务切换信号占用,总中断EA信号改在了通道7。从图中可以看出,关闭总中断EA=0从整体上看对于三个任务也没有什么影响,并且对定时器0(不是不可屏蔽的模式)和定时器3中断也没有什么影响。这个结果说明对于微山x51-uCOSII移植版V1.10,用户程序根本不可能有效地关闭总中断,因此只要一碰到RTOS的核心函数里面的临界区保护退出语句,中断立马就被打开了。(18)结论:对于微山x51移植版V1.10,用户不能够自由地关闭和打开总中断,对非系统中断进行控制,虽然这不会影响到RTOS系统本身和任务的调度。六、uCOS-II-2.93.01移植版范例二测试
(19)uCOS-II-2.93.01 for STC32G12K128移植版的临界区保护方法为利用局部变量保存总中断状态的可嵌套的方法3,下图是该版本对本文范例二的测试结果:
从图中可以看到开机LOGO信号之后,任务B一开始执行系统就停机了,所有中断不再发生,任务调度无法进行。
(20)这时如果将任务B中关闭和打开总中断EA的语句注释掉,程序便能正常运行,见下图:
其中通道1是没有注释掉的EA电平信号。这证明上面的死机是关闭总中断产生的。对比微山x51临界区保护方法1的结果,可以知道这里的问题出在可嵌套的方法3上。当总中断被用户(不是RTOS系统)关闭后,执行临界区进入保护语句时,保存的是总中断关闭状态,然后执行临界区退出保护语句时恢复的仍然是总中断关闭状态,因此总中断永远不会再被打开,整个系统死机。
(21)结论:对于uCOS-II-2.93.01 for STC32G12K128移植版,用户不能够自由地关闭和打开总中断,对非系统中断进行控制,并且甚至会关闭RTOS系统本身和任务的调度。





杨为民 发表于 2023-10-15 07:15:02

本帖最后由 杨为民 于 2023-10-15 09:02 编辑

七、 FreeRTOS STC portV1.0.2移植版 范例二测试(22)FreeRTOS STC port V1.0.2移植版的临界区保护方法为直接关闭总中断的不可嵌套的方法1:
下图是该版本对本文范例二的测试结果:
从图中可以看出,关闭总中断EA=0从整体上看对于三个任务也没有什么影响,并且对定时器0(不是不可屏蔽的模式)和定时器3中断也没有什么影响。这个结果说明对于FreeRTOS STC port V1.0.2移植版,用户程序根本不可能有效地关闭总中断,因为只要一碰到RTOS的核心函数里面的临界区保护退出语句,中断立马就被打开了。
(23)结论:对于FreeRTOS STC port V1.0.2移植版,用户不能够自由地关闭和打开总中断,对非系统中断进行控制,虽然这不会影响到RTOS系统本身和任务的调度。

tzz1983 发表于 2023-10-15 09:42:23

老杨, 您针对251内核自己重新写一个RTOS吧, 哈哈, 曾经我有过这种想法, 但没有这么多精力, 而且现有的OS功能已经能够满足实际项目的需求, 所以也没有动力.
而我观杨老师您有充足的精力, 并且非常的热爱, 所以这项任务非常适合您.
正如CosyOS所说, 移植的毕竞是移植的, 没有土生土长的那么合身, 现在您可以结合UCOS和FREERTOS的优点, 来量身为251内核定做一个全新的RTOS.
1. 精简, 保留主要的核心的功能, 去掉一些通用的,不实用的功能. 提高速度, 节省RAM使用.
2. 取长补短, UCOS没有同级任务优先级, 这个可以加上. 另外飞信功能不错, 可以加上这个功能.
3. 简化应用, 各种OS应用尽量简化参数, 使使用者用起来更加舒服,比如现在UCOS创建任务, 要先在任务函数体外申明栈RAM, 这里能参照一下RTOS, 由OS管理RAM分配则可减少一个参数

杨为民 发表于 2023-10-15 11:26:38

本帖最后由 杨为民 于 2023-10-15 11:29 编辑

八、 对CosyOS V2.3.1系统用范例二测试的结果(24)“CosyOS是一款来自中国的开源实时操作系统,最大亮点是所有内核全局不关总中断(零中断延迟)。”由于CosyOS编程难以掌握,所以笔者就对“CosyOS移植到STC8H单片机的测试程序”(见附件)按照范例二的内容进行了修改,然后进行了测试。首先将任务B中的关闭/打开总中断EA的语句注释后进行测试:
其中第55行关闭总中断EA=0被注释,第65行打开总中断EA=1被注释。对于CosyOS系统,总中断在系统开始运行时就已经被系统打开了,在第55行和第65行程序被注释的情况下,对本文范例二的测试结果如下图:
可以看到在通道1的EA=0到EA=1之间,通道4信号有5个60毫秒的翻转,与上面的程序第58行到第61行程序相对应。
下图是将EA=0附近的信号放大了看:
其中各个通道信号正常。
(25)将第55行和第65行程序的注释去掉后整体的信号如下:
从图中可以看出,从执行第55行程序关闭总中断EA=0那一刻起,通道4的任务B信号异常:原本5个60毫秒的翻转变成了1个,通道1上的信号异常,说明第65行打开总中断EA=1程序很快就被执行,之前第64行程序将通道1设置为高电平。由于总中断EA被关闭的时间很短,所以通道6的定时器3中断没有受到影响照常发生。
(26)将上面逻辑分析仪的信号在第55行程序EA=0附近放大截屏如下:
1)从通道4任务B信号可以看到当EA=0后,上面程序中的第60行“uDelay_ms(60);”的休眠60毫秒的程序被错误地忽略了4次,每个循环时间仅仅是“3微秒”。2)并且循环5次(5x3=15微秒)后,就执行第65行打开总中断EA=1的语句,使得通道1的信号变高了。3)不仅如此,当总中断打开后,在执行第66行程序前,额外地插入了一个第60行的“uDelay_ms(60);”的休眠60毫秒的程序。这些情况说明:用户程序根本不能关闭总中断,一旦关闭,就会产生异常,有些系统语句(如uDelay_ms)会被忽略,用户程序得不到正确执行。(27)结论:对于CosyOS系统用户不能够自由地关闭总中断,关闭总中断将会导致RTOS系统异常。换言之,对于CosyOS,虽然其系统本身不会关闭总中断,但也不允许用户编程关闭总中断。(28)猜测:产生上面奇异现象的原因可能与CosyOS采用硬件中断模拟“软中断”指令,并且对“软中断”指令建立防止重入的队列有关。




CosyOS 发表于 2023-10-15 16:38:25

杨为民 发表于 2023-10-15 11:26
八、 对CosyOS V2.3.1系统用范例二测试的结果(24)“CosyOS是一款来自中国的开源实时操作系统,最大亮点是 ...

关闭总中断其实就是进入临界区了,CosyOS现有的设计是不允许用户在临界区内调用阻塞类的服务,uDelay是阻塞延时,属于阻塞类服务。
对于这种情况,可采用软件延时替代阻塞延时即可解决。

杨为民 发表于 2023-10-15 18:27:06

本帖最后由 杨为民 于 2023-10-15 18:28 编辑

CosyOS 发表于 2023-10-15 16:38
关闭总中断其实就是进入临界区了,CosyOS现有的设计是不允许用户在临界区内调用阻塞类的服务,uDelay是阻 ...
“关闭总中断其实就是进入临界区”

(1)就一般的RTOS而言,关闭总中断不等于进入临界区,顶楼的挑战者x51移植版就是例子,在很多的有软中断指令和不可屏蔽中断的单片机上的RTOS就没有这个说法。
(2)根据你的介绍,对于CosyOS,作为亮点,你已经采用不关闭总中断的临界区保护方法,比如用关闭ET0。你曾经在那个“PK”的帖子里反复强调CosyOS的一个创新点就是临界区保护不关闭总中断,我也曾发帖专门阐明为什么临界区保护必须要关闭总中断而不是只关闭系统使用的中断。
(3)那么现在,使用CosyOS的用户程序只要一“关闭总中断其实就是进入临界区”,你这句话的意思就是证实了“关闭总中断是CosyOS临界区保护方法”这个结论。既然如此,我建议CosyOS就直接用“关闭总中断作为CosyOS临界区保护方法”,这样其保护效果就会与移植的uC/OS和FreeRTOS主流单片机RTOS一样好。
(4)直接声明“CosyOS现有的设计是不允许用户在临界区内调用阻塞类的服务”非常好,要点赞{:4_250:}。我建议改为重要说明:“对于CosyOS,用户可以在自己的程序中关闭总中断,进行自己的中断控制。只是以后用户在调用CosyOS系统的涉及任务切换的功能之前,必须先打开总中断。这样做的原因是CosyOS系统使用硬件中断模拟软中断进行任务切换”。
(5)其实对于CosyOS,这个限制不是永远的,等待STC32G/F系列单片机开放软中断“TRAP”指令后,这个限制就自然消除了。
(6)这个测试程序是针对你的CosyOS特别设计过的,从上面的例子可以直观地看出当总中断关闭后,那些“调用阻塞类的服务”是如何在你的队列中排队的,以及当总中断恢复后,你的那些队列是如何FIFO的。从这次测试看,你的队列处理程序存在BUG,没有恢复5个“uDelay”队列,只恢复了一次60毫秒的“uDelay”操作。


CosyOS 发表于 2023-10-15 19:58:55

杨为民 发表于 2023-10-15 18:27
“关闭总中断其实就是进入临界区”

(1)就一般的RTOS而言,关闭总中断不等于进入临界区,顶楼的挑战者x5 ...

1、CosyOS内核中从来不会关闭总中断,但也提供了全局临界区(关闭总中断)给用户,用户有需要时可以进入全局临界区或自行关闭总中断。
2、关于用户自己关闭总中断的注意事项及临界区中调用服务的限制条件等,未来我会写在使用说明中。
3、CosyOS即将推出新版CosyOS-Ⅱ,但遗憾的是仍然不能支持在临界区中调用阻塞类的服务,但这个功能我会考虑,在未来看是否有可能支持。


ZengZhengxian 发表于 2025-6-7 15:01:29

添加了任务D可以再添加任务E为什么不行

ZengZhengxian 发表于 2025-6-7 15:22:18

ZengZhengxian 发表于 2025-6-7 15:01
添加了任务D可以再添加任务E为什么不行

实时任务堆栈定义哪里总的不超过2048貌似可以

杨为民 发表于 2025-6-7 15:41:31

ZengZhengxian 发表于 2025-6-7 15:22
实时任务堆栈定义哪里总的不超过2048貌似可以

你指的是哪一个RTOS?
页: [1]
查看完整版本: STC单片机 uC/OS-II核心技术(11):uC/OS-II系统对用户程序打开/关闭总中断的响应