从0开始的FreeRTOS(4)

“从0开始的FreeRTOS”系列教程第四讲

作者:satori

这一次我们来进行基于FreeRTOS的任务管理实验。
在开讲之前,推荐一下Zou Changjun翻译的FreeRTOS实时内核使用指南(官方网站上的英文原名是Mastering_the_FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide),在后面讲解API时我们力求精简易懂,所以不会说太多详细的内容,具体可以参见该文档和官方API手册(文末有本文档的下载链接)。

回顾一下上次我们介绍的有关FreeRTOS的进程的知识:
主要有:进程的概念,进程的调度机制
对于FreeRTOS而言,不同优先级的进程之间采用优先级调度算法,对于同优先级的进程之间采用时间片轮转调度算法+FCFS算法。

本次实验我们主要的实验内容为
任务的创建
同优先级进程之间的时间片轮转调度算法
不同优先级进程之间的优先级调度算法
任务的删除
任务的挂起(延时函数)

首先我们先来学习一下和FreeRTOS的任务创建有关的API:

对于初学者而言,比较需要关心的参数有以下几个:pvTaskCode,pcName和uxPriority
pvTaskCode是任务函数名
pcName是用户起的函数名
uxPriority是任务优先级
在cude建立的工程中,我们不会直接使用freertos的API,而是会使用CMSIS-RTOS的API:

#define osThreadDef (
       name,                             //进程名
    priority,                          //进程优先级
    instances,                       //进程函数
    stacksz                           //栈大小
)

其中priority一般使用的是CMISIS-RTOS自己定义的七个优先级(详见上一讲介绍的结构体)

osThreadId osThreadCreate   (
    const osThreadDef_t *   thread_def,         //传递在osThreadDef中输入的参数
    void *  argument                                             //参数
)

这里我们通过一个实例来学习进程的创建:
实验1:
使用CMSIS-RTOS创建一个进程:
仿照第二讲中的方式新建一个工程
并启用串口1(后续的教程中串口会非常常用)

参数设置如下

将默认的任务的名字改成task_1

创建工程,在freertos.c上加入

#include "stm32f1xx_hal.h"

在usart.c下加入以下代码,就可以在32中使用printf功能了

#ifdef __GNUC__
  /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
     set to 'Yes') calls __io_putchar() */
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**

  * @brief  Retargets the C library printf function to the USART.
  * @param  None
  * @retval None
    */
    PUTCHAR_PROTOTYPE
    {
    /* Place your implementation of fputc here */
    /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);          //具体根据自己启用的串口修改这个函数

    return ch;

    }

在freertos.c中添加如下代码

/* USER CODE BEGIN FunctionPrototypes */
void delay(int x);
/* USER CODE END FunctionPrototypes */

/* task1_handler function */
void task1_handler(void const * argument)
{

  /* USER CODE BEGIN task1_handler */
  /* Infinite loop */
  for(;;)
  {
        HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_5);
        printf("this is task_1 running\r\n");
        delay(500);
  }
  /* USER CODE END task1_handler */
}

/* USER CODE BEGIN Application */
void delay(int x)
{
    for(int i=0;i<x;i++)
    {
        for(int j=0;j<1000;j++);
    }
}
/* USER CODE END Application */

编译后烧录

可以发现板子上的绿灯闪烁+串口发送数据

然后我们注释掉所有和task_1有关的代码,来尝试不借助cubemx自己生成一个系统任务
(实际上关于cubemx,我的个人意见是,创建工程时这是一个非常方便的工具,但是带来的后续开发的麻烦也很多,比如要修改外设配置的时候,要经历cube中修改------>重新生成工程---->继续写代码这样一个过程,如果你只是要做修改串口波特率这类很简单的参数修改的话,何苦非要经过上面这个繁琐的过程而非直接在代码中修改呢?)
需要添加的内容如下

/声明任务句柄
osThreadId task_2Handle;

//声明任务函数
void task2_handler(void const * argument);

//利用osTreadDef和osThreadCreate两个函数定义任务参数+创建任务
osThreadDef(task_2,                            //任务名
        task2_handler,                    //任务函数
         osPriorityNormal,               //任务优先级
         0,                                     // 子进程数
         128);                                //任务栈
task_2Handle = osThreadCreate(osThread(task_2),                  //任务名要和上面的函数中一致
                    NULL);

/关于两个函数更具体的讲解可以看官方API手册
http://www.keil.com/pack/doc/CMSIS_Dev/RTOS/html/group__CMSIS__RTOS__ThreadMgmt.html#gac59b5713cb083702dce759c73fd90dff

最后添加任务函数

void task2_handler(void const * argument)
{

  /* USER CODE BEGIN task1_handler */
  /* Infinite loop */
  for(;;)
  {
        HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5);
        printf("this is task_2 running\r\n");
        delay(500);
  }
  /* USER CODE END task1_handler */
}

编译下载,查看实验效果
红灯闪烁,串口发送数据如下

实验2:
时间片轮转调度实验
取消task_1有关代码的注释,让task_1和task_2同时开始运行,观察实验结果——

1.红灯和绿灯同时闪烁

2.串口发送数据如下

可以发现串口发送的数据存在错位的情况,思考一下这是为什么?

实验3:
优先级调度实验
在创建task2的函数中修改task2的优先级

osThreadDef(task_2, task2_handler, osPriorityAboveNormal, 0, 128);
task_2Handle = osThreadCreate(osThread(task_2), NULL);

编译下载后发现只有红灯闪烁
串口发送数据如下

这个现象的原理是只有在同优先级的任务间才存在时间片轮转调度,当task2优先级高于task1时,系统会始终执行task2

再修改代码如下

void task2_handler(void const * argument)
{

  /* USER CODE BEGIN task1_handler */
  /* Infinite loop */
  for(;;)
  {
        HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5);
        printf("this is task_2 running\r\n");
        osDelay(500);
  }
  /* USER CODE END task1_handler */
}

会发现任务交替运行
这就体现出了osDelay和普通的延时之间的区别
osDelay的原理是将一个任务修改到最低优先级(IDLE优先级),使任意一个就绪进程都可以抢占cpu

通过以上三个实验,我们学习了任务创建,时间片轮转调度和优先级调度的实践
实际上在rtos中有相当丰富的进程管理函数,包括获取进程id,设置进程优先级,设置进程优先级等(可以用来实现动态优先级算法
这里就不多加介绍了,有兴趣的可以自己去了解

最后附上推荐教材(官方文档的中文翻译版)

《FreeRTOS实时内核使用指南》:
链接:https://pan.baidu.com/s/1qouYjnNSsa0u6KxI-0jMRQ
提取码:al12

原文地址:https://www.cnblogs.com/sasasatori/p/12231964.html

时间: 2024-10-15 09:21:38

从0开始的FreeRTOS(4)的相关文章

从0开始的FreeRTOS(2)

"从0开始的FreeRTOS"系列教程第二讲 作者:satori 这一期教程中,我们将介绍FreeRTOS源码的内容,如何使用cubemx快速生成一个包含freertos的工程,以及包含freertos的工程的结构. https://sourceforge.net/projects/freertos/files/FreeRTOS/ 在上面的网址中下载FreeRTOS源码之后我们得到一个压缩包 解压之后我们看到如下的文件,其中FreeRTOS文件夹中包含了源码和一些平台上的实例demo,

从0开始的FreeRTOS(1)

"从0开始的FreeRTOS"系列教程第一讲 作者:satori 大家好,这次给大家带来了Freertos的教程. 这个系列的教程的主要目的是带大家了解实时系统(real time operating system)的基本概念,熟悉freertos的api使用方法,具备基本的使用rtos进行工程开发的能力 系列计划分几期录完,内容分别为 任务管理 队列管理 软件定时器管理 中断管理 资源管理 事件组 任务通知 本教程的开发环境: 硬件环境 stm32f103ZET6 软件版本 Keil

在Amazon FreeRTOS V10中使用运行时统计信息

在MCU on Eclipse网站上看到Erich Styger在8月2日发的博文,一篇关于在Amazon FreeRTOS V10中使用运行时统计信息的文章,本人觉得很有启发,特将其翻译过来以备参考.原文网址:https://mcuoneclipse.com/2018/08/02/tutorial-using-runtime-statistics-with-amazon-freertos-v10/ FreeRTOS包含一个很好的功能,可以向我提供有关每个任务在系统上运行的时间的信息: Free

1、FreeRTOS移植

目录 1.FreeRTOS目录结构 2.移植 3.FreeRTOSConfig.h 文件分析 正文 1.FreeRTOS目录结构 FreeRTOS FreeRTOS简略目录如下: ├─FreeRTOS │ ├─Demo // 各种开发工具的完整Demo,开发者可以方便的以此搭建出自己的项目,甚至直接使用 │ │ ├─Common // 所有例程都可以使用的演示例程文件 │ │ └─其他 // 对应平台和开发工具的项目例程(命名:平台_开发工具,例如:CORTEX_M4F_M0_LPC43xx_K

鬃嘴释怀说太多就成真不了。

子阻撞砖奏尊仔籽着 释怀说太多就成真不了. http://passport.baidu.com/?business&un=vip&un=%E5%A4%A9%E6%B0%B4%E4%B8%8A%E9%97%A8%E8%BF%99%E5%B0%8F%E5%A7%90#0 http://passport.baidu.com/?business&un=vip&un=%E7%99%BD%E9%93%B6%E4%B8%8A%E9%97%A8%E8%BF%99%E5%B0%8F%E5%A

澜星粘鼐贩逊耐盼系甭妊倏纪傲傲sdfghjk

http://passport.baidu.com/?business&un=R&un=%E5%A4%A7%E5%AE%81%E6%A1%91%E6%8B%BF%E9%80%9A%E5%B0%8F%E5%A7%90#0 http://passport.baidu.com/?business&un=R&un=%E4%B9%A1%E5%AE%81%E6%A1%91%E6%8B%BF%E9%80%9A%E5%B0%8F%E5%A7%90#0 http://passport.bai

在Ubuntu14.04上OpenStack Juno安装部署

在Ubuntu14.04上OpenStack Juno安装部署 0 安装方式 0.1 安装方式 安装方式 说明 目标 备注 单结点 一台服务器运行所有的nova-xxx组件,同时也驱动虚拟实例. 这种配置只为尝试Nova,或者为了开发目的进行安装.   1控制节点+N个计算节点 一个控制结点运行除nova-compute外的所有nova-services,然后其他compute结点运行nova-compute.所有的计算节点需要和控制节点进行镜像交互,网络交互,控制节点是整个架构的瓶颈. 这种配

2008 SCI 影响因子(Impact Factor)

Excel download 期刊名缩写 影响因子 ISSN号 CA-CANCER J CLIN 74.575 0007-9235 NEW ENGL J MED 50.017 0028-4793 ANNU REV IMMUNOL 41.059 0732-0582 NAT REV MOL CELL BIO 35.423 1471-0072 PHYSIOL REV 35.000 0031-9333 REV MOD PHYS 33.985 0034-6861 JAMA-J AM MED ASSOC 3

【转载】MDK环境下让STM32用上FreeRTOS v8.1.2和FreeRTOS+Trace v2.6.0全过程

[转载]https://www.amobbs.com/thread-5601460-1-2.html?_dsign=6a59067b 本人选择使用FreeRTOS的最大原因就是想使用FreeRTOS+Trace,这是一个图形化的Debug工具,利用这个工具,你可以看到各线程.中断.消息队列等的运行历史,对于新手来说,学习一个操作系统的运行原理是个好工具,而对于工程应用人员而言,它又是一个不可多得的辅助工具,它能让你获得一种"掌控"的感觉,实在是非常好用.现在我把我建立模板工程的整个过程