Freertos学习总结(基础知识篇)

通过学习韦东山老师的课程,对于Freertos有了一个较为系统的观念,下面对于这段时间的时间进行一个总结。

堆, heap ,就是一块空闲的内存,需要提供管理函数;
malloc :从堆里划出一块空间给程序使用;
free :用完后,再把它标记为 " 空闲 " 的,可以再次使用;
栈, stack ,函数调用时局部变量保存在栈中,当前程序的环境也是保存在栈中;
可以从堆中分配一块空间用作栈;

数据类型和编码规范

 变量名

 函数名

1、任务管理

以日常生活为例,比如这个母亲要同时做两件事:
喂饭:这是一个任务
回信息:这是另一个任务
这可以引入很多概念:
任务状态 (State)
当前正在喂饭,它是 running 状态;另一个 " 回信息 " 的任务就是 "not running" 状态
"not running" 状态还可以细分:
ready :就绪,随时可以运行
blocked :阻塞,卡住了,母亲在等待同事回信息
suspended :挂起,同事废话太多,不管他了
优先级 (Priority)
(Stack) :对于程序,是记在栈里 ,每个任务有自己的栈。
事件驱动
协助式调度 (Co-operative Scheduling)
1.1任务的创建和删除

 

 1.1.1 创建任务

void vTask1 ( void * pvParameters ) {  while(1) {}  }
void vTask2 ( void * pvParameters ) {  while(1) {}  }
int main ( void )
{
prvSetupHardware ();
xTaskCreate ( vTask1 , "Task 1" , 1000 , NULL , 1 , NULL );
xTaskCreate ( vTask2 , "Task 2" , 1000 , NULL , 1 , NULL );
/* 启动调度器 */
vTaskStartScheduler ();
/* 如果程序运行到了这里就表示出错了 , 一般是内存不足 */
return 0 ;
}
或者可这么写(拿我做过的项目举个例子)
#define LED0_TESK       1     // LED0任务  开启 (1) 禁用 (0) 

/******************* LED0任务 *******************************/
#if LED0_TESK

//任务优先级
#define LED0_TASK_PRIO        2
//任务堆栈大小    
#define LED0_STK_SIZE         256  
//任务句柄
TaskHandle_t LED0Task_Handler;
//任务函数
void led0_task(void *pvParameters);

#endif

int main(void)
 { //创建开始任务
    xTaskCreate((TaskFunction_t )start_task,            //任务函数
                (const char*    )"start_task",          //任务名称
                (uint16_t       )START_STK_SIZE,        //任务堆栈大小
                (void*          )NULL,                  //传递给任务函数的参数
                (UBaseType_t    )START_TASK_PRIO,       //任务优先级
                (TaskHandle_t*  )&StartTask_Handler);   //任务句柄              
    vTaskStartScheduler();          //开启任务调度
}

void start_task(void *pvParameters)
{
   taskENTER_CRITICAL();           //进入临界区   
#if LED0_TESK
   //创建LED0任务
    xTaskCreate((TaskFunction_t )led0_task,         
                (const char*    )"led0_task",       
                (uint16_t       )LED0_STK_SIZE, 
                (void*          )NULL,                
                (UBaseType_t    )LED0_TASK_PRIO,    
                (TaskHandle_t*  )&LED0Task_Handler);
                                
#endif                        

}

#if LED0_TESK

void led0_task(void *pvParameters)
{

    while(1)
    {

        vTaskDelay(10);                
    }
}   

#endif

1.1.2 任务删除

如果有两个任务,在任务2中任务2自杀,任务1的函数中,如果不调用vTaskDelay,则Idle任务(空闲任务)用于没有机会执行,它就无法释放创建任务2是分配的内存。

而任务 1 在不断地创建任务,不断地消耗内存,最终内存耗尽再也无法创建新的任务。

要注意的是:如果使用 vTaskDelete() 来删除任务,那么你就要确保空闲任务有机会执行,否则就无 法释放被删除任务的内存。
1.2 任务优先级和 Tick
1.2.1 任务优先级

优先级的取值范围是:0~(configMAX_PRIORITIES – 1),数值越大优先级越高,高优先级的任务先运行。

FreeRTOS 的调度器可以使用 2 种方法来快速找出优先级最高的、可以运行的任务。使用不同的方法时, configMAX_PRIORITIES 的取值有所不同。
通用方法:
A.使用 C 函数实现,对所有的架构都是同样的代码。对 configMAX_PRIORITIES 的取值没有限制。但 是configMAX_PRIORITIES 的取值还是尽量小,因为取值越大越浪费内存,也浪费时间。
configUSE_PORT_OPTIMISED_TASK_SELECTION 被定义为 0 、或者未定义时,使用此方法。
架构相关的优化的方法
B.架构相关的汇编指令,可以从一个 32 位的数里快速地找出为 1 的最高位。使用这些指令,可以快速 找出优先级最高的、可以运行的任务。
使用这种方法时, configMAX_PRIORITIES 的取值不能超过 32
configUSE_PORT_OPTIMISED_TASK_SELECTION 被定义为 1 时,使用此方法。

1.2.2 Tick
FreeRTOS 中也有心跳,它使用定时器产生固定间隔的中断。这叫 Tick 、滴答,比如每 10ms 发生一次时钟中断。
两次中断之间的时间被称为时间片 (time slice tick period).
时间片的长度由 configTICK_RATE_HZ 决定,假设 configTICK_RATE_HZ 100 ,那么时间片长度就是10ms。
相同优先级的任务怎么切换呢?
A.任务 2 t1 执行到 t2
B.在t2 发生 tick 中断,进入 tick 中断处理函数:
选择下一个要运行的任务
执行完中断处理函数后,切换到新的任务:任务 1
C.任务 1 t2 执行到 t3
从图中可以看出,任务运行的时间并不是严格从 t1,t2,t3 哪里开始
1.2.3 修改优先级
修改任务 优先级

 

设置任务优先级

 

1.3 任务状态
我们可以把任务分为四种状态
运行 (Runing)
阻塞状态 (Blocked)
暂停状态 (Suspended)
就绪状态 (Ready)

1.4 Delay函数

 

1.5  空闲任务及其钩子函数

Idle任务(空闲任务)的作用:释放被删除的任务的内存
一个良好的程序,它的任务都是事件驱动的:平时大部分时间处于阻塞状态。有可能我们自己创建的所有任务都无法执行,但是调度器必须能找到一个可以运行的任务:所以,我们要提供空闲任务。在使用 vTaskStartScheduler() 函数来创建、启动调度器时,这个函数内部会创建空闲任务:
空闲任务优先级为 0 :它不能阻碍用户任务运行
空闲任务要么处于就绪态,要么处于运行态,永远不会阻塞
钩子函数( Idle Task Hook Functions

使用钩子函数的前提

A.把这个宏定义为 1 configUSE_IDLE_HOOK
B.实现 vApplicationIdleHook 函数

1.6 调度算法

所谓调度算法,就是怎么确定哪个就绪态的任务可以切换为运行状态。
通过配置文件 FreeRTOSConfig.h 的两个配置项来配置调度算法:
configUSE_PREEMPTION
configUSE_TIME_SLICING。
还有第三个配置项: configUSE_TICKLESS_IDLE ,它是一个高级选项,用于关闭 Tick 中断来实现省电。
调度算法的行为主要体现在两方面:高优先级的任务先运行、同优先级的就绪态任务如何被选中。
调度算法要确保同优先级的就绪态任务,能" 轮流 " 运行,策略是 " 轮转调度 "(Round Robin Scheduling) 。轮转调度并不保证任务的运行时间是公平分配的,我们还可以细化时间的分配方法。
3 个角度统一理解多种调度算法:

A.可否抢占?高优先级的任务能否优先执行(配置项: configUSE_PREEMPTION)

B.可抢占的前提下,同优先级的任务是否轮流执行(配置项:configUSE_TIME_SLICING)

C.在"可抢占"+"时间片轮转"的前提下,进一步细化:空闲任务是否让步于用户任务(配置项: configIDLE_SHOULD_YIELD)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值