信号量的定义
是一种解决同步问题的机制,实现对共享资源的有序访问
信号量特点:
当计数值大于0,代表有信号量资源;释放信号量,信号量计数值+1;获取则-1
队列和信号量的差异
二值信号量:
a.相当于队列长度等于1的队列
b.通常用于互斥访问或任务同步
c.只有空与满两种情况
使用二值信号量过程
创建二值信号量->释放二值信号量->获取二值信号量
动态方法创建二值信号量 xSemaphoreCreateBinary()
释放二值信号量 BaseType_t xSemaphoreGive(QueueHandle_t xSemaphore)
参数:目标信号量 返回值:pdPASS 释放成功,errQUEUE_FULL 释放失败
获取二值信号量 BaseType_t xSemaphoreTake(QueueHandle_t xSemaphore,xBlockTime)
参数:目标信号量,阻塞时间 返回值:pdTRUE 获取成功,pdFALSE 获取失败
二值信号量代码
// freertos_demo.c
#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
#include "./MALLOC/malloc.h"
/*FreeRTOS************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/*******************************************************************************/
/*FreeRTOS配置*/
/* START_TASK 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define START_TASK_PRIO 1
#define START_TASK_STACK_SIZE 128
TaskHandle_t start_task_handler;
void start_task( void * pvParameters );
/* TASK1 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK1_PRIO 2
#define TASK1_STACK_SIZE 128
TaskHandle_t task1_handler;
void task1( void * pvParameters );
/* TASK2 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK2_PRIO 3
#define TASK2_STACK_SIZE 128
TaskHandle_t task2_handler;
void task2( void * pvParameters );
/***************************************************************************************/
QueueHandle_t semphore_handle; //定义队列句柄
/**
* @brief FreeRTOS例程入口函数
* @param 无
* @retval 无
*/
void freertos_demo(void)
{
semphore_handle = xSemaphoreCreateBinary(); //创建二值信号量
if(semphore_handle != NULL)
{
printf("二值信号量创建成功!!!\r\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();
}
void start_task( void * pvParameters )
{
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);
taskEXIT_CRITICAL(); /* 退出临界区 */
}
/* 任务一,释放二值信号量 */
void task1( void * pvParameters )
{
uint8_t key = 0;
BaseType_t err;
while(1)
{
key = key_scan(0);
if(key == KEY0_PRES) //判断按键是否按下
{
if(semphore_handle != NULL)
{
err = xSemaphoreGive(semphore_handle); //释放二值信号量
if(err == pdPASS)
{
printf("信号量释放成功!!\r\n");
}else printf("信号量释放失败!!\r\n");
}
}
vTaskDelay(10);
}
}
/* 任务二,获取二值信号量 */
void task2( void * pvParameters )
{
uint32_t i = 0;
BaseType_t err;
while(1)
{
err = xSemaphoreTake(semphore_handle,portMAX_DELAY); /* 获取信号量并死等 */
if(err == pdTRUE)
{
printf("获取信号量成功\r\n"); //任务始终处于阻塞状态,一旦有信号产生就解除阻塞,因为抢占优先级高,发生任务切换
}else printf("已超时%d\r\n",++i);
}
}
//freertos_demo.h
#ifndef __FREERTOS_DEMO_H
#define __FREERTOS_DEMO_H
void freertos_demo(void);
#endif
main.c
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./BSP/SDRAM/sdram.h"
#include "./MALLOC/malloc.h"
#include "freertos_demo.h"
#include "./BSP/TIMER/btim.h"
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(360, 25, 2, 8); /* 设置时钟,180Mhz */
delay_init(180); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
led_init(); /* 初始化LED */
key_init(); /* 初始化按键 */
sdram_init(); /* SRAM初始化 */
lcd_init(); /* 初始化LCD */
my_mem_init(SRAMIN); /* 初始化内部内存池 */
my_mem_init(SRAMEX); /* 初始化外部内存池 */
my_mem_init(SRAMCCM); /* 初始化CCM内存池 */
freertos_demo();
}
计数型信号量:
a.队列长度大于1的队列
b.适用场景 事件计数,资源管理
创建计数型信号量函数
xSemaphoreCreateCounting(uxMaxCount,uxInitialCount)
参数:计数最大值,计数初始值 返回值:队列(QueueHandle_t 型)
获取信号量当前计数值
uxSemaphoneGetCount(QueueHandle_t xSemaphore)
参数:目标信号量句柄 返回值:整数(UBaseType_t 型)
计数型信号实验代码
//freertos_demo.c
#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
#include "./MALLOC/malloc.h"
/*FreeRTOS****************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/***************************************************************************************/
/*FreeRTOS配置*/
/* START_TASK 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define START_TASK_PRIO 1
#define START_TASK_STACK_SIZE 128
TaskHandle_t start_task_handler;
void start_task( void * pvParameters );
/* TASK1 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK1_PRIO 2
#define TASK1_STACK_SIZE 128
TaskHandle_t task1_handler;
void task1( void * pvParameters );
/* TASK2 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK2_PRIO 3
#define TASK2_STACK_SIZE 128
TaskHandle_t task2_handler;
void task2( void * pvParameters );
/************************************************************************************/
QueueHandle_t count_semphore_handle; //定义队列变量
/**
* @brief FreeRTOS例程入口函数
* @param 无
* @retval 无
*/
void freertos_demo(void)
{
count_semphore_handle = xSemaphoreCreateCounting(100 , 0); /* 创建计数型信号量 */
if(count_semphore_handle != NULL)
{
printf("计数型信号量创建成功!!!\r\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();
}
void start_task( void * pvParameters )
{
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);
taskEXIT_CRITICAL(); /* 退出临界区 */
}
/* 任务一,释放计数型信号量 */
void task1( void * pvParameters )
{
uint8_t key = 0;
while(1)
{
key = key_scan(0);
if(key == KEY0_PRES)
{
if(count_semphore_handle != NULL) //判断信号量不为空
{
xSemaphoreGive(count_semphore_handle); /* 释放信号量 */
}
}
vTaskDelay(10);
}
}
/* 任务二,获取计数型信号量 */
void task2( void * pvParameters )
{
BaseType_t err = 0;
while(1)
{
err = xSemaphoreTake(count_semphore_handle,portMAX_DELAY); /* 获取信号量并死等 */
if(err == pdTRUE)
{
printf("信号量的计数值为:%d\r\n",(int)uxSemaphoreGetCount(count_semphore_handle));//获取信号量计数值
}
vTaskDelay(1000); //延迟1秒,任务依旧是就绪态
}
}
互斥信号量:
a.拥有优先级继承的二值信号量
b.同步应用中二值信号量最适合
c.只能用于任务中,不能用于中断服务函数
d.优先级继承的含义:
使用:a.将FreeRTOSConfig.h中configUSE_MUTEXES置1
b.创建互斥信号量(会自动释放一次)->获取信号量->释放信号量
动态创建:xSemaphoreCreateMutex() 无参
返回值:NULL 创建失败,队列(QueueHandle_t 型)创建成功
其他API函数与二值信号量一致,除了中断部分API,因为互斥信号量不能在中断中使用
互斥信号代码
//freertos_demo.c
#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
#include "./MALLOC/malloc.h"
/*FreeRTOS************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/************************************************************************************/
/*FreeRTOS配置*/
/* START_TASK 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define START_TASK_PRIO 1
#define START_TASK_STACK_SIZE 128
TaskHandle_t start_task_handler;
void start_task( void * pvParameters );
/* TASK1 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK1_PRIO 2
#define TASK1_STACK_SIZE 128
TaskHandle_t low_task_handler;
void low_task( void * pvParameters );
/* TASK2 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK2_PRIO 3
#define TASK2_STACK_SIZE 128
TaskHandle_t middle_task_handler;
void middle_task( void * pvParameters );
/* TASK3 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK3_PRIO 4
#define TASK3_STACK_SIZE 128
TaskHandle_t high_task_handler;
void high_task( void * pvParameters );
/************************************************************************************/
QueueHandle_t mutex_semphore_handle;
/**
* @brief FreeRTOS例程入口函数
* @param 无
* @retval 无
*/
void freertos_demo(void)
{
mutex_semphore_handle = xSemaphoreCreateMutex(); /* 创建互斥信号量,并且主动释放一次信号量 */
if(mutex_semphore_handle != NULL)
{
printf("互斥信号量创建成功!!!\r\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();
}
void start_task( void * pvParameters )
{
taskENTER_CRITICAL(); /* 进入临界区 */
xTaskCreate((TaskFunction_t ) low_task,
(char * ) "low_task",
(configSTACK_DEPTH_TYPE ) TASK1_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK1_PRIO,
(TaskHandle_t * ) &low_task_handler );
xTaskCreate((TaskFunction_t ) middle_task,
(char * ) "middle_task",
(configSTACK_DEPTH_TYPE ) TASK2_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK2_PRIO,
(TaskHandle_t * ) &middle_task_handler );
xTaskCreate((TaskFunction_t ) high_task,
(char * ) "high_task",
(configSTACK_DEPTH_TYPE ) TASK3_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK3_PRIO,
(TaskHandle_t * ) &high_task_handler );
vTaskDelete(NULL);
taskEXIT_CRITICAL(); /* 退出临界区 */
}
/* 任务一,低优先级任务 */
void low_task( void * pvParameters )
{
while(1)
{
printf("low_task获取信号量\r\n");
xSemaphoreTake(mutex_semphore_handle,portMAX_DELAY);//获取互斥信号量
printf("low_task正在运行!!!\r\n");
delay_ms(3000);
printf("low_task释放信号量\r\n");
xSemaphoreGive(mutex_semphore_handle); //释放互斥信号量
vTaskDelay(1000);
}
}
/* 任务二,中优先级任务 */
void middle_task( void * pvParameters )
{
while(1)
{
printf("middle_task正在运行!!!\r\n");
vTaskDelay(1000);
}
}
/* 任务三,高优先级任务 */
void high_task( void * pvParameters )
{
while(1)
{
printf("high_task获取信号量\r\n");
xSemaphoreTake(mutex_semphore_handle,portMAX_DELAY);
printf("high_task正在运行!!!\r\n");
delay_ms(1000);
printf("high_task释放信号量\r\n");
xSemaphoreGive(mutex_semphore_handle);
vTaskDelay(1000);
}
}