FreeRTOS之二值信号量与计数信号量
声明:本人按照正点原子的FreeRTOS例程进行学习的,欢迎各位大佬指责和批评,谢谢!
- 二值信号量
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "timer.h"
#include "lcd.h"
#include "key.h"
#include "beep.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "malloc.h"
#include "semphr.h"
#define START_TASK_PRIO 1 //任务优先级
#define START_STK_SIZE 256 //任务堆栈大小
TaskHandle_t StartTask_Handler; //任务句柄
void start_task(void *pvParameters); //任务函数
#define LED_TASK_PRIO 2 //任务优先级
#define LED_STK_SIZE 128 //任务堆栈大小
TaskHandle_t LedTask_Handler; //任务句柄
void led_task(void *pvParameters); //任务函数
#define TASK1_TASK_PRIO 3 //任务优先级
#define TASK1_STK_SIZE 256 //任务堆栈大小
TaskHandle_t Task1Task_Handler; //任务句柄
void task1_task(void *pvParameters); //任务函数
#define TASK2_TASK_PRIO 4 //任务优先级
#define TASK2_STK_SIZE 128 //任务堆栈大小
TaskHandle_t Task2Task_Handler; //任务句柄
void task2_task(void *pvParameters); //任务函数
SemaphoreHandle_t BinarySemaphore = NULL; //二值信号量句柄
/**
*二值信号量:其实更偏向应用于同步功能,发送信号量与接收信号量之间进行同步,传递的量值不是1就是0.
当信号量的共享区域满了就是1,不满就是0,可以是这么理解。
此实验,实现的是:
任务1中,当按键按下,发送信号量
任务2中,获取信号量,串口调试助手显示结果。
*/
//LCD刷屏时使用的颜色
int lcd_discolor[14]={ WHITE, BLACK, BLUE, BRED,
GRED, GBLUE, RED, MAGENTA,
GREEN, CYAN, YELLOW,BROWN,
BRRED, GRAY };
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
delay_init(168); //初始化延时函数
uart_init(115200); //初始化串口
LED_Init(); //初始化LED端口
KEY_Init();
BEEP_Init();
LCD_Init(); //初始化LCD
my_mem_init(SRAMIN); //初始化内存池
POINT_COLOR = RED;
LCD_ShowString(30,10,200,16,16,"ATK STM32F407");
LCD_ShowString(30,30,200,16,16,"FreeRTOS 测试");
LCD_ShowString(30,50,200,16,16,"任务状态查询");
//创建开始任务
xTaskCreate((TaskFunction_t )start_task, //任务函数
(const char* )"start_task", //任务名称
(uint16_t )START_STK_SIZE, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )START_TASK_PRIO, //任务优先级
(TaskHandle_t* )&StartTask_Handler); //任务句柄
vTaskStartScheduler(); //开启任务调度
}
//开始任务任务函数
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //进入临界区
//创建二值信号量
BinarySemaphore = xSemaphoreCreateBinary();
if(BinarySemaphore != NULL)
printf("创建二值信号量成功\r\n");
//创建LED任务
xTaskCreate((TaskFunction_t )led_task,
(const char* )"led_task",
(uint16_t )LED_STK_SIZE,
(void* )NULL,
(UBaseType_t )LED_TASK_PRIO,
(TaskHandle_t* )&LedTask_Handler);
//创建TASK1任务
xTaskCreate((TaskFunction_t )task1_task,
(const char* )"task1_task",
(uint16_t )TASK1_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK1_TASK_PRIO,
(TaskHandle_t* )&Task1Task_Handler);
//创建TASK2任务
xTaskCreate((TaskFunction_t )task2_task,
(const char* )"task2_task",
(uint16_t )TASK2_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK2_TASK_PRIO,
(TaskHandle_t* )&Task2Task_Handler);
vTaskDelete(StartTask_Handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
//led0任务函数
void led_task(void *pvParameters)
{
while(1)
{
LED0=!LED0;
vTaskDelay(500); //延时500ms,也就是500个时钟节拍
}
}
//task1任务函数
void task1_task(void *pvParameters)
{
BaseType_t xreturn = pdPASS;
while(1)
{
if(KEY_Scan(1) == KEY1_PRES)
{/*KEY1按下*/
xreturn = xSemaphoreGive(BinarySemaphore);
if(xreturn == pdTRUE)
{
printf("发送信号量成功\r\n");
}
}
}
}
//task2任务函数
void task2_task(void *pvParameters)
{
BaseType_t err=pdTRUE;
while(1)
{
err = xSemaphoreTake(BinarySemaphore,portMAX_DELAY);//BinarySemaphore:传入的信号量 portMAX_DELAY :最大阻塞的时间,一直阻塞
if(err == pdTRUE)
{
printf("获取信号量成功\r\n");
}
else
{
printf("获取信号量失败\r\n");
vTaskDelay(10);
}
}
}
- 计数信号量
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "timer.h"
#include "lcd.h"
#include "key.h"
#include "beep.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "malloc.h"
#include "semphr.h"
#define START_TASK_PRIO 1 //任务优先级
#define START_STK_SIZE 256 //任务堆栈大小
TaskHandle_t StartTask_Handler; //任务句柄
void start_task(void *pvParameters); //任务函数
#define LED_TASK_PRIO 2 //任务优先级
#define LED_STK_SIZE 128 //任务堆栈大小
TaskHandle_t LedTask_Handler; //任务句柄
void led_task(void *pvParameters); //任务函数
#define TASK1_TASK_PRIO 3 //任务优先级
#define TASK1_STK_SIZE 256 //任务堆栈大小
TaskHandle_t Task1Task_Handler; //任务句柄
void task1_task(void *pvParameters); //任务函数
#define TASK2_TASK_PRIO 4 //任务优先级
#define TASK2_STK_SIZE 128 //任务堆栈大小
TaskHandle_t Task2Task_Handler; //任务句柄
void task2_task(void *pvParameters); //任务函数
SemaphoreHandle_t CountSemaphore = NULL; //计数信号量句柄
/**
*计数信号量
*/
//LCD刷屏时使用的颜色
int lcd_discolor[14]={ WHITE, BLACK, BLUE, BRED,
GRED, GBLUE, RED, MAGENTA,
GREEN, CYAN, YELLOW,BROWN,
BRRED, GRAY };
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
delay_init(168); //初始化延时函数
uart_init(115200); //初始化串口
LED_Init(); //初始化LED端口
KEY_Init();
BEEP_Init();
LCD_Init(); //初始化LCD
my_mem_init(SRAMIN); //初始化内存池
POINT_COLOR = RED;
LCD_ShowString(30,10,200,16,16,"ATK STM32F407");
LCD_ShowString(30,30,200,16,16,"FreeRTOS 测试");
LCD_ShowString(30,50,200,16,16,"任务状态查询");
//创建开始任务
xTaskCreate((TaskFunction_t )start_task, //任务函数
(const char* )"start_task", //任务名称
(uint16_t )START_STK_SIZE, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )START_TASK_PRIO, //任务优先级
(TaskHandle_t* )&StartTask_Handler); //任务句柄
vTaskStartScheduler(); //开启任务调度
}
//开始任务任务函数
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //进入临界区
//创建二值信号量
CountSemaphore = xSemaphoreCreateCounting(5,5); //
if(CountSemaphore != NULL)
printf("创建计数信号量成功\r\n");
//创建LED任务
xTaskCreate((TaskFunction_t )led_task,
(const char* )"led_task",
(uint16_t )LED_STK_SIZE,
(void* )NULL,
(UBaseType_t )LED_TASK_PRIO,
(TaskHandle_t* )&LedTask_Handler);
//创建TASK1任务
xTaskCreate((TaskFunction_t )task1_task,
(const char* )"task1_task",
(uint16_t )TASK1_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK1_TASK_PRIO,
(TaskHandle_t* )&Task1Task_Handler);
//创建TASK2任务
xTaskCreate((TaskFunction_t )task2_task,
(const char* )"task2_task",
(uint16_t )TASK2_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK2_TASK_PRIO,
(TaskHandle_t* )&Task2Task_Handler);
vTaskDelete(StartTask_Handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
//led0任务函数
void led_task(void *pvParameters)
{
while(1)
{
LED0=!LED0;
vTaskDelay(500); //延时500ms,也就是500个时钟节拍
}
}
//task1任务函数
void task1_task(void *pvParameters)
{ /*按键,KEY0按下就获取,KEY1按下就释放*/
BaseType_t xreturn = pdPASS;
while(1)
{
if(KEY_Scan(1) == KEY0_PRES)
{/*KEY0按下*/
xreturn = xSemaphoreTake(CountSemaphore,0);//获取
if(xreturn == pdTRUE)
printf("按键0被按下,获取到一个停车位\r\n");
else
printf("按键0被按下,不好意思,停车位已满\r\n");
}
vTaskDelay(20);
}
}
//task2任务函数
void task2_task(void *pvParameters)
{
/*按键,KEY0按下就获取,KEY1按下就释放*/
BaseType_t xreturn = pdPASS;
while(1)
{
if(KEY_Scan(1) == KEY1_PRES)
{/*KEY1按下*/
xreturn = xSemaphoreGive(CountSemaphore);//释放
if(xreturn == pdTRUE)
printf("KEY1按下,释放一个停车位\r\n");
else
printf("KEY1按下,但已无车位可以释放\r\n");
}
vTaskDelay(20);
}
}
下面在串口调试助手查看打印的结果:
结束