freertos基础

include/FreeRTOS.h中包含freertos版本,目前使用的版本是FreeRTOS Kernel V10.2.1。
如下内容主要来自正点原子FreeRTOS实时内核实用指南。

0 配置

FreeRTOS的系统配置文件为 FreeRTOSConfig.h,在此配置文件中可以完成 FreeRTOS的裁剪和配置。

使用“ INCLUDE_”开头的宏用来表示使能或除能FreeRTOS中相应的 API函数, 作用就是用来配置 FreeRTOS中的可选 API函数的。

CONFIG开始的宏用来配置系统参数:

configTICK_RATE_HZ:设置FreeRTOS的系统时钟节拍频率,单位为 HZ。

此频率就是滴答定时器的中断频率,需要使用此宏来配置滴答定时器的中断,一般将此宏设置为1000,周期就是1ms。

configUSE_PREEMPTION为1时使用抢占式调度器,为 0时使用协程 。
如果使用抢占式调度器的话内核会在每个时钟节拍中断中进行任务切换。
当使用协程的话会在如下地方进行任务切换:一个任务调用了函数 taskYIELD(); 一个任务调用了可以使任务进入阻塞态的 API函数;应用程序明确定义了在中断中执行上下文切换。

configUSE_TIME_SLICING:默认情况下,FreeRTOS使用 抢占式 调度器,这意味着调度器永远都在执行已经就绪了的最高优先级任务, 优先级相同的任务在时钟节拍中断中进行切换。
当宏 configUSE_TIME_SLICING为 0的时候不会在时钟节拍中断中执行相同优先级任务的任务切换,默认情况下宏configUSE_TIME_SLICING为 1。

configIDLE_SHOULD_YIELD:此宏定义了与空闲任务(idle Task)处于同等优先级的其他用户任务的行为。
当为0 的时候空闲任务不会为其他处于同优先级的任务让出CPU 使用权。
当为1 的时候空闲任务就会为处于同等优先级的用户任务让出CPU 使用权,除非没有就绪的用户任务,这样花费在空闲任务上的时间就会很少。

1 任务

void ATaskFunction( void *pvParameters );
portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode, const signed portCHAR * const pcName,
unsigned portSHORT usStackDepth, void *pvParameters, 
unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask );

void vTaskDelay( portTickType xTicksToDelay );
void vTaskDelayUntil( portTickType * pxPreviousWakeTime, portTickType xTimeIncrement );

void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority );
unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask );

void vTaskDelete( xTaskHandle pxTaskToDelete );

 

2 队列

xQueueHandle

xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize );

portBASE_TYPE xQueueSendToFront( xQueueHandle xQueue, const void * pvItemToQueue, portTickType xTicksToWait );
portBASE_TYPE xQueueSendToBack( xQueueHandle xQueue, const void * pvItemToQueue, portTickType xTicksToWait );

portBASE_TYPE xQueueReceive( xQueueHandle xQueue, const void * pvBuffer, portTickType xTicksToWait );
portBASE_TYPE xQueuePeek( xQueueHandle xQueue, const void * pvBuffer, portTickType xTicksToWait );
xQueuePeek()也是从从队列中接收数据单元,不同的是并不从队列中删出接收到的单元。
xQueuePeek()从队列首接收到数据后,不会修改队列中的数据,也不会改变数据在队列中的存储顺序。
unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle xQueue );
用于查询队列中当前有效数据单元个数。

3 中断

二值信号量同步
P(s)/Take:获取信号量
V(s)/Give:释放信号量
xSemaphoreHandle
void vSemaphoreCreateBinary( xSemaphoreHandle xSemaphore );
portBASE_TYPE xSemaphoreTake( xSemaphoreHandle xSemaphore, portTickType xTicksToWait );
portBASE_TYPE xSemaphoreGiveFromISR( xSemaphoreHandle xSemaphore, portBASE_TYPE *pxHigherPriorityTaskWoken );
计数信号量
1) 事件计数。用于事件计数的计数信号量,在被创建时其计数值被初始化为0。
2)资源管理。用于资源管理的信号量,在创建时其计数值被初始化为可用资源总数。
xSemaphoreHandle xSemaphoreCreateCounting( unsigned portBASE_TYPE uxMaxCount, unsigned portBASE_TYPE uxInitialCount );
队列
信号量用于事件通信。而队列不仅可以用于事件通信,还可以用来传递数据。
portBASE_TYPE xQueueSendToFrontFromISR( xQueueHandle xQueue, void *pvItemToQueue port, BASE_TYPE *pxHigherPriorityTaskWoken );
portBASE_TYPE xQueueSendToBackFromISR( xQueueHandle xQueue, void *pvItemToQueue port, BASE_TYPE *pxHigherPriorityTaskWoken );

4 资源管理

资源冲突例程:访问外设、读-改-写操作、变量的非原子访问、函数重入。
临界区
taskENTER_CRITICAL()与 taskEXIT_CRITICAL()
挂起(锁定)调度器
void vTaskSuspendAll( void );
portBASE_TYPE xTaskResumeAll( void );
互斥信号量
xSemaphoreHandle xSemaphoreCreateMutex( void );
守护任务
守护任务是对某个资源具有唯一所有权的任务。只有守护任务才可以直接访问其守护的资源——其它任务要访问该资源只能间接地通过守护任务提供的服务。

5 内存管理

pvPortMalloc()
vPortFree()

6 错误排查

栈溢出
unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask );
主要用来查询指定任务的运行历史中,其栈空间还差多少就要溢出。这个值被称为栈空间的”高水线(High Water Mark)”。
任务栈空间的实际使用量会随着任务执行和中断处理过程上下浮动。
uxTaskGetStackHighWaterMark()返回从任务启动执行开始的运行历史中,栈空间具有的最小剩余量。这个值即是栈空间使用达到最深时的剩下的未使用的栈空间。这个值越是接近 0,则这个任务就越是离栈溢出不远了。
运行时栈侦测
FreeRTOS 包含两种运行时栈侦测机制,由 FreeRTOSConfig.h 中的配置常量configCHECK_FOR_STACK_OVERFLOW 进行控制。这两种方式都会增加上下切换开销。
栈溢出钩子函数(或称回调函数)由内核在侦测到栈溢出时调用。要使用栈溢出钩子函数,需要进行以下配置:
  • 在 FreeRTOSConfig.h 中把 configCHECK_FOR_STACK_OVERFLOW 设为 1 或 2。
  • 提供钩子函数的具体实现 void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed portCHAR *pcTaskName );
 

7. 时间

时钟节拍
xTickCount是FreeRTOS的系统时钟节拍计数器, 每个滴答定时器中断中 xTickCount就会加一。xTickCount的具体操作过程是在函数 xTaskIncrementTick()中进行的。
xTaskIncrementTick()每个时钟节拍中断 (滴答定时器中断 )调用一次,增加时钟节拍计数器 xTickCount的值,并且检查是否有任务需要取消阻塞。
 
延迟
void vTaskDelay( portTickType xTicksToDelay); // xTicksToDelay 延迟多少个心跳周期
// portTICK_RATE_MS 用来将以毫秒为单位的时间值转换为以心跳周期为单位的时间值。
// vTaskDelay( 250 / portTICK_RATE_MS ); 延迟250ms
// #define portTICK_RATE_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) // 1 tick/ms
// configTICK_RATE_HZ其含义是1秒钟TICK中断产生的次数
// #define configTICK_RATE_HZ                  ( ( TickType_t ) 1000 )
 

8. eventGroup

#include “FreeRTOS.h”
#include “event_groups.h”

EventGroupHandle_t xEventGroupCreate( void );
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer );
void vEventGroupDelete( EventGroupHandle_t xEventGroup );

EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear );
BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear );
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup );
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup );
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken );

EventBits_t xEventGroupWaitBits( const EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait );
 
参考:
posted @ 2019-10-03 10:44  yuxi_o  阅读(2272)  评论(0编辑  收藏  举报