粉丝3386获赞1.7万


朋友们大家好,今天我来介绍属于 r t o s 操作系统的任务调度。之前的几期视频中,我们介绍了 r t o s 的概念,以及为什么要使用 r t o s 操作系统,然后介绍了如何在 free r t o s 中创建任务。 那么今天我来介绍 freert os 中任务调度的规则。一个单片机需要同时实现很多功能,比如屏幕显示、串口通信、电机控制、读取传感器数据等。这就如同一个人在同时做很多件事。 我们把单片机比作餐厅的大厨,他在忙碌的时候需要一个人操作好几个锅,同时炒好几道菜。如果让普通人去做这件事,难免会手忙脚乱,但是餐厅的大厨却可以轻松应对。同理, 我们在给单片机编程的时候,也希望一个单片机可以做尽可能多的事情,这样不仅可以简化硬件方案,也可以降低产品的成本,在市场上取得更大的竞争力。就比如一个厨师同时做几道菜这件事情 用裸机编程的思维该如何实现呢?大致流程会是下边这个样子,先进入闷函数,然后各种初始化,直到进入一个 vs 循环,在里边按照事先写死的顺序,一遍一遍重复执行。 这种操作方式的弊端在上期视频中我们已经讨论过,这里不再赘述,因为时间相隔久远,没有印象的同学可以去看之前的视频。如果把上边的代码移至到 freertos 中,则会是下边这样在经过一系列的初始化之后,把所需要的工 以任务的形式创建出来。这些任务在执行的时候没有固定的先后顺序,是通过一系列的规则来确定哪些任务先被执行,哪些任务暂时不能执行。 freerts 中的任务可以有以下几种状态,运行、就绪,阻塞、挂起。第一,运行。他是指当前任务正在执行,他处于运行状态,而且正在使用处理器。 如果运行 rtys 的处理器只有一个内核,那么在任何给定的时间都只能有一个任务处于运行状态。第二,就绪。指任务能够执行,但目前没有被执行, 因为同等或者更高优先级的不同任务已经处于运行状态,就绪状态不同于阻塞或者挂起状态。第三,阻塞。如果任务正在等待 时间或者外部时间,则任务处于阻塞状态。例如,如果一个任务调用 v 塔斯格迪丽函数,他将会被阻塞,直到设定的延时结束。任务也可以通过阻塞来等待队列信号量、事件组通知等。处于阻塞状态的任务通常有个超时时间, 超过这个时间后,任务将被解除阻塞状态,即使该任务所等待的事件没有发生。 阻塞状态下任务不使用处理器,时间也不能进入运行状态。第四,挂起。与阻塞状态下的任务一样,挂起状态下的任务不能被选择进入运行状态,但处于挂起状态的任务不会超时。 任务只有通过 spend 和 resume 函数才能进入或退出挂起状态。再知道一个任务可以处于的四种状态 之后,我们来看如何对任务进行调度。第一种调度方式,人群调度。我们规定一个非常短暂的时间为一个时间片,这里以一毫秒为例,假如有两个任务处于同一个优先级, 每个任务运行一个时间片之后,切换给另外一个任务运行,依次轮流运行,这种方式就是轮巡调度,就是处于同一个优先级的任务,他们依次轮流的执行每个任务,每次执行一个时间片。 第二种调度方式,抢占式调度是指调度器始终运行优先级最高,而且处于就绪状态的任务。当一个低优先级的任务正在执行时,发生外部中断,使一个处于阻塞状态但优先级更高的任务获得了 他正在等待的信号量,那么调度器就会停止当前正在运行的低优先级的任务,切换到高优先级的任务,即便当前任务的时间片并未结束。 freertos 默认使用强战士调度策略 会同等优先级的任务使用时间片。轮巡调度调度器不会永久更改任务的优先级,尽管他可能会因为优先级继承而暂时提高任务的优先级。 最近工作上的事情比较多,所以更新频率很低,后边有空的话会尽可能多做几期视频,那么这期视频就到这里了,谢谢大家。


整体的使用呢?结构体变量定义就是他有两种定义,看到没?变量定义一, 结果你变成定义是什么呢?是不?使用类型别名的时候我们怎么定义呢?就用 stragger 结构体名加变量名。其实这个我之前在给大家举过例子的哈,我们一般程序员他不会想哇,他每次我都要写个 stroco, 对不对?比较麻烦,所以我们会把这个 stroco 给他去掉,不要最好了,但是你现在如果说你这是用结构体来定义变量,不用太不对口的话,你就没办法省掉,没办法省掉你就必须得有这个, 对,这就比较麻烦,所以我们一般程序员不用这种方式,而是用第二种方式,使用结构体类型别名来定义这个变量名,那么使用类型别名的时候,我们就可以把这个 structure 哎,给他省略掉啦, 这就是他的好处,好处就是我们可以省掉这个玩意, 我们怎么省掉了,我们等一下再看。然后呢?结果你使用注意的第三点就是结构体变量访问呢?访问成员呢?我们用点之前我没跟大家说过哈,我以为大家都懂,但是发现好多人还是不懂哈。 结构题,指针,看一下,上面是变量,下面是指针。结构题,指针访问呢,用这个符号, 一个横杠,一个小,一个箭头,对吧?所以你记住,只要是变量,我就用这个点去访问他此成员,只要是指针,我就用这个 横杠一个大于号去访问他的成员。然后你你一般在我们的 mtk 上面输入这个以后呢,会提示他会有个列表哎,提示你选择 一二三四,你选哪一个?自己选就可以了,或者也可以自己输入哈,所以他的注意点组织其实没有多少哈,这里我给大家简单列了四个,就是使用上面的就是两个,一个是点,一个是杠, 然后呢定义上面的话呢,一般我们推荐大家用第二种,就是用结构体类型别名。

如何快速创建 stm 三十二工程?我这里使用的是 stm 三十二 qbm x, 这是一个可视化 stm 三十二代码生成软件。下面由我演示下如何创建工程。 首先选择好自己需要的芯片型号,不同的芯片会有不同配置下, 为了方便调试,我这里开启 swd 调试功能,并且启用了外部始终。接着是设置单片机工作频率, 这里只需要输入想要的频率,然后点击回车就可以自动计算出分频参数,这个功能太方便了。最后一步是给工程取一个高端霸气的名字,我是使用 carry 开发,所以开发环境选择 m d k。 最后点击右上角的生成 按钮,生成工程代码,编译并运行下代码,测试下是否正常。对了,如果想看生成代码的大小,还需要指定一下 map 文件的存储位置,然后再重新编译一下项目,双击工程名字就可以看到了。 为了跟踪代码变化,我会用 d 来管理代码,不过项目中每次编译都会生成很多临时文件,需要把这些文件忽视名单中,这样即使这些文件变化也不会被跟踪。然后对代码进行第一次提交。 然后我们重新打开 q b m x, 添加一些新配置,重新生成一下代码试试效果。可以看到给已经把被修改过的代码标记 出来,但是 visco 无法显示中文,因为 carry 是使用 g b k 编码,而 visco 的是 u t f 八,所以这里要强制指定 g b k, 所以可以像我这样创建配置文件。 visco 的打开就会默认使用 g b k 编码,打开 中文就不会再乱码了, bt 也把对应的修改内容高亮显示,可以放心大胆的修改代码了。好了,就说到这里,要是觉得本视频对你有用,记得给我点个关注。

下面呢,我们来以 a few rts 为例,来给大家介绍这个 few rts 的一个操作系统。 那么我们首先来看一下 feel rts 这个名字,这个名字呢,可以分成两部分,第一部分是 f r e e feel 啊,第二部分呢是 rts, 那 feel 啊,就是免费的,自由的,不受约束的这个意思。那么阿 qs 呢,就我们前面说的一个实时操作系统啊,他的一个首字母的一个缩写, 那么可以看出啊,从名字就可以看出啊, feelrts 啊,他就是一个免费的 rts 的一个系统。那么这里要注意哈, itos, 他并不是指一个某一个确定的系统, 而是指一类系统实时操作系统,那比如 mucose 啊, mucose 啊,还有我们的现在学的 i feel itos, 或者是 it straight 等等啊,他是指一类十操作系统,那么操作系统啊,他是允许多个任务同时运行的, 那这个呢,叫做多任务,实际上一个处理器核心呢,在某一时刻只能运行一个任务, 这跟我们裸机执行是一个道理。我们的 cbu 在执行我们的工人的时候,我们一个时刻只能执行一件事啊,他只能干一件事。 那么操作系统中的任务调度器啊,他的责任呢,就是决定在某一时刻究竟运行哪一个任务,那么任务调度啊,在各个任务之间进行一个切换,这个速度呢,非常快, 这样就给我们造成同一时刻会有多个任务同时运行的一种错解啊,学过啊,动态数码馆的啊,朋友应该知道,利用我们人的一个余晖效应啊,来来, 让我们感知啊,他是同时显示啊,他是这个是一个道理啊,就是说他的一个切换任务切换的速度啊,非常快,让我们感觉到这个些东,这些任务啊,是同时进行运行的啊,同时运行的,那么操作系统的分类方式啊,可以由 任务调度器的这个工作方式来决定。比如有的操作系统啊,给每个任务分配同样的运行时间,那么时间到了就轮到下一个任务执行, 那么 unni 啊,这种操作系统啊,他就是这种啊。而 ts 的十任务调度器呢,被设计为可预测的, 而这正是嵌入是实时操作系统啊,所需要的实时环境中,要求我们的操作系统呢,必须对某一个事件做出实时的一种响应,因此啊,系统任务调入器的行为必须是可以预测的。 那么像 furts 这种传统的 rts 类操作系统呢,是给由用户来给每个任务分配一个任务优先级, 那么任务调度器呢,可以根据这个优先级来决定下一个啊,运行的是哪一个任务,根据你的优先级的高低啊, 那么 furts 啊,它是一个,呃,是 rts 的一种,那它的一个是一种十分小巧,可以在资源有限的微控制器当中进进行一个运行。当然 furts 不仅局限于微控制性当中使用, 那他在一些啊,其他的一些大型的这种啊, mcu 或者是一些啊 mpu, 他也可以运行 furts 啊。 那么如果你学习过,在学习服用 rts 之前,学习过没有 cos 这种操作系统的话,你会发现 furts 的它的文件数量啊,远低于没有 cos 二或者是三啊,没有 cos 啊,我们在我们的这个资料里面也有他的一些啊历程啊,你可以后续对比一下他的工程啊,他的一个 呃圆码的一个数量啊,相差是非常大的,那么 feel rts 的特点呢?我们来看一下 furts, 它是一个可裁剪的小型的 rqs 的一个系统,那么它的特点呢,包含这么多啊, furts 的内核支持抢占式 啊,还有合作室和时间片的一个调度,那么抢占时啊,是我们实时操作系统当中啊,必须要的啊,因为我们要让我们的一个啊,高优先级的任务啊,优先执行啊,抢占低优先级的啊,随便的 资源来执行。那么还有 sf rts 的衍生字,我们的这个 furts, 那 sf 这个 rts 在代码完整性上呢,要比 furts 的更胜一筹,但是这个系统呢是要收费的啊,所以呢啊,我们 在嵌入式当中啊,基本上用 furts 已经足够,还有我们的 furts 提供了一个用于低工号的一个 tylus 的这种模式 啊,这种模式呢是在啊,我们的低功耗需要我们的产品需要低功耗的时候,我们可以应用啊,他其实呢,就是对我们的一个 空闲任务的时候,把我们的这些外设时钟不需要使用的外设时钟啊给关闭啊,如果说退出的空闲模式的时候,那我们可以打开 对应的一些外设时钟,从而降低我们的工号啊。系统的组建呢,在创建的时候可以选择动态或者是静态的 rem 啊,这个呢,在我们后面 啊学习这个呃任务创建的时候我们就会接触到啊,可以通过我们动态的一个创动态内存或者是静态内存来创建我们的任务啊,比如我们的任务的创建消息对电,还有信号量软件定时器等等 啊,这都是我们的一些操作系统内部的一些啊,资源啊资源。那么还有已经在这个超过三十种架构的芯片上面呢,进行了移植 啊,在 furts 的官方啊,提供给了我们一些啊,一字号的一些工程啊,相对于我们的这个 stm 四二啊, 还有幺零三四零七四二九等等七六七啊,都给我们移植好了,所以呢,我们可以啊,把这些县城的一些工程啊应用到我们的工程哎,芯片当中来啊,非常简单,这官方已经给我们移植好了,我们直接使用就可以 啊, vrtsmpu 支持这个 criticsm 内核的一些 mpo 的一些单元啊,像我们有 mpo 的话是 f 四, f 四以上的一些系列芯片啊,他都可以拥有 mpmpo 啊,当然 mfurqs 他也对这个支持 furts 的系统呢,简单小巧易用啊,通常情况下呢,占内核内核占用呢四到九 k 的一个自洁空间啊,对于我们 stm 三来说啊,这个远远啊,远远已经足够了啊,我们的一个 芯片的内核啊文件,我们芯片的 ram 啊,已经足够啊,满足这个 furts 的一个运行。 然后呢,他有一个特点啊,非常高的可移植性啊,因为它采用的是 c 元,纯 c 元来编写的,所以呢啊,对于移植性来说啊,服用 rts 是非常方便移植的啊,移植到各种 平台啊,然后呢,还支持实时任务和携程啊,这里也叫合作式协同程序,那么我们这里呢,携程的话,我们这里 fmrts 现在已经不用他了啊,不用他了, 这是我们的 furts 的这些特点。还有就是在任务与任务,任务与中段之间可以 直使用任务通知消息队列二直信号量,数字型信号量,还有地规互次信号量以及互次信号量进行通信和同步啊,这些呢,我们后续都会学习到啊,都会学习到的 啊,创新的试验组啊,试验组我们也会学习到,以及我们优先级继承,这是在互资信号量当中会使用到,因为通过这种优先级继承的话,可以实现啊, 必尽量的避免他的一个啊,优先及翻转的这一种啊特性。 还有高效的软件定时器,这种呢是纯软件的一种定时器,和我们硬件定时器呢,功能是类似啊,但是我们 atm 上他有硬件啊,硬件的一个定时器啊,这里 furtis 呢,是提供我们的软件定时器,当我们硬件定时不够的时候,我们可以通过软件定时器来实现一些啊,时间上的一些定时的一些功能 啊,还有强大的跟踪执行功能啊,还有堆占溢出检测功能,通过他的一些红定义来设置啊,如果设置了一些这种检测功能的话,那么你需要编写一些啊啊,回调函数,也就是钩子函数之类的 啊,还有任务数量呢,它不限啊,理论上这些任务数量是可以不限制的,但实际上受限于我们的 ram 啊,我们的芯片 ram 不可能说无限大的啊,你的任务数量越多,你的 ram 呢?占用的也就越多啊,任务 优先级不限啊。同样同样的一个道理啊。这是我们的这个 furts 的一个。呃,特点的一个介绍啊?特点的一个介绍。
![[STM32Cubemx简介及使用]是什么?如何创建工程? #单片机 #STM32 #stm32cubemx](https://p3-pc-sign.douyinpic.com/image-cut-tos-priv/0d6b5058623833f7d069c193e79fb546~tplv-dy-resize-origshort-autoq-75:330.jpeg?lk3s=138a59ce&x-expires=2099332800&x-signature=4JFbmrvZ%2Fqm62PJ6WvNCxIIoZO0%3D&from=327834062&s=PackSourceEnum_AWEME_DETAIL&se=false&sc=cover&biz_tag=pcweb_cover&l=20260714042650727045CA7AA10A2F42D0)
s t m 三二 q 波 max 是 s t m 三二 q 波工具家族中的一员,从 m c u m p u 选型、银角配置、系统适中 以及外设时钟设置到外设参数配置、中间键参数配置,他给 s t m 三二开发者们提供了一种简单方便并且直观的方式 来完成这些工作。所有的配置完成后,它还可以根据所选的 i d e 生成对应的工程和初日化 c 代码。除此之外, s t m 三二 q 波 max 还提供了工号计算工具,可作为产品设计中工号评估的参考。 pro max, 我们可以在菜单栏文件这里新建工程和加载以前创建好的 工程,那么我们如果想改变界面显示的字体大小,可以在 window 这里进行选择。那么我们在 hop 里还有一个很常用的功能,就是倒数第二个,这里可以安装我们的依赖包, 比如我们如果想安装 f 零的依赖包,就可以点击前面这个小三角,点开之后,这里我们可以看到他最前方这个小方块是空空白的,就证明我们没有安装,那我们可以点击这个这个选项,然后下面进行 进行 instar 安装,点击安装它就会在线给我们安装这个依赖包,等我们安装好之后,就会像 f 一前面这样变成了绿色,就证明我们安装好了。 那我们如果想新建工程呢?打开新建新建菜单栏,打开之后,我们可以在这里输入我们想要创建工程的芯片, 比如 s t m 三二 f 幺零三 c 八 t 六。我们输上之后,再 这一栏就可以看到所需要创建工程的芯片,让我们双击就可以进入图形化配置界面,打开之后我们可以看到芯片的图形化已经出来了。在银角配置之前,我们需要点击 sis, 这里 将第八个方式调整为 s w d 的,这样的话我们就可以用 s w d 的方式进行程序的稍写,比如我们使用 s t link 就可以 可以稍写程序了。那么我们如果想点亮一个 led 灯呢?经过查看原理图,假如我们的控制 led 灯的引角是 p b 零,我们就可以左键点击 p b 零,这里我们可以看到 pb 零相关的引脚配置就显示出来了,比如我们点灯的,那肯定是输出模式,所以我们就可以点击 gpl autoput, 点击好之后 我们可以看到它的颜色已经变了,变成了绿色,就证明我们可以用了。那 gpl 相关的详细配置呢?可以在试窗这里点击 gpl, 在 gpl 这里可以看到刚才配置的 p b 零,点击它能够在下方这里看到它详细的一些配置,那如果我们上电让它为 低电瓶的话,这就选 low, 如果要让它为高电瓶的,可以选 h。 下面这个是他的模式,是推碗输出的还是开漏输出的?通常情况下我们用推碗输出,所以这里配置推碗的,那上输出的上拉和下拉呢?一般不使用,所以都选 no。 那么我们的输出速度对于 led 灯来说,输出速度没有什么要求,可以默认用烙就行了。那最终我们配置完之后,需要生成工程,点击我们可以在这里输入工工程的名字。 第二个选项,这里是工程的路径,那在这里呢有我们输出的 id, 如果我们想用的是 k o, 就选择 m d k 杠 m, 这样的话就 我们生成的工程就是 m d k 杠 m 的了,就是 ko 可以使用了。那第二个选项呢?能够配置我们生成的代码,如果选择这个选项,那么我们生成的代码就是 只是需要的库,那选择第一个选项就是我们生成的代码为全部的库,这里还有一个地方需要配置, 点击勾选上,那么我们生成的代码就为模块化编程的方式,如果不选项就只有慢慢点 c 文件,那么所有的程序都会在慢点 c 中堆在一起, 我们勾选上生成工程,点击右上角这一侧生成,生成好之后我们就可以点击打开工程, 工程打开以后,我们可以在这里看到我们的慢点斯文件就已经生成好了,那么我们实现具体逻辑功能的函数就可以在这里进行编写了。

用 q 五新建一个 stm 三二工程,目前 stm 三二开发方式主要有三种,一、直接操作寄存器方式二,使用标准库方式 三、使用 hoco 方式。直接操作寄存器方式是我们直接配置寄存器程序,执行效率最高,但是由于 stm 三二结构复杂,这种开发方式不推荐 使用。标准库就是使用 st 官方封装的一些操作寄存器的库函数,让我们提高开发效率。 本期内容就是使用标准库创建工程。最后一种 hel 库方式就是可以使用图形化界面配置,可以快速入门,但是他隐藏了底层逻辑,不利于我们深入学习,可以学习标准库之后再去学习这种开发方式。 我们现在开始创建工程,这个是今天要用到的标准库,如果有需要可以留言我之后可以发出来。这个是已经解压出来的文件,我们打开看一下, 这个内部文件夹就是今天所需要的文件。由于工程文件比较多,所以我们开始创建工程前需要先创建一个文件夹,我们命名为 stm 三十二 project, 现在打开 q 五开始创建工程, 点击 project, 点击第一个,这里我们选择刚才创建的文件夹, 给我们的工程起一个名字,然后点击保存,这时候就会跳出选择芯片型号的页面,我今天 使用的是 stm 三二 f 幺零三 c 八 t 六,大家可以按自己的芯片选择相应的型号,选择之后点击确定这个页面,我们可以直接关闭。现在我们这个工程还无法使用,还缺少启动文件,我们现在去内部库中复制一下, 打开我们的工程文件夹和 lab 文件夹,启动文件都在 com sis 文件夹中,这里文件目录比较深,跟着我的操作找到启动文件, 这个 startup 就是全部启动文件所在,这里有很多编译器版本,我们选择 on, 将里面的文件全部复制下来。 在我们的工程目录中创建一个 start 文件夹,我们打开它,将刚才的文件 复制进来,回到刚才的 startup 所在位置,我们还需要复制这几个文件,也复制到 startup 文件夹中,我们还需要内核文件在列补文件夹, comes this 文件夹, cm 三文件夹, call support 文件夹中,将这两个文件也复制到 startup 文件夹里。 接下来回到工程,将刚才复制文件都加载到工程中,点击这个文件夹,我们改个名字,改成 start, 点击上方三个小方格,我们在这里添加文件,点击 add files, 选择 start 文件夹,点击文件类型,选择全部文件类型, 选择前面两个文件,点击 at 添加文件,这些 startup 文件选择后缀为 m d 点 s 的文件,点击添加 下方这些文件全部添加,最后点击关闭就可以了,然后退出就完成了。添加这里就可以看到添加的文件了, 然后我们需要把 start 文件加的路径也添加进来,点击上方的魔术棒,选择 c c 加加选项卡,点击这里。再点这里,我们选择 start, 点击确定, 然后点击 ok, 这样文件目录就添加好了。我们再添加一个妹函数,先在工程文件夹中新建一个 user 文件夹, 回到工程,我们添加一个 user 组,点击这里添加组,名字改成 user, 然后我们右键添加一个 man 函数文件,选择 c 文件 键,名字是 main 路径,选择我们刚才创建的 user 文件夹,点击确定。我们右键添加一个头文件,点击这里添加,然后我们快速写一下 main 函数, 我们点击这里编译一下,可以看到有很多错误,这是因为我们的编译器是版本六,切换到五就可以了,点击这里选择版本五,我们再次编译一下, 可以看到已经没有错误了,这时候已经可以使用寄存器方式开发程序了,我们是需要用标准库开发,我们还需要再复制一些文件进来。打开 lab 库文件键 家和我们的工程文件夹,我们先在工程文件夹中新建一个列布文件夹,然后在列布库文件夹中选择第二个文件夹, 点击打开。我们要把 src 和 ink 两个文件夹中的文件全部复制到我们刚才创建的文件夹中,然后回到我们的工程,把它们添加进工程,点击上方三个小方格,在这里新建一个名为 leave 的组, 按照刚才添加 start 文件的方法在这里添加我们刚才复制的文件,现在已经添加好 lab 文件了,这是已经添加好的文件,我们可以在这里把 lab 组向上挪一下位置, 现在我们再复制一下库参考历程里面的配置文件和中断入口文件,打开库文件夹和工程文件夹,找到 历程,这里就是历程了,我们打开选择第二个文件夹,在这里复制下面这三个文件到我们的 user 文件夹就可以了。然后打开我们的工程,把它们添加到我们的 user 组里面,按照刚才的方法添加进来, 现在整个工程文件已经复制好了,我们添加一下内部文件路径, 我们最后配置一下红定义,右键打开头文件,将文件拉到最下面,找到这个红定义, 将这个红定义复制下来。接着我们点击魔术棒,选择 c c 加加选项卡,将刚才复制的红粘贴到这里,这样就可以了,点击 ok, 关闭,回到我们的魅函数,现在工程已经基本完成了,我们编译一下 可以看到很多错误,看这些错误的意思是找不到文件,说明我们还有文件路径没有添加,我们按照刚才的方法添加一下路径,这里是没有添加 uso 文件加路径,我们添加一下, 我们再次编译一下,可以看到已经没有错误了。工程到这里已经创建好了,喜欢的小伙伴记得点赞关注哦,我们下期见。

hello, 欢迎各位小版回来,这里是 kiss king 上期视频,我们一起使用串口的轮巡模式,实现了使用串口来控制学习板上的彩色 led。 不过同时我们也知道了轮巡模式的一些弊端,比如程序必须等待发送或者接收结束才能接着执行,再比如只能接收确定长度的数据。那么怎样解决这些问题呢?本期视频我们就先来学学如何使用中断模式解决程序等待问题。 正式介绍创口的中断模式之前,我们不妨先来看看轮巡模式的底层机制是怎样的。在 s t m 三二每个创口的内部有这样两个计存器,发送数据计存器与发送移位计存器。当我们调用 hell, 由于 r t transmit 发送一段数据时, s t m 三二的 c、 p、 u 会依 次将数据移到计存器中。发送一位计算器中的数据会按照我们设定的比特率转化成高低电频,从 t x 引角输出 发送数据计算器中的数据会在发送移位计算器发送完成后,被移到发送移位计算器进行下次发送。而在此过程中, cpu 需要不断地去查询发送数据计算器中的数据是否已经移送到了发送移位计算器,移了的话就赶紧把下个数据塞进来, 如果还没有移,那就再接着不停的查询,直到把本次要发送的数据全部发完,或者用时超过我们设定的超时时间。轮循模式下的串口接收也是类似。第二,用 hell, 由于 r t 与 c 五函数后从二 x 引脚接收的高低电瓶信号一 次转换后存入接收一位计存器,接收一位计算器,每接收完一帧就将数据移到接收数据计算器, cpu 会一直查询接收数据计算器中是否有新数据可以读, 一旦检测到,就马上把数据从计算器移到我们用来接收数据的变量中,直到接收完我们希望接收的字结束或者时间超时。 很明显,在轮巡模式下,不管是发送还是接收, cpu 一直处于忙碌状态,一轮一轮的去查询计算器是否可用,无暇顾及其他的任务。我们一般称这种一直等待使程序暂时无法向下执行的状态为堵塞。 那么如何解决这种长期占用 cpu 的堵塞问题呢? s t m 三二为我们提供了创口的中段模式。使用中段模式的创口 发送时, cpu 将数据塞入计存器后,就可以继续去进行其他任务了。当发送一位计存器的数据发送出去之后,都会触发发送数据计存器空中断把 cpu 叫回来。 cpu 在中断处理函数中将数据塞入发送数据计存器后,就又可以去处理其他代码了, 如此反复,直到全部发送完成。当然这一过程并不需要我们自己去实现。回到我们上期视频的工程,来到 q 白 mx, 打开我们的老朋友中断控制器 nvic, 打开 usatr 的中断功能,然后保存并生成代码。 使用中段发送数据的函数与轮循发送十分类似。 hell, 由于 r t transmit 杠 it, 也就是只加上了杠 it 后缀,它的参数也与轮循发送的前三个相同。 第一个参数还是用来发送的串口,也就是 h u v r t 二的指针。第二个参数依旧是要发送的数据的,指针第三个参数也是要发送的数据的长度,由于中断发送不需要长期占用 c p u, 使程序堵塞,所以也就不再需要第四个参数设置超时时间了。 将轮讯发送注视掉,我们编译下载试一试,可以看到效果依旧,说明中断模式的创口发送可以正常将数据发出了。虽然宏观上我们并没有看出效果上有何区别,但在比较复杂的项目中,节省出的 cpu 时间可以做许多事情。 再来看看中段模式下的创口接收,开启创口中段接收的函数也是一样,在 hell u a r t receive 后加杠 it 即可,其参数也是一样,只是没有超时时间的设定。不过要注意的, 由于其不会堵塞程序的执行,也就是还没等到接收到数据就会接着向下执行,这就会造成当执行到下次循环时,可能上次的数据还没有接收完,就又执行开启创口中断接收了, 所以我们将其放在循环前只执行一次。另外也注视掉轮循模式的接收函数, 在轮巡模式下 hail 由于 rt receive 函数是堵塞执行的,当它执行完时,我们就知道数据已经接收完成,放到用于接收的变量里了,接下来就可以进行分析。但中段模式的 hale 由于 rt receive 杠 it 并不堵塞,它开启中段接收后就继续向下执行了, 所以不能直接在其运行后就立即对数据进行分析,因为此时数据很可能还没有接收完成。那我们要怎样知道核实数据接收完成, 对接收的数据进行分析处理呢?当然是使用中断处理函数了。当我们使用 hell u r t receive 高 it 进行中断接收后,每当接收一位计算器,将一帧数据移入接收数据,计算器, 就会触发一次接收数据计算器飞空中断。把正在处理其他事情的 cpu 叫回来,把数据读入变量中,然后 cpu 再去处理其他事情,直到接收到我们设定的数据长度,完成本次接收。 来到我们之前在学习外部中断时就打开过的 s t m 三二 f 一 x x 杠 it 点 c 文件,在最底部就可以找到 us a r t 二杠 r q handler 函数。是的,它就是 us a r t 二的中段向量对应的中段处理函数,就好像 我们之前学习外国中断时用到的 exti 十五杠十 rq handler 一样。不过这次我们的逻辑代码不能再写在 rq handler 里了,这是因为每个 usart 中只有一个中断相量。 除了我们要用的接收中断计算器非空中断,还有我们刚才提到的发送数据计算器空中断、线路空闲中断等好几个中断也共用了此中断处理函数。 所以就需要一点点简单的判断,才能确定当前是何原因触发的中断。当然,这点简单的判断代码 ubermax 与 hell 库早就帮我们处理好了,按住 ctrl 点击进入到 hell u v r t r q handle 函数就可以看到。 那怎样在这简单的创口中断处理逻辑中执行我们自己的代码呢?还有库为我们提供了 cobac, 也就是回调函数机制。所谓回调函数,就是指当有什么事情发生时,就会调用这个函数。我们跨过这些简单的逻辑,可以找到一个 l u v r t r x c p l t coback 的代码定义, 这就是一个回调函数,其中 c p l t 是 complete, 也就是完成的意思。顾名思义,这个函数会在接收完成时执行。 具体来说,虽然接收一位计算器,每接收到一针数据都会触发一次中断,但海尔库的中断处理流程,也就是刚刚那点简单的代码 我们做了优化,只有当接收到我们想要的字结数,也就是接收完成时,才会调用 here。 由于 r t r x complete call back 毁掉函数,所以我们将代码写到 hell。 由于 r t r x complete call back 中,也就能在串口接收 玩的第一时刻对收到的数据进行分析处理了。不过在这个 hello 库文件中写我们自己的用户代码可不是个好办法, 所以海尔库为这个函数定义添加了杠杠位可前缀,代表此数是个弱定义,我们可以在其他地方重新定义一个此函数。工程中,我们通常会开一个专门的文件对此类函数进行定义。不过为了专注本次的知识点,我们就将其在闷点 c 进行实现吧。 制这个函数定义,然后回到问点 c 在优则库的理应注视队中进行粘贴。重新定义此函数。其实将之前的代码逻辑剪切过来就好了,因为都是在接收到数据后的处理逻辑, 但是我们靠中断好不容易省出来的 cpu 资源,微友循环中却什么都不干,确实有点说不过去, 不过为了不把小伙伴们绕晕了,我们还是写句注释,假装这里有一些复杂代码吧。 另外还有一件事,不仅问函数 r x complete callback, 函数也用到了 receive data, 所以我们将它提升为全局变量吧,将它剪切,然后为了规范放到 user cool pv 注射队中, pv 就是 private variables 自由变量的意思,便宜下载看看效果。 通过串口助手发送二,一红灯成功亮起,而且指定也返回来了,看来中断接收也确实起了作用,正常执行了,那我们再发送 b 一试试。 哎,蓝色小灯没有亮起,指令也没有返回来,这是什么情况呢?这其实是因为我们只是在程序刚开始的时候启动了一次串口中断接收,接收完一次后就 不再接收了,那怎么办呢?我们刚刚说了,不要在 vl 循环中不断的去开启创口中断接收,其实解决办法也很简单,只需要在处理完一次创口接收回调后,为下次的接收启动创口中断接收就好了,便于下载再试试。 好的,这下就没有问题了,不知道有没有小伙伴被绕晕了呢?其实本期视频讲的内容很简单, 底层的东西刚入门的大家了解了解就好了。真正要使用串口的中断模式,只需要勾选开启相应串口的中段,待发送函数和接收函数后,加杠 it 后缀,以及将处理逻辑移入到 hell ue r t r x complain 的 callback 即可。 通过中断,我们成功解决了串口操作一直占用 cpu 的问题。还要如何解决接收不确定长度数据的 的问题呢?有没有更好的方式进一步减少 cpu 的占用?下期视频我们就来试试用 stm 三二提供的扩展函数实现接收不确定长度数据,以及如何使用 dma 替代 cpu 搬运数据,同时还有如何使用蓝牙模块,如何解析一些稍复杂的串口数据包协议? 求关注求点赞,求硬币,求收藏,求转发!求转发求转发!你的肯定是 up 持续更新的动力!听说给 up 一键三连的小伙伴全部都成为了 stm 三二大牛,我们下期视频一会见,拜拜!

这个 q 呢软件呢?我们的这个 m、 d、 k 啊,也就是我们这个 q 软件啊,它会自动给我们定位到这个地方啊, 大家们看这看到没有?定位的这个地方啊,这看到没有?这些啊,就是我们 第一个参数的一个取值范围,就这么多啊,你只可以从这些里面去选,选一个你需要用的啊,复制到这个里面啊, 同样的啊,同样的,我要双击它,对不对?这个是第二个参数啊,对,我也不知道该怎么去去写,对不对?我头一第一次用嘛,我不知道这个第二个参数怎么去写,同样的啊,双击它对,选中之后按 f 十二,那 m d、 k 呢? 结果给我们定位到这个位置哈,你往下看一看,看看到这没? 这些东西啊,就是这些数值啊,就已就是就是我们第二个参数的一个可选的范围,比如说这个参数,你只能从这些里面去选择啊,这就是我们通常说的就这两句话。这两句话呢,我们更多的 就是说就是来帮助我们选去选这两个参数啊,作用啊,嗯,就是是这么一个作用。那么我们接下来呢,看一下最核心的一句话啊,就是这个函数 也是最核心的一,就这么一句话。嗯,咱们大概看一看啊,其实按照 我们之前讲的这些知识啊,其实他应该就是操作了一个,对不对?某一个端口下的 bsrr 计存器啊,给他复了一个值,对不对?就是给啊,就是将这个值然后复制给某一端口下的 bsrr 计存器, 应该就这么个意思,对不对?具体又是怎么一回事啊?我们再接着往下看哈,我们接着去分析一下, 好了,我们现在就来分析一下哈,那么你看一下哈,这是一个至位函数,对吧?第一个参数呢是 a 端口,第二个参数呢选的八拐角,那么这个函数对不对?其实就是他呀,对不对?他之后呢?其实 你就我们把这个对不对套到这里面来翻译一下的话,对不对?再加上这么一句话哈,那么就是套下来的话,那肯定就是在 gpla 下的 bsr 计算器,对不对?我给他负了一个值,值呢,叫 拼吧,对吧? g p l 拼吧,那么 g p l 拼吧又等于多少呢?同样啊,你双击在这个地方双击 g p l 拼吧,按 f 十二 m d k 呢,就会给我们定位到这个位置啊,这是个红定义,对吧? g p l 拼吧,它等于多少呢? 无符号整形十六位,这是十六禁制,零 x 十六禁制吗?零幺零零,那么我们翻译一下, 将这三句话连起来,我们翻译一下,就是说将零 x 零幺零零对复制给 g p l a 端口下的 b s r r 计算器, 那么 b s r 计算器会有一个什么的变化呢?对吧?还是啊,老办法对不对?同样的啊,我们把这个十六进制对不对写成二进制,第一个零,当然是四个零零零零零, dary 啊,这,这个是一,可以写成啊,零零零幺,对吧?这个零零零零零, 这个零啊,零零零零,看到没啊?关键点就在这哈,看到没?它的未断八啊,是个一啊,那么也就是说这句 话一执行之后啊,那么 gp ioa 端口下的 bsrr 计存器的卫段八就被置位了,置位就是通常我们说说所说的写一啊,就给他写了一个一,那么 bsrr 又是一个什么寄存器呢, 对吧?这个地方我们来看一下这张图呢,我们是啊,斋字 s t m 三二的 中文参考手册的第八章,对吧?它第八章呢,主要是对 gpio 中的这个计算器啊,就是各个计算器的功能啊,他给你做了一个介绍,那么我们今天用到的这个计算器,他就叫什么?叫端口, 所谓设置清除计算器,那么它的偏移量啊,我们用不到复位值呢,嗯, 就是零,对吧?就是 s d m 三二一上电一初始化。该计算器啊,所有的位啊,都是零,都是零, 那么这个计算器同样的哈,未断零,未断三十一,也是一个三十二位计存器,这个三十二位计存器看注解呢,它的每一位啊,都有,都有功能,比如说这个计存器啊, 他所有的未啊,都有功能,没有空的,他都有用。那么我们说了这句话,一执行完之后呢,他的未断八就变成了一啊,对不对? 位段八变成一,那么分析一下呗,这是位段零,这是位段八,对吧?位段八等于一,也就是说 b s 八等于一。我们看一下这啊,这只写了一个 w, w 是什么意思? w 啊,就代表该位啊,就只能,只能什么?

欢迎您继续收看由铁头山羊工作组为您精心准备的 s t m 三二入门之路系列食品。 在本期视频中,我将带您深入理解 gpl 输入模式的内在原理。 这个输入模式已经是我们学习到的第二种 gpl 模式了,你还记得吗?我们学习到的第一种 gpl 模式叫做通用输出推碗模式,它的特点就是内部有一对这样的电子开关,一个推一个拉, 这两个电子开关呢,对外能够输出高电瓶三点三伏或者低电瓶零伏。我们曾经使用这种模式来驱动 led 灯。今天我们要研究的呢是这种输入模式,我们曾经使用这种模式来读取按键的状态,您还记得这段代码吗?没错,这就是上次我们用来初始画按键的一段代码。 这段贷款的作用呢,就是为我们开发板上的按键 k 一分配一个 l 银角,并将这个 l 银角的模式呢配置成输入模式。 请您注意这句话,机票 init 点 mode 等于机票 mode 的 input, 这里的机票 mode 的 input 就表示我们今天要介绍的输入模式。 您是否还记得,在这种模式下,我们曾经使用 h l g p r read pin 来读 选 l 的状态,如果 l 的状态是高电瓶,我们就会读到 gpu pin set。 如果 lv 音脚上是低电瓶,我们就会读到 gpl pin reset。 但是 l 银角上的电压是如何转换成 gpl pin set, gpl pinry set, 或者说数字量零和一的呢?今天呢,我们带着这个疑问来了解一下 gpl 的输入模式。 在 stm 三二参考手册的第一百六十三页,有这么一张图很好的诠释了 gps 输入模式的工作原理, 这张图呢就是 gpl 的内部结构框图,现在呢,我带着大家来捋一遍,请您看芯片 最右侧这里有一条线,还有一个伸出来的小方块,他呢就代表了 l 银角,也就是芯片四周的那些银白色的金属银角。 这两个呢,是两个保护二极管,用来把 l 银角的输入电压限制在一个合理的范围内, 因为呢,如果您的输入电压过高或者过低,都会烧毁这个芯片的内部电路。您会疑问,过低的电压怎么会烧毁芯片的内部电路呢?那如果给他接的是一个负一百伏的电压呢?对不对? 我们来解释一下,这两个二极管是怎样把输入电压限制在一定范围内的?是这样的,您看啊,当您输入的这个电压大于威力低的时候,这 这个上面的这个二极管就导通了,所以呢,这个点的电压他是不会超过 vdd 加上这个二极管的正向导通电压的。 相反呢,当您像这个 io 端口输入的电压过低时,如果低于这个 vss, 那么这个二极管就导通了,所以呢,这个点的电压他也不会低于 vss, 去减去这个保护二极管的正向导通电压。 这样呢,这个点的电压不就被限制在 vs 和 vss 和 vdd 之间了吗?这就是这两个保护二极管的工作原理。 但是呢,我要提醒您的是,这两个保护二极管他也不是万能的,当您输入的电压过大的时候呢,比如说您手上的静电放电,这时候即使有这两 两个保护二极管的存在,也同样会烧害我们芯片的内部结构。看完了这两个保护二极管之后呢,我们再往里走, 您看这里有两个电阻,一个电阻呢,接到高电瓶 v d d 在 s t m 三二里,这个供电电压就是三点三伏。另一个电阻呢,他接了 d 电瓶 v s s, 也就是零伏。 我们把这个电阻呢叫做内部上拉电阻,我们把这个电阻呢叫做内部下拉电阻。 您还记得吗?在我们讲基本按键电路的时候,我们曾经介绍过这个上压电阻的概念。这个内部上压电阻呢,其实跟我们按键电路里边的上压电阻是一 一回事。请您回忆一下,这个电路上下电阻的作用是,当这个 l 银角悬空的时候,这个上下电阻会把 l 银角上的电压拉到一个高电瓶,也就是呢,给这个 l 端口一个默认的高电压。 其实呢,芯片内部的这个上压电阻跟这个电阻的作用啊,是一模一样的。因此呢,您下次再画这个电路的时候,你完全可以省略掉这个外部的上压电阻,而使用这个芯片内部的上压电阻就可以了。 您再看这个内部下拉电阻,它的作用呢,跟内部上下电阻差不多。这个内部上下电阻呢,是当 l 银角悬空的时候,给这个 l 银角一个默认的 高电瓶,这个内部下拉电阻的作用呢,正好相反,就是当这个 l 银角悬空的时候,给他一个默认的低电瓶,也就是零伏。请您注意观察,在这两个电阻上,他都有一个开关, 这两个开关呢,他们分别用来使能或者禁止上拉电阻和下拉电阻,你看这里都写着昂 off, 就是开和关, 请您注意哈,如果您只使能这个上下电阻,也就是把这个开关闭合的话,那么 l 银角上就有一个默认的高电瓶,三点三伏,也就是当这个 l 银角悬空的时候,他的默认电瓶就是三点三伏, 这种模式呢就叫做树上拉模式。如果您只使能这个下拉电阻,也就是只把这个开关 闭合,那么当 l 银角悬空的时候,这个 l 银角上就会有一个默认的低电瓶,我们把这种模式叫做输入下拉模式, 如果您把这两个开关都断开,这个时候 io 银角上是没有默认电瓶的,也就是当这个 l 银角悬空的时候,它上面的电压是不确定的,我们把这种模式叫做输入浮空模式, 请您注意这两个开关他是不能同时闭合的,也就是说您不能同时使能这个上拉电阻和下拉电阻,所以呢模式呢就只有三种, 要么就是输入上拉模式,要么就是输入下拉模式。如果您两个店组都不使能的话,就是输入浮空模式。那在代码中我们如何去选择 这种输入上拉电阻或者输入下拉电阻呢?下面呢我们来演示一下如何去配置他的上拉电阻,下拉电阻让他处于上拉模式,下拉模式或者浮控模式中的一种。 那我们把这个初始化的代码省略掉,我们直接去写我们需要的代码。首先呢您先声明一个结构体, 给他起个名字,然后呢啊,我们要出手画我们的 gpl, 这个时候我们去选他的 pin 等于, 嗯,我们先就用点点代替,然后在你选择输入上拉电阻和输入下拉电阻这种模式的时候呢,您一定要确保您的这个 io 的模式是输入模式,所以呢, 您的这个模式应当去选择 这个 gplmo 的 input, 也就是工作在输入模式下,您才可以去选择这个输入上下电阻和下下电阻的参数,其他模式是不行的,必须要选择这个输入模式。 然后呢,配置完这个参数之后,我们再来认识一个新的参数,就是我们之前老师去讲的这个 pro 参数。 这个 pose 参数呢,也就是专门用来选择在输入模式下是否使能那两个电阻的参数,我们把它把鼠标放在这个参数上,然后按键盘的 f 三按钮,然后找 一下这个这个值的可取范围,你看哈,他一共有三个可选的值,那分别是 gpr nope, 基本上 no poor, 也就是 no poo up or no pour down act activation, 也就是既不激活上压电阻,也不使拿下拉电阻,那这个 no poor 就是对应的我们的输入浮控模式,也就是上上压电阻和下压电阻都是被禁止的。 第二个呢, gpl 泼 up 泼 up activation, 也就是使能我们的上拉电阻,也就是呢给 io 银角一个默认的高电品,这个呢就对应了我们的输入上拉模式。最后这一个呢, pro 档也就对应了我们的输入下拉模式,比如说如果我们把那个基本按键电路里边的上下电阻给它省略掉,然后这个时候呢,我们就应该把这个输入模式的上下电阻给它使能了,那么我们就应该选择这个参数, 这样呢,我们通过这个 hl gpl init 这个方法, 把我们选好的这个参数呢丢给这个 api, 这个时候我们就可以啊,把我们的输入上拉电阻给使能了,嗯,代码就是这么写,让我们沿着这个电路再 往里走。您看这个时候我们就碰到了一个三角形,里边有一些图案,这个符号呢,他就叫做史密特出发器, 为什么要在这个位置去放一个史密特触发器呢?请您看这张图,您看上面的这条曲线 vi 呢,它就表示史密特触发器的输入端,也就是 l 银角上的电瓶。您看在 l 银角上,他的电压可能是一些连续变化的纸, 它既不是高电压三点三伏,也不会是低电压零伏,而是介于这两个值之间的任意一个值。您再看下面这条曲线,这个曲线 vo 呢,表示失明的 触发器的输出端,你看在这条曲线上,他的值要么是一,要么是零。也就是说呢,经过了史密特出发器之后,艾欧银角上连续变化的电压量就转换成了一或者零这种数字量, 把这种连续变化的电压量转化成一或者零这样的数字量。这是施密特触发器的第一个功能,他还有一个功能,那就是施密特触发器,他还能够起到稳定电路的作用, 这个施米特触发器呢,他有一个特点,请您看这张图,当这个输入电压从低电瓶向高电瓶跳变的时候,他只有超过了这个高电压的门线,就是 vth 才会有这个跳变的边缘。 当您这个已经是高电压的时候,您往这个低电压去跳边的时候,只有这个电压它低于 vtl, 也就是低跳边门线,它才会有一个这样的跳边边缘, 这有什么好处呢?这就是如果您的这个输入电压在这个临界范围内来回波动的时候,这个电路它是不受影响的,也就是它的电压会保持稳定, 所以呢这个失明的触发器还有一个防抖的功能,加引号的防抖啊,就是防止这个电压来回震荡的时候,对您的这个输出的值啊产生影响,防止他多次的去跳并。 我们呢再从头去捋一遍。首先呢从这个艾微银角开始, 经过了两个保护二极管的保护,然后呢这边有两个电阻,这个呢是上拉电阻,这个呢是下拉电阻,这两个电阻的作用呢是给艾欧银角一个默认纸, 然后呢再往里走,这个连续的信号经过史密特出发器之后就变成了零或者一这种数字量,这个数字量呢最后是存储到这个计算器里面, 这个时候呢您就可以调用 api, 就是 hl gpr read pin 这个 api 来读取 io 的值了,这呢就是 io 银角输入的原理。 好了,今天的分享就到这里,感谢您的收看下期视频,期待与您再见!