FreeRTOS第2天:

1. 二值信号量简介(386.11)

什么是信号量?

  • 信号量(Semaphore),是在多任务环境下使用的一种机制,是可以用来保证两个或多个关键代码段不被并
    发调用。
  • 信号量这个名字,我们可以把它拆分来看,信号可以起到通知信号的作用,然后我们的量还可以用来表示资
    源的数量,当我们的量只有0和1的时候,它就可以被称作二值信号量,只有两个状态,当我们的那个量没有
    限制的时候,它就可以被称作为计数型信号量。
  • 信号量也是队列的一种。

什么是二值信号量?

  • 二值信号量其实就是一个长度为1,大小为零的队列,只有0和1两种状态,通常情况下,我们用它来进行互
    斥访问或任务同步。
  • 互斥访问:比如门钥匙,只有获取到钥匙才可以开门
  • 任务同步:比如我录完视频你才可以看视频
    在这里插入图片描述

二值信号量相关 API 函数

在这里插入图片描述

  1. 创建二值信号量
SemaphoreHandle_t xSemaphoreCreateBinary( void )
  • 参数:
  • 返回值:
    • 成功,返回对应二值信号量的句柄;
    • 失败,返回 NULL 。
  1. 释放二值信号量
BaseType_t  xSemaphoreGive( SemaphoreHandle_t xSemaphore )
  • 参数:
    • xSemaphore:要释放的信号量句柄
  • 返回值:
    • 成功,返回 pdPASS ;
    • 失败,返回 errQUEUE_FULL 。
  1. 获取二值信号量
BaseType_t  xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait );
  • 参数:
    • xSemaphore:要获取的信号量句柄
    • xTicksToWait:超时时间,0 表示不超时,portMAX_DELAY表示卡死等待;
  • 返回值:
    • 成功,返回 pdPASS ;
    • 失败,返回 errQUEUE_FULL 。

2. 二值信号量实操(387.12)

实验需求

  • 创建一个二值信号量,按下 KEY1 则释放信号量,按下 KEY2 获取信号量。

cubeMX配置(基于1.muban)

在这里插入图片描述
在这里插入图片描述

代码实现

  • 代码(5.semaphore_binary_test)
myBinarySemHandle = xSemaphoreCreateBinary();
void StartTaskGive(void const * argument)
{
  /* USER CODE BEGIN StartTaskGive */
  /* Infinite loop */
  for(;;)
  {
    if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
		{
			osDelay(20);
			if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
			{
				if(xSemaphoreGive(myBinarySemHandle) == pdTRUE)
					printf("二值信号量放入成功\r\n");
				else
					printf("二值信号量放入失败\r\n");
			}
			while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET);
		}
    osDelay(10);
  }
  /* USER CODE END StartTaskGive */
}
void StartTaskTake(void const * argument)
{
  /* USER CODE BEGIN StartTaskTake */
  /* Infinite loop */
  for(;;)
  {
    if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET)
		{
			osDelay(20);
			if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET)
			{
				if(xSemaphoreTake(myBinarySemHandle, portMAX_DELAY) == pdTRUE)
					printf("二值信号量获取成功\r\n");
				else
					printf("二值信号量获取失败\r\n");
			}
			while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET);
		}
    osDelay(10);
  }
  /* USER CODE END StartTaskTake */
}

在这里插入图片描述

3. 计数型信号量简介及实操(388.13)

什么是计数型信号量?

  • 计数型信号量相当于队列长度大于 1 的队列,因此计数型信号量能够容纳多个资源,这在计数型信号量被创
    建的时候确定的。
    在这里插入图片描述
    在这里插入图片描述

计数型信号量相关 API 函数

在这里插入图片描述

  • 计数型信号量的释放和获取与二值信号量完全相同!
SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount);
  • 参数:
    • uxMaxCount:可以达到的最大计数值
    • uxInitialCount:创建信号量时分配给信号量的计数值
  • 返回值:
    • 成功,返回对应计数型信号量的句柄;
    • 失败,返回 NULL 。

实验需求

  • 创建一个计数型信号量,按下 KEY1 则释放信号量,按下 KEY2 获取信号量。

cubeMX配置(基于5.semaphore_binary_test)

  • 将 Config parameters 标签里的 USE_COUNTING_SEMAPHORES 设置为 Enabled 。
    在这里插入图片描述
    在这里插入图片描述

代码实现

  • 代码(6.semaphore_counting_test)
myCountingSemHandle = xSemaphoreCreateCounting(3, 0);
void StartTaskGive(void const * argument)
{
 /* USER CODE BEGIN StartTaskGive */
 /* Infinite loop */
 for(;;)
{
    if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
   {
      osDelay(20);
      if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
     {
        if (xSemaphoreGive(myCountingSemHandle) == pdTRUE)
          printf("计数信号量放入成功\r\n");
        else
          printf("计数信号量放入失败\r\n");
     }
      while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET);
   }
  osDelay(10);
}
 /* USER CODE END StartTaskGive */
}
void StartTaskTake(void const * argument)
{
 /* USER CODE BEGIN StartTaskTake */
 /* Infinite loop */
 for(;;)
{
    if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET)
   {
      osDelay(20);
      if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET)
     {
        if (xSemaphoreTake(myCountingSemHandle, 0 ) == pdTRUE)
          printf("计数信号量获取成功\r\n");
        else
          printf("计数信号量获取失败\r\n");
     }
      while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET);
   }
  osDelay(10);
}
 /* USER CODE END StartTaskTake */
}

在这里插入图片描述

4. 互斥量简介(389.14)

什么是互斥量?

  • 在多数情况下,互斥型信号量和二值型信号量非常相似,但是从功能上二值型信号量用于同步,而互斥型信
    号量用于资源保护。
    互斥型信号量和二值型信号量还有一个最大的区别,互斥型信号量可以有效解决优先级反转现象。

什么是优先级翻转?

在这里插入图片描述

  • 以上图为例,系统中有 3 个不同优先级的任务 H/M/L,最高优先级任务 H 和最低优先级任务 L 通过信号量机
    制,共享资源。目前任务 L 占有资源,锁定了信号量,Task H 运行后将被阻塞,直到 Task L 释放信号量后,
    Task H 才能够退出阻塞状态继续运行。但是 Task H 在等待 Task L 释放信号量的过程中,中等优先级任务 M 抢
    占了任务 L,从而延迟了信号量的释放时间,导致 Task H 阻塞了更长时间,这种现象称为优先级倒置或反
    转。
  • 优先级继承:当一个互斥信号量正在被一个低优先级的任务持有时, 如果此时有个高优先级的任务也尝试获
    取这个互斥信号量,那么这个高优先级的任务就会被阻塞。不过这个高优先级的任务会将低优先级任务的优
    先级提升到与自己相同的优先级。
  • 优先级继承并不能完全的消除优先级翻转的问题,它只是尽可能的降低优先级翻转带来的影响。

互斥量相关 API 函数

  • 互斥信号量不能用于中断服务函数中!
    在这里插入图片描述
SemaphoreHandle_t xSemaphoreCreateMutex( void )
  • 参数:
  • 返回值:
    • 成功,返回对应互斥量的句柄;
    • 失败,返回 NULL 。

5. 互斥量实操(390.15)

实验需求 1. 演示优先级翻转

  • cubeMX配置(基于1.muban)
    在这里插入图片描述
    在这里插入图片描述
  • 代码(7.mutex_test)
    在这里插入图片描述

实验需求 2. 使用互斥量优化优先级翻转问题

  • cubeMX配置(基于7.mutex_test)
    在这里插入图片描述
    在这里插入图片描述
  • 代码(7.mutex_test2)
void StartTaskH(void const * argument)
{
  /* USER CODE BEGIN StartTaskH */
  /* Infinite loop */
  for(;;)
  {
		xSemaphoreTake(myMutexHandle, portMAX_DELAY);
		printf("TaskH: 我开始进入厕所,发功中。。。\r\n");
		HAL_Delay(3000);
		printf("TaskH: 我上完厕所了,真舒服。。。\r\n");
		xSemaphoreGive(myMutexHandle);
    osDelay(1000);
    osDelay(1);
  }
  /* USER CODE END StartTaskH */
}
void StartTaskM(void const * argument)
{
  /* USER CODE BEGIN StartTaskM */
  /* Infinite loop */
  for(;;)
  {
		printf("TaskM: 我就是为了占有CPU资源,带女朋友去兜风~~~\r\n");
    osDelay(1000);
  }
  /* USER CODE END StartTaskM */
}
void StartTaskL(void const * argument)
{
  /* USER CODE BEGIN StartTaskL */
  /* Infinite loop */
  for(;;)
  {	
		xSemaphoreTake(myMutexHandle, portMAX_DELAY);//获取互斥量
		printf("TaskL: 我开始进入厕所,发功中。。。\r\n");
		HAL_Delay(3000);
		printf("TaskL: 我上完厕所了,真舒服。。。\r\n");
		xSemaphoreGive(myMutexHandle);//释放互斥量
    osDelay(1);
  }
  /* USER CODE END StartTaskL */
}

在这里插入图片描述

6. 事件标志组简介(391.16)

什么是事件标志组?

  • 事件标志位: 表明某个事件是否发生,联想:全局变量 flag。通常按位表示,每一个位表示一个事件(高 8 位
    不算)
  • 事件标志组 是一组事件标志位的集合, 可以简单的理解事件标志组,就是一个整数。
  • 事件标志组本质是一个 16 位或 32 位无符号的数据类型 EventBits_t ,由 configUSE_16_BIT_TICKS 决定。
  • 虽然使用了 32 位无符号的数据类型变量来存储事件标志, 但其中的高 8 位用作存储事件标志组的控制信息,低 24 位用作存储事件标志 ,所以说一个事件组最多可以存储 24 个事件标志!
    在这里插入图片描述

事件标志组相关 API 函数

在这里插入图片描述

  1. 创建事件标志组
EventGroupHandle_t xEventGroupCreate( void );
  • 参数:
  • 返回值:
    • 成功,返回对应事件标志组的句柄;
    • 失败,返回 NULL 。
  1. 设置事件标志位
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );
  • 参数:
    • xEventGroup:对应事件组句柄。
    • uxBitsToSet:指定要在事件组中设置的一个或多个位的按位值。
  • 返回值:
    • 设置之后事件组中的事件标志位值。
  1. 清除事件标志位
EventBits_t xEventGroupClearBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear );
  • 参数:
    • xEventGroup:对应事件组句柄。
    • uxBitsToClear:指定要在事件组中清除的一个或多个位的按位值。
  • 返回值:
    • 清零之前事件组中事件标志位的值。
  1. 等待事件标志位
EventBits_t xEventGroupWaitBits(
           const EventGroupHandle_t xEventGroup,
           const EventBits_t uxBitsToWaitFor,
           const BaseType_t xClearOnExit,
           const BaseType_t xWaitForAllBits,
           TickType_t xTicksToWait );
  • 参数:
    • xEventGroup:对应的事件标志组句柄
    • uxBitsToWaitFor:指定事件组中要等待的一个或多个事件位的按位值
    • xClearOnExit:pdTRUE——清除对应事件位,pdFALSE——不清除
    • xWaitForAllBits:pdTRUE——所有等待事件位全为 1(逻辑与),pdFALSE——等待的事件位有一个为 1(逻辑或)
    • xTicksToWait:超时
  • 返回值:
    • 等待的事件标志位值:等待事件标志位成功,返回等待到的事件标志位
    • 其他值:等待事件标志位失败,返回事件组中的事件标志位

7. 事件标志组实操(392.17)

实验需求

  • 创建一个事件标志组和两个任务( task1 和 task2),task1 检测按键,如果检测到 KEY1 和 KEY2 都按过,
    则执行 task2 。

代码实现

  • 基于1.muban
    在这里插入图片描述
  • 代码(8.events_test)
EventGroupHandle_t  eventgroup_handle;
eventgroup_handle = xEventGroupCreate();
void StartTask1(void const * argument)
{
  /* USER CODE BEGIN StartTask1 */
  /* Infinite loop */
  for(;;)
  {
		// 等待 KEY1 按下
		if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
		{
			osDelay(20);
			if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
			{
				xEventGroupSetBits(eventgroup_handle, 0x01);
			}
			while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET);
		}
		// 等待 KEY2 按下
		if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET)
		{
			osDelay(20);
			if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET)
			{
				xEventGroupSetBits(eventgroup_handle, 0x02);
			}
			while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET);
		}
    osDelay(1);
  }
  /* USER CODE END StartTask1 */
}
void StartTask2(void const * argument)
{
  /* USER CODE BEGIN StartTask2 */
	EventBits_t event_bit =0;
  /* Infinite loop */
  for(;;)
  {
  	event_bit = xEventGroupWaitBits(eventgroup_handle, 0x01 | 0x02, pdTRUE, pdFALSE, portMAX_DELAY);
    printf("返回值:%#x,请假成功,可以去玩啦!\r\n", event_bit);
	osDelay(1);
  }
  /* USER CODE END StartTask2 */
}

在这里插入图片描述

8. 任务通知简介(393.18)

什么是任务通知?

  • FreeRTOS 从版本 V8.2.0 开始提供任务通知这个功能,每个任务都有一个 32 位的通知值。按照 FreeRTOS
    官方的说法,使用消息通知比通过二进制信号量方式解除阻塞任务快 45%, 并且更加省内存(无需创建队列)。
  • 在大多数情况下,任务通知可以替代二值信号量、计数信号量、事件标志组,可以替代长度为 1 的队列(可
    以保存一个 32 位整数或指针值),并且任务通知速度更快、使用的RAM更少!

任务通知值的更新方式

  • FreeRTOS 提供以下几种方式发送通知给任务 :
    • 发送消息给任务,如果有通知未读, 不覆盖通知值
    • 发送消息给任务,直接覆盖通知值
    • 发送消息给任务,设置通知值的一个或者多个位
    • 发送消息给任务,递增通知值
  • 通过对以上方式的合理使用,可以在一定场合下替代原本的队列、信号量、事件标志组等。

任务通知的优势和劣势

  • 任务通知的优势
  1. 使用任务通知向任务发送事件或数据,比使用队列、事件标志组或信号量快得多。
  2. 使用其他方法时都要先创建对应的结构体,使用任务通知时无需额外创建结构体。
  • 任务通知的劣势
  1. 只有任务可以等待通知,中断服务函数中不可以,因为中断没有 TCB 。
  2. 通知只能一对一,因为通知必须指定任务。
  3. 等待通知的任务可以被阻塞, 但是发送消息的任务,任何情况下都不会被阻塞等待。
  4. 任务通知是通过更新任务通知值来发送数据的,任务结构体中只有一个任务通知值,只能保持一个数
    据。

任务通知相关 API 函数

1. 发送通知

在这里插入图片描述

BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction );
  • 参数:
    • xTaskToNotify:需要接收通知的任务句柄;
    • ulValue:用于更新接收任务通知值, 具体如何更新由形参 eAction 决定;
    • eAction:一个枚举,代表如何使用任务通知的值;
      在这里插入图片描述
  • 返回值:
    • 如果被通知任务还没取走上一个通知,又接收了一个通知,则这次通知值未能更新并返回 pdFALSE, 而其他
      情况均返回 pdPASS。
BaseType_t xTaskNotifyAndQuery( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotifyValue );
  • 参数:
    • xTaskToNotify:需要接收通知的任务句柄;
    • ulValue:用于更新接收任务通知值, 具体如何更新由形参 eAction 决定;
    • eAction:一个枚举,代表如何使用任务通知的值;
    • pulPreviousNotifyValue:对象任务的上一个任务通知值,如果为 NULL, 则不需要回传, 这个时候就等价于函数 xTaskNotify()。
  • 返回值:
    • 如果被通知任务还没取走上一个通知,又接收了一个通知,则这次通知值未能更新并返回 pdFALSE, 而其他
      情况均返回 pdPASS。
BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );
  • 参数:
    • xTaskToNotify:接收通知的任务句柄, 并让其自身的任务通知值加 1。
  • 返回值:
    • 总是返回 pdPASS。

2. 等待通知

等待通知API函数只能用在任务,不可应用于中断中!
在这里插入图片描述

uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );
  • 参数:
    • xClearCountOnExit:指定在成功接收通知后,将通知值清零或减 1,pdTRUE:把通知值清零(二值信号量);pdFALSE:把通知值减一(计数型信号量);
    • xTicksToWait:阻塞等待任务通知值的最大时间;
  • 返回值:
    • 0:接收失败
    • 非0:接收成功,返回任务通知的通知值
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait );
  • 参数:
    • ulBitsToClearOnEntry:函数执行前清零任务通知值那些位 。
    • ulBitsToClearOnExit:表示在函数退出前,清零任务通知值那些位,在清 0 前,接收到的任务通知值会先被保存到形参*pulNotificationValue 中。
    • pulNotificationValue:用于保存接收到的任务通知值。 如果 不需要使用,则设置为 NULL 即可 。
    • xTicksToWait:等待消息通知的最大等待时间。

9. 任务通知实操(394.19)

  1. 模拟二值信号量
  • 基于1.muban
    在这里插入图片描述
  • 代码(9.notify_binary_test)
    在这里插入图片描述
    在这里插入图片描述
  1. 模拟计数型信号量
  • 代码(9. notify_counting_test)(基于9.notify_binary_test修改)
    在这里插入图片描述

在这里插入图片描述
3. 模拟事件标志组

  • 代码(9. notify_events_test)(基于9.notify_counting_test修改)
    在这里插入图片描述
    在这里插入图片描述
  1. 模拟邮箱
  • 代码(9. notify_queue_test)(基于9.notify_events_test修改)
    在这里插入图片描述
    在这里插入图片描述

10. 延时函数(395.20)

  • 延时函数分类
    • 相对延时:vTaskDelay
    • 绝对延时:vTaskDelayUntil
      在这里插入图片描述

在这里插入图片描述

  • vTaskDelay 与 HAL_Delay 的区别
    • vTaskDelay 作用是让任务阻塞,任务阻塞后,RTOS 系统调用其它处于就绪状态的优先级最高的任务来执
      行。
    • HAL_Delay 一直不停的调用获取系统时间的函数,直到指定的时间流逝然后退出,故其占用了全部 CPU 时
      间。
      在这里插入图片描述
      在这里插入图片描述

11. 软件定时器简介(396.21)

什么是定时器?

  • 简单可以理解为闹钟,到达指定一段时间后,就会响铃。
  • STM32 芯片自带硬件定时器,精度较高,达到定时时间后会触发中断,也可以生成 PWM 、输入捕获、输出比较,等等,功能强大,但是由于硬件的限制,个数有限。
  • 软件定时器也可以实现定时功能,达到定时时间后可调用回调函数,可以在回调函数里处理信息。

软件定时器优缺点

  • 优点:
  1. 简单、成本低;
  2. 只要内存足够,可创建多个;
  • 缺点:
    • 精度较低,容易受中断影响。在大多数情况下够用,但对于精度要求比较高的场合不建议使用。

软件定时器原理

  • 定时器是一个可选的、不属于 FreeRTOS 内核的功能,它是由定时器服务任务来提供的。
  • 在调用函数 vTaskStartScheduler() 开启任务调度器的时候,会创建一个用于管理软件定时器的任务,这个
    任务就叫做软件定时器服务任务。
  1. 负责软件定时器超时的逻辑判断
  2. 调用超时软件定时器的超时回调函数
  3. 处理软件定时器命令队列
  • FreeRTOS提供了很多定时器有关的API函数,这些API函数大多都使用FreeRTOS的队列发送命令给定时器服
    务任务。这个队列叫做定时器命令队列。 定时器命令队列是提供给FreeRTOS的软件定时器使用的,用户不
    能直接访问!

    在这里插入图片描述

软件定时器相关配置

软件定时器有一个定时器服务任务和定时器命令队列,这两个东西肯定是要配置的,相关的配置也是放到文件 FreeRTOSConfig.h 中的,涉及到的配置如下:

1、configUSE_TIMERS

  • 如果要使用软件定时器的话宏configUSE_TIMERS一定要设置为1,当设置为1的话定时器服务任务就会在启
    动FreeRTOS调度器的时候自动创建。

2、configTIMER_TASK_PRIORITY

  • 设置软件定时器服务任务的任务优先级,可以为0~(configMAX_PRIORITIES-1)。优先级一定要根据实际的应
    用要求来设置。如果定时器服务任务的优先级设置的高的话,定时器命令队列中的命令和定时器回调函数就会及时的得到处理。

3、configTIMER_QUEUE_LENGTH

  • 此宏用来设置定时器命令队列的队列长度。

4、configTIMER_TASK_STACK_DEPTH

  • 此宏用来设置定时器服务任务的任务堆栈大小。

单次定时器和周期定时器

  • 单次定时器: 只超时一次,调用一次回调函数。可手动再开启定时器;
  • 周期定时器: 多次超时,多次调用回调函数。

软件定时器相关 API 函数

在这里插入图片描述

  1. 创建软件定时器
TimerHandle_t xTimerCreate
        ( const char * const pcTimerName,
         const TickType_t xTimerPeriod,
         const UBaseType_t uxAutoReload,
         void * const pvTimerID,
         TimerCallbackFunction_t pxCallbackFunction );
  • 参数:
    • pcTimerName:软件定时器名称
    • xTimerPeriodInTicks:定时超时时间,单位:系统时钟节拍。宏 pdMS_TO_TICKS() 可用于将以毫秒为单位指定的时间转换为以 tick 为单位指定的时间。
    • uxAutoReload:定时器模式, pdTRUE:周期定时器, pdFALSE:单次定时器
    • pvTimerID:软件定时器 ID,用于多个软件定时器公用一个超时回调函数
    • pxCallbackFunction:软件定时器超时回调函数
  • 返回值:
    • 成功:定时器句柄
    • 失败:NULL
  1. 开启软件定时器
BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xBlockTime );
  • 参数:
    • xTimer:待开启的软件定时器的句柄
    • xTickToWait:发送命令到软件定时器命令队列的最大等待时间
  • 返回值:
    • pdPASS:开启成功
    • pdFAIL:开启失败
  1. 停止软件定时器
BaseType_t xTimerStop( TimerHandle_t xTimer, TickType_t xBlockTime );
  • 参数与返回值同上。
  1. 复位软件定时器
BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xBlockTime );
  • 参数与返回值同上。
  • 该功能将使软件定时器的重新开启定时,复位后的软件定时器以复位时的时刻作为开启时刻重新定时。
  1. 更改软件定时器定时时间
BaseType_t xTimerChangePeriod( TimerHandle_t xTimer, TickType_t xNewPeriod, TickType_t xBlockTime );
  • xNewPeriod:新的定时超时时间,单位:系统时钟节拍。
  • 其余参数与返回值同上。

12. 软件定时器实操(397.22)

实验需求

  • 创建两个定时器:
    • 定时器1,周期定时器,每1 秒打印一次 Jessie shuai
    • 定时器2,单次定时器,启动后 2 秒打印一次 Hi,Jessie!

cubeMX配置

  • 基于1.muban修改
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 代码(10. timer_test)
    在这里插入图片描述
    在这里插入图片描述

13. 中断管理(398.23)

中断定义

  • 请参考 51 及 STM32 中断相关课程。

中断优先级

  • 任何中断的优先级都大于任务!
  • 在我们的操作系统,中断同样是具有优先级的,并且我们也可以设置它的优先级,但是他的优先级并不是从
    0~15 ,默认情况下它是从 5~15 ,0~4 这 5 个中断优先级不是 FreeRTOS 控制的(5是取决于
    configMAX_SYSCALL_INTERRUPT_PRIORITY)。

相关注意

  1. 在中断中必需使用中断相关的函数;
  2. 中断服务函数运行时间越短越好。

实验需求

  • 创建一个队列及一个任务,按下按键 KEY1 触发中断,在中断服务函数里向队列里发送数据,任务则阻塞接
    收队列数据。

cubeMX配置

在这里插入图片描述
在这里插入图片描述

代码实现

  • stm32f1xx_it.c
#include "cmsis_os.h"
extern osMessageQId myQueue01Handle;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  uint32_t snd = 6;
  xQueueSendFromISR(myQueue01Handle, &snd, NULL);
}
  • freertos.c
void StartDefaultTask(void const * argument)
{
 /* USER CODE BEGIN StartDefaultTask */
  uint32_t rev = 0;
 /* Infinite loop */
 for(;;)
{
    if (xQueueReceive(myQueue01Handle, &rev, portMAX_DELAY) == pdTRUE)
      printf("rev = %d\r\n", rev);
  	osDelay(1);
}
 /* USER CODE END StartDefaultTask */
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/210496.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Android BT HCI分析简介

对于蓝牙开发者来说,通过HCI log可以帮助我们更好地分析问题,理解蓝牙协议,就好像网络开发一定要会使用Wireshark分析网络协议一样。 本篇主要介绍HCI log的作用、如何抓取一份HCI log,并结合一个实际的例子来说明如何分析HCI log…

eclipse中设置自动补齐代码

eclipse中设置自动补齐代码 01 在window里找到preference 02 在preference里搜索content assist 03 在Java的content assist设置 设置为.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 04 apply and close即可

mysql在linux环境下安装(rpm)以及初始化后的登录配置

注:该安装步骤转载于CSDN,下方配置为原创 按照图片安装并初始化完成MySQL等操作后进行; 安装对于rpm包集合 1-查看安装情况(有4个路径) whereis mysql 2-查看服务状态 systemctl status mysql 3-初始化数据库 mysqld --initial…

mybatis源码(五)springboot pagehelper实现查询分页

1、背景 springboot的pagehelper插件能够实现对mybatis查询的分页管理,而且在使用时只需要提前声明即可,不需要修改已有的查询语句。使用如下: 之前对这个功能一直很感兴趣,但是一直没完整看过,今天准备详细梳理下。按…

施人玫瑰手留余香和影像组学、医学人工智能未来漫谈

今天收到进阶班学员的留言: 提示:本文有硬核软文嫌疑,请慎重阅读。“ 我用您给我们讲的CLEAR,与一个审稿人进行了battle。有理有据。评估下来,我感觉我们的文章还是挺符合CLEAR的。” 我从来不排斥在商言商&#xff0…

初识数据结构及复杂度

1、数据结构 数据结构数据结构(描述和组织数据),Java会把一些数据结构封装起来,在java中数据结构叫做集合。 数据结构:(data structer)是计算机存储、组织数据的方式,指相互之间存在…

使用 mtcnn 和 facenet 进行人脸识别

一、前言 人脸识别目前有比较多的应用了,比如门禁系统,手机的人脸解锁等等,今天,我们也来实现一个简单的人脸识别。 二、思维导图 三、详细步骤 3.1 准备 3.1.1 facenet 权重文件下载 下载地址:https://drive.goo…

用户反馈组件实现(Vue3+ElementPlus)含图片拖拽上传

用户反馈组件实现&#xff08;Vue3ElementPlus&#xff09;含图片拖拽上传 1. 页面效果1.1 正常展示1.2 鼠标悬浮1.3 表单 2. 代码部分1.2 html、ts1.2 less部分 3. 编码过程遇到的问题 1. 页面效果 1.1 正常展示 1.2 鼠标悬浮 1.3 表单 2. 代码部分 1.2 html、ts <templ…

虚拟机备份数据自动化验证原理

备份数据成功备份下来了&#xff0c;但是备份数据是否可用可靠&#xff1f;对于这个问题&#xff0c;最好最可靠的方法是将备份数据实际恢复出来验证。 但是这样的方法&#xff0c;不仅费时费力&#xff0c;而且需要随着备份数据的定期产生&#xff0c;还应当定期做备份数据验…

在国内Facebook广告怎么解决充值渠道问题?

怎么解决Facebook预充值跑广告营销的付款方式问题呢&#xff1f; Facebook跑广告是很多做出口营销的公司或团队喜欢的平台之一&#xff0c;那就避免不了需要支付给Facebook平台广告费用了&#xff0c;那到底用什么方式去充值到FB号上去解决呢&#xff1f;FB预充值有什么咔可以…

产业迭代 共谋新生 喜尔康智家总冠名2023中国建材与家居行业焕新发展大会

2023年家居市场迎来了全新的变化&#xff0c;行业不断向绿色化、智能化方向发展&#xff0c;特别是在商务部等13部门发布《关于促进家居消费若干措施的通知》后&#xff0c;更加注重推动大家居市场产业升级迭代和高质量发展。在这个过程中&#xff0c;绿色化、智能化转型成为家…

同旺科技 USB TO SPI / I2C --- 调试W5500_读写网关地址

所需设备&#xff1a; 内附链接 1、USB转SPI_I2C适配器(专业版); 首先&#xff0c;连接W5500模块与同旺科技USB TO SPI / I2C适配器&#xff0c;如下图&#xff1a; 这里的网关地址设置为192.168.1.1 先将网关地址写入寄存器&#xff0c;然后再读取出来&#xff1a;

智能优化算法应用:基于共生生物算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于共生生物算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于共生生物算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.共生生物算法4.实验参数设定5.算法结果6.参考…

frp实现内网穿透(多端口穿透)

frp实现内网穿透 准备一个公网服务器&#xff08;腾讯、阿里、华为的云服务器&#xff09; 下载frp的安装包 下载对应系统的安装包&#xff0c;不要下错文件。 注意amd对应x86架构的系统 arm对应 arm架构系统&#xff08;macos&#xff09; 点击下载 查看文档将对应的安装包放…

VUE设计与实现共读系列之ref的实现【响应式原理】

前言 我们先顺一下vue使用响应式数据的流程&#xff1a; vue 是通过 ref 和 reactive 来创建响应式值&#xff0c;改变响应式值&#xff0c;视图跟着发生变化。 我们今天就来看一下ref和reactive是如何实现的 准备 首先&#xff0c;打开ref函数的位置 我们可以看到一个被re…

UVA1368 DNA Consensus String

DNA Consensus String The Hamming distance is the number of different characters at each position from two strings of equal length. For example, assume we are given the two strings “AGCAT” and “GGAAT.” The Hamming distance of these two strings is 2 bec…

Adobe Bridge——牵线搭桥

今天我们又一次来分享Adobe全家桶紧剩的几位成员之一&#xff0c;今天介绍的这一位成员&#xff0c;是Adobe公司开发的一个组织工具程序。 从Bridge中可以查看、搜索、排序、管理和处理图像文件,还可以使用Adobe Bridge 来创建新文件夹、对文件进行重命名、移动和删除操作、编辑…

【计算机概论 ①】- 电脑:辅助人脑的好工具

目录 一、电脑硬件的五大单元 二、一切设计的起点&#xff1a;CPU 的架构 三、其他单元的设备 四、运行流程 五、电脑的分类 六、电脑上面常用的计算单位&#xff08;容量、速度等&#xff09; 操作系统跟硬件有相当程度的关联性&#xff0c;所以&#xff0c;如果不了解一…

hls实现播放m3u8视频将视频流进行切片 HLS.js简介

github官网GitHub - video-dev/hls.js: HLS.js is a JavaScript library that plays HLS in browsers with support for MSE.HLS.js is a JavaScript library that plays HLS in browsers with support for MSE. - GitHub - video-dev/hls.js: HLS.js is a JavaScript library …