IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32中的FreeRTOS-#2(对任务的操作) -> 正文阅读

[嵌入式]STM32中的FreeRTOS-#2(对任务的操作)

**内容回顾:**上一节,我们通过使用优先级不同的三个任务,同时在串口打印了信息。但是大家肯定会有疑问,为什么相同优先级的任务不能同时通过串口打印数据,不同优先级的任务反倒可以“同时”打印?本节将深入探讨任务调用的顺序问题。

这是FreeRTOS系列的第二篇教程,在本教程中,我们将看到一些与Tasks相关的操作。这包括创建任务,在任务之间切换,暂停和恢复任务,终止任务等等。

CubeMX设置

让我们先从设置CubeMX开始。如下所示,我使用CMSIS V1,因为它被大多数STM32芯片型号支持。其他的一切都保持默认。
在这里插入图片描述
在包含参数选项卡中,使能vTaskDelayUntill选项。vTaskDelayUntill函数用于将任务延迟到指定的时间。周期性任务可以使用此函数,以确保固定的执行频率。关于函数vTaskDelayUntil的使用请阅读[官方文档](FreeRTOS - A FREE Open Source Simple RTOS Scheduler API documentation)。

  函数原型

  **void vTaskDelayUntil( TickType_t \*pxPreviousWakeTime, const TickType_t xTimeIncrement );**

官方示例

 // Perform an action every 10 ticks.
 void vTaskFunction( void * pvParameters )
 {
 	TickType_t xLastWakeTime;
 	const TickType_t xFrequency = 10;
     // Initialise the xLastWakeTime variable with the current time.
     xLastWakeTime = xTaskGetTickCount();
     for( ;; )
     {
         // Wait for the next cycle.
         vTaskDelayUntil( &xLastWakeTime, xFrequency );
         // Perform action here.
     }
 }

创建任务

按照教程1的方法,在CubeMX中新创建一个Task-2,优先级定义为“osPriorityNormal”,与默认的任务优先级相同。创建任务后,我们现在有两个可用的任务。一个是默认的Task,另一个是Task2。

在defaultTask和Task2的执行代码中添加内容

// 默认任务
void StartDefaultTask(void const * argument)
{
  /* USER CODE BEGIN StartDefaultTask */
  static int indx=0;	// 库代码会用到index,为避免可能的冲突,写做indx
  /* Infinite loop */
  for(;;)
  {
    printf("Task1 is going,index=%d  ",indx++);
    osDelay(1000);
}
// 任务2
void StartTask02(void const * argument)
{
  /* USER CODE BEGIN StartTask02 */
  static int indx=0;
  /* Infinite loop */
  for(;;)
  {
    printf("Task2 is going,index=%d  ",indx++);
    osDelay(2000);
}

运行代码后,我们将得到如下所示的结果。Task1和Task2均是2秒执行一次
在这里插入图片描述

  • 表面上看,Task2输出信息的时候,Task1没有输出信息,似乎Task2导致Task1没有被执行,但是Task1相邻两次的信息输出中,index的值相差为2,表明在二者之间,Task1其实已经被执行过一次,但是信息没有成功被输出。
  • FreeRTOS支持多个任务具有相同的优先级,当配置成可抢占式内核时,调度算法既支持基于优先级的调度,也支持时间片轮流调度。
  • 任何时候调度器运行时它都选择处于就绪状态下的优先级最高的那个任务;如果有多个任务处于同一优先级,则FreeRTOS每个时钟节拍的中断服务程序中,将对这些任务应用时间片调度算法,轮流执行这些任务。
  • 为了验证Task1任然是1秒执行一次,在Task1和Task2的执行代买中加入LED0和LED1的翻转代码,用示波器进行测试
// 默认任务
void StartDefaultTask(void const * argument)
{
  /* USER CODE BEGIN StartDefaultTask */
  static int index=0;
  /* Infinite loop */
  for(;;)
  {
    // printf("Task1 is going,index=%d  ",index++);
    HAL_GPIO_TogglePin(BSP_LED1_GPIO_Port,BSP_LED1_Pin);
    osDelay(1000);
}
// 任务2
void StartTask02(void const * argument)
{
  /* USER CODE BEGIN StartTask02 */
  static int index=0;
  /* Infinite loop */
  for(;;)
  {
  	// printf("Task2 is going,index=%d  ",index++);
    HAL_GPIO_TogglePin(BSP_LED1_GPIO_Port,BSP_LED1_Pin);
    osDelay(2000);
}

Task1和Task2执行验证
可见,在Task-2和Task-1“同时”调用串口打印消息会导致信息输出不完整。之所以Task-1的信息未被打印,一与HAL库和printf函数有关,二与时间片调度有关。在后续教程中我们会给出这个问题的解决方法,如果您此时感兴趣,可以参考以下资料

修改Task-2的优先级定义为“osPriorityAboveNormal”,比Task-1的优先级高。
在这里插入图片描述
程序运行过程分析:

  • 当内核取得控制权时,它会创建 2 个 Task,一个是 Default Task,记为Task1,另一个是 Task2。
  • 现在内核有 2 个任务要运行,所以它会选择优先级更高的任务,即 Task2。 printf 语句将被执行,Task 将进入阻塞模式 2 秒,处理器资源被释放。
  • 在此之后,内核将立即运行Task1。 再次运行 printf 语句后,默认任务将进入阻塞状态 1 秒,这一秒什么都不会运行。
  • 1 秒钟后,Task1将变为就绪并运行。 它将打印信息,并进入阻塞状态 1 秒。
  • 1秒钟后,Task1将再次唤醒,同时任务 2 也将退出阻塞模式,因为任务 2 进入阻塞模式已经过去了 2 秒。
  • 内核再次运行 2 个任务,因此它将首先运行更高优先级的任务,即 Task2。
  • 这个循环将以相同的顺序继续。

任务的挂起和恢复

当一个Task被挂起时,它将一直处于阻塞状态,直到再次恢复。为了挂起一个任务,我们将使用osThreadSuspend。其参数是要挂起的任务的线程ID(或者说是句柄)。

现在,为了恢复这个挂起的任务,我们将使用另一个名为osThreadResume的函数。同样,这个函数的参数也是挂起任务的线程ID。我将使用下面给出的另一个条件来继续这个任务

综上,在Task2的代码中添加

// 挂起任务
if (index==4)
{			 
	osThreadSuspend(defaultTaskHandle);
}
// 恢复任务
if (indx ==7)
{
    printf ("Resuming DefaultTask\n");
    osThreadResume(defaultTaskHandle);
}

运行代码后,结果如下图所示
在这里插入图片描述
让我们看看到底发生了什么

  • 任务将按照适当的顺序运行,直到index等于3。
  • 在输出index =3语句后,index将递增为4。此时Task2将进入阻塞状态,默认任务将运行。
  • 2秒后,task2获得控制权,并执行一行中的下一条语句。因为index等于4,所以defaultTask被挂起。
  • 现在内核只有一个任务要运行,它将每2秒运行一次Task2。当索引变为7后,默认任务将被恢复,两个任务将继续同时运行。

终止任务

有过PC编程经验的同学可能知道,与任务挂起不同,一旦任务被终止,就无法重新恢复。要终止任务,我们将使用osThreadTerminate函数,其参数是要终止的线程的线程ID。

if (indx == 3)
{
    printf ("Terminating DefaultTask\n");
    osThreadTerminate(defaultTaskHandle);
}

上面代码的结果如下所示
在这里插入图片描述
如上所示,当index变量变为3时,默认任务将终止,只有任务2在此之后运行。

在一段时间内阻塞任务

这就像在某一特定时间后自动恢复任务。我们将使用函数osDelayUntil来完成此操作。这个函数的参数如下

osDelayUntil (uint32_t *PreviousWakeTime, uint32_t millisec)

PreviousWakeTime是指向一个变量的指针,该变量保存了任务最后被解除阻塞的时间。millisec是延时的时间。

uint32_t PreviousWakeTime;
if (index ==3)
{
    PreviousWakeTime = osKernelSysTick();
    printf("Berore:PreviousWakeTime=%d",PreviousWakeTime);
    osDelayUntil(&PreviousWakeTime, 4000);
    printf("After:PreviousWakeTime=%d",PreviousWakeTime);
}
printf("After:PreviousWakeTime=%d",PreviousWakeTime);

上面代码的结果如下所示
在这里插入图片描述
所以这两个任务都会运行,直到索引变为3,Task2将被挂起,默认任务将继续运行4秒。任务2在4秒后恢复,两个任务同样同时运行。osDelayUntil相当于是个延时函数,只不过在这个延时函数延时的过程中,资源被释放,用于执行其他任务。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-10-21 12:20:51  更:2021-10-21 12:31:32 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:22:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码