Freertos操作系统学习
任务关系
有点类似ucos 但是涉及到api函数 需要理解创建任务的api都有神马功能
创建任务函数完成任务的创建 任务函数完成具体的任务
任务函数必须返回void 而且带有一个void指针参数,任务函数不能被执行完不能有返回值
Viod指针参数用于配合创建任务函数中的参数指针变量
创建任务函数是个api函数函数具体实现如下
pvTaskCode 是指向任务函数的指针
pcName 为任务起的名字(名字的长度可以通过修改某个变量改变)
usStacKDepth 分配任务运行时栈空间的大小
pvParameters 传递到任务中的参数的指针(与任务与外界沟通时需要)
uxPriority 任务的优先级设定
pxCreatedTask 用于传出任务的句柄(可以不用)
创建任务函数有两个返回值
有两个可能的返回值: 1. pdTRUE
表明任务创建成功。 2. errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY
由于内存空间不足,
FreeRTOS 无法分配足够的空间来保存任务结构数据和任务栈,因此无法创
建任务。
任务的优先级号越低 任务的优先级越低(与ucos相反)与ucos不同的是任务
可以共享一个优先级
任务运行状态
阻塞态:任务在运行时等待 1定时时间到达 2等待接收数据
挂起态:对于调度器而言不可见让任务进入挂起态的函数
vTaskSuspend()API 退出挂起态
vTaskResume() 或 vTaskResumeFromISR() API
(大多数应用程序都不会用到挂起态)
就绪态:准备运行状态 vTaskDelay() API 函数来代替空循环 目的是让任务进入阻塞状态,阻塞状态
时调度器寻找高优先级的就绪任务执行 阻塞时间到达后进入高优先级的 任务执行
vTaskDelayUntil(portTickType*pxPreviousWakeTime,
portTickType xTimeIncrem 类似于 vTaskDelay() 用于精确的延时(解除阻塞的时刻是绝对的) pxPreviousWakeTime xLastWakeTime = xTaskGetTickCount() (保存上一个离开阻塞的时刻) 一般只需要初始化一次,不需要修改 xTimeIncrem 延时时间的设置
合并阻塞与非阻塞任务(阻塞任务优先级为2 非阻塞任务优先级为1)
阻塞任务运行完调用延时进入阻塞态调度器开始寻找就绪态任务
非阻塞任务一直执行当阻塞任务到达延时调度器进入阻塞任务
执行。空闲任务永远没有机会运行(同一个优先级的任务在调度器看来
是一样的所以运行时一会运行它一会运行另一个,)
空闲任务
用空闲任务钩子函数来在添加应用程序 1用于执行低优先级程序或需要 执行不停处理的功能代码 2让处理器进入低功耗模式 空闲任务的运行规则1不能阻塞或者挂起(只有在其他任务不运行时才运行) 2如果应用程序用到了 vTaskDelete() AP 函数,则空闲钩子函数必须能够 尽快返回。 因为在任务被删除后,空闲任务负责回收内核资源。如果空闲任务一直运行在钩 子函数中,则无法进行回收工作。 钩子函数原型 void vApplicationIdleHook( void );钩子函数必须定义为此名无参数也无返回值 FreeRTOSConfig.h 中的配置常量 configUSE_IDLE_HOOK 必须定义为 1,这样空 闲任务钩子函数才会被调用。
改变任务优先级函数 vTaskPrioritySet() API 函数 用于调度器启动后改变任务优先级 void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority ) pxTask:需要修改的任务的句柄 uxNewPriority 需要改变的优先级
查询任务的优先级 unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask ); pxTask:任务的句柄 返回值为任务的优先级
通过任务间相互改变优先级可以实现循环
删除任务 void vTaskDelete( xTaskHandle pxTaskToDelete ) 通过目标任务的句柄删除任务 空闲任务负责释放内核
队列简介
队列是先进先出FIFO的从尾部写入从首部读出队列不属于任何任务
是独立与任务之外的 可以由多个任务写入但很少由多任务读出
在队列创建时需要对其深度和每个单元大小进行设定
当任务读取队列时可以进入阻塞态,当其他任务往队列写入信息后
退出阻塞态 当多个任务读取队列进入阻塞态时退出阻塞态的顺序按
优先级来 当优先级相同时谁等的时间长谁退出阻塞态
队列创建
xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength,unsigned portBASE_TYPE uxItemSize )
(队列空间是在堆中的) ### 队列的发送函数
xQueueHandle 创建队列的返回值 如果不成功返回NULL 成功的话返回值为队列的句柄
用于队列其他操作
uxQueueLength 队列存储的最大单元数目 队列深度
uxItemSize 队列中数据单元的长度 以字节为单位
portBASE_TYPE xQueueSendToFront( xQueueHandle xQueue,
const void * pvItemToQueue,
portTickType xTicksToWait ); 用于将数据发送到队列首
portBASE_TYPE xQueueSendToBack( xQueueHandle xQueue,
const void * pvItemToQueue,
portTickType xTicksToWait );用于将数据发送到队列尾等同于与portBASE_TYPE xQueueSend()
xQueue 创建的队列的句柄(队列的返回值)
pvItemToQueue 待发送的数据的首地址指针
xTicksToWait 阻塞超时时间。如果在发送时队列已满,这个时间即是任务处于阻塞态等待队列空间有效
的最长等待时间 可以设为0 (任务直接返回不进入阻塞态)
函数的返回值有两个 1paPASS数据被成功发送 2errQUEUE_FULL表示队列已经满了
队列的接收函数 portBASE_TYPE xQueueReceive( xQueueHandle xQueue,const void * pvBuffer, portTickType xTicksToWait );接收到数据后会删除队列中的数据
portBASE_TYPE xQueuePeek( xQueueHandle xQueue,const void * pvBuffer,
portTickType xTicksToWait );接收到数据后不删除原数据也不改变队列中数据顺序
xQueue 队列的句柄
pvBuffer 接收数据的缓存指针
xTicksToWait 队列在接收时为空则等待,任务进入阻塞态
返回值有两种 1pdPASS 成功接收到数据 2errQUEUE_FULL 队列空没有接受到数据
unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle xQueue );
用于查询队列中有效数据的个数
taskYIELD()用于任务切换当任务进行完后可以调用此函数
可以直接跳过需要等待的时间片 让调度器进行
切换
接收任务的优先级高于发送任务两个发送任务同优先级。当队列中有数据时就会执行接收任务所以队列中最对只存一个数据,程序执行时先执行接收任务此时队列中无数据接收任务进入阻塞态 调度器执行发送任务1,当发送数据后(此时发送任务1还没执行完)打破接收任务阻塞态 执行接收任务 ,任务执行完后队列中无数据此时又进入阻塞态 接收任务1继续执行当执行到taskYIELD()后调到接收任务2 如同接收任务1如此反复。(接收任务1,2是同优先级的类似任务)
注意事项
1指针指向的内存空间的所有权必须明确 当任务通过指针共享内存时 应从根本上保证不会有任意两个任务同时修改内存数据 原则上内存在其指针发送到队列之前起内容只允许发送任务访问 2 指针指向的内存必须有效不能访问已经删除的内存 不能访问栈的内存
中断管理
系统需要处理来自各个源头产生的事件对于处理时间和响应时间 有不同的要求 1时间通过中断被检测到 2中断服务程序(isr)
延时中断处理