一、CubeMX工程配置
时钟源配置
时钟树直接输入最大频率
LED配置
配置串口一
freertos配置
任务创建两个任务
生成工程
二、Keil代码
在嵌入式系统和实时系统中,信号量是一种常用的同步工具,用于协调多个任务之间的访问共享资源。二值信号量是信号量的一种特殊形式,其取值仅为0或1,常被用于二进制的互斥(Mutex)操作。
新添加一个任务
freertos.c
首先添加串口和信号量头文件
/* USER CODE BEGIN Includes */
#include "usart.h"
#include "semphr.h"
/* USER CODE END Includes */
在 FreeRTOS 中,可以使用 xSemaphoreCreateBinary()
函数来创建一个二值信号量。
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */
//创建句柄
SemaphoreHandle_t binarySemaphore;
/* USER CODE END FunctionPrototypes */
/* USER CODE BEGIN RTOS_SEMAPHORES */
/* add semaphores, ... */
// 创建二值信号量
binarySemaphore = xSemaphoreCreateBinary();
if (binarySemaphore == NULL) {
// 信号量创建失败,进行错误处理
while (1);
}
/* USER CODE END RTOS_SEMAPHORES */
xSemaphoreTake()
用于获取信号量,而 xSemaphoreGive()
用于释放信号量。在二值信号量中,获取操作通常是等待信号量变为可用,而释放操作通常是将信号量设置为可用。
void StartDefaultTask(void const * argument)
{
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
for(;;)
{
// 做一些工作
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
osDelay(1000);
// 发送信号量通知 Task2
xSemaphoreGive(binarySemaphore);
// 其他任务代码
}
/* USER CODE END StartDefaultTask */
}
/* USER CODE END Header_StartTask02 */
void StartTask02(void const * argument)
{
/* USER CODE BEGIN StartTask02 */
/* Infinite loop */
for(;;)
{
// 等待二值信号量可用
if (xSemaphoreTake(binarySemaphore, portMAX_DELAY)) {
// 临界区代码
HAL_UART_Transmit(&huart1,(uint8_t*)"receive ok",10,0xffff);
// 释放二值信号量
xSemaphoreGive(binarySemaphore);
}
osDelay(1000);
}
/* USER CODE END StartTask02 */
}
portMAX_DELAY
是 FreeRTOS 中的一个特殊常量,它用于表示一个无限等待的时间。在 FreeRTOS 中,等待时间通常以时钟节拍(tick)的形式表示,而 portMAX_DELAY
表示任务或线程在调用等待函数时会一直等待,直到事件发生而不超时。
具体来说,portMAX_DELAY
被定义为 0xffffffffUL
,即32位无符号整数的最大值。当你将 portMAX_DELAY
作为等待时间传递给 FreeRTOS 的等待函数时,这意味着任务将一直等待,直到事件发生,而不会超时。
运行结果
LED每隔一秒闪烁,并且串口会发送接收成功
三、计数信号量
计数信号量和二值信号量区别,计数信号量类似于二进制信号量,但是随信号量释放的次数改变而改变。计数信号量是一种在多任务环境中用于同步和资源共享的机制。在 FreeRTOS 中,可以使用计数信号量(Counting Semaphore)来实现任务之间的同步和资源计数。
首先在freertos中选择V2版本,CubeMX V1版本的没有计数信号量
freertos.c
首先添加串口和信号量头文件
/* USER CODE BEGIN Includes */
#include "usart.h"
#include "semphr.h"
/* USER CODE END Includes */
添加串口重定向函数
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
#include
int fputc(int ch,FILE *f)
{
HAL_UART_Transmit(&huart1,(uint8_t*)&ch,1,0xFFFF);
return ch;
}
/* USER CODE END PTD */
定义句柄
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */
//计数信号量句柄
SemaphoreHandle_t countingSemaphore;
/* USER CODE END FunctionPrototypes */
创建计数信号量
/* USER CODE BEGIN RTOS_SEMAPHORES */
/* add semaphores, ... */
// 创建计数信号量,最大计数值为5,初始值为0
countingSemaphore = xSemaphoreCreateCounting(5, 0);
if (countingSemaphore == NULL) {
// 信号量创建失败,进行错误处理
while (1);
}
/* USER CODE END RTOS_SEMAPHORES */
xSemaphoreGive()
用于增加计数信号量的值,xSemaphoreTake()
用于减小计数信号量的值。计数信号量允许你控制可用资源的数量。
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
for(;;)
{
//获取计数信号量的当前计数值
uint32_t countValue = uxSemaphoreGetCount(countingSemaphore);
if(countValue == 0){
if(osThreadSuspend(myTask02Handle)==osOK){//挂起任务2
printf("task2 suspend ok\r\n");
xSemaphoreGive(countingSemaphore); // 计数信号量增量
}
}
else if(countValue ==1){ xSemaphoreGive(countingSemaphore); printf("Task1:%d\r\n",countValue);} // 计数信号量增量
else if(countValue ==2){ xSemaphoreGive(countingSemaphore); printf("Task1:%d\r\n",countValue);} // 计数信号量增量
else if(countValue ==3){ xSemaphoreGive(countingSemaphore); printf("Task1:%d\r\n",countValue);} // 计数信号量增量
else if(countValue ==4){ xSemaphoreGive(countingSemaphore); printf("Task1:%d\r\n",countValue);} // 计数信号量增量
else if(countValue ==5){
osThreadResume(myTask02Handle);
}
// 任务1正常工作led
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
osDelay(2000);
}
/* USER CODE END StartDefaultTask */
}
/* USER CODE END Header_StartTask02 */
void StartTask02(void *argument)
{
/* USER CODE BEGIN StartTask02 */
/* Infinite loop */
for(;;)
{
// 获取计数信号量的当前计数值
uint32_t countValue = uxSemaphoreGetCount(countingSemaphore);
osDelay(500);
if(countValue == 5){
if(osThreadSuspend(defaultTaskHandle)==osOK){//挂起任务1
printf("task1 suspend ok\r\n");
xSemaphoreTake(countingSemaphore, portMAX_DELAY);
printf("Task2:%d\r\n",countValue);
}
}
else if(countValue ==4){ xSemaphoreTake(countingSemaphore, portMAX_DELAY); printf("Task2:%d\r\n",countValue);}//计数信号量减量释放
else if(countValue ==3){ xSemaphoreTake(countingSemaphore, portMAX_DELAY); printf("Task2:%d\r\n",countValue);}
else if(countValue ==2){ xSemaphoreTake(countingSemaphore, portMAX_DELAY); printf("Task2:%d\r\n",countValue);}
else if(countValue ==1){ xSemaphoreTake(countingSemaphore, portMAX_DELAY); printf("Task2:%d\r\n",countValue);}
else if(countValue ==0){
osThreadResume(defaultTaskHandle);
}
osDelay(2000);
}
/* USER CODE END StartTask02 */
}
运行效果
链接: https://pan.baidu.com/s/1T-_kplH0PwDPpj3v1AAK5Q?pwd=8dfe 提取码: 8dfe