FreeRtos——单任务
原创(当然借鉴了官网资料^_^):
在之前的移植工作准备好之后,我们需要调用freertos提供给我们的API函数实现操作系统地运行。首先,第一个函数:
任务函数
任务是由 C 语言函数实现的。唯一特别的只是任务的函数原型,其必须返回 void,
而且带有一个 void 指针参数。
void ATaskFunction( void *pvParameters );任务函数原型
每个任务都是在自己权限范围内的一个小程序。其具有程序入口,通常会运行在一个死循环中,也不会退出。
- /*********************************************************************************
- * @ 函数名 : vTaskLed1
- * @ 功能说明: LED1 任务,实现一个周期性的闪烁
- * @ 参数 : pvParameters,当任务创建的时候传进来,可以没有
- * @ 返回值 : 无
- ********************************************************************************/
- void vTaskLed1(void *pvParameters)
- {
- /* 任务都是一个无限,不能返回 */
- while()
- {
- LED2( ON );
- /* 阻塞延时,单位ms */
- vTaskDelay( );
- LED2( OFF );
- vTaskDelay( );
- }
- }
这就是本次实验的任务函数,控制LED灯的亮灭,注意任务函数中的while(1),以及返回void。
FreeRTOS 任务不允许以任何方式从实现函数中返回——它们绝不能有一
条”return”语句,也不能执行到函数末尾。如果一个任务不再需要,可以显式地将其删
除。这也在程序清单 2 展现。
一个任务函数可以用来创建若干个任务——创建出的任务均是独立的执行实例,拥
有属于自己的栈空间,以及属于自己的自动变量(栈变量),即任务函数本身定义的变量。
应用程序可以包含多个任务。如果运行应用程序的微控制器只有一个核(core),那
么在任意给定时间,实际上只会有一个任务被执行。这就意味着一个任务可以有一个或
两个状态,即运行状态和非运行状态。我们先考虑这种最简单的模型——但请牢记这其
实是过于简单,我们稍后将会看到非运行状态实际上又可划分为若干个子状态。
当某个任务处于运行态时,处理器就正在执行它的代码。当一个任务处于非运行态
时,该任务进行休眠,它的所有状态都被妥善保存,以便在下一次调试器决定让它进入
运行态时可以恢复执行。当任务恢复执行时,其将精确地从离开运行态时正准备执行的
那一条指令开始执行。
任务从非运行态转移到运行态被称为”切换入或切入(switched in)”或”交换入
(swapped in)”。相反,任务从运行态转移到非运行态被称为”切换出或切出(switched
out)”或”交换出(swapped out)”。 FreeRTOS 的调度器是能让任务切入切出的唯一实体。
创建任务使用 FreeRTOS 的 API 函数 xTaskCreate()。
usStackDepth :
当任务创建时,内核会分为每个任务分配属于任务自己的唯一状态。
usStackDepth 值用于告诉内核为它分配多大的栈空间。
这个值指定的是栈空间可以保存多少个字(word),而不是多少个字
节(byte)。比如说,如果是 32 位宽的栈空间,传入的 usStackDepth
值为 100,则将会分配 400 字节的栈空间(100 * 4bytes)。栈深度乘
以栈宽度的结果千万不能超过一个 size_t 类型变量所能表达的最大
值。
应用程序通过定义常量 configMINIMAL_STACK_SIZE 来决定空闲
任务任用的栈空间大小。在 FreeRTOS 为微控制器架构提供的
Demo 应用程序中,赋予此常量的值是对所有任务的最小建议值。
如果你的任务会使用大量栈空间,那么你应当赋予一个更大的值。
没有任何简单的方法可以决定一个任务到底需要多大的栈空间。计
算出来虽然是可能的,但大多数用户会先简单地赋予一个自认为合
理的值,然后利用 FreeRTOS 提供的特性来确证分配的空间既不欠
缺也不浪费。第六章包括了一些信息,可以知道如何去查询任务使
用了多少栈空间。
在我的stm32上:
- /*********************************************************************************
- * @ 函数名 : AppTaskCreate
- * @ 功能说明: 任务创建,为了方便管理,所有的任务创建函数都可以放在这个函数里面
- * @ 参数 : 无
- * @ 返回值 : 无
- ********************************************************************************/
- static void AppTaskCreate(void)
- {
- xTaskCreate(vTaskLed1, /* 任务函数名 */
- "Task Led1", /* 任务名,字符串形式,方便调试 */
- , /* 栈大小,单位为字,即4个字节 */
- NULL, /* 任务形参 */
- , /* 优先级,数值越大,优先级越高 */
- &xHandleTaskLED1); /* 任务句柄 */
- }
- int main(void)
- {
- NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
- /* LED 端口初始化 */
- LED_GPIO_Config();
- /*创建任务*/
- AppTaskCreate();
- /*启动任务调度器,任务开始执行*/
- vTaskStartScheduler();
- while ()
- {
- }
- }
这样编译下载之后,可以看到LED灯闪烁,即移植成功,其中省略了基础硬件初始化部分,建立在你可以不使用操作系统点亮LED灯的基础上,完成系统移植。
其中关于任务参数做一点说明:
在我的LED实验中没有使用任务参数,但是如果有相似功能的函数,我们可以不用使用多个任务函数实体,而在一个任务函数中多次创建任务,具体例子如下所示:
例 1 中创建的两个任务几乎完全相同,唯一的区别就是打印输出的字符串。这种重
复性可以通过创建同一个任务代码的两个实例来去除。这时任务参数就可以用来传递各
自打印输出的字符串。
程序清单 8 包含了例 2 中用到的唯一一个任务函数代码(vTaskFunction)。这一个
任务函数代替了例 1 中的两个任务函数(vTask1 与 vTask2)。这个函数的任务参数被强
制转化为 char*以得到任务需要打印输出的字符串。
- void vTaskFunction( void *pvParameters )
- {
- char *pcTaskName;
- volatile unsigned long ul;
- /* 需要打印输出的字符串从入口参数传入。强制转换为字符指针。 */
- pcTaskName = ( char * ) pvParameters;
- /* As per most tasks, this task is implemented in an infinite loop. */
- for( ;; )
- {
- /* Print out the name of this task. */
- vPrintString( pcTaskName );
- /* Delay for a period. */
- for( ul = ; ul < mainDELAY_LOOP_COUNT; ul++ )
- {
- /* This loop is just a very crude delay implementation. There is
- nothing to do in here. Later exercises will replace this crude
- loop with a proper delay/sleep function. */
- }
- }
- }
- 程序清单 例 中用于创建两个任务实例的任务函
尽管现在只有一个任务实现代码(vTaskFunction),但是可以创建多个任务实例。每
个任务实例都可以在 FreeRTOS 调度器的控制下独运行。
传递给 API 函数 xTaskCreate()的参数 pvPrameters 用于传入字符串文本。如程序
清单 9 所示。
- /* 定义将要通过任务参数传递的字符串。定义为const,且不是在栈空间上,以保证任务执行时也有效。 */
- static const char *pcTextForTask1 = “Task is running\r\n”;
- static const char *pcTextForTask2 = “Task is running\t\n”;
- int main( void )
- {
- /* Create one of the two tasks. */
- xTaskCreate( vTaskFunction, /* 指向任务函数的指针. */
- "Task 1", /* 任务名. */
- , /* 栈深度. */
- (void*)pcTextForTask1, /* 通过任务参数传入需要打印输出的文本. */
- , /* 此任务运行在优先级1上. */
- NULL ); /* 不会用到此任务的句柄. */
- /* 同样的方法创建另一个任务。至此,由相同的任务代码(vTaskFunction)创建了多个任务,仅仅是传入
- 的参数不同。同一个任务创建了两个实例。 */
- xTaskCreate( vTaskFunction, "Task 2", , (void*)pcTextForTask2, , NULL );
- /* Start the scheduler so our tasks start executing. */
- vTaskStartScheduler();
- /* If all is well then main() will never reach here as the scheduler will
- now be running the tasks. If main() does reach here then it is likely that
- there was insufficient heap memory available for the idle task to be created.
- CHAPTER 5 provides more information on memory management. */
- for( ;; );
- }
- 程序清单 例 中的 main()函数实现代码
既然官方手册都给出了参考了,那么作为学习,我们也该操练一下,使用任务参数,完成三个LED灯切换:
更改任务函数如下:
- void vTaskLed1(void *pvParameters)
- {
- /* 任务都是一个无限,不能返回 */
- int *piParameters;
- piParameters=(int *)pvParameters;
- while()
- {
- if(*piParameters==)
- {
- LED1( ON );
- /* 阻塞延时,单位ms */
- vTaskDelay( );
- LED1( OFF );
- vTaskDelay( );
- }
- else if(*piParameters==)
- {
- LED2( ON );
- /* 阻塞延时,单位ms */
- vTaskDelay( );
- LED2( OFF );
- vTaskDelay( );
- }
- else if(*piParameters==)
- {
- LED3( ON );
- /* 阻塞延时,单位ms */
- vTaskDelay( );
- LED3( OFF );
- vTaskDelay( );
- }
- }
- }
全局区增加标志定义:
static const int task_led1=1;
static const int task_led2=2;
static const int task_led3=3;
更改任务创建函数,注意任务参数处不再是NULL;
- static void AppTaskCreate(void)
- {
- xTaskCreate(vTaskLed1, /* 任务函数名 */
- "Task Led1", /* 任务名,字符串形式,方便调试 */
- , /* 栈大小,单位为字,即4个字节 */
- (void *)&task_led3, // task_led1-task_led3可以切换 /* 任务形参 */
- , /* 优先级,数值越大,优先级越高 */
- &xHandleTaskLED1); /* 任务句柄 */
- }
经过测试,程序正常运行,更改任务参数1-3,可以看到三个不同颜色的灯在闪烁,达到训练目的。
其中需要注意,任务参数的原型:void * const pvParameters;如果我们不强制转化成void *将会报错。是不是觉得奇怪,void类型的指针不应该兼容吗?当然,你只用把我定义变量的标志的const去掉,就不用强制转化成void *了,那么是什么原因呢?const int a;对a取地址是const int *类型,是底层const了,不容忽略。这里和keil编译器有关系,在gcc中,虽然有警告,但是可以通过编译并运行。但是这样的类型不兼容情况我们应该避免。
FreeRtos——单任务的更多相关文章
- FreeRTOS基础篇教程目录汇总
以下教程(大部分章节)(尤其理论介绍部分)转载自安富莱电子,官网链接: http://forum.armfly.com/forum.php 然后根据安富莱的教程自己做了分析和测试,希望大家共同进步. ...
- freeRTOS中文实用教程4--资源管理互斥
1.前言 访问一个被多任务共享,或是被任务与中断共享的资源时,需要采用”互斥”技术以保证数据在任何时候都保持一致性.这样做的目的是要确保任务从开始访问资源就具有排它性,直至这个资源又恢复到完整状态 F ...
- FreeRtos——多任务
官方资料整理测试: 多任务和单任务几乎没有差别.只用多创建一个或多个任务,其他地方和单任务时相同. static void AppTaskCreate(void) { xTaskCreate(vTas ...
- 不可被忽视的操作系统( FreeRTOS )【1】
把大多数人每个星期的双休过过成了奢侈的节假日放假,把每天23点后定义为自己的自由时间,应该如何去思考这个问题 ? 双休的两天里,不!是放假的两天里,终于有较长的时间好好的学习一下一直断断续续的Free ...
- FreeRTOS学习笔记——FreeRTOS 任务基础知识
RTOS 系统的核心就是任务管理,FreeRTOS 也不例外,而且大多数学习RTOS 系统的工程师或者学生主要就是为了使用RTOS 的多任务处理功能,初步上手RTOS 系统首先必须掌握的也是任务的创建 ...
- FREERTOS 手册阅读笔记
郑重声明,版权所有! 转载需说明. FREERTOS堆栈大小的单位是word,不是byte. 根据处理器架构优化系统的任务优先级不能超过32,If the architecture optimized ...
- FreeRTOS 中断优先级嵌套错误引发HardFault异常解决(转)
最近在使用FreeRTOS的时候,突然发现程序在运行了几分钟之后所有的任务都不再调用了,只有几个中断能正常使用,看来是系统挂掉了,连续测试了几次想找出问题,可是这个真的有点不知所措. 我 ...
- Keil环境中建立带FreeRTOS的STM32L项目
本文是网上转载,版权所有. Keil环境中建立带FreeRTOS的STM32L项目 1.先把source文件夹复制至project目录,然后在keil中添加RTOS文件,如图: 其中heap_2.c按 ...
- FreeRTOS学习及移植笔记之二:在IAR和STM32F103VET上移植FreeRTOS
上一次,我们简单的测试了FreeRTOS的基于IAR EWARM v6.4和STM32F103VET6平台的Demo,对其有了一个基本认识.接下来我们开始自己移植FreeRTOS的过程. 1.创建一个 ...
随机推荐
- C#转义字符[转]
C#转义字符: 一种特殊的字符常量 以反斜线"\"开头,后跟一个或几个字符 具有特定的含义,不同于字符原有的意义,故称“转义”字符. 主要用来表示那些用一般字符不便于表示的控制代码 ...
- 巧妙使用 CSS3 的褪色和动画效果制作消息提醒框
现代Web设计技术允许开发者快速实现大多数浏览器支持的动画.我想警告消息是很常见的,因为默认的JavaScript警告框的样式往往(与你自己设计的漂亮样式)很不协调很囧.这使开发者步入找出哪种解决方案 ...
- IOS中WebView的使用
UIWebView是iOS sdk中一个最常用的控件.是内置的浏览器控件,我们可以用它来浏览网页.打开文档等等,UIWebView能够加载html/htm.pdf.docx.txt等格式的文件 系统 ...
- mysql的日志管理
日志操作是数据库维护中最重要的手段之一,日志文件会记录MySQL服务器的各种信息,所以当MySQL服务器遭到意外损坏时,不仅可以通过日志文件来查看出错的原因,而且还可以通过日志文件进行数据恢复. MY ...
- java socket 编程经典实例
服务器监听.并接收每个客户端的信息再群发到每个客户端 服务端 package com.java.xiong.Net17; import java.io.BufferedReader; import j ...
- Word该值小于列表中的前一条目
在Word中进行多级编号时,前面一个二级标题是2.1,可后面一个二级标题是4.1,于是想把4.1改成2.2,使用 选中有问题的编号,右击"设置列表缩进",在打开的对话框中我们可以看 ...
- gsoap
C++中如何使用gsoap开发WebService 1. 什么是gSOAPgSOAP是一个夸平台的,用于开发Web Service服务端和客户端的工具,在Windows.Linux.MAC OS和UN ...
- Servlet实现文件上传,可多文件上传
一.Servlet实现文件上传,需要添加第三方提供的jar包 接着把这两个jar包放到 lib文件夹下: 二: 文件上传的表单提交方式必须是POST方式, 编码类型:enctype="mul ...
- Android日常开发总结
全部Activity可继承自BaseActivity,便于统一风格与处理公共事件,构建对话框统一构建器的建立,万一需要整体变动,一处修改到处有效. 数据库表段字段常量和SQL逻辑分离,更清晰,建议使用 ...
- 【Linux】cat命令
用途 cat用于将一个档案的内容连续的打印在屏幕上 全称 cat的全称是Conctaenate 参数 -A :相当于-vTE的整合选项,可列出一些特殊字符而不是空白而已 -b :列出行号,仅针对非空白 ...