原创(当然借鉴了官网资料^_^):

在之前的移植工作准备好之后,我们需要调用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——单任务的更多相关文章

  1. FreeRTOS基础篇教程目录汇总

    以下教程(大部分章节)(尤其理论介绍部分)转载自安富莱电子,官网链接: http://forum.armfly.com/forum.php 然后根据安富莱的教程自己做了分析和测试,希望大家共同进步. ...

  2. freeRTOS中文实用教程4--资源管理互斥

    1.前言 访问一个被多任务共享,或是被任务与中断共享的资源时,需要采用”互斥”技术以保证数据在任何时候都保持一致性.这样做的目的是要确保任务从开始访问资源就具有排它性,直至这个资源又恢复到完整状态 F ...

  3. FreeRtos——多任务

    官方资料整理测试: 多任务和单任务几乎没有差别.只用多创建一个或多个任务,其他地方和单任务时相同. static void AppTaskCreate(void) { xTaskCreate(vTas ...

  4. 不可被忽视的操作系统( FreeRTOS )【1】

    把大多数人每个星期的双休过过成了奢侈的节假日放假,把每天23点后定义为自己的自由时间,应该如何去思考这个问题 ? 双休的两天里,不!是放假的两天里,终于有较长的时间好好的学习一下一直断断续续的Free ...

  5. FreeRTOS学习笔记——FreeRTOS 任务基础知识

    RTOS 系统的核心就是任务管理,FreeRTOS 也不例外,而且大多数学习RTOS 系统的工程师或者学生主要就是为了使用RTOS 的多任务处理功能,初步上手RTOS 系统首先必须掌握的也是任务的创建 ...

  6. FREERTOS 手册阅读笔记

    郑重声明,版权所有! 转载需说明. FREERTOS堆栈大小的单位是word,不是byte. 根据处理器架构优化系统的任务优先级不能超过32,If the architecture optimized ...

  7. FreeRTOS 中断优先级嵌套错误引发HardFault异常解决(转)

      最近在使用FreeRTOS的时候,突然发现程序在运行了几分钟之后所有的任务都不再调用了,只有几个中断能正常使用,看来是系统挂掉了,连续测试了几次想找出问题,可是这个真的有点不知所措.      我 ...

  8. Keil环境中建立带FreeRTOS的STM32L项目

    本文是网上转载,版权所有. Keil环境中建立带FreeRTOS的STM32L项目 1.先把source文件夹复制至project目录,然后在keil中添加RTOS文件,如图: 其中heap_2.c按 ...

  9. FreeRTOS学习及移植笔记之二:在IAR和STM32F103VET上移植FreeRTOS

    上一次,我们简单的测试了FreeRTOS的基于IAR EWARM v6.4和STM32F103VET6平台的Demo,对其有了一个基本认识.接下来我们开始自己移植FreeRTOS的过程. 1.创建一个 ...

随机推荐

  1. java 中函数的参数传递详细介绍

    java中函数的参数传递 总结: 1.将对象(对象的引用)作为参数传递时传递的是引用(相当于指针).也就是说函数内对参数所做的修改会影响原来的对象.  2.当将基本类型或基本类型的包装集作为参数传递时 ...

  2. Linux下读取RFID卡号(C串口编程)

    由于项目需要用到RFID.GPRS.摄像头等模块所以便看了一下,整理了一下学习思路,本篇先是整理一下串口读取RFID卡号的程序思路,后面还会更其他的 RFID模块: 本次采用的是125K的RFID读卡 ...

  3. HTML5-IOS WEB APP应用程序(IOS META)

    触摸屏网站的开发其实现在来讲比前几年移动端网站开发好多了,触摸屏设备IOS.Android.BBOS6等系统自带浏览器均为WEBKIT核心,这就说明PC上面尚未立行的HTML5 CSS3能够运用在这里 ...

  4. ES6 中 Symbol.split的用法

    class Split1 { constructor(value) { this.value = value; } [Symbol.split](string) { var index = strin ...

  5. java通过反射调用不同参数的方法

    import java.lang.reflect.Method; public class testReflect { /** * @param args */ public static void ...

  6. 最短路+状态压缩dp(旅行商问题)hdu-4568-Hunter

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4568 题目大意: 给一个矩阵 n*m (n m<=200),方格里如果是0~9表示通过它时要花 ...

  7. iOS socket Stream 服务器端 及 客户端 演示

    iOS socket Stream 测试环境,mac osx 10.8 一:建立服务器端 由于mac osx10.8 已经集成 python2和 Twisted,我们可以直接利用此,构建一个简单的so ...

  8. 【转】DNS查询过程

    DNS查询过程 DNS的查询过程是指在客户端通过DNS服务器将一个IP地址转换为一个FQDN(Fully Qualified Domain Name,完全合格的域名),或将一个FQDN转化为一个IP地 ...

  9. AsyncTask doinbackground onProgressUpdate onCancelled onPostExecute的基本使用

    对于异步操作的原理我就不讲了.在这我着重讲怎么使用异步操作的doinbackground onProgressUpdate onCancelled onPostExecute这四个方法 doinbac ...

  10. 彻底告别加解密模块代码拷贝-JCE核心Cpiher详解

    前提 javax.crypto.Cipher,翻译为密码,其实叫做密码器更加合适.Cipher是JCA(Java Cryptographic Extension,Java加密扩展)的核心,提供基于多种 ...