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分析的正确吗?