一种裸奔多任务嵌入式操作系统模型.docx
- 文档编号:16919258
- 上传时间:2023-04-24
- 格式:DOCX
- 页数:20
- 大小:20.68KB
一种裸奔多任务嵌入式操作系统模型.docx
《一种裸奔多任务嵌入式操作系统模型.docx》由会员分享,可在线阅读,更多相关《一种裸奔多任务嵌入式操作系统模型.docx(20页珍藏版)》请在冰豆网上搜索。
一种裸奔多任务嵌入式操作系统模型
一种裸奔多任务模型
一个网友的总结:
stateMachine + timerTick + queue。
在RTOS环境下的多任务模型:
任务通常阻塞在一个OS调用上(比如从消息队列取数据)。
外部如果想让该任务运转,就要向消息队列发送消息。
任务收到消息时,根据当前状态,决定如何处理消息。
这就是状态机。
任务将消息队列中的消息处理完毕后,重新进入阻塞状态。
任务在处理中,有时要延时一段时间,然后才继续工作:
为了充分使用CPU,可以通过OS调用让其它任务去工作。
OS通常会提供一个taskDelay调用。
当任务调用taskDelay时,即进入阻塞状态,直到超时,才重新进入可工作状态(就绪状态)。
下面说说裸奔环境下的多任务模型:
裸奔也可以多任务,但调度是由用户自主控制。
在RTOS环境下,一般提供抢占式调度。
在裸奔时,一般是任务在处理告一段落后,主动结束处理。
RTOS环境下的任务,一般处于一个while
(1)循环中。
while
(1){
从消息队列接收消息。
如果没有,将阻塞。
处理消息。
}
裸奔下的任务,一般采用查询方式:
{
查询是否有待处理的事件。
如果没有,返回。
如果有,根据任务的当前状态,进行处理。
处理完毕后,可能返回,也可能将待处理事件全部处理完毕后再返回。
}
裸奔任务其实也处于一个while
(1)循环中,只不过这个循环在任务外部。
main()
{
A_taskInit(); //任务的初始化
B_taskInit();
...
while
(1){
A_taskProc(); //任务的处理
B_taskProc();
}
}
状态机既适用于OS环境,也适用于裸奔环境。
但在裸奔环境下,状态可能被切分得更细。
例如后面讲的如何在裸奔环境实现taskDelay()。
消息队列既适用于OS环境,也适用于裸奔环境。
在OS环境下,消息队列机制由OS提供。
在裸奔环境下,消息队列要自己来实现。
如果对队列的概念不清楚,可参考《数据结构》教材。
这个队列机制,可做成通用模块,在不同的程序中复用。
消息队列用于缓冲事件。
事件不知道什么时候会到来,也不能保证来了就能迅速得到处理。
使用消息队列,可以保证每个事件都被处理到,以及处理顺序。
一般在两种情况下会用到消息队列:
存储外部事件:
外部事件由中断收集,然后存储到队列。
串口接收程序中的接收循环缓冲区,可理解为消息队列。
任务间通讯:
一个任务给其它任务发送消息。
timerTick,就是系统中的时钟基准。
OS中总是有一个这样的基准。
在裸奔时,我们要用一个定时器(或RTC或watchdog)来建立这个时间基准。
一个tick间隔可以设置为10ms(典型RTOS的缺省设置)。
让定时器10ms中断一次,中断发生时给tickNum++。
以前,我在定时器中断中设置1S标志、200ms标志等等。
时间相关的任务根据这些标志判断是否要执行。
近来,一般让任务直接去察看tickNum。
两次相减来判断定时是否到达。
也可以在系统中建立一个通用定时器任务,管理与不同任务相关的多个定时器;在定时到达时,由定时器任务去调用相应的callback。
系统时钟基准是所谓“零耗时裸奔”的基础。
timerTick的分辨率,决定了只适于于较大的时间延时。
在做时序时的小延时,用传统方法好了。
OS中的taskDelay()在裸奔环境下的一种实现:
OS环境:
void xxxTask(void)
{
while
(1){
//waitEvent
//do step_1
taskDelay(TIME_OUT_TICK_NUM);
//do step_2
}
}
裸奔环境:
void xxxTask(void)
{
static unsigned int taskStat = STAT_GENERAL; //任务状态变量
static timer_t startTick;
timer_t currTick;
if (taskStat == STAT_GENERAL)
{
//check event
//if no event
return;
//do step_1
startTick = sysGetTick(); //sysGetTick()就是察看系统时间
taskStat = STAT_WAIT;
return;
}
else if (taskStat == STAT_WAIT)
{
currTick = sysGetTick(); //sysGetTick()就是察看系统时间
if ((currTick - startTick) >= TIME_OUT_TICK_NUM)
{
//do step_2
taskStat = STAT_GENERAL;
return;
}
else
return;
}
}
老生常谈---一种裸奔多任务模型ourdev_629752P0O6JH.txt(文件大小:
4K) (原文件名:
老生常谈---一种裸奔多任务模型.txt)
C51多任务编程思想ourdev_629753EWA0LM.pdf(文件大小:
143K) (原文件名:
C51多任务编程思想.pdf)
基于51单片机的C语言多任务操作 完美版ourdev_629754PETS4B.rar(文件大小:
3K) (原文件名:
基于51单片机的C语言多任务操作 完美版.rar)
Easy51RTOS的原理
//Easy51RTOS操作系统头文件
#include "os_cfg.h"
#include "functns.h" //常用一些功能函数
unsigned char TempBuffer[6]; //显示温度字符串
unsigned char str2[12]={' ',' ',' ',0,0,0,0,0,0,0xdf,0x43,0};
//任务0:
测温度送显
void task0(void)
{
temp=ReadTemperature();
IntToStr(temp,TempBuffer);
str2[3]=TempBuffer[0];
str2[4]=TempBuffer[1];
str2[5]=TempBuffer[2];
str2[6]=TempBuffer[3];
str2[7]=TempBuffer[4];
str2[8]=TempBuffer[5];
GotoXY(0,1);
Print(str2);
delay_nms(300);
}
//任务1:
键盘扫描,LCD显示
void task1(void)
{
if(CHANGE==0) //判断change温度键是否按下
{
set_temp=key_set(); //设定需要更改的温度值
if(set_temp { fengshan(); //设定的温度<实际温度,则打开电机风扇 } else if(set_temp>temp) { dianlu(); //若大于,则打开电炉(这里用LED模拟一下) } } } //任务2 void task2() { } //任务3 void task3() { } //任务4 void task4(void) { } //任务5 void task5(void) { } //任务6 void task6() { } //任务7 void task7() { } //main主函数 void main(void) { OS_InitTimer0(); EA=1; LCD_Init(); LCD_w_data(1,1,Temp_Str); LCD_w_data(2,1,Key_Str); while (1) { if (OS_Delay[0]==0){task0();OS_Delay[0]=100;} //温度测量,每秒1次 if (OS_Delay[1]==0){task1();OS_Delay[1]=10;} //键盘扫描,键值存储 if (OS_Delay[2]==0){task2();OS_Delay[2]=100;} //读出存储的键值,LCD显示 if (OS_Delay[3]==0){task3();OS_Delay[3]=50;} if (OS_Delay[4]==0){task4();OS_Delay[4]=100;} if (OS_Delay[5]==0){task5();OS_Delay[5]=60;} if (OS_Delay[6]==0){task6();OS_Delay[6]=70;} if (OS_Delay[7]==0){task7();OS_Delay[7]=80;} Delay(50); //Taskturn; } } //定时中断服务 void OS_Timer0(void) interrupt 1 using 2 { uchar i; //CRY_OSC,TIME_PER_SEC在easycfg.h中配置 TH0 = 255-CRY_OSC/TIME_PER_SEC/12/256; TL0 = 255-CRY_OSC/TIME_PER_SEC/12%256; //每节拍对任务延时变量减1 ,减至 0 后,任务就绪。 for(i=0;i { if(OS_Delay[i]! =0) OS_Delay[i]--; } //Runing(On); } //和传统的前后感觉基本上是一样的… //唯一的优点呢,是感觉OS_Delay[n]数组起到了分配各 Easy51RTOS的原理ourdev_629755MEIQGP.txt(文件大小: 3K) (原文件名: Easy51RTOS的原理.txt) 基于51单片机的C语言多任务操作 完美版 /* 1.本程序不使用任何汇编指令 2.由定时器T0产生中断,切换进程 3.由于中断或调用子程序,要把PC堆栈,故可以以SP为基址的地方找到PC 4.中断或子程序返回,要把SP出栈给PC,故可以操作SP改变程序入口 5.本程序经调试运行 电路图已上传 6.程序编译是会有一个警告提示,为正常现象,因为保存R0-R7时,重新定义地址, 出现地址覆盖的警告提示。 7.用户以此模板写程序只需写用户的进程子程序和用户初始化子程序,并把各进程参数 放在规定地方,各程序放在规定地方就可以;所有的任务调度已处理好。 */ //头文件 #include //#include //#include //宏定义 #defineuchar unsigned char #define uint unsigned int #define TN 65436 //进程1,2,3执行时间之比为 T1: T2: T3 (时间单位us) #define TN1 55536 //1个进程循环周期内进程1执行的时间T1us TN1=(65536-T1) #define TN2 55536 //1个进程循环周期内进程2执行的时间T2us TN2=(65536-T1) #define TN3 55536 //1个进程循环周期内进程3执行的时间T3us TN3=(65536-T1) // #define N1 4 // 进程1的延时参数 #define N2 4 // 进程2的延时参数 #define N3 4 // 进程3的延时参数 idata uchar temp[8] _at_ 0x00; //R0--R7 uchar tempbf1[8]; //用于保存R0--R7 进程1 uchar tempbf2[8]; //用于保存R0--R7 进程2 uchar tempbf3[8]; //用于保存R0--R7 进程3 //定义全局变量 uint address1,address2,address3; uchar test1_1=0,test2_1=0,test3_1=0,PID=1; //各进程的标志位,是否为第一次执行,0第一次,非0非第一次;PID进程号; uint ac1,ac2,ac3; //, PC_Next; 各进程的初始地址寄存器. //test1 的参数 由于进程切换时 没有保存普通变量, //所以各进程的普通参数需要定义成全局变量. uint m1,i1,j1,k1; uchar table1[4]; //在此加入 用户进程1参数 //test2 的参数 int m2,i2,j2,k2; uchar table2[4]; //在此加入 用户进程2参数 //test3 的参数 int m3,i3,j3,k3; uchar table3[4]; //在此加入 用户进程1参数 //声明 //unsigned int Get_Next_PC(void);//调用子程序,获取PC void chushihua(void); //初始化函数 void yonghuchushihua(void); //用户初始化函数 void test1(void); //进程一 void test2(void); void test3(void); //main函数 void main(void) { // PC_Next=Get_Next_PC(); chushihua(); ac1=(unsigned int)(test1); //获取进程1的入口地址 ac2=(unsigned int)(test2);//获取进程2的入口地址 ac3=(unsigned int)(test3); //获取进程3的入口地址 yonghuchushihua(); TR0=1; while (1); } //初始化时钟 void chushihua(void) { TMOD=0x01;// EA=1; ET0=1; TH0=TN/256; TL0=TN%256; } //中断处理,进程调度 void time0() interrupt 1 using 1 { uchar ib; TR0=0; //进程顺序分配 PID++; if(PID==4) {PID=1;} //进程调度 switch(PID) { case 1: { if(test3_1! =0)//第一次否? { //保存现场,还回地址 address3=*((unsigned char *)(SP-4));//PC的高字节 address3 <<= 8; address3+=*((unsigned char *)(SP-5)); //PC的低字节 table3[0]=*((unsigned char *)(SP)); //现场保护 table3[1]=*((unsigned char *)(SP-1)); //现场保护 table3[2]=*((unsigned char *)(SP-2)); //现场保护 table3[3]=*((unsigned char *)(SP-3)); //现场保护 for(ib=0;ib<=7;ib++) //保护R0--R7 { tempbf3[ib]=temp[ib]; } } if(test1_1==0) //第一次执行 { //执行新进程,恢复现场 test1_1=1; *((unsigned char *)(SP-4))=ac1>>8; //PC的高字节 *((unsigned char *)(SP-5))=ac1 & 0x00ff; //PC的低字节 } else//非第一次执行 { //执行新进程,恢复现场 *((unsigned char *)(SP-4))=address1>>8; //PC的高字节 *((unsigned char *)(SP-5))=address1 & 0x00ff; //PC的低字节 *((unsigned char *)(SP))=table1[0]; //现场恢复 *((unsigned char *)(SP-1))=table1[1]; //现场恢复 *((unsigned char *)(SP-2))=table1[2]; //现场恢复 *((unsigned char *)(SP-3))=table1[3]; //现场恢复 for(ib=0;ib<=7;ib++) //恢复R0--R7 { temp[ib]=tempbf1[ib]; } } TH0=TN1/256; TL0=TN1%256; TR0=1; }break; case 2: { if(test1_1! =0) //第一次否? { //保存现场,还回地址,否 address1=*((unsigned char *)(SP-4)); //PC的高字节 address1 <<= 8; address1+=*((unsigned char *)(SP-5)); //PC的低字节 table1[0]=*((unsigned char *)(SP)); //现场保护 table1[1]=*((unsigned char *)(SP-1));//现场保护 table1[2]=*((unsigned char *)(SP-2));//现场保护 table1[3]=*((unsigned char *)(SP-3)); //现场保护 for(ib=0;ib<=7;ib++) //保护R0--R7 { tempbf1[ib]=temp[ib]; } } if(test2_1==0)//第一次 { //执行进程2,恢复现场 test2_1=1; *((unsigned char *)(SP-4))=ac2>>8; //PC的高字节 *((unsigned char *)(SP-5))=ac2 & 0x00ff; //PC的低字节 } else //非第一次 { //执行进程2,恢复现场 *((unsigned char *)(SP-4))=address2>>8;//PC的高字节 *((unsigned char *)(SP-5))=address2 & 0x00ff; //PC的低字节 *((unsigned char *)(SP))=table2[0]; //现场恢复 *((unsigned char *)(SP-1))=table2[1]; //现场恢复 *((unsigned char *)(SP-2))=table2[2]; //现场恢复 *((unsigned char *)(SP-3))=table2[3]; //现场恢复 for(ib=0;ib<=7;ib++)//恢复R0--R7 { temp[ib]=tempbf2[ib]; } } TH0=TN2/256; TL0=TN2%256; TR0=1; }break; case 3: { if(test2_1! =0) { //保存现场,还回地址 address2=*((unsigned char *)(SP-4)); //PC的高字节 address2 <<= 8; address2+=*((unsigned char *)(SP-5)); //PC的低字节 table2[0]=*(
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 一种 裸奔 任务 嵌入式 操作系统 模型