在STM32下完成基于FreeRTOS的多任务程序
一、FreeRTOS简介
作为一个轻量级的操作系统,FreeRTOS提供的功能包括:任务管理、时间管理、信号量、消息队列、内存管理、记录功能等,可基本满足较小系统的需要。FreeRTOS内核支持优先级调度算法,每个任务可根据重要程度的不同被赋予一定的优先级,CPU总是让处于就绪态的、优先级最高的任务先运行。FreeRT0S内核同时支持轮换调度算法,系统允许不同的任务使用相同的优先级,在没有更高优先级任务就绪的情况下,同一优先级的任务共享CPU的使用时间。FreeRTOS的内核可根据用户需要设置为可剥夺型内核或不可剥夺型内核。当FreeRTOS被设置为可剥夺型内核时,处于就绪态的高优先级任务能剥夺低优先级任务的CPU使用权,这样可保证系统满足实时性的要求;当FreeRTOS被设置为不可剥夺型内核时,处于就绪态的高优先级任务只有等当前运行任务主动释放CPU的使用权后才能获得运行,这样可提高CPU的运行效率。
二、任务要求
学习FreeRTOS原理,在STM32下完成一个基于FreeRTOS的多任务程序,执行3个周期性task。
task1:每间隔500ms闪烁(变化)一次LED;
task2:每间隔2000ms,向串口发送一次指令数据“helloworld!";
task3:每间隔5000ms,从AHT20采集一次温湿度数据
(不考虑硬件情况,仅写出整个多任务框架模拟代码)。
三、具体过程
1.FreeRTOS相关代码
根据提供的资料,打开相应的keil文件代码。
2.修改代码
本人是选择led的相关代码进行修改。
(1)task1,每间隔500ms闪烁(变化)一次LED。
①main.c里面找到任务句柄语句,可以不做修改。
static TaskHandle_t LED_Task_Handle = NULL;
②main.c里面找到函数声明语句,可以不做修改。
static void LED_Task(void* pvParameters);
③在AppTaskCreate函数里面,找到创建的LED任务,查看代码。
xReturn = xTaskCreate((TaskFunction_t )LED_Task,
(const char* )"LED_Task",
(uint16_t )512,
(void* )NULL,
(UBaseType_t )2,
(TaskHandle_t* )&LED_Task_Handle);
if(pdPASS == xReturn)
printf("´´½¨LED_TaskÈÎÎñ³É¹¦!\r\n");
④在程序里面找到相关函数,可以不做修改(完成的功能为间隔500ms,使得LED灯亮或者熄灭)。
static void LED_Task(void* parameter)
{
while (1)
{
LED1_ON;
vTaskDelay(500);
printf("LED_Task Running,LED1_ON\r\n");
LED1_OFF;
vTaskDelay(500);
printf("LED_Task Running,LED1_OFF\r\n");
}
}
⑤到此有关task1的相关函数完成。
(2)task2,每间隔2000ms,向串口发送一次指令数据“helloworld!"。
①main.c里面找到任务句柄语句,添加如下代码。
static TaskHandle_t HELLO_Task_Handle = NULL; /* HELLO任务句柄*/
②main.c里面找到函数声明,为HELLO任务进行函数声明,不然后面引用会报错。
static void HELLO_Task(void* pvParameters);
③在AppTaskCreate函数里面,创建HELLO任务,可以模仿LED任务进行修改,只需要修改任务入口函数、任务的名称、任务的优先级、任务控制块指针。
xReturn = xTaskCreate((TaskFunction_t )HELLO_Task, /* 任务入口函数 */
(const char* )"HELLO_Task",/* 任务的名称 */
(uint16_t )512, /* 任务栈大小 */
(void* )NULL, /* 任务入口函数 */
(UBaseType_t )3, /* 任务的优先级 */
(TaskHandle_t* )&HELLO_Task_Handle);/* 任务控制块指针 */
if(pdPASS == xReturn)
printf("创建HELLO_Task任务成功!\r\n");
④在程序添加HELLO_Task函数(完成功能为每间隔2000ms,向串口发送一次指令数据“helloworld!")。
static void HELLO_Task(void* pvParameters)
{
while(1)
{
vTaskDelay(2000); /* 延时发送2000个tick */
printf("helloword!");
}
}
⑤到此有关task2的相关函数完成。
(3)每间隔5000ms,从AHT20采集一次温湿度数据(不考虑硬件情况,仅写出了整个多任务框架模拟代码)。
①main.c里面找到任务句柄语句,添加如下代码。
static TaskHandle_t AHT_Task_Handle = NULL;
②main.c里面找到函数声明,为HELLO任务进行函数声明。
static void AHT_Task(void* pvParameters);
③在AppTaskCreate函数里面,创建HELLO任务。
xReturn = xTaskCreate((TaskFunction_t )AHT_Task,
(const char* )"AHT_Task",
(uint16_t )512,
(void* )NULL,
(UBaseType_t )4,
(TaskHandle_t* )&AHT_Task_Handle);
if(pdPASS == xReturn)
printf("´´½¨AHT_TaskÈÎÎñ³É¹¦!\r\n");
④在程序添加AHT_Task函数(每间隔5000ms,从AHT20采集一次温湿度数据)。
static void AHT_Task(void* pvParameters)
{
while(1)
{
vTaskDelay(5000); /* ÑÓʱ5000¸ötick */
printf("硬件不全,延迟5000ms输出该提示信息");
}
}
⑤到此有关task3的相关函数完成。
3.整体main.c代码
/**
*********************************************************************
* @file main.c
* @author fire
* @version V1.0
* @date 2018-xx-xx
* @brief FreeRTOS v9.0.0 + STM32 ¶¯Ì¬´´½¨ÈÎÎñ
*********************************************************************
* @attention
*
* ʵÑéƽ̨:Ò°»ð STM32ȫϵÁпª·¢°å
* ÂÛ̳ :http://www.firebbs.cn
* ÌÔ±¦ :https://fire-stm32.taobao.com
*
**********************************************************************
*/
/*
*************************************************************************
* °üº¬µÄÍ·Îļþ
*************************************************************************
*/
/* FreeRTOSÍ·Îļþ */
#include "FreeRTOS.h"
#include "task.h"
/* ¿ª·¢°åÓ²¼þbspÍ·Îļþ */
#include "bsp_led.h"
#include "bsp_usart.h"
/**************************** ÈÎÎñ¾ä±ú ********************************/
/*
* ÈÎÎñ¾ä±úÊÇÒ»¸öÖ¸Õ룬ÓÃÓÚÖ¸ÏòÒ»¸öÈÎÎñ£¬µ±ÈÎÎñ´´½¨ºÃÖ®ºó£¬Ëü¾Í¾ßÓÐÁËÒ»¸öÈÎÎñ¾ä±ú
* ÒÔºóÎÒÃÇÒªÏë²Ù×÷Õâ¸öÈÎÎñ¶¼ÐèҪͨ¹ýÕâ¸öÈÎÎñ¾ä±ú£¬Èç¹ûÊÇ×ÔÉíµÄÈÎÎñ²Ù×÷×Ô¼º£¬ÄÇô
* Õâ¸ö¾ä±ú¿ÉÒÔΪNULL¡£
*/
/* ´´½¨ÈÎÎñ¾ä±ú */
static TaskHandle_t AppTaskCreate_Handle = NULL;
/* LEDÈÎÎñ¾ä±ú */
static TaskHandle_t LED_Task_Handle = NULL;
static TaskHandle_t HELLO_Task_Handle = NULL; /* HelloÈÎÎñ¾ä±ú*/
static TaskHandle_t AHT_Task_Handle = NULL; /* AHTÈÎÎñ¾ä±ú*/
/********************************** Äں˶ÔÏó¾ä±ú *********************************/
/*
* ÐźÅÁ¿£¬ÏûÏ¢¶ÓÁУ¬Ê¼þ±êÖ¾×飬Èí¼þ¶¨Ê±Æ÷ÕâЩ¶¼ÊôÓÚÄں˵ĶÔÏó£¬ÒªÏëʹÓÃÕâЩÄÚºË
* ¶ÔÏ󣬱ØÐëÏÈ´´½¨£¬´´½¨³É¹¦Ö®ºó»á·µ»ØÒ»¸öÏàÓ¦µÄ¾ä±ú¡£Êµ¼ÊÉϾÍÊÇÒ»¸öÖ¸Õ룬ºóÐøÎÒ
* ÃǾͿÉÒÔͨ¹ýÕâ¸ö¾ä±ú²Ù×÷ÕâЩÄں˶ÔÏó¡£
*
* Äں˶ÔÏó˵°×Á˾ÍÊÇÒ»ÖÖÈ«¾ÖµÄÊý¾Ý½á¹¹£¬Í¨¹ýÕâЩÊý¾Ý½á¹¹ÎÒÃÇ¿ÉÒÔʵÏÖÈÎÎñ¼äµÄͨÐÅ£¬
* ÈÎÎñ¼äµÄʼþͬ²½µÈ¸÷ÖÖ¹¦ÄÜ¡£ÖÁÓÚÕâЩ¹¦ÄܵÄʵÏÖÎÒÃÇÊÇͨ¹ýµ÷ÓÃÕâЩÄں˶ÔÏóµÄº¯Êý
* À´Íê³ÉµÄ
*
*/
/******************************* È«¾Ö±äÁ¿ÉùÃ÷ ************************************/
/*
* µ±ÎÒÃÇÔÚдӦÓóÌÐòµÄʱºò£¬¿ÉÄÜÐèÒªÓõ½Ò»Ð©È«¾Ö±äÁ¿¡£
*/
/*
*************************************************************************
* º¯ÊýÉùÃ÷
*************************************************************************
*/
static void AppTaskCreate(void);/* ÓÃÓÚ´´½¨ÈÎÎñ */
static void LED_Task(void* pvParameters);/* LED_TaskÈÎÎñʵÏÖ */
static void HELLO_Task(void* pvParameters);/* HELLO_TaskÈÎÎñʵÏÖ */
static void AHT_Task(void* pvParameters);/* AHT_TaskÈÎÎñʵÏÖ */
static void BSP_Init(void);/* ÓÃÓÚ³õʼ»¯°åÔØÏà¹Ø×ÊÔ´ */
/*****************************************************************
* @brief Ö÷º¯Êý
* @param ÎÞ
* @retval ÎÞ
* @note µÚÒ»²½£º¿ª·¢°åÓ²¼þ³õʼ»¯
µÚ¶þ²½£º´´½¨APPÓ¦ÓÃÈÎÎñ
µÚÈý²½£ºÆô¶¯FreeRTOS£¬¿ªÊ¼¶àÈÎÎñµ÷¶È
****************************************************************/
int main(void)
{
BaseType_t xReturn = pdPASS;/* ¶¨ÒåÒ»¸ö´´½¨ÐÅÏ¢·µ»ØÖµ£¬Ä¬ÈÏΪpdPASS */
/* ¿ª·¢°åÓ²¼þ³õʼ»¯ */
BSP_Init();
printf("ÕâÊÇÒ»¸ö[Ò°»ð]-STM32ȫϵÁпª·¢°å-FreeRTOS-¶¯Ì¬´´½¨ÈÎÎñ!\r\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); /* Õý³£²»»áÖ´Ðе½ÕâÀï */
}
/***********************************************************************
* @ º¯ÊýÃû £º AppTaskCreate
* @ ¹¦ÄÜ˵Ã÷£º ΪÁË·½±ã¹ÜÀí£¬ËùÓеÄÈÎÎñ´´½¨º¯Êý¶¼·ÅÔÚÕâ¸öº¯ÊýÀïÃæ
* @ ²ÎÊý £º ÎÞ
* @ ·µ»ØÖµ £º ÎÞ
**********************************************************************/
static void AppTaskCreate(void)
{
BaseType_t xReturn = pdPASS;/* ¶¨ÒåÒ»¸ö´´½¨ÐÅÏ¢·µ»ØÖµ£¬Ä¬ÈÏΪpdPASS */
taskENTER_CRITICAL(); //½øÈëÁÙ½çÇø
/* ´´½¨LED_TaskÈÎÎñ */
xReturn = xTaskCreate((TaskFunction_t )LED_Task, /* ÈÎÎñÈë¿Úº¯Êý */
(const char* )"LED_Task",/* ÈÎÎñÃû×Ö */
(uint16_t )512, /* ÈÎÎñÕ»´óС */
(void* )NULL, /* ÈÎÎñÈë¿Úº¯Êý²ÎÊý */
(UBaseType_t )2, /* ÈÎÎñµÄÓÅÏȼ¶ */
(TaskHandle_t* )&LED_Task_Handle);/* ÈÎÎñ¿ØÖÆ¿éÖ¸Õë */
if(pdPASS == xReturn)
printf("´´½¨LED_TaskÈÎÎñ³É¹¦!\r\n");
/* ´´½¨HELLO_TaskÈÎÎñ */
xReturn = xTaskCreate((TaskFunction_t )HELLO_Task, /* ÈÎÎñÈë¿Úº¯Êý */
(const char* )"HELLO_Task",/* ÈÎÎñÃû×Ö */
(uint16_t )512, /* ÈÎÎñÕ»´óС */
(void* )NULL, /* ÈÎÎñÈë¿Úº¯Êý²ÎÊý */
(UBaseType_t )3, /* ÈÎÎñµÄÓÅÏȼ¶ */
(TaskHandle_t* )&HELLO_Task_Handle);/* ÈÎÎñ¿ØÖÆ¿éÖ¸Õë */
if(pdPASS == xReturn)
printf("´´½¨HELLO_TaskÈÎÎñ³É¹¦!\r\n");
/* ´´½¨AHT_TaskÈÎÎñ */
xReturn = xTaskCreate((TaskFunction_t )AHT_Task, /* ÈÎÎñÈë¿Úº¯Êý */
(const char* )"AHT_Task",/* ÈÎÎñÃû×Ö */
(uint16_t )512, /* ÈÎÎñÕ»´óС */
(void* )NULL, /* ÈÎÎñÈë¿Úº¯Êý²ÎÊý */
(UBaseType_t )4, /* ÈÎÎñµÄÓÅÏȼ¶ */
(TaskHandle_t* )&AHT_Task_Handle);/* ÈÎÎñ¿ØÖÆ¿éÖ¸Õë */
if(pdPASS == xReturn)
printf("´´½¨AHT_TaskÈÎÎñ³É¹¦!\r\n");
vTaskDelete(AppTaskCreate_Handle); //ɾ³ýAppTaskCreateÈÎÎñ
taskEXIT_CRITICAL(); //Í˳öÁÙ½çÇø
}
/**********************************************************************
* @ º¯ÊýÃû £º LED_Task
* @ ¹¦ÄÜ˵Ã÷£º LED_TaskÈÎÎñÖ÷Ìå
* @ ²ÎÊý £º
* @ ·µ»ØÖµ £º ÎÞ
********************************************************************/
static void LED_Task(void* parameter)
{
while (1)
{
LED1_ON;
vTaskDelay(500); /* ÑÓʱ500¸ötick */
printf("LED_Task Running,LED1_ON\r\n");
LED1_OFF;
vTaskDelay(500); /* ÑÓʱ500¸ötick */
printf("LED_Task Running,LED1_OFF\r\n");
}
}
/**********************************************************************
* @ º¯ÊýÃû £º HELLO_Task
* @ ¹¦ÄÜ˵Ã÷£º HELLO_TaskÈÎÎñÖ÷Ìå
* @ ²ÎÊý £º
* @ ·µ»ØÖµ £º ÎÞ
********************************************************************/
static void HELLO_Task(void* pvParameters)
{
while(1)
{
vTaskDelay(2000); /* ÑÓʱ2000¸ötick */
printf("helloword!"); /*·¢ËÍhelloword£¡Ö¸Áî*/
}
}
/**********************************************************************
* @ º¯ÊýÃû £º AHT_Task
* @ ¹¦ÄÜ˵Ã÷£º AHT_TaskÈÎÎñÖ÷Ìå
* @ ²ÎÊý £º
* @ ·µ»ØÖµ £º ÎÞ
********************************************************************/
static void AHT_Task(void* pvParameters)
{
while(1)
{
vTaskDelay(5000); /* ÑÓʱ5000¸ötick */
printf("Ó²¼þ²»È«£¬ÑÓ³Ù5000msÊä³ö¸ÃÌáʾÐÅÏ¢");
}
}
/***********************************************************************
* @ º¯ÊýÃû £º BSP_Init
* @ ¹¦ÄÜ˵Ã÷£º °å¼¶ÍâÉè³õʼ»¯£¬ËùÓаå×ÓÉϵijõʼ»¯¾ù¿É·ÅÔÚÕâ¸öº¯ÊýÀïÃæ
* @ ²ÎÊý £º
* @ ·µ»ØÖµ £º ÎÞ
*********************************************************************/
static void BSP_Init(void)
{
/*
* STM32ÖжÏÓÅÏȼ¶·Ö×éΪ4£¬¼´4bit¶¼ÓÃÀ´±íʾÇÀÕ¼ÓÅÏȼ¶£¬·¶Î§Îª£º0~15
* ÓÅÏȼ¶·Ö×éÖ»ÐèÒª·Ö×éÒ»´Î¼´¿É£¬ÒÔºóÈç¹ûÓÐÆäËûµÄÈÎÎñÐèÒªÓõ½Öжϣ¬
* ¶¼Í³Ò»ÓÃÕâ¸öÓÅÏȼ¶·Ö×飬ǧÍò²»ÒªÔÙ·Ö×飬Çмɡ£
*/
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
/* LED ³õʼ»¯ */
LED_GPIO_Config();
/* ´®¿Ú³õʼ»¯ */
USART_Config();
}
/********************************END OF FILE****************************/
在下直接从keil中复制过来的,乱码部分是注释,不影响程序正常运行
4.创建程序
5.生成hex文件
选中工程,右击选中第一个,弹出如下窗口,按照下图进行设置,一定要生成hex文件!
6.烧录
①将电脑与板子连接好,注意检查不要连接错误。
②安装野火资料里的CH340驱动。
③安装野火资料里面的mcuisp,并导入刚刚生成的hex文件。
6.实验结果。
根据设置500msLED灯亮或者熄灭,2000ms发送“helloword!”。
四、总结
野火提供的相关资料很全面,可以直接找到FreeRTOS的相关程序代码,在已有代码的基础上进行修改,难度和工作量大大减少。同时,本次实验将软件和硬件结合起来,体会到了玩电子的快乐!