FreeRTOS的启动流程

目前的RTOS中有两种比较流行的启动方式

万事俱备  只欠东风:在main函数中将硬件初始化,rtos系统初始化,所有任务的创建都完成  再启动RTOS的调度器(在刚刚创建的的任务中选择一个优先级最高的) 开始多任务的调度

伪代码:

int main()
{
HardWare_Init();
RTOS_Init();

//创建任务1 但是任务1不会执行  因为调度器还没有开启
RTOS_TaskCreate(Task1);
RTOS_TaskCreate(Task2);
//启动RTOS 开始调度
RTOS_Start();

}

void Task1(void * arg)
{
while(1)
{
//任务实体 必须有阻塞的情况出现
}
}

void Task2(void * arg)
{
while(1)
{
//任务实体 必须有阻塞的情况出现
}
}

小心翼翼 十分谨慎:在main函数中将硬件和RTOS系统初始化好 然后创建一个启动任务后就启动调度器  在启动任务中创建各种应用任务   当所有的任务创建成功后  启动任务就把自己删除

伪代码:

int main()
{
HardWare_Init();
RTOD_init();
//创建一个任务
RTOS_TaskCreate(APPTaskCreate);
//启动RTOS 开始调度
RTOS_Start();

}


void AppTaskCreate(void *arg)
{
//创建任务1 然后执行
RTOS_TaskCreate(Task1);
//当任务1阻塞时 继续创建任务2 然后执行
RTOS_TaskCreate(Task2);

//任务创建完成  删除起始任务
RTOS_TaskDelete(AppTaskCreate);
}

void Task1(void *arg)
{
while(1)
{
}
}

void Task2(void * arg)
{
while(1)
{
}
}

启动流程:

在系统上电时第一个执行的是启动文件中由汇编编写的复位函数Reset_Handle  复位函数之后会调用C库函数__main ,主要作用是初始化系统的堆和栈   最后调用C中的main函数

  1. Rest_Handle
  2. __main
  3. main()

其中Ret_Handle函数的内容

Ret_Handle  PROC
            EXPORT Ret_Handle
            IMPORT __mian
            IMPORT StstemInit
            LDR R0,=SystemInit
            BLX R0
            LDR R0,=__main
            BX R0
            ENDP

创建任务 xTaskCreate()函数:

    在 main函数中  可以直接对FreeRTOS进行创建任务操作    因为FreeRTOS会自动帮我们做初始化的事情  如初始化堆内存    所以我们自己在main函数中自己直接初始化我们的板极外设  然后进行任务创建即可--xTaskCreate,FreeRTOS会帮我们进行一系列的初始化,帮我们初始化堆栈内存。

在创建任务时,我们需要开启调度器,因为创建任务是把任务添加到系统中,还没真正调度 并且空闲任务(FreeRTOS一旦启动就必须要保证系统中每时每科都有任务执行 并且空闲任务不能被挂起与删除 并且空闲任务的优先级是最低的  以便系统中其他任务能够随时抢占空闲任务的CPU使用权)也没实现  定时器任务也没实现  这些都是在开启任务调度函数vTaskStartSchedule中实现  处理完这些  系统才真正才是启动

vTaskStartSchedule()函数内容:

void vTaskStartSchedule(void)
{
   BaseType_t xReturn;
   //添加空闲任务
#if(configSUPPORT_STATIC_ALLOCATION==1)
   {
    StaticTask_t *pxIdleTaskTCBBuffer=NULL;
    StackType_t *pxIdleTaskStackBuffer=NULL;
    uint32_t ulIdleTaskStackSize;
    //空闲任务一般使用用户提供的RAM创建-获取  然后RAM的地址创建空闲任务  这是静态创建任务
    vApplicationGetIdleTaskMemory(&pxIdleTaskTCBBuffer,&pxIdleTaskStackBuffer,&ulIdleTaskStackSize);
   xIdleTaskHandle=xTaskCreateStatic(prvIdleTask,"IDLE",ulIdleTaskStackSize,(void *)NULL,(tskIDLE_PRIORITY|portPRIVILEGE_BIT),pxIdleTaskStackBuffer,pxIdleTaskTBBuffer);
  if (xIdleTaskHandle!=NULL){
      xReturn=pdPASS;
      else
     {
       xReturn=pdFALL;
      }
     }
   }

#else
//动态任务创建idle
{
//使用动态分配的RAM创建空闲任务
  xReturn=xTaskHandle(prvIdleTask,"IDLE",ConfigMINIMAL_STACK_SIZE,(void *)NULL,(taskIDLE_PRIORITY|portPRIVILEGE_BIT),&xIdleTaskHandle);
}
#endif


........
.......
.......
.....
}

创建定时器任务:

BaseType_t cTimerCreateTimerTask(void)
{
   BaseType_t xReturn =pdFAIL;
   //检查使用了哪些活动计时器的列表 以及用于与计数器服务通信的队列 已经初始化
   prvCheckForValidListAndQueue();
   //动态创建定时器任务
   xReturn=xTaskCreate(prvTimerTask,"tmr_svc",configTIMER_TASK_STCAK_DEPTH,NULL,
   ((UBaseType_t)configTIMER_TASK_PRIORITY)|portPRIVILEGE_BIT,&xTimerTaskHanlde);
   configASSERT(xReturn);
}

关于异常:

FreeRTOS为了任务启动和任务切换使用了三个异常:SVC,PendSV,SysTick:

SVC:系统服务调用  用于任务启动  用户使用SVC发出对系统服务函数的呼叫请求   以这种方法调用它们来间接访问硬件  他会产生一个SVC异常

PendSV:用于完成任务切换,他可以像普通你的中断一样被挂起 最大的特性是如果当前有优先级比他高的中断正在运行  PendSV会延迟执行  知道高优先级的中断执行完成  这样就不会打断其他中断的运行

SysTick:用于产生系统节拍时钟,提供一个时间片  如果多个任务共享同一个优先级  每次SysTick中断  下一个任务将获得一个时间片

在main函数中只需要创建并启动一些任务和硬件初始化

int  main(void)
{
   BaseType_t xReturn =pdPASS;
   Init();
   xRetrun=xTaskCreate((TaskFunction_t)AppTaskCreate,(const char *)"AppTaskCreate",(uint16_t)512,(void *)NULL,(UBaseType_t )1,(TaskHandle_t *)&AppTaskCreate_Handle);
if(pdPASS==xReturn)
    vTaskStartSchedule();
else
   return -1;
  while(1);
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值