//在网上搜索51单片机多任务支持代码,都太复杂,要么就是伪系统; //本代码使用T1定时切换,在此基础上,如果再进行完善可以完成不同时间片轮转以及消息挂起等功能 //本代码编译通过,需要23个data单元,8051也轻松运行。 //用keil 编译测试通过,代码完整。感觉有用的请评价。 #include "reg51.h" #include "absacc.h" #define DEEP 6 //堆栈深度,自身压栈2字节地址,中断压栈2字节数据,ACC PSW,DEEP必须>=4 #define PROC 3 //自由任务数量,不包含主函数main() #define DS 15556 //定时常数,用于0.1秒定时 =65536-(OSC/12*0.1)-20 //use interrupt function build a real multi task system 用中断实现真正的多任务系统 //主要能够实现编程的可读性易读性,模块化 //in multi task system, 参数声明最好声明成全局变量,避免出现覆盖现象 //中断系统进行多任务需要设置堆栈当调用一个任务时需要保存相应的堆栈,可以设置私有堆栈深度为DEEP=6 //如果任务1的当前值是16,栈顶就是16+ DEEP,系统应该监控该数值 //任务2的栈栈底就是 16+ DEEP //版本1.0 2012-09-03 //liwg//@//weichai.com//wenguang.li//@//163.com// unsigned int a; unsigned char sta[PROC]=0; //设置堆栈指针寄存器 unsigned char activeproc=0; //活动进程指针 void init() //中断初始化函数 { unsigned char c; for(c=0;c
PROC )activeproc=0; //切换到下一个任务,轮转 EA=1; //开启中断 SP=sta[activeproc]; //转移堆栈指针到新任务 } void Timer1_Overflow() interrupt 3 using 0 //定时器1 溢出中断 用于切换进程 { TR1=0; TH1=DS/256; TL1=DS%256; TR1=1; //进程切换内容 EA=0; //关闭所有中断 while(sta[++activeproc]==0) //栈指针==0的进程不装入 { if (activeproc>PROC )activeproc=0; //切换到下一个任务,轮转 } if (activeproc>PROC )activeproc=0; EA=1; //开启中断 SP=sta[activeproc]; //转移堆栈指针到新任务 //切换完毕 } void loadtask(unsigned int funcname, unsigned char slot) { char lowadd,hiadd,tmpsp; lowadd=funcname%256 ; //任务入口地址低8位 hiadd=funcname/256; //任务入口地址高8 tmpsp=SP+DEEP*slot; //设置堆栈指针 DBYTE[tmpsp]=lowadd; //存入堆栈数据低八位地址 DBYTE[++tmpsp]=hiadd; //存入堆栈数据高八位地址 sta[slot]= tmpsp+2 ; //2是因为系统中断的时候要有保护ACC,PSW的堆栈操作,任务切换是用系统中断完成的,具体情况根据汇编代码确认。 if(sta[0]==0)sta[0]=SP+2; //main()是函数0 } //任务1 每个任务都必须是死循环 void task1 () { while(1){ P0++;//add your code here. } } //任务2 每个任务都必须是死循环 void task2 () { while(1){ P1++;//add your code here. } } //任务3 每个任务都必须是死循环 void task3() { while(1){ P2++;//add your code here. } } main() { init(); loadtask(task1,1); //载入任务1 //loadtask(task2,2); //载入任务2 loadtask(task3,3); //载入任务3 sysrun(); //打开中断开关,任务轮转启动 while(1) //主程序死循环任务0 { //add your code here. } }