信号量
信号量是一种解决同步问题的机制,可以实现对共享资源的有序访问。其中,“同步”指的是任务间的同步,即信号量可以使得一个任务等待另一个任务完成某件事情后,才继续执行;而“有序访问”指的是对被多任务或中断访问的共享资源(如全局变量)的管理,当一个任务在访问(读取或写入)一个共享资源时,信号量可以防止其他任务或中断在这期间访问(读取或写入)这个共享资源。例如:
多个任务对信号量进行操作,当计数值大于0,代表有信号量资源,当释放信号量,信号量计数值(资源数)加一,当获取信号量,信号量计数值(资源数)减一。
信号量的计数值都有限制:限定最大值。如果最大值被限定为1,那么它就是二值信号量;如果最大值不是1,它就是计数型信号量。
队列与信号量的对比
二值信号量
使用二值信号量的过程:创建二值信号量 ——>释放二值信号量 ——>获取二值信号量
注意:创建的二值信号量一开始信号量值是为0的,因此,任务在使用信号量前必须先进行释放!!!
1. 动态方式创建二值信号量
创建二值信号量所需的内存,由 FreeRTOS 从FreeRTOS 管理的堆中进行分配。该函数实际上是一个宏定义,在 semphr.h 文件中有定义,具体的代码如下所示。xSemaphoreCreateBinary() 实 际 上 是 调 用 了 函 数xQueueGenericCreate()创建了一个队列长度为 1 且队列项目大小为信号量队列项目大小的二值信号量类型队列。
#define xSemaphoreCreateBinary()
xQueueGenericCreate( ( UBaseType_t ) 1,
semSEMAPHORE_QUEUE_ITEM_LENGTH,
queueQUEUE_TYPE_BINARY_SEMAPHORE)
2.静态方式创建二值信号量
创建二值信号量所需的内存,需要由用户手动分配并提供。该函数实际上是一个宏定义,在 semphr.h 文件中有定义,具体的代码如下所示:
#define xSemaphoreCreateBinaryStatic(pxStaticSemaphore)
xQueueGenericCreateStatic( ( UBaseType_t ) 1,
semSEMAPHORE_QUEUE_ITEM_LENGTH,
NULL,
pxStaticSemaphore,
queueQUEUE_TYPE_BINARY_SEMAPHORE)
3.获取信号量
如果信号量处于没有资源的状态,那么此函数可以选择将任务进行阻塞,如果成功获取了信号量,那信号量的资源数将会减 1。该函数实际上是一个宏定义,在 semphr.h 文件中有定义,具体的代码如下所示:
#define xSemaphoreTake( xSemaphore, xBlockTime)
xQueueSemaphoreTake( ( xSemaphore ), ( xBlockTime ))
我们知道,获取信号量可能会发生阻塞,因此它有阻塞延时这个参数!
二值信号量实验
#include "stm32f4xx.h" // Device header
#include "stdio.h"
#include "FreeRTOS.h"
#include "task.h"
#include "dynamic.h"
#include "mydelay.h"
#include "mykey.h"
#include "semphr.h"
/**********************START_TASK任务配置******************************/
/***********包括任务堆栈大小、任务优先级、任务句柄、创建任务***********/
#define START_TASK_STACK_SIZE 128 //定义堆栈大小为128字(1字等于4字节)
#define START_TASK_PRIO 1 //定义任务优先级,0-31根据任务需求
TaskHandle_t start_task_handler; //定义任务句柄(结构体指针)
void start_task(void* args);
/**********************TASK1任务配置******************************/
/***********包括任务堆栈大小、任务优先级、任务句柄、创建任务***********/
#define TASK1_STACK_SIZE 128 //定义堆栈大小为128字(1字等于4字节)
#define TASK1_PRIO 2 //定义任务优先级,0-31根据任务需求
TaskHandle_t task1_handler; //定义任务句柄(结构体指针)
void task1(void* args);
/**********************TASK2任务配置******************************/
/***********包括任务堆栈大小、任务优先级、任务句柄、创建任务***********/
#define TASK2_STACK_SIZE 128 //定义堆栈大小为128字(1字等于4字节)
#define TASK2_PRIO 3 //定义任务优先级,0-31根据任务需求
TaskHandle_t task2_handler; //定义任务句柄(结构体指针)
void task2(void* args);
QueueHandle_t semphore_handle; //创建二值信号量
/*********开始任务用来创建一个任务,只创建一次,不能是死循环,创建完这个任务后删除开始任务本身***********/
void start_task(void* args)
{
taskENTER_CRITICAL(); /*进入临界区*/
xTaskCreate( (TaskFunction_t) task1,
(char *) "task1",
( configSTACK_DEPTH_TYPE) TASK1_STACK_SIZE,
(void *) NULL,
(UBaseType_t) TASK1_PRIO ,
(TaskHandle_t *) &task1_handler );
xTaskCreate( (TaskFunction_t) task2,
(char *) "task2",
( configSTACK_DEPTH_TYPE) TASK2_STACK_SIZE,
(void *) NULL,
(UBaseType_t) TASK2_PRIO ,
(TaskHandle_t *) &task2_handler );
vTaskDelete(NULL); //删除开始任务自身,传参NULL
taskEXIT_CRITICAL(); /*退出临界区*/
//临界区内不会进行任务的调度切换,出了临界区才会进行任务调度,抢占式
}
int main(void)
{
//硬件初始化
My_UsartInit();
//调用入口函数
semphore_handle=xSemaphoreCreateBinary(); //创建二值信号量
if(semphore_handle!=NULL)
{
printf("二值信号量创建成功\n");
}
/***开始任务的创建***/
xTaskCreate( (TaskFunction_t) start_task,
(char *) "start_task",
( configSTACK_DEPTH_TYPE) START_TASK_STACK_SIZE,
(void *) NULL,
(UBaseType_t) START_TASK_PRIO ,
(TaskHandle_t *) &start_task_handler );
vTaskStartScheduler(); //开启任务调度器
}
/********任务1的任务函数,无返回值且是死循环***********/
/*****任务1:释放二值信号量*******/
void task1(void* args)
{
uint8_t key=0;
BaseType_t xReturn;
while(1)
{
key=KEY_Scan(0);
if(key==KEY0_PRES )
{
xReturn = xSemaphoreGive(semphore_handle); //释放二值信号量
if(xReturn!=pdPASS)
{
printf("释放二值信号量失败\n");
}
}
vTaskDelay(10); //FreeRTOS自带的延时函数,延时10毫秒
}
}
/****如果按键未按下,信号量不会释放,任务2获取信号量就会失败,进入阻塞态不会因为它的优先级高执行,必须等任务1完成****/
/********任务2的任务函数,无返回值且是死循环***********/
/***任务2:获取二值信号量*******/
void task2(void* args)
{
uint32_t i=0;
BaseType_t xReturn;
while(1)
{
xReturn= xSemaphoreTake(semphore_handle,portMAX_DELAY); //获取信号量,一直阻塞等待
if(xReturn==pdTRUE)
{
printf("获取二值信号量成功!:%d\n",++i);
}
}
}
计数型信号量
计数型信号量相当于队列长度大于1 的队列(信号量的上限值),因此计数型信号量能够容纳多个资源,这在计数型信号量被创建的时候确定的。
使用计数型信号量的过程:创建计数型信号量 ——>释放信号量 ——>获取信号量
计数型信号量除了创建函数之外,其余的获取、释放等信号量操作函数,都与二值信号量相同,因此这里重点讲解计数型信号量的创建函数。
动态方式创建计数型信号量
创建计数型信号量所需的内存,由 FreeRTOS从 FreeRTOS 管理的堆中进行分配。该函数实际上是一个宏定义,在 semphr.h 中有定义,具体的代码如下所示:
#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount )
xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ))
函数 xSemaphoreCreateCounting()实际上是调用了函xQueueCreateCountingSemaphore(),函数 xQueueCreateCountingSemaphore()在 queue.c 文件中有定义。
获取信号量当前计数值大小
下面这个函数用于获取信号量当前计数值大小
uxSemaphoreGetCount( xSemaphore );
计数型信号量实验
#include "stm32f4xx.h" // Device header
#include "stdio.h"
#include "myled.h"
#include "myusart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "dynamic.h"
/**********************START_TASK任务配置******************************/
/***********包括任务堆栈大小、任务优先级、任务句柄、创建任务***********/
#define START_TASK_STACK_SIZE 128 //定义堆栈大小为128字(1字等于4字节)
#define START_TASK_PRIO 1 //定义任务优先级,0-31根据任务需求
TaskHandle_t start_task_handler; //定义任务句柄(结构体指针)
void start_task(void* args);
/**********************TASK1任务配置******************************/
/***********包括任务堆栈大小、任务优先级、任务句柄、创建任务***********/
#define TASK1_STACK_SIZE 128 //定义堆栈大小为128字(1字等于4字节)
#define TASK1_PRIO 2 //定义任务优先级,0-31根据任务需求
TaskHandle_t task1_handler; //定义任务句柄(结构体指针)
void task1(void* args);
/**********************TASK2任务配置******************************/
/***********包括任务堆栈大小、任务优先级、任务句柄、创建任务***********/
#define TASK2_STACK_SIZE 128 //定义堆栈大小为128字(1字等于4字节)
#define TASK2_PRIO 3 //定义任务优先级,0-31根据任务需求
TaskHandle_t task2_handler; //定义任务句柄(结构体指针)
void task2(void* args);
QueueHandle_t count_semphore_handle; //创建二值信号量
/*********开始任务用来创建一个任务,只创建一次,不能是死循环,创建完这个任务后删除开始任务本身***********/
void start_task(void* args)
{
taskENTER_CRITICAL(); /*进入临界区*/
xTaskCreate( (TaskFunction_t) task1,
(char *) "task1",
( configSTACK_DEPTH_TYPE) TASK1_STACK_SIZE,
(void *) NULL,
(UBaseType_t) TASK1_PRIO ,
(TaskHandle_t *) &task1_handler );
xTaskCreate( (TaskFunction_t) task2,
(char *) "task2",
( configSTACK_DEPTH_TYPE) TASK2_STACK_SIZE,
(void *) NULL,
(UBaseType_t) TASK2_PRIO ,
(TaskHandle_t *) &task2_handler );
vTaskDelete(NULL); //删除开始任务自身,传参NULL
taskEXIT_CRITICAL(); /*退出临界区*/
//临界区内不会进行任务的调度切换,出了临界区才会进行任务调度,抢占式
}
int main(void)
{
//硬件初始化
My_UsartInit();
//调用入口函数
count_semphore_handle=xSemaphoreCreateCounting( 100, 0 ); //创建计数型信号量
if(count_semphore_handle!=NULL)
{
printf("计数型信号量创建成功\n");
}
/***开始任务的创建***/
xTaskCreate( (TaskFunction_t) start_task,
(char *) "start_task",
( configSTACK_DEPTH_TYPE) START_TASK_STACK_SIZE,
(void *) NULL,
(UBaseType_t) START_TASK_PRIO ,
(TaskHandle_t *) &start_task_handler );
vTaskStartScheduler(); //开启任务调度器
}
/********任务1的任务函数,无返回值且是死循环***********/
/*****任务1:释放计数型信号量*******/
void task1(void* args)
{
uint8_t key=0;
while(1)
{
key=KEY_Scan(0);
if(key==KEY0_PRES )
{
xSemaphoreGive(count_semphore_handle); //释放计数型信号量
}
vTaskDelay(10); //FreeRTOS自带的延时函数,延时10毫秒
}
}
/****如果按键未按下,信号量不会释放,任务2获取信号量就会失败,进入阻塞态不会因为它的优先级高执行,必须等任务1完成****/
/********任务2的任务函数,无返回值且是死循环***********/
/***任务2:获取计数型信号量*******/
void task2(void* args)
{
BaseType_t xReturn;
while(1)
{
xReturn= xSemaphoreTake(count_semphore_handle,portMAX_DELAY); //获取计数型信号量,一直阻塞等待
if(xReturn==pdTRUE)
{
printf("信号量的计数值为:%d\n",(int )uxSemaphoreGetCount(count_semphore_handle));
}
vTaskDelay(1000); //延时1秒
}
}
优先级翻转
高优先级的任务反而慢执行,低优先级的任务反而优先执行。优先级翻转在抢占式内核中是非常常见的,但是在实时操作系统中是不允许出现优先级翻转的,因为优先级翻转会破坏任务的预期顺序,可能会导致未知的严重后果。在使用二值信号量的时候,经常会遇到优先级翻转的问题。
优先级翻转实验
#include "stm32f4xx.h" // Device header
#include "stdio.h"
#include "myled.h"
#include "myusart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "dynamic.h"
/**********************START_TASK任务配置******************************/
/***********包括任务堆栈大小、任务优先级、任务句柄、创建任务***********/
#define START_TASK_STACK_SIZE 128 //定义堆栈大小为128字(1字等于4字节)
#define START_TASK_PRIO 1 //定义任务优先级,0-31根据任务需求
TaskHandle_t start_task_handler; //定义任务句柄(结构体指针)
void start_task(void* args);
/**********************TASK1任务配置******************************/
/***********包括任务堆栈大小、任务优先级、任务句柄、创建任务***********/
#define low_task_STACK_SIZE 128 //定义堆栈大小为128字(1字等于4字节)
#define low_task_PRIO 2 //定义任务优先级,0-31根据任务需求
TaskHandle_t low_task_handler; //定义任务句柄(结构体指针)
void low_task(void* args);
/**********************TASK2任务配置******************************/
/***********包括任务堆栈大小、任务优先级、任务句柄、创建任务***********/
#define middle_task_STACK_SIZE 128 //定义堆栈大小为128字(1字等于4字节)
#define middle_task_PRIO 3 //定义任务优先级,0-31根据任务需求
TaskHandle_t middle_task_handler; //定义任务句柄(结构体指针)
void middle_task(void* args);
/**********************TASK3任务配置******************************/
/***********包括任务堆栈大小、任务优先级、任务句柄、创建任务***********/
#define high_task_STACK_SIZE 128 //定义堆栈大小为128字(1字等于4字节)
#define high_task_PRIO 4 //定义任务优先级,0-31根据任务需求
TaskHandle_t high_task_handler; //定义任务句柄(结构体指针)
void high_task(void* args);
QueueHandle_t semphore_handle; //创建二值信号量句柄
/*********开始任务用来创建一个任务,只创建一次,不能是死循环,创建完这个任务后删除开始任务本身***********/
void start_task(void* args)
{
taskENTER_CRITICAL(); /*进入临界区*/
xTaskCreate( (TaskFunction_t) low_task,
(char *) "low_task",
( configSTACK_DEPTH_TYPE) low_task_STACK_SIZE,
(void *) NULL,
(UBaseType_t) low_task_PRIO ,
(TaskHandle_t *) &low_task_handler );
xTaskCreate( (TaskFunction_t) middle_task,
(char *) "middle_task",
( configSTACK_DEPTH_TYPE) middle_task_STACK_SIZE,
(void *) NULL,
(UBaseType_t) middle_task_PRIO ,
(TaskHandle_t *) &middle_task_handler );
xTaskCreate( (TaskFunction_t) high_task,
(char *) "high_task",
( configSTACK_DEPTH_TYPE) high_task_STACK_SIZE,
(void *) NULL,
(UBaseType_t) high_task_PRIO ,
(TaskHandle_t *) &high_task_handler );
vTaskDelete(NULL); //删除开始任务自身,传参NULL
taskEXIT_CRITICAL(); /*退出临界区*/
//临界区内不会进行任务的调度切换,出了临界区才会进行任务调度,抢占式
}
int main(void)
{
//硬件初始化
My_UsartInit();
//调用入口函数
semphore_handle=xSemaphoreCreateBinary(); //创建二值信号量
if(semphore_handle!=NULL)
{
printf("二值信号量创建成功\n");
}
xSemaphoreGive(semphore_handle); //释放信号量
/***开始任务的创建***/
xTaskCreate( (TaskFunction_t) start_task,
(char *) "start_task",
( configSTACK_DEPTH_TYPE) START_TASK_STACK_SIZE,
(void *) NULL,
(UBaseType_t) START_TASK_PRIO ,
(TaskHandle_t *) &start_task_handler );
vTaskStartScheduler(); //开启任务调度器
}
/********任务1的任务函数,无返回值且是死循环***********/
/*****任务1:低优先级任务*******/
void low_task(void* args)
{
while(1)
{
printf("low_task任务获取信号量!\n");
xSemaphoreTake(semphore_handle,portMAX_DELAY );
printf("low_task任务正在运行!\n");
My_Delay_s(3);
printf("low_task任务释放信号量!\n");
xSemaphoreGive(semphore_handle); //释放信号量
vTaskDelay(1000); //FreeRTOS自带的延时函数,延时10毫秒
}
}
/****如果按键未按下,信号量不会释放,任务2获取信号量就会失败,进入阻塞态不会因为它的优先级高执行,必须等任务1完成****/
/********任务2的任务函数,无返回值且是死循环***********/
/***任务2:中优先级任务*******/
void middle_task(void* args)
{
while(1)
{
printf("middle_task任务正在运行!\n");
vTaskDelay(1000);
}
}
/********任务3的任务函数,无返回值且是死循环***********/
/***任务3:高优先级任务*******/
void high_task(void* args)
{
while(1)
{
printf("high_task任务获取信号量!\n");
xSemaphoreTake(semphore_handle,portMAX_DELAY );
printf("high_task任务正在运行!\n");
My_Delay_s(1);
printf("high_task任务释放信号量!\n");
xSemaphoreGive(semphore_handle); //释放信号量
vTaskDelay(1000); //FreeRTOS自带的延时函数,延时10毫秒
}
}
互斥信号量
互斥信号量其实就是一个拥有优先级继承的二值信号量,在同步的应用中二值信号量最适合。互斥信号量适合用于那些需要互斥访问的应用中! (优先级继承就是用来解决优先级翻转问题的!)
优先级继承:当一个互斥信号量正在被一个低优先级的任务持有时, 如果此时有个高优先级的任务也尝试获取这个互斥信号量,那么这个高优先级的任务就会被阻塞。不过这个高优先级的任务会将低优先级任务的优先级提升到与自己相同的优先级。
因为修改了低优先级任务的优先级,所以,此时中优先级任务不会再抢占低优先级任务执行,只要低优先级执行完毕,然后释放信号量,高优先级任务就可以执行,节省了中优先级任务执行的时间!此时任务H的阻塞时间仅仅是任务L 的执行时间,将优先级翻转的危害降到了最低。
互斥信号量的特点
优先级继承并不能完全的消除优先级翻转的问题,它只是尽可能的降低优先级翻转带来的影响。
注意:互斥信号量不能用于中断服务函数中,原因如下:
(1) 互斥信号量有任务优先级继承的机制, 但是中断不是任务,没有任务优先级, 所以互斥信号量只能用与任务中,不能用于中断服务函数。
(2) 中断服务函数中不能因为要等待互斥信号量而设置阻塞时间进入阻塞态。(中断是一瞬间的事,非常紧急,不可进行阻塞)
使用流程:创建互斥信号量 ——>(take)获取信号量 ——>(give)释放信号量。
创建互斥信号量时,函数内部会主动释放一次信号量!所以,一开始创建的互信信号量的计数值为1,它是有资源的。
互斥信号量除了创建函数之外,其余的获取、释放等信号量操作函数,都与二值信号量相同,因此这里重点讲解互斥信号量的创建函数。
动态方式创建互斥信号量
创建互斥信号量所需的内存,由 FreeRTOS 从FreeRTOS 管理的堆中进行分配。该函数实际上是一个宏定义,在 semphr.h 中有定义,具体的代码如下所示
#define xSemaphoreCreateMutex() xQueueCreateMutex(queueQUEUE_TYPE_MUTEX)
互斥信号量的释放和获取函数与二值信号量相同 !只不过互斥信号量不支持中断中调用!
互斥信号量实验
#include "stm32f4xx.h" // Device header
#include "stdio.h"
#include "FreeRTOS.h"
#include "task.h"
#include "dynamic.h"
#include "mydelay.h"
#include "mykey.h"
#include "semphr.h"
extern TaskHandle_t Start_Handle;
/**********************START_TASK任务配置******************************/
/***********包括任务堆栈大小、任务优先级、任务句柄、创建任务***********/
#define START_TASK_STACK_SIZE 128 //定义堆栈大小为128字(1字等于4字节)
#define START_TASK_PRIO 1 //定义任务优先级,0-31根据任务需求
TaskHandle_t start_task_handler; //定义任务句柄(结构体指针)
void start_task(void* args);
/**********************TASK1任务配置******************************/
/***********包括任务堆栈大小、任务优先级、任务句柄、创建任务***********/
#define low_task_STACK_SIZE 128 //定义堆栈大小为128字(1字等于4字节)
#define low_task_PRIO 2 //定义任务优先级,0-31根据任务需求
TaskHandle_t low_task_handler; //定义任务句柄(结构体指针)
void low_task(void* args);
/**********************TASK2任务配置******************************/
/***********包括任务堆栈大小、任务优先级、任务句柄、创建任务***********/
#define middle_task_STACK_SIZE 128 //定义堆栈大小为128字(1字等于4字节)
#define middle_task_PRIO 3 //定义任务优先级,0-31根据任务需求
TaskHandle_t middle_task_handler; //定义任务句柄(结构体指针)
void middle_task(void* args);
/**********************TASK3任务配置******************************/
/***********包括任务堆栈大小、任务优先级、任务句柄、创建任务***********/
#define high_task_STACK_SIZE 128 //定义堆栈大小为128字(1字等于4字节)
#define high_task_PRIO 4 //定义任务优先级,0-31根据任务需求
TaskHandle_t high_task_handler; //定义任务句柄(结构体指针)
void high_task(void* args);
QueueHandle_t mutex_semphore_handle; //创建互斥信号量句柄
/*********开始任务用来创建一个任务,只创建一次,不能是死循环,创建完这个任务后删除开始任务本身***********/
void start_task(void* args)
{
taskENTER_CRITICAL(); /*进入临界区*/
xTaskCreate( (TaskFunction_t) low_task,
(char *) "low_task",
( configSTACK_DEPTH_TYPE) low_task_STACK_SIZE,
(void *) NULL,
(UBaseType_t) low_task_PRIO ,
(TaskHandle_t *) &low_task_handler );
xTaskCreate( (TaskFunction_t) middle_task,
(char *) "middle_task",
( configSTACK_DEPTH_TYPE) middle_task_STACK_SIZE,
(void *) NULL,
(UBaseType_t) middle_task_PRIO ,
(TaskHandle_t *) &middle_task_handler );
xTaskCreate( (TaskFunction_t) high_task,
(char *) "high_task",
( configSTACK_DEPTH_TYPE) high_task_STACK_SIZE,
(void *) NULL,
(UBaseType_t) high_task_PRIO ,
(TaskHandle_t *) &high_task_handler );
vTaskDelete(NULL); //删除开始任务自身,传参NULL
taskEXIT_CRITICAL(); /*退出临界区*/
//临界区内不会进行任务的调度切换,出了临界区才会进行任务调度,抢占式
}
int main(void)
{
//硬件初始化
My_UsartInit();
//调用入口函数
mutex_semphore_handle= xSemaphoreCreateMutex(); //创建互斥信号量,并且主动释放一次信号量
if(mutex_semphore_handle!=NULL)
{
printf("互斥信号量创建成功\n");
}
/***开始任务的创建***/
xTaskCreate( (TaskFunction_t) start_task,
(char *) "start_task",
( configSTACK_DEPTH_TYPE) START_TASK_STACK_SIZE,
(void *) NULL,
(UBaseType_t) START_TASK_PRIO ,
(TaskHandle_t *) &start_task_handler );
vTaskStartScheduler(); //开启任务调度器
}
/********任务1的任务函数,无返回值且是死循环***********/
/*****任务1:低优先级任务*******/
void low_task(void* args)
{
while(1)
{
printf("low_task任务获取信号量!\n");
xSemaphoreTake(mutex_semphore_handle,portMAX_DELAY );
printf("low_task任务正在运行!\n");
My_Delay_s(3);
printf("low_task任务释放信号量!\n");
xSemaphoreGive(mutex_semphore_handle); //释放信号量
vTaskDelay(1000); //FreeRTOS自带的延时函数,延时10毫秒
}
}
/****如果按键未按下,信号量不会释放,任务2获取信号量就会失败,进入阻塞态不会因为它的优先级高执行,必须等任务1完成****/
/********任务2的任务函数,无返回值且是死循环***********/
/***任务2:中优先级任务*******/
void middle_task(void* args)
{
while(1)
{
printf("middle_task任务正在运行!\n");
vTaskDelay(1000);
}
}
/********任务3的任务函数,无返回值且是死循环***********/
/***任务3:高优先级任务*******/
void high_task(void* args)
{
while(1)
{
printf("high_task任务获取信号量!\n");
xSemaphoreTake(mutex_semphore_handle,portMAX_DELAY );
printf("high_task任务正在运行!\n");
My_Delay_s(1);
printf("high_task任务释放信号量!\n");
xSemaphoreGive(mutex_semphore_handle); //释放信号量
vTaskDelay(1000); //FreeRTOS自带的延时函数,延时10毫秒
}
}
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/m0_55389449/article/details/147547722
|
|