去年玩过一阵单片机,也用过μc/osⅡ的系统,但是就理解内核而言,整个即时操作系统还是过于冗杂,很多的东西很不适合初学者来动手操作,多方查找我发现他的任务机制可以进行功能的进一步简化,
可以类似于任务栈的方式,使用纯C写成而不用汇编代码,闲话少说上代码吧。
我的github上有我的渣代码=_=:https://github.com/lfkdsk
灵魂画作任务图:
随手就是灵魂画作=-=
1.主函数:
1 #include "OS_task.h" 2 #include "89c51.h" 3 #include "main.h" 4 #include "task_switch.h" 5 #include <reg52.h> 6 sbit K1=P0^0; 7 void del10ms() 8 { 9 unsigned char a,b,c; 10 for (c=1;c>0;c--) 11 for(b=0;b<38;b++) 12 for(a=0;a<130;a++); 13 } 14 void task_1() 15 { 16 while(1) 17 { 18 if(K1==0) 19 del10ms(); 20 if(K1==0) 21 { 22 task_switch(); 23 } 24 } 25 } 26 27 void task_2() 28 { 29 while(1) 30 { 31 if(K1==0) 32 del10ms(); 33 if(K1==0) 34 { 35 task_switch(); 36 } 37 } 38 } 39 40 void task_3() 41 { 42 43 while(1) 44 { 45 if(K1==0) //这里是五个放在任务栈里的空函数,只用里一个循环来循环监听按键,可以再循环中加入自己的东西,比如亮起小灯啊,什么的易于观察的现象 46 del10ms(); 47 if(K1==0) 48 { 49 task_switch(); 50 } 51 } 52 } 53 54 void task_4() 55 { 56 while(1) 57 { 58 if(K1==0) 59 del10ms(); 60 if(K1==0) 61 { 62 task_switch(); 63 } 64 } 65 } 66 67 void task_5() 68 { 69 while(1) 70 { 71 if(K1==0) 72 del10ms(); 73 if(K1==0) 74 { 75 task_switch(); 76 } 77 } 78 } 79 void main(void) 80 { 81 // 载入函数 优先级 任务名 任务ID 82 task_load(2,task_1, 0); 83 task_load(3,task_2, 1); 84 task_load(4,task_3, 2); 85 task_load(5,task_4, 3); 86 task_load(6,task_4, 4); 87 OS_Start(0); 88 }
2.任务装载(核心):
1 #ifndef __OS_TASK_H__ 2 #define __OS_TASK_H__ 3 //任务功能 4 //最大任务数 5 #define MAX_TASK 5 6 //堆栈深度 7 #define SRACK_DEPTH 20 8 //保存切换任务时软件压栈字节数 9 #define Num_PUSH_bytes 13 10 //程序控制块结构 11 typedef struct 12 { 13 unsigned char Task_SP; //任务堆栈指针 14 unsigned char Priority; //优先级,值越小,优先级越高 15 16 }PCB; 17 18 extern idata volatile PCB OS_PCB[MAX_TASK];//定义堆栈 19 extern volatile unsigned char OS_TASK_ID;//定义任务ID 20 void task_load(unsigned char PRI,unsigned int FN,unsigned char T_ID); 21 void OS_Start(T_ID); 22 #endif
1 //系统任务程序 2 #include "OS_task.h" 3 #include "89c51.h" 4 #include "main.h" 5 #include "task_switch.h" 6 #include <reg52.h> 7 //程序控制块 8 idata volatile PCB OS_PBC[MAX_TASK]; //volatile是为了每次必须读值 这个是任务栈的最大任务数,任务栈名字叫PCB=-= 9 10 //当前运行任务的ID号 11 volatile unsigned char OS_TASK_ID; 12 13 //声明堆栈,由最大任务数和栈深定义的二维数组 14 unsigned char idata OS_Stack[MAX_TASK][SRACK_DEPTH]; 15 16 //任务装载函数 17 void task_load(unsigned char PRI,unsigned int FN,unsigned char T_ID) 18 { 19 OS_PCB[T_ID].Priority=PRI; //因为是简化的,所以我手动设置了优先级 20 OS_PCB[T_ID].Task_SP=OS_Stack[T_ID]+1; //这里取出了当前正在运行的任务的函数地址的高八位存为指针 21 OS_Stack[T_ID][0] = (unsigned int)FN & 0xff; //低八位存0 22 OS_Stack[T_ID][1] = (unsigned int)FN << 8; //高八位存在1里 23 } 24 25 //任务运行函数 26 void OS_Start(T_ID) 27 { 28 OS_TASK_ID=T_ID; 29 SP=OS_PCB[OS_TASK_ID].Task_SP; //传入一个id,然后把sp指针指向它,sp指针是系统的任务指针,用于指向执行任务的 30 //之后就不管了,就会按照自己的方式运行了 31 }
3.任务切换:
1 //任务交换程序 2 #include "OS_task.h" 3 #include "89c51.h" 4 #include "main.h" 5 #include "task_switch.h" 6 #include <reg52.h> 7 //任务调度函数 8 void task_switch(){ 9 static int i; 10 unsigned char j,MAX; 11 OS_PCB[OS_TASK_ID].Task_SP = SP; //先把运行的指针地址存到该任务id对应的指针空间中 12 for(i=0;i<MAX_TASK;i++) 13 { 14 MAX=j; //然后在循环找到优先级最高的(Priority最小的)
15 if(OS_PCB[j].Priority<OS_PCB[i].Priority||j!=OS_TASK_ID) //如果优先级高,则切换之
16 {
17 j=i;
18 }
19 }
20 OS_TASK_ID=j;
21 SP = OS_PCB[OS_TASK_ID].Task_SP;
22 }