声明:本专栏参考韦东山,野火,正点原子以及其他博主的FreeRTOS教程,如若侵权请告知,马上删帖致歉,个人总结,如有不对,欢迎指正。
- 转:同步与互斥概念理解link
- 实验一:同步
- 实验代码
- 划重点
- 创建队列任务句柄,在这之前得要加入队列头文件
- 创建队列函数
- 各任务处理事件
- 实验二:互斥
- 实验代码
- 划重点
还是来看看同步实验怎么做吧
/**
FreeRTOS v9.0.0 + STM32 动态创建任务
实验平台:韦东山 STM32F103ZE开发板
**/
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
/* 开发板硬件bsp头文件 */
#include "bsp_led.h"
#include "bsp_usart.h"
/* 任务句柄 */
static TaskHandle_t AppTaskCreate_Handle = NULL;
static TaskHandle_t Task1_Handle = NULL;
static TaskHandle_t Task2_Handle = NULL;
static TaskHandle_t Task3_Handle = NULL;
static xQueueHandle MsgQueue; /*队列句柄*/
/* 函数声明 */
static void AppTaskCreate(void);/* 用于创建任务 */
static void Flag1_Task(void* pvParameters);/* LED1_Task任务实现 */
static void Flag2_Task(void* pvParameters);/* LED2_Task任务实现 */
static void Flag3_Task(void* pvParameters);/* LED3_Task任务实现 */
static void BSP_Init(void);/* 用于初始化板载相关资源 */
/*****************************************************************
* @brief 主函数
* @param 无
* @retval 无
* @note 第一步:开发板硬件初始化
第二步:创建APP应用任务
第三步:启动FreeRTOS,开始多任务调度
****************************************************************/
int main(void)
{
BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */
/* 开发板硬件初始化 */
BSP_Init();
printf("这是一个STM32F103ZE开发板-FreeRTOS-动态创建任务!\r\n");
MsgQueue=xQueueCreate(1,sizeof(int));/*创建队列:参数,队列长度,每个长度大小(字节)*/
/* 创建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(); //进入临界区
/* 创建Flag1_Task任务 */
xReturn = xTaskCreate((TaskFunction_t )Flag1_Task, /* 任务入口函数 */
(const char* )"Flag1_Task",/* 任务名字 */
(uint16_t )512, /* 任务栈大小 */
(void* )NULL, /* 任务入口函数参数 */
(UBaseType_t )2, /* 任务的优先级 */
(TaskHandle_t* )&Task1_Handle);/* 任务控制块指针 */
if(pdPASS == xReturn)
printf("创建Flag1_Task任务成功!\r\n");
/* 创建Flag2_Task任务 */
xReturn = xTaskCreate((TaskFunction_t )Flag2_Task, /* 任务入口函数 */
(const char* )"Flag2_Task",/* 任务名字 */
(uint16_t )512, /* 任务栈大小 */
(void* )NULL, /* 任务入口函数参数 */
(UBaseType_t )2, /* 任务的优先级 */
(TaskHandle_t* )&Task2_Handle);/* 任务控制块指针 */
if(pdPASS == xReturn)
printf("创建Flag2_Task任务成功!\r\n");
/* 创建Flag3_Task任务 */
xReturn = xTaskCreate((TaskFunction_t )Flag3_Task, /* 任务入口函数 */
(const char* )"Flag3_Task",/* 任务名字 */
(uint16_t )512, /* 任务栈大小 */
(void* )NULL, /* 任务入口函数参数 */
(UBaseType_t )1, /* 任务的优先级 */
(TaskHandle_t* )&Task3_Handle);/* 任务控制块指针 */
if(pdPASS == xReturn)
printf("创建Flag3_Task任务成功!\r\n");
vTaskDelete(AppTaskCreate_Handle); //删除AppTaskCreate任务
taskEXIT_CRITICAL(); //退出临界区
}
/**********************************************************************
* @ 函数名 : LED_Task
* @ 功能说明: LED_Task任务主体
********************************************************************/
uint8_t flag1;
uint8_t flag2;
uint8_t flag3;
/*优先级2*/
static void Flag1_Task(void* parameter)
{
static int value,i;
while (1)
{
for(i=10000;i>1;i--)
flag1=1;
flag2=0;
flag3=0;
/* 向队列中填充内容 */
value++;
printf("Task1 Running! value=%d\r\n",value);
xQueueSend( MsgQueue, ( void* )&value, queueSEND_TO_BACK); /*发送队列消息,*/
// vTaskDelay(10); /* 延时1个tick */
}
}
/*优先级2*/
static void Flag2_Task(void* parameter)
{
static int value1;
while (1)
{
/*如果读取到队列消息*/
if(xQueueReceive(MsgQueue,(void *)&value1,pdFALSE)==pdPASS)
{
flag1=0;
flag2=1;
flag3=0;
printf("Task2 Running! value=%d\r\n",value1);/*将读取到的数值打印出来*/
}
//vTaskDelay(10); /* 延时1个tick */
}
}
/*优先级2*/
static void Flag3_Task(void* parameter)
{
static int value2;
while (1)
{
flag1=0;
flag2=0;
flag3=1;
printf("Task3 Running! value=%d\r\n",value2);
vTaskDelay(10); /* 延时1个tick */
}
}
/***********************************************************************
* @ 函数名 : BSP_Init
* @ 功能说明: 板级外设初始化,所有板子上的初始化均可放在这个函数里面
* @ 参数 :
* @ 返回值 : 无
*********************************************************************/
static void BSP_Init(void)
{
/*
* STM32中断优先级分组为4,即4bit都用来表示抢占优先级,范围为:0~15
* 优先级分组只需要分组一次即可,以后如果有其他的任务需要用到中断,
* 都统一用这个优先级分组,千万不要再分组,切忌。
*/
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
/* LED 初始化 */
LED_GPIO_Config();
/* 串口初始化 */
USART_Config();
}
/********************************END OF FILE****************************/
flag3Task
根据以上信息可以猜想任务运行过程是怎样的???
任务一和任务二在执行过程中都没有进入到阻塞状态,任务3的优先级是要比任务一和任务二要低的,所以任务三肯定不会运行,那么任务一和任务二相同优先级要如何运行呢??
直接仿真看看
神奇的是串口居然不乱了,任务一先运行,接着任务二打印了信息,这就是通过队列传递信息来实现任务同步
再来做个实验看看任务互斥
/**
FreeRTOS v9.0.0 + STM32 动态创建任务
实验平台:韦东山 STM32F103ZE开发板
**/
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
/* 开发板硬件bsp头文件 */
#include "bsp_led.h"
#include "bsp_usart.h"
/* 任务句柄 */
static TaskHandle_t AppTaskCreate_Handle = NULL;
static TaskHandle_t Task1_Handle = NULL;
static TaskHandle_t Task2_Handle = NULL;
//static TaskHandle_t Task3_Handle = NULL;
//static QueueHandle_t xQueueCalcHandle;
static QueueHandle_t xQueueUARTcHandle;
/* 函数声明 */
static void AppTaskCreate(void);/* 用于创建任务 */
static void Flag1_Task(void* pvParameters);/* LED1_Task任务实现 */
static void Flag2_Task(void* pvParameters);/* LED2_Task任务实现 */
//static void Flag3_Task(void* pvParameters);/* LED3_Task任务实现 */
static void BSP_Init(void);/* 用于初始化板载相关资源 */
/*创建队列*/
int InitUARTLock(void)
{
int val;
xQueueUARTcHandle = xQueueCreate(1, sizeof(int));/*创建队列*/
if (xQueueUARTcHandle == NULL)
{
printf("can not create queue\r\n");
return -1;/*创建失败*/
}
xQueueSend(xQueueUARTcHandle, &val, portMAX_DELAY);/*死等*/
return 0;/*创建成功*/
}
/*接收队列消息*/
void GetUARTLock(void)
{
int val;
xQueueReceive(xQueueUARTcHandle, &val, portMAX_DELAY);
}
/*发送队列消息*/
void PutUARTLock(void)
{
int val;
xQueueSend(xQueueUARTcHandle, &val, portMAX_DELAY);
}
/*****************************************************************
* @brief 主函数
* @param 无
* @retval 无
* @note 第一步:开发板硬件初始化
第二步:创建APP应用任务
第三步:启动FreeRTOS,开始多任务调度
****************************************************************/
int main(void)
{
BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */
/* 开发板硬件初始化 */
BSP_Init();
printf("这是一个STM32F103ZE开发板-FreeRTOS-动态创建任务!\r\n");
InitUARTLock();/*调用创建队列函数*/
/* 创建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(); //进入临界区
/* 创建Flag1_Task任务 */
xReturn = xTaskCreate((TaskFunction_t )Flag1_Task, /* 任务入口函数 */
(const char* )"Flag1_Task",/* 任务名字 */
(uint16_t )512, /* 任务栈大小 */
(void* )NULL, /* 任务入口函数参数 */
(UBaseType_t )2, /* 任务的优先级 */
(TaskHandle_t* )&Task1_Handle);/* 任务控制块指针 */
if(pdPASS == xReturn)
printf("创建Flag1_Task任务成功!\r\n");
/* 创建Flag2_Task任务 */
xReturn = xTaskCreate((TaskFunction_t )Flag2_Task, /* 任务入口函数 */
(const char* )"Flag2_Task",/* 任务名字 */
(uint16_t )512, /* 任务栈大小 */
(void* )NULL, /* 任务入口函数参数 */
(UBaseType_t )2, /* 任务的优先级 */
(TaskHandle_t* )&Task2_Handle);/* 任务控制块指针 */
if(pdPASS == xReturn)
printf("创建Flag2_Task任务成功!\r\n");
/* 创建Flag3_Task任务 */
// xReturn = xTaskCreate((TaskFunction_t )Flag3_Task, /* 任务入口函数 */
// (const char* )"Flag3_Task",/* 任务名字 */
// (uint16_t )512, /* 任务栈大小 */
// (void* )NULL, /* 任务入口函数参数 */
// (UBaseType_t )1, /* 任务的优先级 */
// (TaskHandle_t* )&Task3_Handle);/* 任务控制块指针 */
// if(pdPASS == xReturn)
// printf("创建Flag3_Task任务成功!\r\n");
vTaskDelete(AppTaskCreate_Handle); //删除AppTaskCreate任务
taskEXIT_CRITICAL(); //退出临界区
}
/**********************************************************************
* @ 函数名 : LED_Task
* @ 功能说明: LED_Task任务主体
********************************************************************/
uint8_t flag1;
uint8_t flag2;
uint8_t flag3;
/*优先级2*/
static void Flag1_Task(void* parameter)
{
while (1)
{
GetUARTLock();/*调用接收消息函数获得使用权*/
printf("Task1 Running!\r\n");
PutUARTLock();/*调用发送消息函数释放使用权*/
vTaskDelay(1); /* 延时1个tick */
}
}
/*优先级2*/
static void Flag2_Task(void* parameter)
{
while (1)
{
GetUARTLock();/*调用接收消息函数获得使用权*/
printf("Task2 Running!\r\n");
PutUARTLock();/*调用发送消息函数释放使用权*/
vTaskDelay(1); /* 延时1个tick */
}
}
/*优先级1*/
//static void Flag3_Task(void* parameter)
//{
// static int value2;
// while (1)
// {
// flag1=0;
// flag2=0;
// flag3=1;
// printf("Task3 Running! value=%d\r\n",value2);
// vTaskDelay(10); /* 延时1个tick */
//
// }
//}
/***********************************************************************
* @ 函数名 : BSP_Init
* @ 功能说明: 板级外设初始化,所有板子上的初始化均可放在这个函数里面
* @ 参数 :
* @ 返回值 : 无
*********************************************************************/
static void BSP_Init(void)
{
/*
* STM32中断优先级分组为4,即4bit都用来表示抢占优先级,范围为:0~15
* 优先级分组只需要分组一次即可,以后如果有其他的任务需要用到中断,
* 都统一用这个优先级分组,千万不要再分组,切忌。
*/
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
/* LED 初始化 */
LED_GPIO_Config();
/* 串口初始化 */
USART_Config();
}
/********************************END OF FILE****************************/
这次实验创建了两个任务,任务优先级相同都为2
创建这几个函数
在任务处理事件中,像临界保护一样进行首先调用接收消息的函数获得使用权,再调用发送消息函数释放使用权。(队列里面有数据表示别人可以读这个队列)
git仓库源码地址:https://gitee.com/he-dejiang/free-rtos.git