STM32下完成一个基于FreeRTOS的多任务程序
简介
①实时操作系统(Real-time operating system, RTOS),
又称即时操作系统,它会按照排序运行、管理系统资源,并为开发应用程序提供一致的基础。
实时操作系统与一般的操作系统相比,最大的特色就是“实时性”,如果有一个任务需要执行,实时操作系统会马上(在较短时间内)执行该任务,不会有较长的延时。这种特性保证了各个任务的及时执行。我们刚刚开始记住“实时”就可以了,其他的后面再学。
了解完实时操作系统的定义,就来数一数目前主流的实时操作系统了。常见的实时操作系统有FreeRTOS、uCOS 等,国内比较著名的实时操作系统有RT-thread 和Huawei LiteOS 等。这次说的主要是FreeRTOS系统,因为它是世界上主流的实时操作系统之一,并且开源,小巧,免费,经过多年的风风雨雨,它已经有充足的资料提供给他人查阅,不用担心学习的过程中找不到资料。
②Free RTOS
FreeRTOS是当下热门的操作系统之一,并且开源免费,相较于ucos这个系统来说代码量比较小,能够移植到大部分微处理器上,特别适合新入门的学习。
FreeRTOS是一个迷你的实时操作系统内核。作为一个轻量级的操作系统,功能包括:任务管理、时间管理、信号量、消息队列、内存管理、记录功能、软件定时器、协程等,可基本满足较小系统的需要。任务调度机制是嵌入式实时操作系统的一个重要概念,也是其核心技术。对于可剥夺型内核,优先级高的任务一旦就绪就能剥夺优先级较低任务的CPU使用权,提高了系统的实时响应能力。不同于μC/OS-II,FreeRTOS对系统任务的数量没有限制,既支持优先级调度算法也支持轮换调度算法,因此FreeRTOS采用双向链表而不是采用查任务就绪表的方法来进行任务调度。(任务调度这些有兴趣可以看看计算机操作系统那本书了解了解。)
任务
学习FreeRTOS原理,在STM32下完成一个基于FreeRTOS的多任务程序,执行3个周期性task,具体任务不限,但建议如下:
task1,每间隔500ms闪烁(变化)一次LED;
task2,每间隔2000ms,向串口发送一次指令数据“helloworld!";
task3,每间隔5000ms,从AHT20采集一次温湿度数据(不考虑硬件情况,仅写出整个多任务框架模拟代码)。
实现
这次实现的环境是在野火的MINI开发板中实现的,因此可以获得很多官方的资料;在官方资料里面已经给我们搭建了一个整体的框架,我们只需要在这个框架下面添加一些我们需要的任务代码就可以了。
链接:https://pan.baidu.com/s/1i8ww5jAd_vF46K8jhgrI8A
提取码:3l25
上面的哪个资料里面有MINI的大部分资料,需要的可以自行下载学习
1、我们在下载了官方的资料之后,可以找到官方提供的一个移植的压缩包
选择下面的任务文件
2、打开解压之后的文件之后,可以在Project下面找到一个KEIL5的工程文件,直接打开之后就会看到官方为我们搭建的架构了。
3、部分代码分析
在这个框架里面已经为我们定义好了我们创建多任务所需要的所有环境。需要的头文件都已经为我们准备好了。
①任务句柄
static TaskHandle_t AppTaskCreate_Handle = NULL;
static TaskHandle_t LED1_Task_Handle = NULL;
static TaskHandle_t LED2_Task_Handle = NULL;
static TaskHandle_t Hello_Task_Handle = NULL;
很明显这是创建了4个任务,其中第一个是用来创建任务,通过这个启动任务调度,开始执行下面的3个任务,下面的3个任务就是我们自己创建的了,通过名字就知道这些任务的作用。
②创建任务
xReturn = xTaskCreate((TaskFunction_t )LED2_Task, /* ÈÎÎñÈë¿Úº¯Êý */
(const char* )"LED2_Task",/* ÈÎÎñÃû×Ö */
(uint16_t )512, /* ÈÎÎñÕ»´óС */
(void* )NULL, /* ÈÎÎñÈë¿Úº¯Êý²ÎÊý */
(UBaseType_t )3, /* ÈÎÎñµÄÓÅÏȼ¶ */
(TaskHandle_t* )&LED2_Task_Handle);/* ÈÎÎñ¿ØÖÆ¿éÖ¸Õë */
if(pdPASS == xReturn)
printf("´´½¨LED2_TaskÈÎÎñ³É¹¦!\r\n\n");
这个就是对我们需要创建的任务进行一些初始化之类的定义具体的意义为:
任务入口函数
任务名字
任务栈大小
任务入口函数参数
任务的优先级
任务控制块指针
这之后我们才可以在这个任务里里面添加自己所要执行的具体任务。
4、代码写好之后运行编译没有错误就可以将代码烧到MINI开发板中了。
在这里我用的下载线是ST-LINK,直接用数据线连接到了MINI中的串口里面。
在KEIL5里配置下载环境。
①点击魔术棒,选择Debug
②进入setting,选择如下,此时如果没有错就会出现你的Devivce Name
③选择Flash Download,按图勾选。在下面添加ADD中的第一个。
这样配置好之后就可以下载到MINI中了。
结果
实验的结果
串口发送的数据
主代码
#include "FreeRTOS.h"
#include "task.h"
#include "bsp_led.h"
#include "bsp_usart.h"
static TaskHandle_t AppTaskCreate_Handle = NULL;
static TaskHandle_t LED1_Task_Handle = NULL;
static TaskHandle_t LED2_Task_Handle = NULL;
static TaskHandle_t Hello_Task_Handle = NULL;
static TaskHandle_t WD_Task_Handle = NULL;
static void AppTaskCreate(void);
static void LED1_Task(void* pvParameters);
static void LED2_Task(void* pvParameters);
static void Hello_Task(void* pvParameters);
static void WD_Task(void* pvParameters);
static void BSP_Init(void);
int main(void)
{
BaseType_t xReturn = pdPASS;/* ¶¨ÒåÒ»¸ö´´½¨ÐÅÏ¢·µ»ØÖµ£¬Ä¬ÈÏΪpdPASS */
/* ¿ª·¢°åÓ²¼þ³õʼ»¯ */
BSP_Init();
printf("ÕâÊÇÒ»¸ö[Ò°»ð]-STM32ȫϵÁпª·¢°å-FreeRTOS-¶¯Ì¬´´½¨¶àÈÎÎñʵÑé!\r\n\n");
/* ´´½¨AppTaskCreateÈÎÎñ */
xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate, /* ÈÎÎñÈë¿Úº¯Êý */
(const char* )"AppTaskCreate",/* ÈÎÎñÃû×Ö */
(uint16_t )512, /* ÈÎÎñÕ»´óС */
(void* )NULL,/* ÈÎÎñÈë¿Úº¯Êý²ÎÊý */
(UBaseType_t )1, /* ÈÎÎñµÄÓÅÏȼ¶ */
(TaskHandle_t* )&AppTaskCreate_Handle);/* ÈÎÎñ¿ØÖÆ¿éÖ¸Õë */
/* Æô¶¯ÈÎÎñµ÷¶È */
if(pdPASS == xReturn)
vTaskStartScheduler(); /* Æô¶¯ÈÎÎñ£¬¿ªÆôµ÷¶È */
else
return -1;
while(1); /* Õý³£²»»áÖ´Ðе½ÕâÀï */
}
static void AppTaskCreate(void)
{
BaseType_t xReturn = pdPASS;/* ¶¨ÒåÒ»¸ö´´½¨ÐÅÏ¢·µ»ØÖµ£¬Ä¬ÈÏΪpdPASS */
taskENTER_CRITICAL(); //½øÈëÁÙ½çÇø
/* ´´½¨LED1_TaskÈÎÎñ */
xReturn = xTaskCreate((TaskFunction_t )LED1_Task, /* ÈÎÎñÈë¿Úº¯Êý */
(const char* )"LED1_Task",/* ÈÎÎñÃû×Ö */
(uint16_t )512, /* ÈÎÎñÕ»´óС */
(void* )NULL, /* ÈÎÎñÈë¿Úº¯Êý²ÎÊý */
(UBaseType_t )2, /* ÈÎÎñµÄÓÅÏȼ¶ */
(TaskHandle_t* )&LED1_Task_Handle);/* ÈÎÎñ¿ØÖÆ¿éÖ¸Õë */
if(pdPASS == xReturn)
printf("´´½¨LED1_TaskÈÎÎñ³É¹¦!\r\n\n");
/* ´´½¨LED2_TaskÈÎÎñ */
xReturn = xTaskCreate((TaskFunction_t )LED2_Task, /* ÈÎÎñÈë¿Úº¯Êý */
(const char* )"LED2_Task",/* ÈÎÎñÃû×Ö */
(uint16_t )512, /* ÈÎÎñÕ»´óС */
(void* )NULL, /* ÈÎÎñÈë¿Úº¯Êý²ÎÊý */
(UBaseType_t )3, /* ÈÎÎñµÄÓÅÏȼ¶ */
(TaskHandle_t* )&LED2_Task_Handle);/* ÈÎÎñ¿ØÖÆ¿éÖ¸Õë */
if(pdPASS == xReturn)
printf("´´½¨LED2_TaskÈÎÎñ³É¹¦!\r\n\n");
xReturn = xTaskCreate((TaskFunction_t )Hello_Task, /* ÈÎÎñÈë¿Úº¯Êý */
(const char* )"Hello_Task",/* ÈÎÎñÃû×Ö */
(uint16_t )512, /* ÈÎÎñÕ»´óС */
(void* )NULL, /* ÈÎÎñÈë¿Úº¯Êý²ÎÊý */
(UBaseType_t )4, /* ÈÎÎñµÄÓÅÏȼ¶ */
(TaskHandle_t* )&Hello_Task_Handle);/* ÈÎÎñ¿ØÖÆ¿éÖ¸Õë */
if(pdPASS == xReturn)
printf("´´½¨Hello_TaskÈÎÎñ³É¹¦!\r\n\n");
xReturn = xTaskCreate((TaskFunction_t )WD_Task, /* ÈÎÎñÈë¿Úº¯Êý */
(const char* )"WD_Task",/* ÈÎÎñÃû×Ö */
(uint16_t )512, /* ÈÎÎñÕ»´óС */
(void* )NULL, /* ÈÎÎñÈë¿Úº¯Êý²ÎÊý */
(UBaseType_t )5, /* ÈÎÎñµÄÓÅÏȼ¶ */
(TaskHandle_t* )&WD_Task_Handle);/* ÈÎÎñ¿ØÖÆ¿éÖ¸Õë */
if(pdPASS == xReturn)
printf("´´½¨Wd_TaskÈÎÎñ³É¹¦!\r\n\n");
vTaskDelete(AppTaskCreate_Handle); //ɾ³ýAppTaskCreateÈÎÎñ
taskEXIT_CRITICAL(); //Í˳öÁÙ½çÇø
}
static void LED1_Task(void* parameter)
{
while (1)
{
LED1_ON;
vTaskDelay(500); /* ÑÓʱ500¸ötick */
printf("LED1_Task Running,LED1_ON\r\n");
LED1_OFF;
vTaskDelay(500); /* ÑÓʱ500¸ötick */
printf("LED1_Task Running,LED1_OFF\r\n");
}
}
static void LED2_Task(void* parameter)
{
while (1)
{
LED2_ON;
vTaskDelay(500); /* ÑÓʱ500¸ötick */
printf("LED2_Task Running,LED2_ON\r\n");
LED2_OFF;
vTaskDelay(500); /* ÑÓʱ500¸ötick */
printf("LED2_Task Running,LED2_OFF\r\n");
}
}
static void Hello_Task(void* parameter)
{
while(1)
{
vTaskDelay(2000);
printf("Êä³ö³É¹¦\r\n");
}
}
static void WD_Task(void* parameter)
{
while(1)
{
vTaskDelay(5000);
printf("ûÓÐÓ²¼þ\r\n");
}
}
static void BSP_Init(void)
{
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
LED_GPIO_Config();
USART_Config();
}
上一篇: ubuntu中配置samba