找回密码
 立即注册
楼主: wuzhengmin

发现--【协程方式】实现【多任务调度 / 多线程】,好巧妙的方法!

[复制链接]
  • 打卡等级:常住居民III
  • 打卡总天数:143
  • 最近打卡:2026-03-08 08:36:28
已绑定手机

22

主题

2365

回帖

3529

积分

论坛元老

积分
3529
发表于 2025-12-27 20:53:44 | 显示全部楼层
在这段:
                task_start(0);//协程0开始
                P00 = ~P00;//每次执行取反P00端口电平
                task_delay(100);//设定延时100ms,是非阻塞的延时
                task_wait(!P32);//P32电平作为判断条件,为1则等待,为0则继续向下执行
                //因为按键按下为0,所以正常是一直闪烁,按下P32则LED00停止闪烁
                task_end(1);//为1则循环执行,为0就只执行1次

你调用的task_delay(100);//设定延时100ms,是非阻塞的延时
_this_task.time就会对应的传入task_num=0的延时时间100,

#define task_delay(delay_ms) user_task[_this_task].state=__LINE__;\
user_task[_this_task].time=delay_ms;case __LINE__:if(user_task[_this_task].time!=0)break;
//延时后继续向下,内部填入延时ms时间,等待时间后继续向下

这样时间就一一对应,不会搞错

这样每个任务都可以有独立的非阻塞延时时间
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:143
  • 最近打卡:2026-03-08 08:36:28
已绑定手机

22

主题

2365

回帖

3529

积分

论坛元老

积分
3529
发表于 2025-12-27 21:03:11 | 显示全部楼层
#define task_start(task_num) _this_task=task_num;if(task_num<Task_Max_Num)switch(user_task[_this_task].state){case 0:
//初始化线程,调用前必备

第二个task_num<Task_Max_Num是保险措施,当前的任务数量不能超过最大任务数量

因为这里:

extern _task user_task[Task_Max_Num];//每个协程的运行记忆变量

是有上限的!

后面是switch(user_task[_this_task].state)

每次进来会传入我们当前的state

//每个任务的数据结构
typedef struct
{
        unsigned int time;
        unsigned long state;
} _task;

并且总是从case 0: 开始

state是无符号长整型



回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:143
  • 最近打卡:2026-03-08 08:36:28
已绑定手机

22

主题

2365

回帖

3529

积分

论坛元老

积分
3529
发表于 2025-12-27 21:08:09 | 显示全部楼层
state是无符号长整型,因为:

#define task_wait(ifx) user_task[_this_task].state=__LINE__;case __LINE__:if(ifx)break;
//是否继续向下,内部填入表达式,为1则等待,为0则不等待

state=__LINE__;实际是使用了行标

下图的task_delay(200);//设定延时200ms,是非阻塞的延时
的行标就是41,state=__LINE__就不能太小,32位的

unsigned long state;就OK



截图202512272107149916.jpg
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:143
  • 最近打卡:2026-03-08 08:36:28
已绑定手机

22

主题

2365

回帖

3529

积分

论坛元老

积分
3529
发表于 2025-12-27 21:19:30 | 显示全部楼层
下面看task_wait

#define task_wait(ifx) user_task[_this_task].state=__LINE__;case __LINE__:if(ifx)break;
//是否继续向下,内部填入表达式,为1则等待,为0则不等待

首先把当前任务的state设置为当前的行:_this_task].state=__LINE__;

下次执行的行就是case __LINE__:  (保护现场)

接着跳转到#define task_start(task_num) _this_task=task_num;if(task_num<Task_Max_Num)switch(user_task[_this_task].state){case 0:
//初始化线程,调用前必备

中的switch(user_task[_this_task].state){case 0:  case 行来

if(ifx)break中的函数ifx为1就等待,为0则不等待继续往下执行








       
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:143
  • 最近打卡:2026-03-08 08:36:28
已绑定手机

22

主题

2365

回帖

3529

积分

论坛元老

积分
3529
发表于 2025-12-27 21:37:52 | 显示全部楼层
接下来看定时器软延时(非阻塞延时)

#define task_delay(delay_ms) user_task[_this_task].state=__LINE__;\
user_task[_this_task].time=delay_ms;case __LINE__:if(user_task[_this_task].time!=0)break;
//延时后继续向下,内部填入延时ms时间,等待时间后继续向下

首先把当前行给我们的状态变量:
user_task[_this_task].state=__LINE__;

这样下次进switch(user_task[_this的时候,知道是哪行(就是保护现场)

就是说user_task[_this_task].state=__LINE__;\
user_task[_this_task].time=delay_ms;部分只执行一次,

第二次就执行case __LINE__:if(user_task[_this_task].time!=0)break;

就是把本任务的延时时间传入user_task[_this_task].time

unsigned int time;  tme的最大是65536

它会判断定时器的time是否=0

user_task[_this_task].time!=0)

因为每1ms要执行一次下面的函数:

//函数说明:用于设定软定时器的时间基准,需要每隔1ms(推荐时间)调用一次
void set_task_mode(void)
{
        char task_num;//临时变量
        for(task_num = 0; task_num < Task_Max_Num; task_num++)//遍历所有的软定时器
                if(user_task[task_num].time > 0)user_task[task_num].time--;//需要自减的减1
}

time!=0)break;就执行下面的switch,所以不阻塞,是软延时

各种进程之间可以切换,不用死等,有点像操作系统...........









回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:143
  • 最近打卡:2026-03-08 08:36:28
已绑定手机

22

主题

2365

回帖

3529

积分

论坛元老

积分
3529
发表于 2025-12-27 21:51:47 | 显示全部楼层
for 循环:

#define task_for(init, cnt) init;user_task[_this_task].state = __LINE__;\
case __LINE__: for(_task_for_cnt = 1;_task_for_cnt--;cnt,user_task[_this_task].state = __LINE__)
//传入两个表达式,init是初始化(仅调用一次),cnt是自增自减表达式(每次运行都调用一次(task_for_end返回来也算))

init,是初始化
init;user_task[_this_task].state = __LINE__;\仅执行一次

case __LINE__: 这里是当前行,意思是以后每次进来都从这里开始

接下来:

for(_task_for_cnt = 1;_task_for_cnt--;cnt,user_task[_this_task].state = __LINE__)

extern char _task_for_cnt;//使用task_for时所需的临时变量

看:cnt,user_task[_this_task].state = __LINE__)
,逗号的意思是当前的语句没有完成,(for本身是靠;来分别)把当前的state 变成当前的行

保证下次继续进入case __LINE__:

看下图:






截图202512272151451477.jpg
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:143
  • 最近打卡:2026-03-08 08:36:28
已绑定手机

22

主题

2365

回帖

3529

积分

论坛元老

积分
3529
发表于 2025-12-27 21:58:38 | 显示全部楼层
实际就是先把48行的行号保存好

等到57行完成后才能回到48行

其实是利用了for语句本身的特性

当然还要有
#define task_break(ifx) if(ifx)break;
//对ifx的条件进行判断,为1则回到task_for/task_while的开始,为0则往下继续执行
来配对跳转,2者联合使用

ifx=1 回到task_for/task_while的开始,为0则往下继续执行

其实#define task_break(ifx) if(ifx)break;就是for的判断语句!




回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:143
  • 最近打卡:2026-03-08 08:36:28
已绑定手机

22

主题

2365

回帖

3529

积分

论坛元老

积分
3529
发表于 2025-12-27 22:08:09 | 显示全部楼层
上面的方法就实现了内部嵌套

再看看 task_while

#define task_while(ifx) user_task[_this_task].state = __LINE__;\
case __LINE__: for(_task_for_cnt = 1;(_task_for_cnt--)&&(ifx);user_task[_this_task].state = __LINE__)
//while(1)循环,判断条件通过task_break进行判断跳出

实际是task_for(init, cnt)的一个变种

(ifx)是个函数宏定义

task_while(ifx)就是task_for(init, cnt)的没有参数的版本

task_while(1)就一直死循环

也必须和task_break配对使用:

#define task_break(ifx) if(ifx)break;
//对ifx的条件进行判断,为1则回到task_for/task_while的开始,为0则往下继续执行

task_break(ifx)是task_while(ifx)的跳出条件

对ifx的条件进行判断,为1则回到task_for/task_while的开始,为0则往下继续执行
       








回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:143
  • 最近打卡:2026-03-08 08:36:28
已绑定手机

22

主题

2365

回帖

3529

积分

论坛元老

积分
3529
发表于 2025-12-27 22:10:22 | 显示全部楼层
最后是define task_end(reload) if(reload)user_task[_this_task].state=0;else user_task[_this_task].state = __LINE__;break;}
//线程结束,内部填入是否重新开始线程,1为重新开始,0为结束等待

task_end(reload)是判断是否要循环,1为重新开始,0为结束等待
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:587
  • 最近打卡:2026-03-14 06:54:36

42

主题

212

回帖

976

积分

高级会员

积分
976
发表于 2026-1-22 11:25:32 | 显示全部楼层
看了,行号利用是亮点,就是定时器设置太过复杂了。
回复

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2026-3-14 22:43 , Processed in 0.114218 second(s), 83 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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