sdwys 发表于 2024-10-31 15:33:57


/* 启动任务 */
#define uStartTask(task, status) sUSV_StartTask(&u_taskhand_##task, (s_voidvoid_tfp)task, status) /** \return ecode */

/* 启动任务 */
#define sUSV_StartTask(hand, entry, status) \
( \
        (m_boolvoid_tf(su_enter_critical_one))() || true ? su_startup_task((s_taskhand_tsp)hand, entry, !status ? OS_STATUS_READY : OS_STATUS_SUSPENDED) : false \
)


(m_boolvoid_tf(su_enter_critical_one))() || true这个表达式值是true,那为什么 启动任务 表达式这样写

( \
        (m_boolvoid_tf(su_enter_critical_one))() || true ? su_startup_task((s_taskhand_tsp)hand, entry, !status ? OS_STATUS_READY : OS_STATUS_SUSPENDED) : false \
)

(m_boolvoid_tf(su_enter_critical_one))() 能不能解释下这个表达式的意思。

CosyOS 发表于 2024-10-31 18:10:22

本帖最后由 CosyOS 于 2024-10-31 19:02 编辑

sdwys 发表于 2024-10-31 15:33
/* 启动任务 */
#define uStartTask(task, status) sUSV_StartTask(&u_taskhand_##task, (s_voidvoid_tfp) ...
你的问题涉及到 CosyOS 的一个核心关键技术:
独家技术实现系统服务函数的可重入,使51彻底摆脱可重入栈、全面提速。
原理是:对于任务中调用的服务,先进入任务临界区,而后再调用服务函数,
这样服务函数是不会发生重入的,可以为不可重入函数。
使得在C51下,CosyOS内核无需可重入栈支持,全面提速。

当然也还有服务函数会发生重入的情况,需要用另外的技术来解决,暂时先不提。

对于启动任务来说,首先是要进入任务临界区,而后再调用 su_startup_task 来启动任务。

su_enter_critical_one 是 进入任务临界区函数:void su_enter_critical_one (void);

(m_boolvoid_tf(su_enter_critical_one))() 是把 su_enter_critical_one 强制转换为 返回bool型的函数,
原因是它要 || ture 做条件判断,所以必须要有返回值。

由于 编译器知道,任何值 || true 的结果必然为真,所以:
1、不会做条件判断(
      不会理会 (m_boolvoid_tf(su_enter_critical_one))() 的返回值,
      也不会 || true
);
2、但 su_enter_critical_one 是一个函数,所以必须要调用执行,不能优化掉;
3、而后必然会调用 su_startup_task。

所以最终编译后的结果就是,先调用 su_enter_critical_one,再调用 su_startup_task 并返回,其它全部优化掉。

至于为何要采用 三目运算 来实现,当然是为了 返回值 啊,服务要返回 结果 或 错误码 或 指针 等!


在 sv_task.h 中,会有大量的这种 任务服务的宏定义,都是相同的原理。


你再看一下 103楼,以前对该技术做过详细的介绍:
https://www.stcaimcu.com/forum.p ... 1807&extra=&page=11





CosyOS 发表于 2024-10-31 20:30:29

sdwys 发表于 2024-10-31 15:33
/* 启动任务 */
#define uStartTask(task, status) sUSV_StartTask(&u_taskhand_##task, (s_voidvoid_tfp) ...

再总结一下思路就是:

1、要先进入任务临界区,而后再调用服务函数。
这样做的目的是:服务函数可以是不可重入函数。
所以,要先调用 进入任务临界区函数,再调用服务函数。

2、由于服务函数要返回值,而且是后调用,所以必须采用 三目运算 才能实现。

3、在实现的同时,还希望能优化掉不必要的环节。

最终,经过我一段时间的研究、试验,才有了这个方法。

giveyou 发表于 2024-11-1 16:06:01

CosyOS是一款来自中国的开源实时操作系统

stc-xuewei 发表于 2024-11-1 17:04:18

你好,工程芯片用的是STC32G12K128,修改INT2代替INT0,在mcucfg_80251.h文件中修改如下:
// <o> 中断向量地址
// <i> 中断向量地址
#define MCUCFG_PENDSV_VECTORADDR      0053H

// <o> 中断开启
// <i> 此项您应在文本编辑界面中定义。
// <i> 示例:EX0 = 1
#define mPendSV_Enable                  EX2 = 1

// <o> 中断关闭
// <i> 此项您应在文本编辑界面中定义。
// <i> 示例:EX0 = 0
#define mPendSV_Disable               EX2 = 0

// <o> 中断触发(置中断标志位)
// <i> 此项您应在文本编辑界面中定义。
// <i> 示例:IE0 = 1
#define mPendSV_Set                     INT2IF = 1

// <o> 中断清零(清中断标志位)
// <i> 此项您应在文本编辑界面中定义,必须使用汇编代码。
// <i> 即使该标志位能够在中断服务程序中硬件自动清零,仍建议用户不要省略,以确保其可靠清零。
// <i> 示例:CLR IE0
#define mPendSV_Clear                                         CLR INT2IF

编译工程出现如下报警,不知什么原因?
Port\port_80251s.s(100): error A45: UNDEFINED SYMBOL

stc-xuewei 发表于 2024-11-1 17:21:32

找到了,需要在port_80251.s文件中修改,修改如下:

;///////////////////////////////////////////////////////////////////////////////
;
; 用户定义寄存器
;
; 1、mcucfg_80251.h -> PendSV中断配置 -> 中断清零,涉及的寄存器;
; 2、用户自定义任务切换现场保护,汇编语言保护方案,涉及的寄存器;
;
; 通常,直接包含标准头文件(h、inc)即可。
; 如果包含h文件导致编译报错,说明h文件中存在汇编器不能识别的C语言语法,
; 您可包含inc文件或重写新的h文件,也可在此处直接定义相关寄存器。
;
AUXINTIF    DATA    0EFH
INT2IF   BIT   AUXINTIF^4

CosyOS 发表于 2024-11-1 18:15:10

stc-xuewei 发表于 2024-11-1 17:21
找到了,需要在port_80251.s文件中修改,修改如下:

;///////////////////////////////////////////////// ...

恭喜你答对了,{:4_250:}

sdwys 发表于 2024-11-1 23:29:49

这是用腾讯AI分析出来的这段代码的功能,作者看看AI分析的正确吗?

// 这段代码定义了任务管理器(Task Manager)的定时器ID(TMID)
// 根据OS_TIMQRYTOTAL的值不同,OS_TMID_TASKMGR的值也会相应变化
// OS_TIMQRYTOTAL表示系统中定时器的总数,OS_TMID_TASKMGR则是任务管理器使用的定时器ID
// 通过这种方式,可以根据系统中定时器的数量动态地分配任务管理器使用的定时器ID

#define OS_TMID_TASKMGR    4
#elif OS_TIMQRYTOTAL == 6
#define OS_TMID_TASKMGR    5
#elif OS_TIMQRYTOTAL == 7
#define OS_TMID_TASKMGR    6
#elif OS_TIMQRYTOTAL == 8
#define OS_TMID_TASKMGR    7
......后面的代码省略掉了

CosyOS 发表于 2024-11-2 01:16:19

本帖最后由 CosyOS 于 2024-11-2 01:34 编辑

sdwys 发表于 2024-11-1 23:29
这是用腾讯AI分析出来的这段代码的功能,作者看看AI分析的正确吗?

// 这段代码定义了任务管理器(Task Ma ...
看来AI真的很智能,分析的结果 可以打 90分了(满分100的话)。

OS_TASKTOTAL // 所有任务总数
OS_TIMINTTOTAL // 所有定时中断总数
OS_TIMQRYTOTAL // 所有定时查询总数
SYSCFG_USERTASKTOTAL // 用户任务总数
SYSCFG_USERTIMINTTOTAL // 用户定时中断总数
SYSCFG_USERTIMQRYTOTAL // 用户定时查询总数

我给你讲一下原理:
CosyOS 至多有4个系统任务,分别是 Taskmgr、Debugger、Starter、Sysidle,
其中 Taskmgr 是 定时查询任务,Debugger 是定时中断任务;
1个定时查询钩子,debug_hook。

OS 在 SYSCFG_DEBUGGING == __ENABLED__ 的前提下,
共有 2个定时查询(Taskmgr、debug_hook),1个定时中断(Debugger)。

所以:
#if SYSCFG_DEBUGGING == 0
#define OS_TASKTOTAL      (SYSCFG_USERTASKTOTAL + 2) // 用户任务总数 + Starter、Sysidle
#define OS_TIMINTTOTAL   SYSCFG_USERTIMINTTOTAL
#define OS_TIMQRYTOTAL   SYSCFG_USERTIMQRYTOTAL
#else
#define OS_TASKTOTAL      (SYSCFG_USERTASKTOTAL + 4) // 用户任务总数 + Taskmgr、Debugger、Starter、Sysidle
#define OS_TIMINTTOTAL    (SYSCFG_USERTIMINTTOTAL + 1) // 用户定时中断总数 + Debugger
#define OS_TIMQRYTOTAL    (SYSCFG_USERTIMQRYTOTAL + 2) // 用户定时查询总数 + Taskmgr、debug_hook
#endif

CosyOS 规定,用户的 定时中断定时器 和 定时查询定时器,ID均是从0开始;
系统的 定时中断定时器 和 定时查询定时器,ID自动跟在用户的定时器ID后面。

所以:
1、
用户的定时中断定时器ID 是 0~SYSCFG_USERTIMINTTOTAL-1,
Debugger 的 定时中断定时器ID 是 SYSCFG_USERTIMINTTOTAL;
所以,#define OS_TMID_DEBUGGER   SYSCFG_USERTIMINTTOTAL

2、
用户的定时查询定时器ID 是 0~SYSCFG_USERTIMQRYTOTAL-1,
debug_hook 的 定时查询定时器ID 是 SYSCFG_USERTIMQRYTOTAL,
所以,#define OS_TMID_DEBUGHOOKSYSCFG_USERTIMQRYTOTAL

3、
Taskgmr 的 定时查询定时器ID 是 SYSCFG_USERTIMQRYTOTAL+1,也就是 OS_TIMQRYTOTAL-1。
但 Taskgmr 的 定时查询定时器ID 必须直接宏定义为常量,
而不能是 算术表达式(SYSCFG_USERTIMQRYTOTAL+1 或 OS_TIMQRYTOTAL-1),
原因是 在创建任务时,这个定时器ID 要做 字符串拼接(代码拼接),所以必须直接给出常量,
所以,才需要一大段条件编译来定义 OS_TMID_TASKMGR。






sdwys 发表于 2024-11-2 16:29:35

本帖最后由 sdwys 于 2024-11-2 16:45 编辑

这个结构体定义的东西大多数能模糊的知道做什么用,于是让AI来分析了下,作者看看AI分析的正确吗?
页: 85 86 87 88 89 90 91 92 93 94 [95] 96 97 98 99 100 101 102 103 104
查看完整版本: 全局不关总中断的 RTOS,CosyOS-III-V1.2.0, 送 擎天柱-AI8051U转89C52核心板