第六章 FreeRTOS任务相关API函数
6.1 任务创建和删除API函数
1、函数xTaskCreate() 使用动态的方法创建一个任务。
configSUPPORT_DYNAMIC_ALLOCATION
新创建的任务默认就是就绪态的,如果当前没有比它更高优先级的任务运行那么此任务就会立即进入运行态
开始运行,不管在任务调度器启动前还是启动后,都可以创建任务。
所需要的RAM就会自动的从FreeRTOS的堆中分配,因此必须提供内存管理文件
xTaskCreate( interrupt_task, //任务函数
"interrupt_task", //任务名字
interrupt_STACK_SIZE, //任务堆栈大小
( void * ) NULL, //传递给任务函数的参数
interrupt_task_PRIORITY,//任务优先级
(TaskHandle_t*) &interruptTask_Handler );//任务句柄
2、函数xTaskCreateStatic()
使用此函数创建的任务所需的RAM需要用户来提供。
4、函数vTaskDelete()
当调用函数vTaskDelete()删除任务以后此任务之前申请的堆栈和控制块内存会在空闲任务中被释放,
因此当调用函数vTaskDelete()删除任务以后必须给空闲任务一定的运行时间。
6.4 任务挂起和恢复API函数
1、函数vTaskSuspend()
void vTaskSuspend(TaskHandle_t xTaskToSuspend)
xTaskToSuspend: 要挂起任务的句柄。
2、函数vTaskResume()
void vTaskResume(TaskHandle_t xTaskToResume)
xTaskToResume: 要恢复的任务句柄
3、函数xTaskResumeFromISR() 中断版本
BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume)
xTaskToResume: 要恢复的任务句柄。
第七章 FreeRTOS列表和列表项
7.1 什么是列表和列表项
7.1.1 列表
列表用来追踪FreeRTOS中的任务,列表相关的东西在文件list.c和list.h
List_t
typedef struct xLIST
{
listFIRST_LIST_INTEGRITY_CHECK_VALUE(1) /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
configLIST_VOLATILE UBaseType_t uxNumberOfItems;(2)
ListItem_t * configLIST_VOLATILE pxIndex;(3) /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */
MiniListItem_t xListEnd; (4) /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */
listSECOND_LIST_INTEGRITY_CHECK_VALUE (5) /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
} List_t;
(1)和(5) 用来检查列表完整性
(2)、uxNumberOfItems 用来记录列表中列表项的数量
(3)、pxIndex 用来记录当前列表项索引号,用于遍历列表。
(4)、列表中最后一个列表项,用来表示列表结束。
7.2 列表和列表项初始化
7.2.1 列表初始化
vListInitialise()
void vListInitialise( List_t * const pxList )
{
/* The list structure contains a list item which is used to mark the
end of the list. To initialise the list the list end is inserted
as the only list entry. */
pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */
/* The list end value is the highest possible value in the list to
ensure it remains at the end of the list. */
pxList->xListEnd.xItemValue = portMAX_DELAY;
/* The list end next and previous pointers point to itself so we know
when the list is empty. */
pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */
pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );/*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */
pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
/* Write known values into the list if
configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
}
第八章 FreeRTOS任务创建和调度器开启
空闲任务的用途:
1、判断系统是否有任务删除
2、运行用户设置的空闲任务钩子函数
3、判断是否开启低功耗tickless模式,如果开启的话还需要做相应的处理。
第九章 FreeRTOS任务切换
9.1 PendSV 异常
可以通过将中断控制和状态寄存器ICSR的bit28,也就是PendSV挂起位置1来触发PendSV中断。
OS支持特性
权威指南 第10章 OS支持特性
10.1 OS支持特性简介
影子栈指针。 有两个栈指针可用,MSP用于OS内核以及中断处理,PSP则用于应用任务。
SysTick定时器。 位于处理器内部的简单定时器,使得同一个嵌入式OS可用在多种Cortex-M微控制器上。
SVC和PendSV异常。 这两种异常对于嵌入式OS中的操作非常重要,如上下文切换的实现等。
非特权执行等级。 可以利用其实现一种基本安全模型,限制某些应用任务的访问权限。特权和非特权等级的分离
还可同存储器保护单元(MPU)一起使用,进一步提高嵌入式系统的健壮性。
排他访问。 排他加载和存储指令用于OS中的信号量和互斥体(MUTEX)操作。
一个名为指令跟踪宏单元(ITM)的调试特性可在多种调试工具中用于OS调试。
10.2 影子栈指针
主栈指针(MSP)为默认的栈指针。
进程栈指针(PSP)
对于嵌入式OS或RTOS的系统,异常处理(包括部分OS内核)使用MSP,而应用任务则使用PSP。
每个应用任务都有自己的栈空间。OS中的上下文切换代码在每次上下文切换时都会更新PSP。
10.3 SVC 异常
10.4 PendSV 异常
PendSV(可挂起的系统调用)
taskYIELD()
执行系统调用
任务切换函数taskYIELD()
9.2.2 系统滴答定时器(Systick)中断
FreeRTOS中滴答定时器(SysTick)中断服务函数中也会进行任务切换,
9.3 PendSV中断服务函数
#define xPortPendSVHandler PendSV_Handler
9.4 查找下一个要运行的任务
vTaskSwitchContext()来获取下一个要运行的任务,也就是查找已经就绪了的优先级最高的任务。
9.6 FreeRTOS时间片调度
configUSE_PREEMPTION
configUSE_TIME_SLICING
第十章 RreeRTOS系统内核控制函数
第十一章 FreeRTOS其他任务API函数
第十二章 FreeRTOS时间管理
vTaskDelay()是相对模式(相对延时函数)
vTaskDelayUntil()是绝对模式(绝对延时函数)
INCLUDE_vTaskDelay
prvAddCurrentTaskToDelayedList() 用于将当前任务添加到等待列表中。
第十三章 FreeRTOS队列
13.1 队列简介
1、数据存储
1、多任务访问
队列不是属于某个任务指定的任务的,任何任务都可以向队列中发送消息,或者从队列中提取消息。
2、出队阻塞
当任务尝试从一个队列中读取消息的时候可以指定一个阻塞时间,这个阻塞时间就是当任务从队列中读取
消息无效的时候任务阻塞的时间。
出队就是从队列中读取消息,出队阻塞是针对从队列中读取消息的任务而言的。
当阻塞时间设置为portMAX_DELAY的话,任务就会一直进入阻塞态等待,直到收到数据为止。
3、入队阻塞
和出队阻塞一样
4、 队列操作过程图示
向队列中发送消息是采用拷贝的方式,所以一旦消息发送完成变量x就可以再次被使用,赋其他的值。
13.2 队列结构体
13.3 队列创建
1、xQueueCreate()
QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength, //要创建的队列的队列长度,这里是队列的项目数。
UBaseType_t uxItemSize) //队列中每个项目(消息)的长度,单位为字节
函数xQueueSend()、 xQueueSendToBack()和xQueueSendToFront()
这三个函数都是用于向队列中发送消息的,发三个函数本质都是宏。只能用于任务函数中,不能用于中断服务
函数,中断服务函数有专用的函数,以“”“FromISR”结尾
xQueueSend(
队列句柄
指向要发送的消息
阻塞时间
)
函数xQueueOverwrite()
此函数也是向队列发送数据的,当队列满了以后会覆写掉旧的数据,不管这个旧数据有没有被其他
任务或中断取走。
xQueueOverwrite(
队列句柄
指向要发送的消息
)
4、函数xQueueSendFromISR()、xQueueSendToBackFromISR()、xQueueSendToFromISR()
13.5 队列上锁和解锁
prvLockQueue()
prvUnlockQueue()
第十四章 FreeRTOS信号量
二值信号量
二值信号量通常用于互斥访问或同步,二值信号量和互斥信号量非常类似,但是还是有一个细微的差别,互斥
信号量拥有优先继承机制,二值信号量没有优先级继承。因此二值信号更适合用于同步,而互斥信号量适合用于
简单的互斥访问。
1、vSemaphoreCreateBinary()
void vSemaphoreCreateBinary(SemaphoreHandle_t xSemaphore)
xSemaphore: 保存创建成功的二值信号量句柄。
释放信号量
函数xSemaphoreGive()
BaseType_t xSemaphoreGive(xSemaphore)
xSemaphore: 要释放的信号量句柄
获取信号量
函数xSemaphoreTake()
TaskHandle_t StartTask_Handler;
6.1 任务创建和删除API函数
1、函数xTaskCreate() 使用动态的方法创建一个任务。
configSUPPORT_DYNAMIC_ALLOCATION
新创建的任务默认就是就绪态的,如果当前没有比它更高优先级的任务运行那么此任务就会立即进入运行态
开始运行,不管在任务调度器启动前还是启动后,都可以创建任务。
所需要的RAM就会自动的从FreeRTOS的堆中分配,因此必须提供内存管理文件
xTaskCreate( interrupt_task, //任务函数
"interrupt_task", //任务名字
interrupt_STACK_SIZE, //任务堆栈大小
( void * ) NULL, //传递给任务函数的参数
interrupt_task_PRIORITY,//任务优先级
(TaskHandle_t*) &interruptTask_Handler );//任务句柄
2、函数xTaskCreateStatic()
使用此函数创建的任务所需的RAM需要用户来提供。
4、函数vTaskDelete()
当调用函数vTaskDelete()删除任务以后此任务之前申请的堆栈和控制块内存会在空闲任务中被释放,
因此当调用函数vTaskDelete()删除任务以后必须给空闲任务一定的运行时间。
6.4 任务挂起和恢复API函数
1、函数vTaskSuspend()
void vTaskSuspend(TaskHandle_t xTaskToSuspend)
xTaskToSuspend: 要挂起任务的句柄。
2、函数vTaskResume()
void vTaskResume(TaskHandle_t xTaskToResume)
xTaskToResume: 要恢复的任务句柄
3、函数xTaskResumeFromISR() 中断版本
BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume)
xTaskToResume: 要恢复的任务句柄。
第七章 FreeRTOS列表和列表项
7.1 什么是列表和列表项
7.1.1 列表
列表用来追踪FreeRTOS中的任务,列表相关的东西在文件list.c和list.h
List_t
typedef struct xLIST
{
listFIRST_LIST_INTEGRITY_CHECK_VALUE(1) /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
configLIST_VOLATILE UBaseType_t uxNumberOfItems;(2)
ListItem_t * configLIST_VOLATILE pxIndex;(3) /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */
MiniListItem_t xListEnd; (4) /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */
listSECOND_LIST_INTEGRITY_CHECK_VALUE (5) /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
} List_t;
(1)和(5) 用来检查列表完整性
(2)、uxNumberOfItems 用来记录列表中列表项的数量
(3)、pxIndex 用来记录当前列表项索引号,用于遍历列表。
(4)、列表中最后一个列表项,用来表示列表结束。
7.2 列表和列表项初始化
7.2.1 列表初始化
vListInitialise()
void vListInitialise( List_t * const pxList )
{
/* The list structure contains a list item which is used to mark the
end of the list. To initialise the list the list end is inserted
as the only list entry. */
pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */
/* The list end value is the highest possible value in the list to
ensure it remains at the end of the list. */
pxList->xListEnd.xItemValue = portMAX_DELAY;
/* The list end next and previous pointers point to itself so we know
when the list is empty. */
pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */
pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );/*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */
pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
/* Write known values into the list if
configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
}
第八章 FreeRTOS任务创建和调度器开启
空闲任务的用途:
1、判断系统是否有任务删除
2、运行用户设置的空闲任务钩子函数
3、判断是否开启低功耗tickless模式,如果开启的话还需要做相应的处理。
第九章 FreeRTOS任务切换
9.1 PendSV 异常
可以通过将中断控制和状态寄存器ICSR的bit28,也就是PendSV挂起位置1来触发PendSV中断。
OS支持特性
权威指南 第10章 OS支持特性
10.1 OS支持特性简介
影子栈指针。 有两个栈指针可用,MSP用于OS内核以及中断处理,PSP则用于应用任务。
SysTick定时器。 位于处理器内部的简单定时器,使得同一个嵌入式OS可用在多种Cortex-M微控制器上。
SVC和PendSV异常。 这两种异常对于嵌入式OS中的操作非常重要,如上下文切换的实现等。
非特权执行等级。 可以利用其实现一种基本安全模型,限制某些应用任务的访问权限。特权和非特权等级的分离
还可同存储器保护单元(MPU)一起使用,进一步提高嵌入式系统的健壮性。
排他访问。 排他加载和存储指令用于OS中的信号量和互斥体(MUTEX)操作。
一个名为指令跟踪宏单元(ITM)的调试特性可在多种调试工具中用于OS调试。
10.2 影子栈指针
主栈指针(MSP)为默认的栈指针。
进程栈指针(PSP)
对于嵌入式OS或RTOS的系统,异常处理(包括部分OS内核)使用MSP,而应用任务则使用PSP。
每个应用任务都有自己的栈空间。OS中的上下文切换代码在每次上下文切换时都会更新PSP。
10.3 SVC 异常
10.4 PendSV 异常
PendSV(可挂起的系统调用)
taskYIELD()
执行系统调用
任务切换函数taskYIELD()
9.2.2 系统滴答定时器(Systick)中断
FreeRTOS中滴答定时器(SysTick)中断服务函数中也会进行任务切换,
9.3 PendSV中断服务函数
#define xPortPendSVHandler PendSV_Handler
9.4 查找下一个要运行的任务
vTaskSwitchContext()来获取下一个要运行的任务,也就是查找已经就绪了的优先级最高的任务。
9.6 FreeRTOS时间片调度
configUSE_PREEMPTION
configUSE_TIME_SLICING
第十章 RreeRTOS系统内核控制函数
第十一章 FreeRTOS其他任务API函数
第十二章 FreeRTOS时间管理
vTaskDelay()是相对模式(相对延时函数)
vTaskDelayUntil()是绝对模式(绝对延时函数)
INCLUDE_vTaskDelay
prvAddCurrentTaskToDelayedList() 用于将当前任务添加到等待列表中。
第十三章 FreeRTOS队列
13.1 队列简介
1、数据存储
1、多任务访问
队列不是属于某个任务指定的任务的,任何任务都可以向队列中发送消息,或者从队列中提取消息。
2、出队阻塞
当任务尝试从一个队列中读取消息的时候可以指定一个阻塞时间,这个阻塞时间就是当任务从队列中读取
消息无效的时候任务阻塞的时间。
出队就是从队列中读取消息,出队阻塞是针对从队列中读取消息的任务而言的。
当阻塞时间设置为portMAX_DELAY的话,任务就会一直进入阻塞态等待,直到收到数据为止。
3、入队阻塞
和出队阻塞一样
4、 队列操作过程图示
向队列中发送消息是采用拷贝的方式,所以一旦消息发送完成变量x就可以再次被使用,赋其他的值。
13.2 队列结构体
13.3 队列创建
1、xQueueCreate()
QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength, //要创建的队列的队列长度,这里是队列的项目数。
UBaseType_t uxItemSize) //队列中每个项目(消息)的长度,单位为字节
函数xQueueSend()、 xQueueSendToBack()和xQueueSendToFront()
这三个函数都是用于向队列中发送消息的,发三个函数本质都是宏。只能用于任务函数中,不能用于中断服务
函数,中断服务函数有专用的函数,以“”“FromISR”结尾
xQueueSend(
队列句柄
指向要发送的消息
阻塞时间
)
函数xQueueOverwrite()
此函数也是向队列发送数据的,当队列满了以后会覆写掉旧的数据,不管这个旧数据有没有被其他
任务或中断取走。
xQueueOverwrite(
队列句柄
指向要发送的消息
)
4、函数xQueueSendFromISR()、xQueueSendToBackFromISR()、xQueueSendToFromISR()
13.5 队列上锁和解锁
prvLockQueue()
prvUnlockQueue()
第十四章 FreeRTOS信号量
二值信号量
二值信号量通常用于互斥访问或同步,二值信号量和互斥信号量非常类似,但是还是有一个细微的差别,互斥
信号量拥有优先继承机制,二值信号量没有优先级继承。因此二值信号更适合用于同步,而互斥信号量适合用于
简单的互斥访问。
1、vSemaphoreCreateBinary()
void vSemaphoreCreateBinary(SemaphoreHandle_t xSemaphore)
xSemaphore: 保存创建成功的二值信号量句柄。
释放信号量
函数xSemaphoreGive()
BaseType_t xSemaphoreGive(xSemaphore)
xSemaphore: 要释放的信号量句柄
获取信号量
函数xSemaphoreTake()
TaskHandle_t StartTask_Handler;