04_FreeRTOS 计数信号量

04_FreeRTOS 计数信号量

本文将介绍:
a. 使用CMSIS API ,介绍FreeRTOS中计数信号量
b. 不使用CMSIS API,直接使用FreeRTOS函数

  1. 简介
    计数信号量可用于控制对资源的访问。要获得对资源的控制,任务必须首先获得信号量。因此减少了信号量计数值。当计数值达到零时,将没有可用资源。当任务使用资源完成时,它将“give”信号量,从而增加信号量计数值。

  2. 设置部分
    CubeMX中启用计数信号量:

  3. FreeRTOS中计数信号量
    3.1 使用CMSIS API ,介绍FreeRTOS中计数信号量
    【在上一篇中修改过来】
    声明任务函数和计数信号量、定义变量

    osThreadId Task1Handle;
    osThreadId Task2Handle;
    osThreadId Task3Handle;
    osThreadId Task4Handle;
    osSemaphoreId BinarySem01Handle;
    /* USER CODE BEGIN PV */
    osSemaphoreId CountingSem;
    
    int resourve[3] = {111,222,333};
    uint8_t indx = 0;
    // uart receive
    uint8_t rx_data = 0;
    

定义创建,线程的优先级由高到低:

```c++
  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  CountingSem = xQueueCreateCountingSemaphore(3,0);
  if (CountingSem == NULL) printf( "Unable to Create Semaphore\n\n");
  else printf( "Counting Semaphore created successfully\n\n");
  /* Create the thread(s) */
  /* definition and creation of Task1 */
  osThreadDef(Task1, Task1_init, osPriorityRealtime, 0, 512);
  Task1Handle = osThreadCreate(osThread(Task1), NULL);

  /* definition and creation of Task2 */
  osThreadDef(Task2, Task2_init, osPriorityHigh, 0, 512);
  Task2Handle = osThreadCreate(osThread(Task2), NULL);

  /* definition and creation of Task3 */
  osThreadDef(Task3, Task3_init, osPriorityAboveNormal, 0, 512);
  Task3Handle = osThreadCreate(osThread(Task3), NULL);

  /* definition and creation of Task4 */
  osThreadDef(Task4, Task4_init, osPriorityNormal, 0, 512);
  Task4Handle = osThreadCreate(osThread(Task4), NULL);
```

首先初始化接受HAL_UART_Receive_IT(&huart1, &rx_data, 1);函数。再把HAL_UART_Receive_IT放在串口全局中断里,可以接收指定长度的字符串,并在接收完成之后产生中断。当给串口一输入字符串g后,就能give 3张令牌。

```c++
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	HAL_UART_Receive_IT(huart, &rx_data, 1);
	if (rx_data == 'g')
	{
		// release the semaphore here
		 /* The xHigherPriorityTaskWoken parameter must be initialized to pdFALSE as
		 it will get set to pdTRUE inside the interrupt safe API function if a
		 context switch is required. */
		BaseType_t xHigherPriorityTaskWoken = pdFALSE;

		xSemaphoreGiveFromISR(CountingSem, &xHigherPriorityTaskWoken);  // ISR SAFE VERSION
		xSemaphoreGiveFromISR(CountingSem, &xHigherPriorityTaskWoken);  // ISR SAFE VERSION
		xSemaphoreGiveFromISR(CountingSem, &xHigherPriorityTaskWoken);  // ISR SAFE VERSION

		/* Pass the xHigherPriorityTaskWoken value into portEND_SWITCHING_ISR(). If
		 xHigherPriorityTaskWoken was set to pdTRUE inside xSemaphoreGiveFromISR()
		 then calling portEND_SWITCHING_ISR() will request a context switch. If
		 xHigherPriorityTaskWoken is still pdFALSE then calling
		 portEND_SWITCHING_ISR() will have no effect */

		portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
	}
}
```

```c++
/* USER CODE END Header_Task1_init */
void Task1_init(void const * argument)
{
  /* USER CODE BEGIN 5 */
	int semcount = 0;
  /* Infinite loop */

	printf("Give 3 semaphores at the beginning\n");
	xSemaphoreGive(CountingSem);
	xSemaphoreGive(CountingSem);
	xSemaphoreGive(CountingSem);
  for(;;)
  {
	  //test
	  printf("Enter Task1 to get the Semaphore\n");
	  semcount = uxSemaphoreGetCount(CountingSem);
	  printf("Tokens available are : %d\n",semcount);
	  xSemaphoreTake(CountingSem,portMAX_DELAY);
	  printf("Leaving Task1 , Data ACCESSED is %d\n",resourve[indx]);
	  printf("------------------------------------------\n");
	  indx++;
	  if(indx>2)
		  indx = 0;
	  vTaskDelay(3000);

  }
  /* USER CODE END 5 */ 
}

/* USER CODE BEGIN Header_Task2_init */
/**
* @brief Function implementing the Task2 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_Task2_init */
void Task2_init(void const * argument)
{
  /* USER CODE BEGIN Task2_init */
	int semcount = 0;
  /* Infinite loop */
  for(;;)
  {
	  printf("Enter Task2 to get the Semaphore\n");
	  semcount = uxSemaphoreGetCount(CountingSem);
	  printf("Tokens available are : %d\n",semcount);
	  xSemaphoreTake(CountingSem,portMAX_DELAY);
	  printf("Leaving Task2 , Data ACCESSED is %d\n",resourve[indx]);
	  printf("------------------------------------------\n");
	  indx++;
	  if(indx>2)
		  indx = 0;
	  vTaskDelay(2000);

  }
  /* USER CODE END Task2_init */
}

/* USER CODE BEGIN Header_Task3_init */
/**
* @brief Function implementing the Task3 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_Task3_init */
void Task3_init(void const * argument)
{
  /* USER CODE BEGIN Task3_init */
	int semcount = 0;
  /* Infinite loop */
  for(;;)
  {
	  printf("Enter Task3 to get the Semaphore\n");
	  semcount = uxSemaphoreGetCount(CountingSem);
	  printf("Tokens available are : %d\n",semcount);
	  xSemaphoreTake(CountingSem,portMAX_DELAY);
	  printf("Leaving Task3 , Data ACCESSED is %d\n",resourve[indx]);
	  printf("------------------------------------------\n");
	  indx++;
	  if(indx>2)
		  indx = 0;
	  vTaskDelay(1000);

  }
  /* USER CODE END Task3_init */
}

/* USER CODE BEGIN Header_Task4_init */
/**
* @brief Function implementing the Task4 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_Task4_init */
void Task4_init(void const * argument)
{
  /* USER CODE BEGIN Task4_init */
	int semcount = 0;
  /* Infinite loop */
  for(;;)
  {
	  printf("Enter Task4 to get the Semaphore\n");
	  semcount = uxSemaphoreGetCount(CountingSem);
	  printf("Tokens available are : %d\n",semcount);
	  xSemaphoreTake(CountingSem,portMAX_DELAY);
	  printf("Leaving Task4 , Data ACCESSED is %d\n",resourve[indx]);
	  printf("------------------------------------------\n");
	  indx++;
	  if(indx>2)
		  indx = 0;
	  vTaskDelay(500);

  }
  /* USER CODE END Task4_init */
}
```

通过xSemaphoreTake获取令(消耗)牌继续执行任务。通过xSemaphoreGiveFromISR生产令牌。通过uxSemaphoreGetCount查看令牌剩余个数。然后再按照优先级执行。

3.2 结果:
初始化给出三个令牌:

通过中断给出三个令牌:

3.3 不使用CMSIS API 介绍计数器信号量
注释掉#include“ cmsis_os.h”手动包含与FreeRTOS相关的文件。
```c++
#include“ FreeRTOS.h”
#include“ task.h”
#include“ timers.h”
#include“ queue.h”
#include“ semphr.h”
#include“ event_groups.h”

#include“ stdlib.h” 
#include“ string.h”
```
2.2 定义Task函数与创建信号量

定义四个不同的人物处理程序和计数信号量处理程序
```c++
//创建任务定义
TaskHandle_t Task1handler;
void Task1_Init(void * pvParameters);

TaskHandle_t Task2handler;
void  Task2_Init(void  * pvParameters);

TaskHandle_t Task3handler;
void  Task3_Init(void  * pvParameters);

TaskHandle_t Task4handler;
void  Task4_Init(void  * pvParameters);

//与信号量相关
SemaphoreHandle_t CountingSem;

//资源相关的
int resource[ 3 ] = { 111,222,333 };
int indx =  0 ;

// uart相关的
uint8_t rx_data =  0 ;
```

在main函数内部,首先需要创建计数信号量。首先需要创造信号量CountingSem = xSemaphoreCreateCounting(3,0),其中3为最大信号量,0为初始计数。如果有错误,并且无法创建信号量,它将返回NULL,否则将返回其他值。

```c++
 CountingSem = xSemaphoreCreateCounting(3,0);
  if (CountingSem == NULL) HAL_UART_Transmit(&huart2, (uint8_t *) "Unable to Create Semaphore\n\n", 28, 100);
  else HAL_UART_Transmit(&huart2, (uint8_t *) "Counting Semaphore created successfully\n\n", 41, 1000);
```
   //创建任务
    
     xTaskCreate(Task1_Init,“Task1” ,128,NULL,3,& Task1handler); 
     xTaskCreate(Task2_Init,“Task2” ,128,NULL,2,& Task2handler); 
     xTaskCreate(Task3_Init,“Task3” ,128,NULL,1,& Task3handler); 
     xTaskCreate(Task4_Init,“Task4” ,128,NULL,0,& Task4handler);

     vTaskStartScheduler();
   ```

数据接收函数:
```c++
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
   HAL_UART_Receive_IT(huart, &rx_data, 1);
   if (rx_data == 'r')
   {
   	// release the semaphore here
   	 /* The xHigherPriorityTaskWoken parameter must be initialized to pdFALSE as
   	 it will get set to pdTRUE inside the interrupt safe API function if a
   	 context switch is required. */
   	BaseType_t xHigherPriorityTaskWoken = pdFALSE;

   	xSemaphoreGiveFromISR(CountingSem, &xHigherPriorityTaskWoken);  // ISR SAFE VERSION
   	xSemaphoreGiveFromISR(CountingSem, &xHigherPriorityTaskWoken);  // ISR SAFE VERSION
   	xSemaphoreGiveFromISR(CountingSem, &xHigherPriorityTaskWoken);  // ISR SAFE VERSION

   	/* Pass the xHigherPriorityTaskWoken value into portEND_SWITCHING_ISR(). If
   	 xHigherPriorityTaskWoken was set to pdTRUE inside xSemaphoreGiveFromISR()
   	 then calling portEND_SWITCHING_ISR() will request a context switch. If
   	 xHigherPriorityTaskWoken is still pdFALSE then calling
   	 portEND_SWITCHING_ISR() will have no effect */

   	portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
   }
}

其他部分一样,结果也一样。

Code下载地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Gkbytes

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值