//----------------------------------------------------多任务处理 以rtos_开头
externunsigned char rtos_wait(unsigned char time); //返回实际优先级 ,当所有高优先级都被占用时返回 0FFH,任务将被忽略。time为延时时间
externrtos_init(unsigned int count); //依据时间片轮转时间后,确定设置定时器count
void task0()
{
P0=0x0FF;
rtos_wait(100);
P0=0x0;
}
void task1()
{
while(1)
{
P1=~P1; //按位取反
rtos_wait(100);
}
}
void task2()
{
while(1)
{
P2=0x0FF;
rtos_wait(200);
P2=0x0;
rtos_wait(200);
}
}
voidmain()
{
P0=0;//初始化端口
P1=0;
P2=0;
rtos_init(0xD8F0); //操作系统初始化,根据单片机晶振,设置定时参数,比如10ms
task0(); //第一个任务。没有循环,任务结束就销毁。相当于200*10即2000ms即2s,在延时过程中运行其它的任务。
task1(); //第二个任务 在循环中任务就一直存在。不要以为这是死循环,进入这里后会自动切换到其它任务,时间到后又回来继续执行后面的。
task2(); //第三个任务,类似第二个任务
while(1);//主任务
}
rtos_c.asm
;********************************************
;RTOS用定时器0的多任务处理程序
;项目增加方式使用。
;程序不影响其它数据,目前程序的前后段不能进行参数传递 。 最多可以同时运行8个任务,
;执行时使用定时器0,定时时间根据初始化时的参数确定,一般为10mS。
;当指定优先级被占用时自动向高优先级调整,在R7中返回实际优先级,当所有高优先级都被占用时返回 0FFH,任务将被忽略。
;占用24H个内存单元。
;如果程序不可再入,需要设定 RWZT 的标志位。调用前先检查相应位。
;如果定时数设置过大,会引起一直在中断中,不能执行外部程序。如果任务执行时间过长,会引起堆栈溢出。
;18.432MHz,单时钟周期模式。不用任务单取反,输出频率 1.3MHz ,指令周期 384 nS 。速度是带系统的 100 倍。
;8个任务,只对管脚取反,T0=FEF0H,输出 2.8K 频率,为最高频率。执行周期不受任务影响。18.432MHz,单时钟周期模式。
;1个任务,只对管脚取反,T0=FFE1H,输出 12K 频率,为最高频率。执行周期受任务影响。每次调度时间为42US。
;*********************************************
;-------------------------------------------------------------示例程序
;externRTOS(unsigned char priority,time,unsigned int *add);
;externRTOS_INI(unsigned int count);
;externRTOS();
;sbitP1_0=P1^0;
;voiddeng(void)
;{
;P1_0=!P1_0;
;JMP(0,100,deng);
;}
;void main()
;{
;JMP(0,100,deng);
;while(1)
;{
;RTOS();
;}
;}
;***********************************************
NAMERTOS_C
?PR?RTOS?RTOS_CSEGMENTCODE
?DT?RTOS?RTOS_CSEGMENT DATA
?ID?RTOS?RTOS_CSEGMENT IDATA
PUBLICRTOS
PUBLIC_RTOS_WAIT
PUBLIC_RTOS_INIT
;---------------------------------------------
;BANBHEQU0A3H;版本号 101221
;定义数据地址
;----------------------------------------------
RSEG?DT?RTOS?RTOS_C
;RWZTEQU29H;任务状态,0为停止,1为正在执行
TL:DS 1;EQU30H;RTOS定时器值,C=FFFFH-ft
TH:DS 1;EQU31H;18.432MHz(12周期)=C400H
RWB:DS 1;EQU33H;任务表
RSEG?ID?RTOS?RTOS_C
RWDZ:DS 16
;EQU80H;任务地址
;EQU8FH
RWS:DS 8
;EQU90H;任务定时数
;EQU97H
;*********************************************
CSEG AT 0BH ;TO入口
JMP RTOS
;*********************************************
RSEG?PR?RTOS?RTOS_C
_RTOS_INIT:;任务初始化1.定时器启动,2.RWB任务表置0
;-------------------------------------------- 在 R6 R7 中,设置定时值
;RTOS定时器值,C=FFFFH-ft,18.432MHz(12周期)=C400H,40MHz(12周期)=7DC9H
;定时器0定时程序,18.432MHz,10MS,方式1
ORL TMOD,#01H ;定时10MS
MOV TL0,R7
MOV TL,R7
MOV TH0,R6
MOV TH,R6
MOV RWB,#0
SETB TR0
SETB ET0
SETB EA
RET ;等待中断
;********************************************** 等待函数,优先级为最低 0 级,等待时间放入 R7 中
;目前函数不能传递参数
_RTOS_WAIT:MOVA,R7
MOVR5,A
MOVR7,#0
CALLYXJSZ ;优先级设置
CJNER7,#8,RWSZ ;任务设置
MOVR7,#0FFH
RET
;---------------------------------------------任务设置
RWSZ:MOVA,R7;送任务数
ADDA,#RWS
MOVR0,A
MOVA,R5
MOV@R0,A
MOVA,R7;送地址
RLA
ADDA,#RWDZ
MOVR0,A
POPACC;跳转地址,在堆栈中
POPB
MOV@R0,B;低地址在低字节
INCR0
MOV@R0,A
MOVB,R7;设置任务列表
CLRA; 当前正在执行的程序如果被中断,并且中断中使用了此任务位,则此次任务将会丢失。
INCB;可以关中断来解决此问题。
SETBC
RWSZ2:RLCA
DJNZB,RWSZ2
ORLRWB,A
RET
;--------------------------
YXJSZ:MOVB,R7
INCB
MOVA,RWB
CLRC
YXJ2:RRCA
DJNZB,YXJ2
YXJ4:JNCYXJ3
RRCA
INCR7
JMPYXJ4
YXJ3:RET
;------------------------------- 中断程序
RTOS:MOV TH0,TH
MOV TL0,TL
JBPSW.3,RTOS1
JBPSW.4,RTOS2
PUSH0
PUSH1
PUSH2
PUSH3
PUSH4
PUSH5
PUSH6
PUSH7
JMPRTOS0
RTOS1:JBPSW.4,RTOS3
PUSH8
PUSH9
PUSH10
PUSH11
PUSH12
PUSH13
PUSH14
PUSH15
JMPRTOS0
RTOS2:
PUSH10H
PUSH11H
PUSH12H
PUSH13H
PUSH14H
PUSH15H
PUSH16H
PUSH17H
JMPRTOS0
RTOS3:PUSH18H
PUSH19H
PUSH1AH
PUSH1BH
PUSH1CH
PUSH1DH
PUSH1EH
PUSH1FH
RTOS0:PUSHPSW
PUSHACC
PUSHB
PUSHDPL
PUSHDPH
CALLRWDD0
POPDPH
POPDPL
POPB
POPACC
POPPSW
JBPSW.3,RTOS01
JBPSW.4,RTOS02
POP7
POP6
POP5
POP4
POP3
POP2
POP1
POP0
RETI
RTOS01:JBPSW.4,RTOS3
POP15
POP14
POP13
POP12
POP11
POP10
POP9
POP8
RETI
RTOS02:
POP17H
POP16H
POP15H
POP14H
POP13H
POP12H
POP11H
POP10H
RETI
RTOS03:POP1FH
POP1EH
POP1DH
POP1CH
POP1BH
POP1AH
POP19H
POP18H
RETI
;-----------------------------中断任务调度
RWDD0:MOVB,#7;任务号
MOVR0,#RWS+7
MOVR1,#0FFH;执行任务号
MOVA,RWB
JNZRWDD3
RET
RWDD3:CLRC
RLCA
JNCRWDD6
CJNE@R0,#0,RWDD2
RWDD4:CJNER1,#0FFH,RWDD6
MOVR1,B
RWDD6:DECR0
DECB
JNZRWDD3
CJNER1,#0FFH,RWCL
RET
RWDD2:DEC@R0
CJNE@R0,#0,RWDD6
JMPRWDD4
;---------------------------------
RWDD:MOVR1,#7
MOVR0,#RWS+7
MOVA,RWB
JNZRWDD03
RET
RWDD03:CLRC
RLCA
JNCRWDD06
CJNE@R0,#0,RWDD06
JMPRWCL
RWDD06:DECR0
DECR1
JNZRWDD03
RET
;--------------------------------------
RWCL:MOVDPTR,#RWDD
PUSHDPL
PUSHDPH
MOVA,R1
RLA
ADDA,#RWDZ
MOVR0,A
MOVA,@R0
PUSHACC;低地址在低字节
INCR0
MOVACC,@R0
PUSHACC
MOVA,#0FFH;清除任务列表 当前正在执行的程序如果在下一个中断到来时还未执行完, 它的优先级将变为最低优先级,
INCR1;可以加入一个执行标志 RWZT 来解决此问题。
CLRC
RWCL22:RLCA
DJNZR1,RWCL22
ANLRWB,A
RETI
;***********************************
END
C语言版切换示例
#include #define MAX_TASKS 2 //任务槽个数.必须和实际任务数一至
#define MAX_TASK_DEP 12 //最大栈深.最低不得少于2 个,保守值为12.
unsigned char idata task_stack[MAX_TASKS][MAX_TASK_DEP];//任务堆栈.
unsigned char idata task_sp[MAX_TASKS];
unsigned char task_id; //当前活动任务号
//任务切换函数(任务调度器)
void task_switch(){
task_sp[task_id] = SP;
if(++task_id == MAX_TASKS)
task_id = 0;
SP = task_sp[task_id];
}
//任务装入函数.将指定的函数(参数1)装入指定(参数2)的任务槽中.如果该槽中原来就有任
//务,则原任务丢失,但系统本身不会发生错误.
void task_load(unsigned int fn, unsigned char tid){
task_sp[tid] = task_stack[tid] + 1;
task_stack[tid][0] = (unsigned int)fn & 0xff; //低字节
task_stack[tid][1] = (unsigned int)fn >> 8; //高字节
}
//从指定的任务开始运行任务调度.调用该宏后,将永不返回.
#define os_start(tid) {task_id = tid,SP = task_sp[tid];return;}
/*============================以下为测试代码==========================*/
void task1(){
static unsigned char i;
while(1){
i++;
task_switch();//编译后在这里打上断点
}
}
void task2(){
static unsigned char j;
while(1){
j+=2;
task_switch();//编译后在这里打上断点
}
}
void main(){
//这里装载了两个任务,因此在定义MAX_TASKS 时也必须定义为2
task_load(task1, 0);//将task1 函数装入0 号槽
task_load(task2, 1);//将task2 函数装入1 号槽
os_start(0);
}