零基础STM32单片机编程入门(五)FreeRTOS实时操作系统详解及实战含源码视频

文章目录

    • 一.概要
    • 二.什么是实时操作系统
    • 三.FreeRTOS的特性
    • 四.FreeRTOS的任务详解
      • 1.任务函数定义
      • 2.任务的创建
      • 3.任务的调度原理
    • 五.CubeMX配置一个FreeRTOS例程
      • 1.硬件准备
      • 2.创建工程
      • 3.调试FreeRTOS任务调度
    • 六.CubeMX工程源代码下载
    • 七.讲解视频链接地址
    • 八.小结

一.概要

FreeRTOS是一个迷你的实时操作系统内核。作为一个轻量级的操作系统,功能包括:任务管理、时间管理、信号量、消息队列、内存管理、记录功能、软件定时器、协程等,可基本满足较小系统的需要。
由于RTOS需占用一定的系统资源(尤其是RAM资源),只有μC/OS-II、embOS、salvo、FreeRTOS等少数实时操作系统能在小RAM单片机上运行。相对μC/OS-II、embOS等商业操作系统,FreeRTOS操作系统是完全免费的操作系统,具有源码公开、可移植、可裁减、调度策略灵活的特点,可以方便地移植到各种单片机上运行。

二.什么是实时操作系统

操作系统是一个控制程序,作为硬件和应用程序之间的桥梁,主要是和硬件打交道,负责协调分配计算资源和内存资源给不同的应用程序使用,并防止系统出现故障。面对来自不同应用程序的大量且互相竞争的资源请求,操作系统通过一个调度算法和内存管理算法尽可能把资源公平且有效率地分配给不同的程序。应用程序则通过调用操作系统提供的API接口获得相应资源完成指定的任务。

实时操作系统(RTOS-Real Time Operating System)中实时(Real Time)指的是任务(Task)或者说实现一个功能的线程(Thread)必须在给定的时间(Deadline)内完成。

三.FreeRTOS的特性

具有抢占式或者合作式的实时操作系统内核
功能可裁剪,最小占用10kB左右rom空间,0.5kB ram空间
灵活的任务优先级分配
具有低功耗模式
有互斥锁、信号量、消息队列等功能
运行过程可追踪
支持中断嵌套

四.FreeRTOS的任务详解

FreeRTOS的核心是任务调度器(Task Scheduler),它负责按照一定的调度策略将任务分配给处理器执行。每个任务都是一个独立的函数,可以有不同的优先级和堆栈大小。任务调度器根据任务的优先级和调度策略决定哪个任务被执行。

下图就是任务调度简单介绍
在这里插入图片描述

下面代码就是个简单的示例代码,通过调用osThreadCreate函数创建了两个任务LED_Thread1(驱动LED灯灭)和LED_Thread2(驱动LED灯亮)。在main函数中,通过调用osKernelStart函数启动了实时系统,使得任务可以被调度执行,由于两个任务都能不断运行,所以能驱动LED灯闪烁。

//定义任务函数1
void LED_Thread1(void const * argument)
{
  (void) argument;
  for (;;)
  {
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);//PC13输出高,LED灭
  osDelay(100);//等待100ms
  }
}
//定义任务函数2
void LED_Thread2(void const * argument)
{
  (void) argument;
  for (;;)
  {
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);//PC13输出低,LED亮
  osDelay(250);//等待250ms
  }
}

int main(void)
{
  HAL_Init();
  SystemClock_Config();//外部8M晶振,系统72M主频
  MX_GPIO_Init();//PC13配置成推挽输出
  MX_FREERTOS_Init();//实时系统初始化
  /* Start scheduler */
	osThreadDef(THREAD1, LED_Thread1, osPriorityNormal, 0, 128);
  THREAD1Handle = osThreadCreate(osThread(THREAD1), NULL);//建立任务1
  /* definition and creation of THREAD2 */
  osThreadDef(THREAD2, LED_Thread2, osPriorityNormal, 0, 128);
  THREAD2Handle = osThreadCreate(osThread(THREAD2), NULL);//建立任务2
  osKernelStart();//实时系统启动
  while (1)
  {
  }

}

1.任务函数定义

无论采用何种方法创建任务,均需要用到任务函数。FreeRTOS 规定任务函数的返回值必须为void,而且带有一个void型指针参数。

void LED_Thread1(void const * argument)
{
  (void) argument;
  for (;;)
  {
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);//PC13输出高,LED灭
  osDelay(100);//等待100ms
  }
}

STM32F103C8T6单片机只有一个内核,那怎么让多个人同时干活呢?其实每个子任务虽然都是死循环,但并不是每个子任务一直都在执行,每个子任务在执行期间,可能需要延时,这边就通过 osDelay(100),等待100ms,单片机就可以停止此任务,然后切换到其它任务执行,这样看起来就是多个人在同时干活了。

2.任务的创建

osThreadDef(THREAD1, LED_Thread1, osPriorityNormal, 0, 128);//定义一个任务,任务名,任务函数,优先级,堆栈大小
THREAD1Handle = osThreadCreate(osThread(THREAD1), NULL);  //根据上面定义的任务,创建一个任务

osThreadDef函数中的128是任务栈大小定义:

任务栈大小指定了任务可以使用多少RAM来存储局部变量和其他临时数据。这个大小应该足够大,能够容纳任务在执行期间可能出现的最大需求。

osThreadDef函数中的LED_Thread1是任务函数:

任务函数是任务执行的代码,它应该是一个无返回值的函数,其参数是一个可选的指针,可以用来传递任何需要的数据,我们代码中的任务就是控制GPIO输出高或者低电平。

osThreadDef函数中的osPriorityNormal任务优先级:

任务优先级决定了任务在操作系统调度下的执行顺序。数值越大,优先级越高。

osThreadCreate函数的返回值THREAD1Handle是任务句柄:

任务句柄是一个指针,可以用来引用已经创建的任务,以便可以在任务创建后对其进行操作,例如删除、挂起、恢复等。

3.任务的调度原理

FreeRTOS默认使用抢占式调度策略,对同等优先级的任务使用时间片轮询调度,时间片轮询就是可轮流享有相同的单片机时间(可设置),一个时间片等于SysTick中断周期。
抢占式调度是指调度器始终运行优先级最高且处于可运行状态的任务,无论任务何时可以运行。如在中断服务函数中更改了优先级最高且可运行的任务,调度器会停止当前执行的低优先级任务,并启动高优先级任务。
刚才程序中的osDelay 是通过将当前任务加入到延时列表中,并设置一个定时器来在指定的延时时间,延时时间过去之后将任务从延时列表中移除并将其设置为就绪状态。这样当定时器触发时,任务重新被加入到就绪列表中,等待被调度器再次调度执行。

上面代码中的LED_Thread1(驱动LED灯灭)和LED_Thread2(驱动LED灯亮)两个任务的调度顺序以及时间,如下图所示,横坐标是时间,箭头代表运行顺序
在这里插入图片描述

下面代码截图就是操作系统底层寻找就绪任务的最高优先级,获取优先级最高的就绪任务的 TCB(任务控制块),然后更新到 pxCurrentTCB ,当前运行的任务只可能有一个,因此pxCurrentTCB只是单个TCB_t指针,它始终指向当前运行的任务。通过xPortPendSVHandler(PendSV_Handler)函数实现调度
在这里插入图片描述
PendSV_Handler 是 ARM Cortex-M 处理器中的一个特殊的中断处理函数,用于处理挂起 PendSV(Pending Supervisor Call)中断。PendSV 中断是 Cortex-M 架构中的一种特殊的软件中断,它可以用来实现任务切换或者其他与系统调度相关的操作。
PendSV_Handler 在中断向量表的位置
在这里插入图片描述

__asm void xPortPendSVHandler( void )

{

extern uxCriticalNesting;

extern pxCurrentTCB;

extern vTaskSwitchContext;

PRESERVE8

mrs r0, psp //(1)        读取进程栈指针,保存在寄存器 R0 里面。

isb

ldr r3, =pxCurrentTCB//(2)   获取当前任务的任务控制块,并将任务控制块的地址保存在寄存器 R2 里面。

ldr r2, [r3] //(3)

tst r14, #0x10 //(4)        判断任务是否使用了 FPU

it eq //(5)

vstmdbeq r0!, {s16-s31}// (6)

stmdb r0!, {r4-r11, r14} //(7)

str r0, [r2] //(8)

stmdb sp!, {r3} //(9)

mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY //(10)       

msr basepri, r0 //(11)           关闭中断,进入临界区

dsb

isb

bl vTaskSwitchContext //(12)    调用函数 vTaskSwitchContext(),此函数用来获取下一个要运行的任务,并将pxCurrentTCB 更新为这个要运行的任务。

mov r0, #0 //(13)

msr basepri, r0 //(14)        打开中断,退出临界区。

ldmia sp!, {r3} //(15)

ldr r1, [r3] //(16)

ldr r0, [r1] //(17)

ldmia r0!, {r4-r11, r14} //(18)

tst r14, #0x10 //(19)

it eq //(20)

vldmiaeq r0!, {s16-s31} //(21)

msr psp, r0 //(22)           更新进程栈指针 PSP 的值

isb

bx r14 //(23)     执行此行代码以后硬件自动恢复寄存器 R0~R3、 R12、 LR、 PC 和 xPSR 的值,确定异常返回以后应该进入处理器模式还是进程模式,使用主栈指针(MSP)还是进程栈指针(PSP)。很明显这里会进入进程模式,并且使用进程栈指针(PSP),寄存器 PC 值会被恢复为即将运行的任务的任务函数,新的任务开始运行!至此,任务切换成功。

}

五.CubeMX配置一个FreeRTOS例程

1.硬件准备

STLINK接STM32F103C8T6小系统板,STLINK接电脑USB口。

在这里插入图片描述

2.创建工程

打开STM32CubeMX软件,新建工程
在这里插入图片描述
Part Number处输入STM32F103C8,再双击就创建新的工程
在这里插入图片描述
配置下载口引脚
在这里插入图片描述
配置外部晶振引脚
在这里插入图片描述

可以查看STM32F103C8T6小系统板原理图,PC13连接LED灯,所以配置PC13为GPIO输出

在这里插入图片描述
配置FreeRTOS
在这里插入图片描述
配置系统主频
在这里插入图片描述
配置工程文件名,保存路径,KEIL5工程输出方式
在这里插入图片描述
生成工程
在这里插入图片描述
用Keil5打开工程
在这里插入图片描述
添加代码
在这里插入图片描述
在这里插入图片描述

3.调试FreeRTOS任务调度

调试代码,能更好理解任务调度。
下载调试,在LED_Thread1打断点,程序能运行到断点处停止
在这里插入图片描述
在LED_Thread2打断点,程序也能运行到断点处停止
在这里插入图片描述

在xPortPendSVHandler调度函数中打断点,可以看到操作系统将要跳转到任务1运行
在这里插入图片描述
单步执行,运行指针就跳转到任务1开始运行
在这里插入图片描述

xPortPendSVHandler调度函数中打断点,可以看到操作系统将要跳转到任务2运行
在这里插入图片描述
单步执行,运行指针就跳转到任务2开始运行
在这里插入图片描述

六.CubeMX工程源代码下载

链接:https://pan.baidu.com/s/1f50X8w2UXnDtbM6U6zwYqw
提取码:0sys
如果链接失效,可以联系博主给最新链接

程序下载下来之后解压就行

七.讲解视频链接地址

FreeRTOS实验

八.小结

FreeRTOS实时操作系统能使在STM32软件开发中,程序结构清晰,单片机执行效率提升许多,在多个任务模块的代码中,可以考虑使用FreeRTOS。

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

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

相关文章

Python | 计算位涡平流项

写在前面 最近忙着复习、考试…都没怎么空敲代码,还得再准备一周考试。。。等考完试再慢慢更新了,今天先来浅更一个简单但是使用的python code 在做动力机制分析时,我们常常需要借助收支方程来诊断不同过程的贡献,其中最常见的一…

使用Python绘制极坐标图

使用Python绘制极坐标图 极坐标图极坐标图的优点使用场景 效果代码 极坐标图 极坐标图(Polar Chart)是一种图表类型,用于显示在极坐标系中的数据。极坐标图使用圆形坐标系,角度表示一个变量的值,半径表示另一个变量的…

【Python】利用代理IP爬取当当网数据做数据分析

前言 在数字化浪潮的推动下,电商平台已经彻底改变了我们的购物方式。从简单的在线交易到复杂的用户交互,电商平台积累了海量的用户数据。这些数据,如同隐藏在深海中的宝藏,等待着被发掘和利用。通过分析用户的浏览、搜索、购买等行…

基于人脸68特征点识别的美颜算法(一) 大眼算法 C++

1、加载一张原图&#xff0c;并识别人脸的68个特征点 cv::Mat img cv::imread("5.jpg");// 人脸68特征点的识别函数vector<Point2f> points_vec dectectFace68(img);// 大眼效果函数Mat dst0 on_BigEye(800, img, points_vec);2、函数 vector<Point2f&g…

使用Perplexity打造产品的27种方式

ChatGPT和Perplexity等聊天机器人正迅速成为产品经理的首选助手。以下是一份全面的指南&#xff0c;介绍PM如何在日常工作中使用Perplexity&#xff0c;该指南基于300多份回复和30次电话后的总结。 理解并制定增长战略&#xff1a;例如&#xff0c;解释增长会计的基本原理&…

Docker的理解

Docker的理解 Docker为什么用Docker&#xff1f;1.提升系统资源利用率2.更快速的交付和部署3.高效的部署和扩容4.更简单的管理 Docker核心技术Docker镜像Docker容器Docker仓库 Docker实现原理Linux NamespaceCgroupUnion FS Docker的应用场景1.微服务架构2.持续集成3.快速部署和…

四.iOS核心动画 - 图层的视觉效果

引言 在前几篇博客中我们讨论了图层的frame,bounds,position以及让图层加载图片。但是图层事实上不仅可以显示图片&#xff0c;或者规则的矩形块&#xff0c;它还有一系列内建的特性来创建美丽优雅的页面元素。在这篇博客中我们就来探索一下CALayer的视觉效果。 视觉效果 图…

机器学习环境搭建

前言 个人笔记&#xff0c;记录框架和小问题&#xff0c;没有太详细记载。。 1、Anaconda安装 下载地址&#xff1a; Free Download | Anaconda &#xff08;慢&#xff09; ​ 国内镜像&#xff1a;https://link.csdn.net/?targethttp%3A%2F%2Fitcxy.xyz%2F241.html 下载…

五国如何实现关键基础设施保护方法的现代化

本叙述介绍了关键基础设施面临的不断演变的风险,并讨论了关键五国(澳大利亚、加拿大、新西兰、英国和美国)如何实现关键基础设施保护方法的现代化。它还确定了加强国内关键基础设施安全性和弹性的共同方法,同时认识到鉴于关键基础设施的相互关联性,国际社会需要采取合作和…

【H.264】五分钟入门H.264协议

<> 博客简介&#xff1a;Linux、rtos系统&#xff0c;arm、stm32等芯片&#xff0c;嵌入式高级工程师、面试官、架构师&#xff0c;日常技术干货、个人总结、职场经验分享   <> 公众号&#xff1a;嵌入式技术部落   <> 系列专栏&#xff1a;C/C、Linux、rt…

以现在的社会形势走向,选什么专业好?

随着高考结束&#xff0c;选专业的话题又开始变得越来越热门。因为很多学生都想知道自己更适合什么样的专业&#xff0c;如何结合未来的社会形势来选择更好的专业&#xff0c;这的确是一个很考验能力的问题&#xff0c;因为有太多人曾经为了选择专业而纠结过。 高考志愿填报选…

基于多源数据的密码攻防领域知识图谱构建

源自&#xff1a; 信息安全与通信保密杂志社 作者&#xff1a;曹增辉 , 郭渊博 , 黄慧敏 摘 要 提高网络空间安全的密码攻防能力&#xff0c;需要形成可表示、可共享、可分析的领域知识模式和知识库。利用自顶向下的构建方法&#xff0c;并通过本体构建方法梳理密码攻防领域…

Nginx 配置文件

Nginx的配置文件的组成部分&#xff1a; 主配置文件&#xff1a;nginx.conf子配置文件&#xff1a;include conf.d/*.conf 全局配置 nginx 有多种模块 核心模块&#xff1a;是 Nginx 服务器正常运行必不可少的模块&#xff0c;提供错误日志记录 、配置文件解析 、事件驱动机…

Android Studio 2023版本切换DNK版本

选择自己需要的版本下载 根目录下的配置路劲注意切换 build.gradle文件下的ndkVersion也要配好对应版本

现代信息检索笔记(二)——布尔检索

目录 信息检索概述 IR vs数据库: 结构化vs 非结构化数据 结构化数据 非结构化数据 半结构化数据 传统信息检索VS现代信息检索 布尔检索 倒排索引 一个例子 建立词项&#xff08;可以是字、词、短语、一句话&#xff09;-文档的关联矩阵。 关联向量 检索效果的评价 …

使用Visual Studio Code记笔记

因为学习需要&#xff0c;记笔记是很有必要的&#xff0c;平常发CSDN&#xff08;都让CSDN是很棒的哈&#xff09;&#xff0c;后来使用VS Code的时候发现了很多插件&#xff0c;觉得做笔记还是相对不错的&#xff0c;主要用到的还是Markdown 主要设计的插件包括&#xff1a; …

第3章:数据结构

树 对稀疏矩阵的压缩方法有三种&#xff1a; 1、三元组顺序表 2、行逻辑连接的顺序表 3、十字链表 同义词才会占用同个位置&#xff0c;从而需要进行多次比较。这些关键字的第一个可以不是e的同义词&#xff0c;可以是排在e之前的关键字正好占了那个位置。 Dijkstra算法主要特点…

MySQL 高级SQL高级语句(二)

一.CREATE VIEW 视图 可以被当作是虚拟表或存储查询。 视图跟表格的不同是&#xff0c;表格中有实际储存数据记录&#xff0c;而视图是建立在表格之上的一个架构&#xff0c;它本身并不实际储存数据记录。 临时表在用户退出或同数据库的连接断开后就自动消失了&#xff0c;而…

javassmmysql 宣和酒店点餐系统37378-计算机毕业设计项目选题推荐(附源码)

目 录 摘要 1 绪论 1.1研究背景 1.2目的 1.3ssm框架介绍 1.3论文结构与章节安排 2 宣和酒店点餐系统系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据流程 3.3.2 业务流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.2 非功能性分析 2.4 系统用例分析 2.5本章…

Pascal 函数入门示例,及其汇编语言分析

1&#xff0c; Pascal 函数的定义格式 pascal 函数的定义语法格式: FUNCTION 函数名(形式参数表):函数类型; VAR 函数的变量说明; BEGIN 函数体; END; 2&#xff0c;Pascal 函数定义调用示例 order_self.pas 代码&#xff1a; PROGRAM example01;va…