freertos学习

Posted by 高庆东 on March 4, 2017

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)

延时中断处理