赞
踩
目前的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函数
其中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);
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。