系统设计核心意图:使用定时器,在延时过程中运行其它的任务。
工程源码:链接: https://pan.baidu.com/s/1LEV9qYmUn6SdemGz7TH6dw 提取码: iua5
切换任务并记录位置,保证在时间到后能切换回来。(在任务中切换出去,在定时器中切换回来。)(时间片轮转)
可以支持同时8个任务。
工程就两个文件:汇编操作系统rtos_c.asm 及 C语言示例 Test.c
Test.c
/*
开发工具:keil c51 V9.0 及注册机
芯片:标准C8051
晶振:12M
源码任务数:加主任务共4个
2019-05-07
*/
//------------------------------------------- 包含文件
#include //#include //#include //----------------------------------------------------多任务处理 以rtos_开头 extern unsigned char rtos_wait(unsigned char time); //返回实际优先级 ,当所有高优先级都被占用时返回 0FFH,任务将被忽略。time为延时时间 extern rtos_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); } } void main() { 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。 ;********************************************* ;------------------------------------------------------------- 示例程序 ;extern RTOS(unsigned char priority,time,unsigned int *add); ;extern RTOS_INI(unsigned int count); ;extern RTOS(); ;sbit P1_0=P1^0; ;void deng(void) ;{ ; P1_0=!P1_0; ; JMP(0,100,deng); ;} ;void main() ;{ ; JMP(0,100,deng); ; while(1) ; { ; RTOS(); ; } ;} ;*********************************************** NAME RTOS_C ?PR?RTOS?RTOS_C SEGMENT CODE ?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: DS 1 ;EQU 30H ;RTOS定时器值,C=FFFFH-ft TH: DS 1 ;EQU 31H ;18.432MHz(12周期)=C400H RWB: DS 1 ;EQU 33H ;任务表 RSEG ?ID?RTOS?RTOS_C RWDZ: DS 16 ; EQU 80H ;任务地址 ; EQU 8FH RWS: DS 8 ; EQU 90H ;任务定时数 ; EQU 97H ;********************************************* 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: MOV A,R7 MOV R5,A MOV R7,#0 CALL YXJSZ ;优先级设置 CJNE R7,#8,RWSZ ;任务设置 MOV R7,#0FFH RET ;---------------------------------------------任务设置 RWSZ: MOV A,R7 ;送任务数 ADD A,#RWS MOV R0,A MOV A,R5 MOV @R0,A MOV A,R7 ;送地址 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 INC B MOV A,RWB CLR C YXJ2: RRC A DJNZ B,YXJ2 YXJ4: JNC YXJ3 RRC A INC R7 JMP YXJ4 YXJ3: RET ;------------------------------- 中断程序 RTOS: MOV TH0,TH MOV TL0,TL JB PSW.3,RTOS1 JB PSW.4,RTOS2 PUSH 0 PUSH 1 PUSH 2 PUSH 3 PUSH 4 PUSH 5 PUSH 6 PUSH 7 JMP RTOS0 RTOS1: JB PSW.4,RTOS3 PUSH 8 PUSH 9 PUSH 10 PUSH 11 PUSH 12 PUSH 13 PUSH 14 PUSH 15 JMP RTOS0 RTOS2: PUSH 10H PUSH 11H PUSH 12H PUSH 13H PUSH 14H PUSH 15H PUSH 16H PUSH 17H JMP RTOS0 RTOS3: PUSH 18H 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 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); }
上一篇:51单片机实验17:LCD1602液晶
下一篇:多任务 多进程 51单片机C语言 完整版
推荐阅读最新更新时间:2024-11-06 12:19
设计资源 培训 开发板 精华推荐
- ADK-3717,基于 HI-3717A ARINC 717 协议 IC 的评估板
- AD637-EVALZ,用于 AD637 RMS 至 DC 转换器的评估板
- 使用 NXP Semiconductors 的 MAX3232CP 的参考设计
- MC78M05 可调输出稳压器的典型应用 @ 7 至 30V
- STEVAL-ILL078V1,基于 LED6000 的评估板,1A,高达 60V Vin 降压 LED 驱动器
- NCP114MXTCGEVB:CMOS 低压差稳压器,300 mA,3.3V,有源放电评估板
- 霍尔传感器模块-OH34N
- L78L15AB正压稳压器高输出电流短路保护的典型应用
- OM13097: 面向LPC84x MCU系列的LPCXpresso845-MAX板
- 使用 Analog Devices 的 LT1578IS8-2.5 的参考设计