返回> 网站首页
8051内核多任务切换 - 改进
yoours2023-02-02 19:18:07
简介一边听听音乐,一边写写文章。
一、介绍
上一篇多任务有个问题,如果存在局部变量则任务切换会导致变量数值混乱。
改进在原有基础上增加堆栈操作。
二、完整示例
#include <stdlib.h>
#include "ioCC1110.h"
// 任务个数.必须和实际任务数一至
#define MAX_TASKS 2
// 最大栈深.最低不得少于2个,压栈用到了15个,切换函数临时用了一个。该数值尽可能大一些
#define MAX_TASK_DEP 20
// 当前活动任务号
unsigned char task_id;
//任务的栈指针
unsigned char __idata task_sp[MAX_TASKS];
// 任务堆栈
unsigned char __idata task_stack[MAX_TASKS][MAX_TASK_DEP];
// 当前活动任务号
unsigned char task_id;
// 从指定的任务开始运行任务调度.调用该宏后,将永不返回.
#define os_start(tid) {task_id = tid,SP = task_sp[tid];}
// 任务函数指针
typedef void (*Fun)();
// 堆栈 采用后进先出方式
// 全部压栈
#define PUSH_ALL() \
asm("push psw");\
asm("push dpH");\
asm("push dpl");\
asm("push a");\
asm("push b");\
asm("mov a, r0");\
asm("push a");\
asm("mov a, r1");\
asm("push a");\
asm("mov a, r2");\
asm("push a");\
asm("mov a, r3");\
asm("push a");\
asm("mov a, r4");\
asm("push a");\
asm("mov a, r5");\
asm("push a");\
asm("mov a, r6");\
asm("push a");\
asm("mov a, r7");\
asm("push a");
// 全部出栈
#define POP_ALL()\
asm("pop a");\
asm("mov r7, a");\
asm("pop a");\
asm("mov r6, a");\
asm("pop a");\
asm("mov r5, a");\
asm("pop a");\
asm("mov r4, a");\
asm("pop a");\
asm("mov r3, a");\
asm("pop a");\
asm("mov r2, a");\
asm("pop a");\
asm("mov r1, a");\
asm("pop a");\
asm("mov r0, a");\
asm("pop b");\
asm("pop a");\
asm("pop dpl");\
asm("pop dpH");\
asm("pop psw");
// 任务切换函数(任务调度器)
// 进入调度函数时,本身会操作堆栈一次
// 在函数返回时会自动将sp中保存的pc程序指针读取到pc寄存器
void task_switch()
{
task_sp[task_id] = SP;
if(++task_id == MAX_TASKS)
task_id = 0;
SP = task_sp[task_id];
}
// 这里以及PUSH_ALL、POP_ALL,使用宏定义方式是为了避免函数调用的自然堆栈操作影响实际堆栈
#define Restore_task_switch()\
PUSH_ALL();\ // 先压栈保存现场数据
task_switch();\
POP_ALL(); // 恢复切换的任务现场数据
void task_load(Fun fn, unsigned char tid)
{
task_sp[tid] = (unsigned int)(task_stack[tid] + 1)&0xFF;
task_stack[tid][0] = (unsigned int)fn & 0xff;
task_stack[tid][1] = (unsigned int)fn >> 8;
}
void task1()
{
unsigned char i;
while(1)
{
i++;
Restore_task_switch();
}
}
void task2()
{
unsigned char j;
while(1)
{
j+=2;
Restore_task_switch();
}
}
void rtosInit()
{
// 这里装载了两个任务,因此在定义MAX_TASKS时也必须定义为2
task_load(task1, 0);// 将task1函数装入0号槽
task_load(task2, 1);// 将task2函数装入1号槽
os_start(0);
}