学习笔记(二)——FreeRTOS

一、队列管理

  在FreeRTOS中,任务之间的通信是通过队列来实现的,队列有以下特点:

  (1)队列可以保存有限个数据单元,称为“深度”,有先入先出的特点,若数据较大,队列最好存放数据的指针而不是数据本身

  (2)队列的数据可以被多个任务存取

  (3)读写队列时阻塞。读写队列时可以设定阻塞时间,读时若队列为空,则进入阻塞直至队列为非空或者超过设定时间进入就绪态。写则对应队列已满。

  队列的使用主要由以下几个函数实现:

  (1)创建任务。返回值为NULL表示空间不足创建失败,非NULL表示成功并保存下来作为队列句柄。

xQueueHandle xQueueCreate(unsigned portBase_TYPE uxQueueLength,  //队列深度
                                            unsigned portBse_TYPE uxItemSize);  //队列中数据单元的长度,以字节为单位

  (2)发送数据到队列。xQueueSendToFront()和xQueueSendToBack()分别表示发送到队头和队尾。

portBASE_TYPE xQueueSendToFront(xQueueHandle xQueue,  //目标队列句柄
    const void *pvItemToQueue,  //发送数据的指针,指向复制到队列的数据单元
    portTickType xTicksToWait);  //设定阻塞时间

  (3)读取数据单元。xQueuePeek()和xQueueReceive()的区别在于peek只读不删。

portBASE_TYPE xQueueReceive( XqueueHandle xQueue,  //被读队列句柄
      const void *pvBuffer,   //接受缓存指针,用于接收复制出来的数据
    portTickType xTicksToWait);  //阻塞时间

  (4)uxQueueMessageWaiting(),用于查询队列有有效数据单元的个数。

二、中断管理

  中断是指cpu运行过程中,遇到某些情况主机停止正在进行的任务转而处理新任务的过程。中断是经常发生的。在FreeRTOS中,由ISR(中断服务程序)处理中断。

       FreeRTOS允许中断嵌套,中断嵌套是指正在执行一个中断任务是,另一个优先级更高的中断提出中断请求,此时cpu会暂时中止当前中断转而执行优先级高的中断,执行完毕后再执行原来的中断。

2.1 利用二值信号量同步进行延迟中断处理

  二值信号量在某个中断发生时,解除阻塞,使任务和中断同步。若中断较为紧急,则可以将优先级设为最高,保证抢占其他任务。(信号量的术语为PV操作,即通过和释放,为原子操作)

  具体操作为,二值信号量可以视为深度为1的队列,队列为空时,延迟处理任务调用xSemaphoreTake()(获取信号量的函数)带阻塞时间的读取队列,若队列为空则处于阻塞状态,事件发生后,ISR通过调用xSemaphoreGiveFromISR()(给予信号量的函数)放置一个信号量到队列中,队列为非空,延迟处理任务切出阻塞态,并移除信号量。信号量由xSemaphoreCreateBinary()函数来创建。

2.2 计数信号量

  若中断事件发生较为频繁,采用二值信号量讲发生以下情况,当二值信号量锁存的时间还未被处理之前又有中断事件产生,后续中断将会丢失。若采用计数信号量,即采用深度大于1的栈,则可以避免此事件发生。计数信号量可以用来事件计数和资源管理,利用xSemaphoreCreateCounting()函数来创建信号量。

2.3 ISR中使用队列

  ISR中使用队列可以用于传递数据。

三、资源管理

  多任务系统中可能发生以下情况,一个任务在使用某个资源时,未结束访问就切出运行态,导致资源数据可能发生损坏货不完整。采用“互斥”可以避免这一情况。

3.1 基本临界区和挂起调度器

  基本临界区指宏taskENTER_CRITICAL()和taskEXIT_CRITICAL()之间的代码区间,在这个区间内,任务不会被切换。因此临界区时间应设定的较短,否则会影响中断响应时间。

  挂起调度器可以创建临界区,该临界区不会被其他任务打断,而中断可以打断,基本临界区内代码则不会被其他任务或中断打断。唤醒调度器是一个相对较长的操作。通过vTaskSuspendAll()可以讲调度器挂起,xTaskResumeAll()将调度器唤醒,且可以嵌套调用。

3.3 互斥量

  互斥量是一种特殊的二值信号量,和上述用于同步的二值信号量不同完成同步后便丢弃不同,互斥量有以下性质:一个任务想访问资源,必须获取互斥量的令牌,完成后需归还令牌,只有获得令牌的信号量才能访问资源。通过xSemaphoreCreateMutex()创建互斥量。

  采用互斥量有两个缺陷

(1)优先级反转。高优先级的任务需要等待低优先级的任务归还令牌。更差的情况是若一个中间优先级任务在执行,则高优先级一直等待低优先级任务,而低优先级任务却无法执行。使用优先级继承能够减轻这种情况,即将持有令牌的任务提升至所有等待互斥量任务的最高优先级,归还互斥量时,再还原为原来的优先级。

(2)死锁。和线程死锁类似,两个任务都在等待对方的资源,两个任务都无法执行,发生死锁。

  应通过设计尽量避免产生这些情况。

3.4 守护任务

  守护任务对某个资源有唯一访问权,其他任务要访问资源只能通过守护任务提功的服务。

四、内存管理

  FreeRTOS自带三种内存分配方案,分别放在heap_1.c,heap_2.c,heap3.c中,用户也可以采用自己的管理方式。heap_1.c将内存栈空间看作一个简单的数组,调用pvPortMalloc()(申请内存函数,释放内存函数为vPortFree())时,将数组分为更小的内存块,数组总大小由FreeRTOSConfig.h中由configTOTAL_HEAP_SIZE设定,数据按顺序分配排列。heap_2.c差不多,就是可以将数据放在数据之间删除的数据原来所占的空间,减少内存浪费和内存碎片。heap_3.c简单调用标准库函数malloc()和free(),通过暂时挂起调度器使其具有线程安全性,空间大小由链接器配置决定。

 

 

 

 

 

posted on 2018-03-07 11:35  黑夜里的黑喵  阅读(159)  评论(0)    收藏  举报

导航