1. 初始化
2. 执行完后,记录下一步地址,返回
3. 接着task_test2()
4. 执行完后,记录下一步地址,返回(与第2步相似)
5. 接着主程序While(1);
6. 定时是10Ms(18.432MHz) .定时时间到就进入定时中断执行
7. 定时中断里,把各定时到减1. 如果为0,就进入该任务处理
在这里有两个任务,定时时间是10*10ms和100*10ms
While(1); 执行10ms过后,定时时间是9*10ms和99*10ms,中断返回主程序。
While(1); 执行20ms过后,定时时间是8*10ms和98*10ms,中断返回主程序。
………………
8. While(1); 执行100ms过后,定时时间是0*10ms和90*10ms, 0*10ms这个任务时间到,进入该任务处理
9. 继续该任务处理,执行到rtos_wait后,又返回。此时返回到中断,因为是从中断里进入的。
10. 返回到中断后,程序把中断剩下内容执行完,再回到主程序。又回到wkile(1); (回到第5步)
附:测试程序如下
extern void rtos_init(unsigned int i);
extern void rtos_wait(unsigned char c);
#include <reg51.h>
unsigned char a=0;
unsigned char b=0;
void task_test()
{
while(1)
{
a++;
rtos_wait(100); //执行完后,记录下一步地址,返回
a++;
}
}
void task_test2()
{
while(1)
{
b++;
rtos_wait(10); //执行完后,记录下一步地址,返回
b++;
}
}
void main()
{
rtos_init(0xc400);
task_test();
task_test2();
while(1);
}
;********************************************
;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。
;*********************************************
;------------------------------------------------------------- 示例程序
;***********************************************
NAME RTOS_C ;程序段名
?PR?RTOS?RTOS_C SEGMENT CODE ;代码段 ; 段名 SEGMENT 段类型
?DT?RTOS?RTOS_C SEGMENT DATA
?ID?RTOS?RTOS_C SEGMENT IDATA
PUBLIC RTOS
PUBLIC _RTOS_WAIT
PUBLIC _RTOS_INIT
;---------------------------------------------
;BANBH EQU 0A3H ;版本号 101221
;定义数据地址
;----------------------------------------------
RSEG ?DT?RTOS?RTOS_C
;RWZT EQU 29H ;任务状态,0为停止,1为正在执行
TL: DS1 ;EQU 30H ;RTOS定时器值,C=FFFFH-ft
TH: DS1 ;EQU 31H ;18.432MHz(12周期)=C400H
RWB: DS1 ;EQU 33H ;任务表
RSEG ?ID?RTOS?RTOS_C
RWDZ: DS16 ;任务堆栈
; EQU 80H ;任务地址
; EQU 8FH
RWS: DS8 ;任务数
; EQU 90H ;任务定时数
; EQU 97H
;*********************************************
CSEG AT 0BH ;TO入口
JMP RTOS
;*********************************************
RSEG ?PR?RTOS?RTOS_C
_RTOS_INIT: ;任务初始化
;--------------------------------------------在 R6 R7 中,设置定时值
;RTOS定时器值,C=FFFFH-ft,18.432MHz(12周期)=C400H,40MHz(12周期)=7DC9H
;定时器0定时程序,18.432MHz,10MS,方式1
ORL TMOD,#01H ;定时10MS ;定时器0初始化,设置TMOD MOV TL0,R7
MOV TL,R7 ;设置TL
MOV TH0,R6
MOV TH,R6 ;设置TH
MOV RWB,#0 ;任务表清0
SETB TR0 ;启动定时器
SETB ET0 ;打开中断
SETB EA ;打开总中断
RET ;等待中断
;**********************************************等待函数,优先级为最低 0 级,等待时间放入 R7 中
; 目前函数不能传递参数
_RTOS_WAIT: MOV A,R7 ;接收参数
MOV R5,A ;接收的数存在R5
MOV R7,#0 ;R7清零
CALL YXJSZ ;优先级设置
CJNE R7,#8,RWSZ ;R7如果不等于8,则任务设置
MOV R7,#0FFH ;返回值0xff 当指定优先级被占用时自动向高优先级调整,在R7中返回实际优先级,当所有高优先级都被占用时返回 0FFH,任务将被忽略。
RET ;返回
;---------------------------------------------
RWSZ: MOV A,R7 ;送任务数
ADD A,#RWS ;
MOV R0,A ;任务数保存到R0
MOV A,R5 ;R5上是 定时时间
MOV @R0,A ;保存定时时间数到【R7+RWS】位置
MOV A,R7 ;送任务数 把当前任务函数地址放入RWDZ中
RL A ;
ADD A,#RWDZ
MOV R0,A
POP ACC ;跳转地址,在堆栈中
POP B
MOV @R0,B ;低地址在低字节
INC R0
MOV @R0,A
MOV B,R7 ;设置任务列表
CLR A ;当前正在执行的程序如果被中断,并且中断中使用了此任务位,则此次任务将会丢失。
INC B ;可以关中断来解决此问题。
SETB C
RWSZ2: RLC A
DJNZ B,RWSZ2
ORL RWB,A
RET
;--------------------------
YXJSZ: MOV B,R7 ;0 ;优先级设置
INC B ;B++1
MOV A,RWB ;0
CLR C ;0
YXJ2: RRC A ;RRC是带进位的循环右移指令
DJNZ B,YXJ2 ;如果B不等于0, b=0
YXJ4: JNC YXJ3 ;C=0,则
RRC A ;
INC R7 ;
JMP YXJ4 ;
YXJ3: RET ;返回
;------------------------------- 中断程序 把所有相关寄存器内容压入堆栈 任务调度完后 再弹出来
RTOS: MOV TH0,TH ;重载定时数
MOV TL0,TL ;
JB PSW.3,RTOS1 ;RS0==1用于选择当前工作寄存器区。8051有8个8位寄存器R0~R7
JB PSW.4,RTOS2 ;RS1==1
PUSH 0 ;RS0=0,RS1=0; 第一组寄存器区
PUSH 1
PUSH 2
PUSH 3
PUSH 4
PUSH 5
PUSH 6
PUSH 7 ;存入椎栈第一组寄存器上的内容
JMP RTOS0 ;都跳到RTOS0
RTOS1: JB PSW.4,RTOS3 ;
PUSH 8 ;RS0=1,RS1=0; 第三组寄存器区
PUSH 9
PUSH 10
PUSH 11
PUSH 12
PUSH 13
PUSH 14
PUSH 15
JMP RTOS0 ;
RTOS2:
PUSH 10H ;RS0=0,RS1=1; 第二组寄存器区
PUSH 11H
PUSH 12H
PUSH 13H
PUSH 14H
PUSH 15H
PUSH 16H
PUSH 17H
JMP RTOS0
RTOS3: PUSH 18H ;RS0=1,RS1=1; 第四组寄存器区
PUSH 19H
PUSH 1AH
PUSH 1BH
PUSH 1CH
PUSH 1DH
PUSH 1EH
PUSH 1FH
RTOS0: PUSH PSW ;入栈
PUSH ACC ;
PUSH B
PUSH DPL
PUSH DPH
CALL RWDD0 ;任务调度
POP DPH ;出栈
POP DPL
POP B
POP ACC
POP PSW
JB PSW.3,RTOS01
JB PSW.4,RTOS02
POP 7
POP 6
POP 5
POP 4
POP 3
POP 2
POP 1
POP 0 ;弹出第一组寄存器区上的变量
RETI ;中断返回
RTOS01: JB PSW.4,RTOS3
POP 15
POP 14
POP 13
POP 12
POP 11
POP 10
POP 9
POP 8
RETI
RTOS02:
POP 17H
POP 16H
POP 15H
POP 14H
POP 13H
POP 12H
POP 11H
POP 10H
RETI
RTOS03: POP 1FH
POP 1EH
POP 1DH
POP 1CH
POP 1BH
POP 1AH
POP 19H
POP 18H
RETI
;----------------------------- 中断任务调度
RWDD0: MOV B,#7 ;任务号
MOV R0,#RWS+7 ;
MOV R1,#0FFH ;执行任务号
MOV A,RWB
JNZ RWDD3
RET
RWDD3: CLR C
RLC A
JNC RWDD6
CJNE @R0,#0,RWDD2
RWDD4: CJNE R1,#0FFH,RWDD6
MOV R1,B
RWDD6: DEC R0
DEC B
JNZ RWDD3
CJNE R1,#0FFH,RWCL
RET
RWDD2: DEC @R0
CJNE @R0,#0,RWDD6
JMP RWDD4
;---------------------------------
RWDD: MOV R1,#7
MOV R0,#RWS+7
MOV A,RWB
JNZ RWDD03
RET
RWDD03: CLR C
RLC A
JNC RWDD06
CJNE @R0,#0,RWDD06
JMP RWCL
RWDD06: DEC R0
DEC R1
JNZ RWDD03
RET
;--------------------------------------
RWCL: MOV DPTR,#RWDD ;任务处理?
PUSH DPL
PUSH DPH
MOV A,R1
RL A
ADD A,#RWDZ
MOV R0,A
MOV A,@R0
PUSH ACC ;低地址在低字节
INC R0
MOV ACC,@R0
PUSH ACC
MOV A,#0FFH ;清除任务列表 当前正在执行的程序如果在下一个中断到来时还未执行完, 它的优先级将变为最低优先级,
INC R1 ;可以加入一个执行标志RWZT 来解决此问题。
CLR C
RWCL22: RLC A
DJNZ R1,RWCL22
ANL RWB,A
RETI
;***********************************
END