1、注意:任务函数内部定义局部变量的内存大小不能大于此任务堆栈内存的大小。

2、FreeRTOS定义任务优先级时,0优先级(空闲中断占用)和最高优先级31级(定时器占用)不能用。

3、用start_task创建任务task1和task2时,start_task只创建一次就行,不用多次创建,所以创建完start_task后,就可以把start_task任务删除,用vTaskDelete()函数删除,要删除那个任务,只需把那个函数的任务句柄放在vTaskDelete后面的括号里面即可,或者直接在括号里面用一个NULL也可以。

4、vTaskList()函数可查询任务的名称、任务运行状态(就绪态、运行态、阻塞态和删除态等)、优先级、任务运行后剩余的堆栈余量等,是一个重量级的函数。注意,当定义一个数组变量去接收vTaskList()函数返回的指针值时,这个数组变量缓存要大些,因为任务多,占用堆栈内存大。且这个数组变量最好定义成全局变量,如果定义成函数局部变量,那内存是从定义这个数组变量的函数开始调用这个数组变量,就需要把这个任务函数的堆栈改大,否则程序会出错。

5、vTaskGetRunTimeStatus()函数,这个函数可查询当前运行的任务中哪个任务比较耗时,可把这个任务拆分成小的任务。减小任务耗时。

6、时序要求严格的时钟通信协议中,如在I2C、SPI正在读取数据,高优先级的任务到来时,高优先级就抢占CPU,导致I2C或SPI无法读取正确的数据,可用临界任务保护函数,在I2C\SPI读取数据时,禁止高优先级抢占CPU,使I2C和SPI读到正确的数据。可调用taskENTER_CRITICAL()函数进入任务保护,调用taskEXIT_CRITICAL()函数退出任务保护。可进行多次嵌套临界段代码保护。注意,在使用临界区保护函数时,要快进快出,避免一些紧急的事件任务需要处理时,临界区保护的任务还未完成,那紧急任务事件得不到实时处理,会出现问题的。如在电力系统和医疗急救中,紧急事件任务得不到处理,会出现大问题。

7、函数askENTER_CRITCAL_FROM_ISR()和函数taskEXIT_CRITCAL_FROM_ISR()是中断级临界区代码段保护函数,用在中断服务函数中,而且这个中断的优先级一定要低于configMAX_SYSCALL_INTERRUPT_PRIORITY(高于这个宏定义定义的中断优先级,不可调用FreeRTOS系统的API)。

8、在使用taskENTER_CRITCAL_FROM_ISR()时,先定义一个变量读取这个函数返回的值,等退出临界保护时,把这个变量作为实参传递给taskEXIT_CRITCAL_FROM_ISR()来退出临界保护。
用法如下:
uint32_t  taskISR_Value;
taskENTER_CRITCAL_FROM_ISR();
被保护代码段
taskEXIT_CRITCAL_FROM_ISR(taskISR_Value);

9、延时函数:vTaskDelay()相对延时函数和vTaskDelayUntil()绝对延时函数。

10、队列是用于任务与任务、任务与中断之间的通信。可在任务与任务、任务与中断之间传递信息,因此队列也叫做消息队列。队列可存储有限的、大小固定的数据项目。任务与任务、任务与中断之间要交流的数据保存在队列中,叫队列项目。队列能保存的最大数据项目数量叫队列的长度。创建队列的时候需指定数据项目的大小和队列的长度。注:信号量也是依据队列来实现的。

11、平时不用操作系统时,用串口中断接收一帧数据,但不知道这帧数据什么时候到来,通常我们会定义一个接收数据标志的全局变量来确定一帧数据是否接收完成,在main函数里面不停轮询判断这个接收标志位是否等于1,如果等于1,则确定接收到了新的帧数据并在main函数或其它子函数进行数据处理,这种方式效率低且耗费CPU。此时可用操作系统做信号量的任务同步,当串口中断服务函数/定时器确定接收到一帧数据,可发出一个信号量。在程序应用中创建一个任务去请求获取接收串口中断服务函数/定时器发出的信号量信息的信号量,当这个信号量无效时,任务会进入阻塞态,把CPU让给其他任务去执行;当信号量有效时,这个任务接着执行处理串口接收到的数据。这个信号量可实现任务与任务之间的同步,也可实现中断(串口中断/定时器中断/外部中断等)和任务之间的同步。

12、二值信号量适合用于同步,如任务与任务之间的同步,任务和中断之间的同步。互斥信号量适合用于简单的互斥访问。

13、在使用二值信号量时,会产生任务优先级翻转。解决任务优先级翻转可以使用互斥信号量。

14、互斥信号量使用的API操作函数和二值信号量使用的API操作函数是相同的。所以互斥信号量也可设置阻塞时间,与二值信号量不同的是,互斥信号量具有优先级继承的特性。当一个互斥信号量正在被一个低优先级的任务使用,而此时有个高优先级的任务也尝试获取这个互斥信号量的话就会被阻塞。不过这个高优先级的任务会将低优先级任务的优先级提升到与自己相同的优先级,这个过程就是优先级继承。优先级继承尽可能地降低了高优先级任务处于阻塞时间,并且将已经出现的“优先级翻转”的影响降到最低。如,现有三个依次为低、中、高的三个任务,中高优先级任务处于就绪挂起态,低优先级任务在运行,此时低优先级任务想要访问共享资源,则需要获取该资源的信号量。低优先级任务获取信号量后并开始访问共享资源,此时,高优先级任务开始运行,也想访问低优先级任务正在使用的共享资源,但是该共享资源的信号量还在被低优先级任务占用着,高优先级任务只能进入挂起态,默默的等待低优先级任务释放该共享资源的信号量。就在高优先级任务默默等待看着低优先级任务什么时候释放共享资源的信号量时,中优先级任务等待的事件发生后,中级优先级任务也开始运行了,由于中优先级任务的优先级高于低优先级任务的优先级,所以就抢占了CPU的使用权。一直等到中优先级任务把自己的事件处理完成后,才把CPU使用权给低优先级任务,低优先级任务继续使用CPU去访问共享资源,待低优先级任务访问共享资源完成了,低优先级任务释放共享资源的信号量,最后高优先级任务才获取低优先级任务释放的信号量去访问共享资源。这种现象看起来就是中优先级任务的优先级要比高优先级任务的优先级高。此时高优先级任务可以使用互斥信号量,把低优先级任务的优先级提高到与自己优先级一样,在低优先级在使用信号量时,高优先级任务进入挂起态,中优先级任务事件发生后想要获取CPU的使用权,但由于高优先级任务把低优先级任务的优先级提高了,中优先级任务只好等待这两个高优先级任务运行完后,才可获得CPU使用权。而原先的高优先级任务等到原低优先级任务释放信号量以后,就可以获取信号量去访问原低优先级任务访问的共享资源。

15、互斥信号量不能用于中断服务器中。原因有两个:一、互斥信号量有优先级继承机制,只能应用在任务中,不能用于中断服务函数。二、中断服务函数中不能因为要等待互斥信号量二设置阻塞时间进入阻塞态。

16、递归信号量与互斥信号量一样,不能用在中服务函数中。

17、创建的软件定时器是休眠状态的,要调用开启软件定时器的函数开启定时器。

18、任务通知可完成消息队列、信号量、事件标志组的功能,不过任务通知是只能实现一对一的,也就是一个任务对一个任务。

19、接收任务可以因为接收任务通知而进入阻塞态,但是发送任务不会因为任务通知发送失败而阻塞。但是队列就有入队阻塞和出对阻塞,信号量是根据队列来实现的,信号量也会出现跟队列一样的情况。

20、虽然任务通知可以模拟二值信号量,但任务通知不能用在资源管理上,只有二值信号量能用。

21、降低系统主频可以降低CPU的功耗。

22、内存管理,heap1特点如下:
(1)适用于那些一旦创建好任务、信号量和队列就再也不会删除的应用,实际上大多数的FreeRTOS 应用都是这样的。
(2)具有可确定性(执行所花费的时间大多数都是一样的),而且不会导致内存碎片。
(3)代码实现和内存分配过程都非常简单,内存是从一个静态数组中分配到的,也就是适合于那些不需要动态内存分配的应用。

22、内存管理,heap2能申请内存特点如下:
(1)可以使用在那些可能会重复的删除任务、队列、信号量等的应用中,要注意有内存碎片产生!
(2)如果分配和释放的内存 n 大小是随机的,那么就要慎重使用了,比如下面的示例:

=》如果一个应用动态的创建和删除任务,而且任务需要分配的堆栈大小都是一样的,那么 heap_2 就非常合适。如果任务所需的堆栈大小每次都是不同,那么 heap_2 就不适合了,因为这样会导致内存碎片产生,最终导致任务分配不到合适的堆栈!不过 heap_4 就很适合这种场景了。

=》如果一个应用中所使用的队列存储区域每次都不同,那么 heap_2 就不适合了,和上面一样,此时可以使用 heap_4。
=》应用需要调用 pvPortMalloc()和 pvPortFree()来申请和释放内存,而不是通过其他FreeRTOS 的其他 API 函数来间接的调用,这种情况下 heap_2 不适合。
(3)如果应用中的任务、队列、信号量和互斥信号量具有不可预料性(如所需的内存大小不能确定,每次所需的内存都不相同,  或者说大多数情况下所需的内存都是不同的)的话可能会导致内存碎片。虽然这是小概率事件,但是还是要引起我们的注意!
(4)具有不可确定性,但是也远比标准 C 中的 mallo()和 free()效率高!heap_2 基本上可以适用于大多数的需要动态分配内的工程中,而 heap_4 更是具有将内存碎片合并成一个大的空闲内存块(就是内存碎片回收)的功能。

23、内存管理,heap3内存分配方法是对标准C中的函数malloc()和free()的简单封装,FreeRTOS对这两函数做了线程保护。特点如下:

(1)需要编译器提供一个内存堆,编译器库要提供 malloc()和 free()函数。若使用STM32的话可以通过修改启动文件中的Heap_Size 来修改内存堆的大小。
(2)具有不确定性。
(3)可能会增加代码量。

24、内存管理,heap4提供了一个最优的匹配算法,不像heap2,heap4会将内存碎片合成一个大的可用内存块。它提供了内存合并算法。
特点如下:
(1)可以用在那些需要重复创建和删除任务、队列、信号量和互斥信号量等的应用中。
(2)不会像 heap_2 那样产生严重的内存碎片,即使分配的内存大小是随机的。
(3)具有不确定性,但是远比 C 标准库中的 malloc()和 free()效率高。heap_4 非常适合于那些需要直接调用函数pvPortMalloc()和 vPortFree()来申请和释放内存的应用,注意,我们移植 FreeRTOS 的时候就选择的 heap_4!heap_4也使用链表结构来管理空闲内存块,链表结构体与 heap_2 一样。 heap_4 也定义了两个局部静态变量 pxStart 和 pxEnd来表示链表头和尾,其中 pxEnd是指向 BlockLink_t 的指针。

25、内存管理,heap_5 基本上和 heap_4 一样,只是 heap_5 支持内存堆使用不连续的内存块。 heap_5 允许内存堆跨越多个不连续的内存段。比如 STM32 的内部 RAM 可以作为内存堆,但是 STM32 内部 RAM 比较小,遇到那些需要大容量 RAM 的应用就不行了,如音视频处理。不过 STM32 可以外接 SRAM 甚至大容量的 SDRAM,如果使用 heap_4 的话你就只能在内部 RAM 和外部SRAM 或 SDRAM 之间二选一了,使用 heap_5 的话就不存在这个问题,两个都可以一起作为内存堆来用。

26、用pvPortMalloc()申请内存、pvPortFree()释放内存,也可查看内存使用剩余量。可用一个指针变量如uint8_t buffer去接收申请到的内存。释放内存以后需要将 buffer 设置为 NULL,函数 pvPortFree()释放内存以后并不会将 buffer清零,此时 buffer 还是上次申请到的内存地址,如果此时再调用指针 buffer 的话你会发现还是可以使用的!感觉好像没有释放内存,所以需要将 buffer 清零。内存申请、内存释放、查看内存使用剩余量如下:
uint8_t *buffer,times = 0;
uint32_t freemem;

申请内存
buffer = pvPortMalloc(20); //申请内存,20个字节 
printf("申请到的内存地址为:%#x\r\n",(int)buffer);

释放内存
if(buffer!=NULL){
   vPortFree(buffer); //释放内存
}
buffer = NULL;

使用内存
if(buffer!=NULL) //buffer 可用,使用 buffer (5)
{
   times++;
   sprintf((char*)buffer,"User %d Times",times);//向buffer中填写一些数据
   printf("%s\r\n",buffer);                     //把刚刚写进去的数据打印出来
}

查看内存剩余大小
freemem = xPortGetFreeHeapSize(); //获取剩余内存大小
注意:我们申请20字节的内存大小,但实际申请到的内存大小要比20字节大,为什么会这样?因为在申请内存的时候,会自动进行内存堆的开始地址对齐,申请的内存地址也需要进行字节对齐。所以我们申请的是20字节,但是经过字节对齐后计算,实际会分配大于20字节的内存给我们。

学习《FreeRTOS源码详解与应用开发》笔记相关推荐

  1. 第二行代码学习笔记——第六章:数据储存全方案——详解持久化技术

    本章要点 任何一个应用程序,总是不停的和数据打交道. 瞬时数据:指储存在内存当中,有可能因为程序关闭或其他原因导致内存被回收而丢失的数据. 数据持久化技术,为了解决关键性数据的丢失. 6.1 持久化技 ...

  2. 第一行代码学习笔记第二章——探究活动

    知识点目录 2.1 活动是什么 2.2 活动的基本用法 2.2.1 手动创建活动 2.2.2 创建和加载布局 2.2.3 在AndroidManifest文件中注册 2.2.4 在活动中使用Toast ...

  3. 第一行代码学习笔记第八章——运用手机多媒体

    知识点目录 8.1 将程序运行到手机上 8.2 使用通知 * 8.2.1 通知的基本使用 * 8.2.2 通知的进阶技巧 * 8.2.3 通知的高级功能 8.3 调用摄像头和相册 * 8.3.1 调用 ...

  4. 第一行代码学习笔记第六章——详解持久化技术

    知识点目录 6.1 持久化技术简介 6.2 文件存储 * 6.2.1 将数据存储到文件中 * 6.2.2 从文件中读取数据 6.3 SharedPreferences存储 * 6.3.1 将数据存储到 ...

  5. 第一行代码学习笔记第三章——UI开发的点点滴滴

    知识点目录 3.1 如何编写程序界面 3.2 常用控件的使用方法 * 3.2.1 TextView * 3.2.2 Button * 3.2.3 EditText * 3.2.4 ImageView ...

  6. 第一行代码学习笔记第十章——探究服务

    知识点目录 10.1 服务是什么 10.2 Android多线程编程 * 10.2.1 线程的基本用法 * 10.2.2 在子线程中更新UI * 10.2.3 解析异步消息处理机制 * 10.2.4 ...

  7. 第一行代码学习笔记第七章——探究内容提供器

    知识点目录 7.1 内容提供器简介 7.2 运行权限 * 7.2.1 Android权限机制详解 * 7.2.2 在程序运行时申请权限 7.3 访问其他程序中的数据 * 7.3.1 ContentRe ...

  8. 第一行代码学习笔记第五章——详解广播机制

    知识点目录 5.1 广播机制 5.2 接收系统广播 * 5.2.1 动态注册监听网络变化 * 5.2.2 静态注册实现开机广播 5.3 发送自定义广播 * 5.3.1 发送标准广播 * 5.3.2 发 ...

  9. 第一行代码学习笔记第九章——使用网络技术

    知识点目录 9.1 WebView的用法 9.2 使用HTTP协议访问网络 * 9.2.1 使用HttpURLConnection * 9.2.2 使用OkHttp 9.3 解析XML格式数据 * 9 ...

  10. 安卓教程----第一行代码学习笔记

    安卓概述 系统架构 Linux内核层,还包括各种底层驱动,如相机驱动.电源驱动等 系统运行库层,包含一些c/c++的库,如浏览器内核webkit.SQLlite.3D绘图openGL.用于java运行 ...

最新文章

  1. 数据分析师的职业规划之路
  2. 图说子图同构算法——VF2算法(一)
  3. camx模型_【推荐】基于CAMx的空气质量模拟及污染来源解析技术
  4. 文本分类入门(十)特征选择算法之开方检验
  5. 项目打包publicpath_将项目部署至github和码云
  6. 同步降压DC-DC转换IC——XC9264
  7. 音视频开发(16)---海康IPC+NVR+EasyDarwin+EasyPusher+VLC实现Web实时播放RTSP视频
  8. annotation:@Override出现The method of type must override asuperclass解决方案
  9. React移动端h5日历组件react-h5-calendar周日历 月日历 周视图 月视图自定义标记点
  10. 神舟刷蓝天w650dbios_神舟z6kp5D1记录一次艰难的刷蓝天bios,总算成功了
  11. 计算机电磁泄露案例,电磁泄漏
  12. 图像学习一:图像的旋转
  13. 解决 win10 桌面 资源管理器未响应
  14. win7安装oracle 黑屏,苹果电脑装Windows7黑屏的原因和解决方案
  15. 降维算法-LDA线性判别分析实例
  16. Licode Demo搭建
  17. unity code-动作系统Animator
  18. IPSec的三个协议和两种模式详解
  19. 计算机效果图线稿的制作方法,线稿效果图 怎么把照片变线稿?将图片改为线稿的方法...
  20. 世界首富一天赚多少钱?说出来怕你受不了

热门文章

  1. jquery插件的写法
  2. SQL Case When Then 条件判断
  3. ubuntu20.04安装noetic版本ros
  4. 充电类型一二次检测过程及充电类型
  5. Android系统架构基本模式解析
  6. python的time库有哪些方法_Python的time模块中的常用方法整理
  7. restful post请求_猿蜕变9——一文搞定SpringMVC的RESTFul套路
  8. 第十六章--访问文件
  9. 从V.C.Space抄来的
  10. PHP中的foreach循环