一、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 <stdio.h> 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