一个视频带你了解 stm 三二中段。在讲 stm 三二中段之前,我们先来了解几个中段相关概念。 首先我们来说一下什么是中断。中断就是在主程序执行过程中出现了特定的触发条件,也叫中断源,然后 cpu 暂停当前正在运行的程序,转而去处理中断程序, 处理完成后又返回原来被暂停的位置继续运行。我们再来说一下什么是中断优先级。中断优先级就是当有多个中断员同时申请中断时, cpu 会根据中断员的轻重缓急进行裁决,优先处理更加紧急的中断员。 最后来说一下什么是中断欠套。当一个中断程序正在运行时,又有新的更高优先级中断员申请中断 断, cpu 就会再次暂停当前中断程序,然后去处理新的中断程序,处理完成后依次进行返回。了解完这几个概念,我们再来讲一下 stm 三二的中断。 cortex m 三内核支持两百五十六个中断, 其中包含了十六个内核中段和两百四十个外部中段,具有两百五十六级的可以编程设置的中段优先级。但是 stm 三二 fe 只适用了 m 三内核的一部分,它只含有八十四个中段元,其中包括十六个内核中段和六十八个外部可屏蔽中段, 而这六十八个外部可屏蔽中断。 f 幺零三系列芯片又只有六十个,所以具体到每个芯片型号可用的中断还是以数据手册为准。这是我截取的数据手册部分中断表, 可以看到每个中段都是有一个固定的地址的,由于硬件的缘故,中段源产生中段时,都是到相应中段源固定的地址去执行中段程序。那为什么我们的中段函数可以写在任意位置呢? 这是因为在固定地址这里,有编译器自动加上了跳转到中断函数的代码,这样就实现了由固定地址到任意位置执行程序了。 这些中段的固定地址列表就是我们说的中段向量表了,我们编程中基本不需要管这个中段向量表,变异器已经帮我们做好了 stm 三二,有这么多中段,是怎么管理他们的呢? 这里就要提到 nvic 了。 nvic 全名叫做嵌套中断向量控制器。 nvic 是一个内核外设室内核,专门用来 来管理中断的,但外部有很多中断同时进来 n v i、 c 就按照程序配置好的优先级,给这些中断排好队,依次送入 c、 p、 u 执行。我们现在来看一下 n v i、 c 具体是怎么管理中断的吧。 nvic 将优先级分为抢占优先级和响应优先级。当一个中段设置了抢占优先级,那么他可以打断其他正在执行的中段,也就是刚才说的中断欠套,抢占优先级控制着中段欠套,而响应优先级控制排队顺序。 nvic 用优先级寄存器的思维来将抢占优先级和响应优先级进行组合。具体可以看下这张图,我们可以用程序来选择使用哪种分组模式,比如我们选择第二组,我们的中段就可以配置零到三 三级抢占优先级的任意一级,也可以配置成零到三级响应优先级的任意一级,中断的抢占优先级高的可以中断嵌套响应优先级高的可以优先执行多个中段,也可以设置成一样的优先级。 这些优先级相同的就会按照数据手册中的中断号进行排序。现在我们就来总结一下吧。 一、 stm 三二 f 幺零三,总共有十六个内部中断和六十个外部中断,具体可用的要参考数据手册。二、 中段产生之后都是到一个固定地址去执行程序编译器会帮我们连接好固定地址与自己写的中段函数。三、 st m 三二的中段的优先级,通过 n v i c 控制 n v i c 将优先级分为抢占和响应,总共五种组合方式。 四、不同的中断抢占优先级和响应优先级可以配置为相同。五、同时产生多个中断时,抢占优先级高的可以中断欠套响应优先级高的可以优先执行。 抢占优先级和响应优先级均相同的,按照默认中顿号执行。今天的视频就到这里了,欢迎留言评论,我们下期见!
粉丝7293获赞2.9万

stm 三二定时器中断代码编写本期视频带大家一起编写一下 stm 三二定时器中断代码。我们打开之前视频新建的工程文件夹, 新建一个 app 文件夹之后,将所有的外设操作文件都放到这里。打开 app 文件夹,新建一个 timer 文件夹,用来放我们本期编写的实验代码。 在 timer 文件夹中新建一个 timer 店 c 文件和一个 timer dh 文件,然后打开我们的工程,把它们都添加进来。先添加一下文件路径, 然后新建一个 a p p 组,把刚才的两个 timer 文件添加进组里。 我们打开 timer, 点 a 全键,写一下防止重 负包含的红定义, 这样写就可以防止重复包含问题。再打开 timer, 点 c 文件,包含一下 stm 三二的头文件。 我们使用外设,首先就要先初始化,这里写一下初始化函数框架, 今天我就使用 t m 二来进行中断实验。第一步就是要打开总线时钟,我们看一下结构图,可以看到 t m 二是在 a p b e 总线上, 所以我们就使用 r c c a p b e paragraph crc m d 这个函数初始化时钟。我们可以右键转到定义,看看怎么填写参数,这里我们要开启 team 二十中,所以我们选择这个,把它复制一下。第二个参数是 enable 还是 disable? 回到我们编写代码这里,把刚才复制的参数粘贴到这里,第二个参数选择 enable。 经过之前视频的分析,我们知道 tm 二有很多失踪员可以选择刚才代码,只是开启总线时钟,我们还需要让控制器选择 rcc 时钟, 打开内部组,可以看到标准库中每个外设都有对应的库文件, e team 点 c 位后缀的就是定时器的库文件了。打开之后,我们在右键打开它的头文件,我们拉到最下面,就可以看到有很多函数,这些函数就是操作定时器这个外设的全部函数了, 你想怎么配置都可以在这里找到对应的功能函数。我们需要定时器的时钟,选择内部 rcc 时钟,也可以找到时钟配置函数。因为通用和高 定时器有很多试中员可以选择,所以这里有很多试中相关函数,我们要使用内部 r c c, 试中员就使用这个 team internal clock config 函数。选中,点击上方的小齐,将用到的函数做一个标记,方便以后查阅。 复制一下这个函数粘贴到这里,不会使用,也可以右键转到定义看下详细信息。这里只有一个参数,是选择哪个定时器,回到这里,我们选择 t m 二, 这样时钟元就配置好了。接下来就该初始化定时器的实际单元相关参数了,也就是配置于分频器,自动重装在职技术模式等。打开库文键,也有功能函数可以配置这些就是这个 team time basically 函数, 我们复制一下它粘贴到我们代码这里。同样的,我们右键转到定义,看一下他需要什么参数。这里是说需要填入哪个定时器和一个 team time bassinate tap deaf 结构体参数,我们复制一下这个结构体类型, 回到我们的代码定义这样一个结构题,参数名字可以随便起,为了见明之意,我命名为 tim time basinet structure, 将这个函数的参数填写完整,第一个参数是 tim 二,第二个参数是刚才定义的结构体取地址, 现在我们填写一下这个结构体的参数,加快一下。先把参数全部引出来,我们看一下 teamclock 的 vision 这个参数怎么写,可以转到定义,查看一下详细信息。这个参数是时钟分割,是时钟圆绿波,这里有 关,和我们本期实验关系不大,我们搜索看下参数,随便配置一个就好了,可以配置成这些参数,我们选择第一个吧,复制一下粘贴到我们的代码这里,我们转到定义,再看一下 cancontomo 的这个参数怎么配置, 这里是说配置技术器的模式,我们搜索一下这个 team count mode 红定义,看一下参数。参数可以配置成这几个,有向上对齐,向下对齐,中央对齐。技术模式我们一般都选择向上对齐,其他模式在别的地方有用,粘贴到这里就可以了。 下面这两个参数就是自动重装在和预分频值了,取值范围都是零到六万五千五百三十五,用来控制定时时间。内部来到预分频的时钟频率是七十二兆赫兹,我们可以把 频率降低七千两百倍,变成十 k 赫兹,这样计数器就是零点一毫秒加一个数,然后再把自动重装载值设为五千,就可以定时零点五秒了。如果你想定时,其他时间稍微计算一下就可以了, 我们就零点五秒定时器中断一次吧。因为设置的值比真实的多一,所以这里还要减一, 上面自动重装在也要减一,填五千减一,这样就配置了定时,时间是零点五秒,当然如果你不想这样组合,也可以自己配置其他数值组合。最后这个参数是高级定时器才用到,我们写零就可以了。 定时器初始化已经写完了,但是这样配置开中断之后就会立刻进入一次中断。如果不想这样,我们还需要清除一下中断标志位 倒库函数,这里找下清楚,中段标志位的函数就是这个函数,我们复制一下,复制到这里, 右键转到定义,看下参数,这里第一个参数是哪个定时器?第二个参数是哪个中段标志位定时器中段有很多,其他中段都是定时器其他功能用到的,我们选择 ten flag update 这个中段复制一下, 第一个参数写 t m 二,第二个参数写刚才复制的,这样初始化定时器才是真的完成了。接下来我们开启 t m 二的中段,我们找下库函数,这个 t m i t config 函数就是开启定时器中段函数了,我们把用到的函数做一下标记, 把这个函数复制到代码,转到定义,看下参数,第一个参数是哪个定时器,第二个参数可以选择 这些中段我们选择 team it update 回到我们的代码填写参数,第三个参数选择 enable 使能,这样定时器中段功能就开启了,但是现在只是将中段输入进内核了,因为内核内部中段都是由 n v i c 控制,所以还需要配置 n v i c。 我们找下库函数,可以看到库文件并没有 n v i c 结尾的,这是因为 n v i c 室内和外设 st m 三二把库函数放到了 mis c 文件内了,打开后我们打开它的头文件,拉到最后就能找到它的库函数了。 n v i c 配置需要先设置优先级分组,使用 envic priority group config 这个函数,然后再使用 n v i c in it 初始化 n v i c。 我们先设置一下右 六线级分组,复制到我们的代码,转到定义,看下参数,可以配置成这些参数。关于 nvic, 不懂的可以看我之前的视频,因为只有一个中段,这里随便选,我选择分组二吧。设计好分组,再来初始化一下 nvic, 复制一下函数, 转到定义看参数配置,这里参数只需要一个 nvic in it type define 结构体,我们在上方定义一下, 名字叫做 nvic in it structure。 将参数地址传进去,再把所有参数都引出来, 转到定义,看下参数怎么复制。第一个参数是中断通道选择,具体在 stm 三十二 fe 零 x dh 文件中,我们打开 stm 三十二 fe 零 x dh 文件 最上面这里就定义着很多中断通道,我们找到后缀为 m d 的红定义,关于后缀 m d 的意思可以暂停看下这里中断通道选择 t m 二 i r q n 复制过去就可以了。第二个参数是控制通道是否开启,我们填 neibo 第三个,第四个就是抢占优先级和响应优先级了,因为只有一个中段可以随意设置,我这里都写二。现在 nvic 就配置好了,我们现在就可以开启定时器了, 使用 t m c m d 函数可以开启定时器,第一个参数写 t m 二,第二个参数写 enable, 这样整个初始化就完成了。这里注意一下, n v i c 分组设置是对所有中短都有效的,也就是整个工程只能配置一次。 如果你有其他中断,这里就要注意一下了。现在我们来写一下中断入口函数。中断入口函数名在 startup 这个启动文件中有定义,不能随便写。这里有所有的中断入口函数,并且都是若定义,我们可以重写 这个 team 二 irq handler 就是 team 二中段入口函数了。复制到我们的代码,快速写一下函数框架。在中段函数中,我们需要手动清除一下中段挂起标志位,我们快速写一下 整体就是先用 team get it status 函数判断一下挂起标志位,然后再用 team clear it pending bit 函数清除一下标志位,中段函数就写好了。我们把初始化函数声明一下,这样整个定时器中段就写好了。现在 我们在主函数中调用一下,在上方包换一下 timer 头文件,这样定时器就每隔零点五秒执行一次中断函数了。我们把想执行的程序放进中断函数中就可以了。快速写一个 led 闪烁的程序,测试一下, 这样 led 灯就是每隔零点五秒亮灭。编一下,再看一下,这里有错误是因为有 c 九九的语法,我们点击魔术棒 c c 加加选项卡,勾选 c 九九 mode, 再次编译一下就没有错误了。现在我们看下现象吧。今天的视频就到这里了,欢迎留言评论,我们下期见。

stm 三二、外部中段标准库代码编写本期使用一个按键作为外部中段的输入控制。 led 灯的亮面电路图就是这样的,按键一端接到 pa 领口,另一端接地 并联的这个电容是为了消抖的,防止按键抖动多次触发中断。我们现在来写一下程序,打开新建的工程文件夹,新建一个 app 文件夹,在 app 文件夹内新建一个 exti 文件夹存储本期的程序, 在 e x t i 文件夹内新建一个 e x t i 点 c 文件和一个点 h 文件,现在打开工程,把这两个文件加入到工程,先添加一下文件路径,这里勾选上 c 九九 mode, 然后再新建一个 app 组,将刚才的文件加入到组里, 现在文件就添加进来了。我们在 e x t i 点 c 文件中包含一下头文件,在 e x t i 点 h 文件中添加一下防止重复包含的红定义,这样准备工作就做完了。我们编一下工程, 现在开始写程序,第一步都是需要写一个初始化函数,用来初始化外设。 e x t i in it 函数名与库函数重复了,我们函数明写成 e x t i config。 初始化的第一步就是打开时钟了,我们本期使用的是 pa 领口,需要打开 gpioa 和 fio 的时钟。 exti 虽然也是外设,但是它的时钟是一直开着的,我们不用管 g p i o a 和 a f i o 都在 a p b 二总线上,所以我们使用 r c c a p b 二、 paragraph cla cmd 函数,打开时钟,右键查看一下参数,复制一下 gpioa 和 afio 两个参数回到我们的程序,粘贴到这里, 因为两个都在同一条总线上,我们打开时钟时可以使用或操作把它们写到一起。后面这个参数选择 innable 时钟打开之后就是初始化 gpio 了, 使用 g p i o innate 函数初始化 g p i o。 右键看一下参数,需要 g p i o。 分组合一个结构体地址参数,我们复制定义一个结构体,结构体名字为 g p i o in it structure, 把结构体地址传入函数函数,第一个参数是 gpioa, 第二个参数是结构体地址,快速把结构体参数引出来。第一个参数是 gpio 模式, 我们电路外部没有上拉电阻,需要使用内部上拉,我们去定义,找一下参数, gpio 模式的参数在这个里面有定义,我们搜索一下,这里就是 gpio 的八种工作模式,我们选择内部上拉输入模式,复制到我们的程序。 第二个参数是 io 口选择,我们选择 gpio 片零。第三个参数是 gpio 速率我们选择最高就好了。按照刚才的方法搜索复制一下参数, g p i o。 已经初始画好了,我们需要配置一下 a f i o。 把 p a 零与 e x t i 零连接起来, a f i o。 的相关库函数也在 g p i o。 库文件中,我们打开 g p i o。 库文件的头文件,拉到最下面这个 g p i o e x t i i like config 函数就是配置 a f i o。 的函数了,我们复制一下它,粘贴到我们的程序,右键转到定义,看下它的参数。第一个参数是 g p i o port sauce g p i o x x, 范围是从 a 到 g, 我们填写到这里,把 x 改成 a, 再回去看下第二个参数,第二个参数是 g p i o 片 south x x 范围是从零到十五,我们复制填写到这里,把 x 改成零, 这样 g p i o。 就连接到了 e x t i 外设了。接下来开始初始化 e x t i 外设,我们打开 e x t i 外设的库文件,右键打开头文件拉到最下面,看下它的可使用的库函数,这里就是它的库函数了。我们使用 e x t i in it 函数初始化 e x t i。 复制到我们的程序,右键转到定义看下参数这里参数需要一个结构体,我们复制定义一下,它名字叫做 x t in it structure。 把结构题地址传入函数中,快速的把结构题参数引出来,我们转到定义,看一下参数怎么填写。 第一个参数是指定要启用或禁用的 e x t i 线,具体定义在 x t i s 这里我们可以搜索一下 e x t i lies, 这些就是 e x t i 零到十九,我们选择 e x t i 零 复制填写到这里。第二个参数是使能还是失能?填写 enable。 第三个参数是 e x t i 模式,我们转到定义搜索看下参数。参数 注,在 e x t i mode type define 这里,我们搜索看下参数可以选择是中断模式还是事件模式,我们选择 e x t i mode interrupt 复制粘贴到这里。 同样的方法看下第四个参数,这个参数是选择触发模式,这里注视有错误,应该是在 xt trigger type define 这里就是这个。我们的 i o 口是上拉输入按键,按下是低电瓶,所以按键按下的一瞬间是下降沿,这里选择下降沿, 把它复制到这里就可以了,这样 e x t i 就初始化好了。现在 e x t i。 已经连接好了内核。最后就是初始化 n v i c 开启中断了。在 m i s c 库文件内找到 n v i c 的初始化函数,打开 m i s c 头文件,拉 到最下面。配置 n v i c 的步骤就是先使用 n v i c priority group config 函数配置一下优先级分组,再使用 n v i c innate 函数初始化 n v i c。 这里加快一下,不理解的小伙伴可以看我之前的视频。 这里第一个参数是初始化的中断通道,可以在 s t m 三十二 f 一零 x d h 文件内找到。 这里就是全部的中段通道了,我们选择 e x t i 零,其他的中段通道可以在这里后缀为 m d 的红,下面找到。 需要注意的是, exti 五到九是共用一个通道,十到十五也是共用一个,如果你是用这其中的某一个通道就要注意一下了。复制 试一下 exti, 领到我们的程序。第二个参数是使能还是失能?填写 enable, 后面两个参数是抢占优先级和响应优先级。本次实验只有一个中断可以随意填写,我这里都写二, 这样整个外部中断初始化就结束了。接下来我们写一下中断入口函数,中断入口函数在 startup 启动文件内有定义,我们使用的是 e x t i 零。选择这里的 e x t i 零 i r q handler 复制一下。写到我们的程序。 在中段函数中还需要我们手动清除一下中段挂起标志位,在这里使用 x t get it status 函数,先判断一下中段是否置位,右键转到定义,看下参数,这里需要选择哪一条外部中段线? 参数是 e x t i line x x, 范围是零到十九。复制一下 e x t i line x 到我们的程序 x 改为零,然后使用 e x t i clear it pending bit 函数清除一下中段挂起标志位, 这样中段入口函数就写好了,我们编译一下。最后在中段函数中写一下测试代码,每次产生中段就将 pc 十三扣转换一下状态,这样测试代码就写好了。把初始化配置函数声明到头文件 转到 man 函数,包含一下头文件,在 man 函数中调用一下初始化配置函数,现在就可以编译稍露镜板子了,我们一起看下现象吧。 今天的视频就到这里了,欢迎留言评论,我们下期见!

stm 三二外部中断结构分析 stm 三二外部中断结构相比定时器等其他外设中断还是比较简单的,我们一起看一下它的结构吧。 这是外部中断 exti 控制器结构框图右下角输入线,这里就是 gpio 经过这样的结构输入进来的,这样的结构就是数据选择通道。 我们知道 stm 三十二的 gpio 分为 a 到几个组,每组 gpio 又有零到十五,总共十六个银角。 这里也有 e、 x、 t、 i。 零到十五,共十六个选择通道,对应着 g、 p、 i、 o 片。零到十五个影角,每个选择通道有 a 到 g 个,输入端,对应着 g、 p、 i、 o, a 到 g 个组,也就是说 g、 p、 i、 o。 每组相同的片接在了同一个选择通道上,所以影角的外部 中断相同的偏移在同一时间只能有一个触发中断。在我们使用多个外部中断时,要避免使用不同组相同的偏引角,比如 p a 零和 p b 零要避免同时使用。 这里其他通道也是同样的结构,这里总共 exti 零到十五,共十六个选择通道,其实还有十六到十九,总共二十个选择通道。这几个外设虽然不属于外部中段,还是接到了外部中段这里 因为外部中断可以低功耗唤醒,所以这里的几个外设都是来借助这个功能实现低功耗唤醒中断功能。 配置选择通道就是由 afio 控制了,这些配置好的选择通道就从输入线这里接到了外部中端控制器上方。这里有很多寄存器,我们可以通过总线来读写这些寄存器, 这两个寄存器可以控制这里的边沿检测电路,通过设置寄存器就可以实现上升沿下降沿双边沿触发中断,触发之后会产生一个高电瓶信号接到后门这里, 同时上方软件中断触发也接到了后门这里,所以外部中断也支持我们程序去触发中断后门出来之后,一路接到了请求挂起寄存器,另一路接到了一个雨门 上方这里通过请求挂起计存器控制相关中段标志位置。一,可供我们程序读写去判断中断类型。请求挂起计存器还会输出一个信号接到一个语门, 同时上方的中断屏蔽寄存器也有一个信号,相当于一个开关,如果没有屏蔽这个中断就输出一个,一两者共同作用,就会输入 不到 nvic 中断控制器了,这样整个中断通道就打通了。我们再来看下下面这一路,这一路就是事件通道了,这里有一个事件屏蔽寄存器, 和中断屏蔽寄存器一样,也相当于一个开关,如果没有屏蔽这个事件就会共同作用输入到脉冲发声器,然后产生一个脉冲接到其他外设,这就是整个外部中断的结构了,我们来总结一下怎么配置外部中断吧。 一、我们要初始化引脚时钟和 a f i o 时钟。二、初始化相应引脚为附用输入模式, a f i o 选择相应通道。 三、设置选择相应通道的中断触发模式,启用所选通道,这样就接通 gpio 与内核的 nvic 了。今天的视频就到这里了,下期写一下程序,欢迎留言评论,我们下期见。

hello, 各位小伙伴们大家好,这里是 kiss king。 在上期视频中,我们一起了解了所谓中断,就是打断程序的正常执行流程,执行一些由突发状况引起的紧急任务, 并且通过一个案件的例子简单了解了如何使用外部中断,还挖了几个坑。 nyc efti 中断、向量中断优先级,他们到底是什么呢?那么本期视频我们就来一起好好聊聊。 先从我们已经接触过的 e x t i 入手,假设我们来到了按键 k 一对应的 g p l 口,也就是 p b 十二,它的 g p l 内部。此结构图我们已经在第五集视频做了详细的讲解。 外部的电瓶信号进入到 gpl 后来到了输入驱动器,首先是经过上拉下拉电阻,然后 经过施米特触发器转化,最后抵达了输入数据计算器或者片上外设。而其实再接下来,电瓶信号还会抵达这样一个结构。这张图在资料包中 stm 三二中文参考手册的第一百三十五页可以找到,我们称其为外部中断实践控制器。 像这样的结构,在我们使用的 s t m 三二 f 一系列芯片中共有十九个。这十九个外部中断控制器共用了一套计算器,但其中的连线都是独立的。 图中的这些连线其实有十九组,每个外部中断都对应着其中的一组线路,所以我们有时也称其为外部中断线。这十九个外部中断线的前十六个,也就是 e x t i 零到 e f t i 十五,分别对应着与其编号相同 的 g p l 口,就是说从 p a 零、 p b 零、 p c 零, p d 零进入的电瓶信号都可以进入 e x t a 零,然后 p a 一 p b e p c e p d e 都是对应着 e x t a 一,一直到 p a 十五, p b 十五, p c 十五, p d 十五也是对应着 e s t a 十五。 对于这张结构图,我们仅需要有大概印象即可,不必深究牢记,所以请抱着轻松愉快的心态观看接下来的知识。注意在接下来的语境中,高电平与一等效,低电平与零等效。 首先是这块区域,实际上这块区域与中断无关,而是与事件相关的结构。所谓事件其实是与中断类似的概念,只不过中断信号会抵达处理器中,调用代码进行处理, 而事件信号却是送达相应的外设,由外设自行处理。这不是我们本期视频的学习范畴,所以先不管他。然后是这一块结构, 电眼检测电路可以检测输入的电瓶信号中有没有发生高低电瓶的转换,也就是有没有出现上升眼或者下降眼,然后再根据上面这两个计算器的配置来决定是否向后输出一个高电瓶信号。 还记得我们上期视频在 q m x 中选择是上升沿触发中断还是下降沿触发中断吗?其实就是在配置这两个计算器, 就比如我们给 p p 十二配置了下降沿触发中断,那么上升沿触发选择计算器的第十二位关闭为零,下降沿触发选择计算器的第十二位开启为一。那么接下来, 当边沿检测电路检测到了下降岩石就会向后传递一个高点频信号,此信号经过一个货门后抵达请求挂起计算器 和我们的特性是两个输入端,只要有一个输入为一,则输出就是一。因而软件中断事件计算器的存在让我们可以通过程序模拟产生一个中断,不过这个功能我们一般也不需要,就先忽略掉。 注意了,请求挂起计算器是一个需要注意的点,其接收到高电瓶信号后会将对应的位置一,例如我们当前举例的是 exti 十二, 因而接收到从第十二根外部中断线来的高电瓶后,请求挂计算器的第十二位会被质疑,然后请求挂计算器又会将此位输出到 一个雨门。雨门的特性是当两个输入都为一时,输出才是一,否则便输出为零。因而此雨门的另一个输入中断屏蔽计算器就掌握了此中断的生杀大权, 只有他的对应位置上唯一输出高电频,请求挂起计算器的信号才能通过雨门进入到 nvic 而中断屏蔽计算器的开启。其实我们在将 pb 十二设置为 gpio exti 十二时, qbmx 就自动帮我们在生成的代码中完成了。 那么来自请求挂起计算器的高点屏信号继续向后就到达中断最高程。 nvicnvic 又称嵌套向量中断控制器,其主要作用便是掌管着这样一张中断向量表。所谓向量,那便是有方向 的量,中断项量的方向就是指向中断处理函数。在所有的外部中断线中,只有 exti 零到 exti 四拥有自己的中断项量,而 exti 五到 exti 九共享中断项量。 exti 九杠五 e x t i 十到 e x t i 十五更像中段向量 e x t i。 十五杠十。也就是说,当来自 e x t i。 十二中断线的信号抵达 n v i c 后, nyc 会找到中段向量 e x 十五杠十,然后按照其指向执行 e x 十五杠十 r q handler 函数。 这下我们就搞清楚了为何上期视频中,我们要将绿色小洞翻转代码写在 e x t i。 十五杠十 r q handler 函数中。不过还有一点需要注意的是, n y c 是在一直检测某个中断线是否处于激活状态的。当中断处理函数,也就是 e x t i。 十五杠十 r q handler 运行完成后, n y c。 倘若依旧检测到 e x t i。 十二中断处于激活状态,就会再次运行 e x t i。 十五杠十 r q handler。 因而,为了让中段处理函数只执行一遍,而不是无限重复,我们需要在中段处理函数中将请求挂旗行器的对应位清除为零。 不过回想一下我们上期视频在 exti 十五杠十 rq handle 中的代码,好像只写了关于绿色脚灯翻转亮面的代码,并没有写什么清除请求挂计算器, 那程序为何可以正常运行,并没有发生所谓的无限重复呢?其实仔细看我们会发现,在 exti 十五杠十 rq handler 中,还有一行 qbmx 自动帮我们生成的代码调用了一个叫做 hell gpio exti rq handler 的函数,并将 kepin 作为参数传了进去。 而 k e p 就是 g p i o p 十二,其对应的外部中断线也就是 e x t i。 十二。我们按住 ctrl 点击 hail g p i o e x t i r q handler 进入到其函数实现,这时我们就会发现它调用了一个名为 hail g p i o e x t i clear it 的函数, 并将我们传入的参数 g p i o p 也就是 k 一 p 或者说 e x t i 十二传给了此函数,而这个函数正是清除请求挂气计分器的函数。电用此函数后,请求挂气计分器的第十二位也就清除为零了,从 不会误导 nyc 再次执行 exti 十五杠十 rq handler。 如此看来,清除请求挂计分器的操作 qbmx 已经贴心的帮我们做好了,没有特殊情况下,我们也就不必再去关心清除请求挂机计分器的问题了。 q 版 max 真不愧是 s t m 三二开发必备神器,那么刚刚我们所描绘的只是发生一个中断的情况,如果两个甚至多个中断同时触发呢?如何安排这些中断的执行顺序呢? 看过上期视频的小伙伴一定想起了在上期视频中,我们是如何解决了黑奥迪丽依赖的 system take time 中断无法运行的问题。是的,中断优先级。在中断项量表中,中断项量不仅有中断处理函数,还有优先级信息。 在 s t m 三二中,中段向量的优先级分为两层,抢占优先级和响应优先级。优先级的数字越小则代表越优先。 有这样两种情况会需要判断争断优先级。第一种情况是,当两个中断几乎同时发生, 这时 nvic 会首先判断两中断的抢占优先级。假如 a 中段的抢占优先级更高,换句话说, a 中段的抢占优先级数字更小,则 a 中段先执行 a 中段执行完成后再执行 b 中段。 但假如 a 中段与 b 中段的抢占学籍相同,那便再比较二者的享用学籍,由享用学籍更高的中段先执行。例如, a、 b 中段抢占学籍相同,但 a 中段的享用学籍更高,则也是 a 中段先执行,然后才是 b 中段。 当然了,假如 a、 b 中断的响优先级也相同的话,那就是按照他们在中断项量表中的顺序决定,这在我们并不关心他们的执行顺序的情况下才会发生,否则我们应该给他们设定不同的优先级。 第二种情况是, a 中段已经在执行过程中, b 中段信号突然到达,那么这时 s、 t、 m 三二只会比较两中段的抢占优先级。 当 b 中段的抢占原籍优于 a 中段时, b 中段就会抢占执行,像打断正常执行流程那样打断 a 中段,等到 b 中段执行完成后,再恢复 a 中段的执行,当然最后会恢复正常流程的执行。 而倘若 b 中段强占先级弱于 a 中段,或者与 a 中段相同,便只能乖乖地 a 中断执行结束再执行了。上期视频中,我们设置了系统滴答的抢占原籍优于我们的 exti 十五杠十,就是为了让系统滴答可以在 exti 十五杠十执行过程中抢占执行,从而为还有的类提供时间基准。 从这几种情况中我们可以看出,响右先级仅在两中段同时发生时起到辅助作用,抢断右先级才是真正的老大哥。 s t m 三二为每个中断项量准备了四个二斤之位来储存中断优先级信息。在 q b m x 中,我们可以自由选择这四位中,几位用来设置抢占优先级,几位用来设置响应优先级。默认设置是四位都用来设置抢占优先级。这时 每个中段限量的抢占先集都可以设置为零到十五,但响应先集只能被迫做零。如果设置为两位为抢占先集,两位为响应先集,则二者都可以设置为零到三。 不过想预选集的用处不大,所以我们一般保持默认的思维都是抢占预选集即可, 我们从头梳理并查漏补缺。从引角进入的高低电瓶信号首先由输入驱动器处理, 此处插一个小知识点,如果中断信号下需要上拉或者下拉,也可以在 qbmx 中直接配置。经过输入驱动器处理过的高低电瓶信号会进入到边沿检测电路,当边沿检测电路捕获到我们设置的边沿信号后,就会像请求 求挂起计算器输出一个高电频信号,请求挂计算器对应的位会质疑。然后只要我们已经开启了此中断,请求挂计算器的信号就可以进入到 nycnyc 会找到此中断线对应的中断项量,并执行相应的中断处理函数。 并且在中断处理函数中需要清除请求挂计算器,以防止中断重复出发。当然,这一操作 qbmx 已经自动帮我们完成,我们仅需要了解有这回事即可。 针对多个中断同时发生的情况,我们可以使用中断优先级来规定执行的顺序。响应优先级用处较小,往往我们只需要设置抢占优先级即可,优先级的数字越小,则优先级越高。怎么样,是不是清晰明了了呢?不过刚刚说的 其实只是外部中断如何触发的情况,实际上串口、 usart、 定时记、 trm、 iphone c 等等外设也可以触发多种相关中断。不过不用担心,他们的中断触发与外部中断也大同小异, 虽然没有外部中断线这套结构,但也会有相应的请求挂计算器与中断屏蔽计算器。触发中断后依旧需要 nyc, 通过中断项量找到并执行中断处理函数,中断处理函数也是需要清除请求挂起计算器。 这些在我们后面的视频中都还会讲解并应用到实战项目当中,别忘了点击关注不迷路!好的,那么本期视频的内容就到这里了,制作不易,求大拇哥大钢镚五角星, 这是我在这条路上继续走下去的动力。下期视频我们将迎来串口通信的学习,我们下期再见!拜拜!

大家好,上节课我们介绍了串口中段加定时记录器实现超时接收设计包的一个编程。这节课的话呢,我们来看一下 s t m 三二单面机的串口空弦中段。 s t m 三二单面机呢,提供了一个串口空弦中段, 我们可以利用呢 stm 三二单面机提供的这个串口空闲中断来实现,类似于用定时救援器实现超时接收设计包的这种编程。这样的话呢,我们就可以不用定时救援器,直接用串口空闲中断,同样的能实现我们这种 数据包和数据包之间有一定时间间隔的这种场合的一个应用。接下来的话呢,我们来了解一下串口的空闲中断空闲的定义,我们先了解一下 这边空闲的定义,指的是总先生在一个字节时间没有接收到新的数据,我们呢会使这个空闲中断呢?他会置位这个空闲中断的话呢,他是检测到有数据被接收之后,再走 网线上有一个字结的时间内,没有在接收到新的数据的时候,他是发生的一个中断。这个大家也了解一下,也就是说我们这个数据包和另一个数据包,他们之间的这个总线空闲的时间至少要是一个字结的时间,这一个字结的时间大概是多少呢?实际上就是一针数据的一个时间, 这一针说句的话,我们前面给大家讲过,对吧?你比如说你是九六零零的播测率,那我传输一个字符的时间应该是九六零零分之一乘以,如果说我们是十位一不算个东西的话, 那这个呢就是他的一个自负时间,那就是说在总线上至少有这么长时间的一个空闲,我们才会产生这么一个空闲中断。这个大家要了解一下,那也就代表什么意思呢?也就代表说我们这边有一个设计包,那这个地方呢,也有一个设计包,这是两个设计包,这个设计包里面呢 可能有这么多个字节,说句这是一个字节,对吧?这是一个字节,那这又是一个字节,这是另外一个说句包,可能有这么多个字节。 这两个说一包之间要有多长时间的时间差呢?我们才认为是产生一个空闲中断呢?这个时间差就是一个字符时间,这一个字符时间。我刚才举例子,如果说你是九六零零的播测率 一个位的话是九六零零分之一,那你这个一个字符,我们按照十位一步串个通信,加上一个起手位,一个停手位,八位数据位,那这个时候呢就是他的一个时间, 这个时间就是我们这个空闲中断的一个时间。这个空闲中断的话,大家要理解的,也就是说 s t m 三二的这个空闲中断,他在串口无数据接收的情况下,他是不会一直产生的。他是什么时候产生呢?他是首先要接收到第一个数据,才会触发我们的空闲中的, 就是说首先要接收到第一个字节,说句,然后的话,如果说你这个地方有四句他会接收,有说就接收,当这个后面没有说句了, 这个时候总线产生长长时间的空闲呢,就是一个字服时间的空闲,这个时候呢才会产生空闲中断。所以呢,当我们一开始没有数据接收的情况下,他是不会产生空闲中断的,也就是说我的总线一开始都是空闲的,这个时候呢,是不会产生空闲中断的,当什么时候呢?当我们第一个字节数据来了之后,就是说有一个起始位 加上了这么一个数据,对吧?加上这么一个数据加这个数据之后,加上停止位这个地方呢,后面没有数据了,如果说你不跟着数据了,产生一个字符的时间的一个时间差, 这个时候才会产生一个空闲中断,那这个空闲中断的话呢,大家要了解一下,我们待会的话呢,来举一个例子,对吧?来看一下。我们这边举 力的话呢,会利用这个串口的中断加上呢我们这边那个空闲中断来实现这个说解包的接收。但实际上我们在利用串口空闲中断的时候呢,主要应该是利用空闲中断加 dmi 加上环形对立 来实现我们这种收集包这个接收,这个是比较好的一种方法。我们给大家介绍这个例子的一个目的的话呢,主要是为了使大家后面在介绍 dma 的时候,你能够快速的去理解我们,那会只要把我们的串口接收中段关掉,然后呢把 dma 打开, 同样的方法就能够实现串口空闲中断加上 dmi, 实现数据的一个接收。我们这节课的目的呢,主要是让大家理解一下串口的空闲中断, 因为我们在串口接收中的当中呢,要不停的接收数据,这个时候的话呢,实际上效果并不是特别好,因为呢它会加大我们的 cpu 的负担,因为每一个数据来了,那 cpu 呢都要 进到这个中断里面去处理,那这样的话呢并不好,实际上我们真正要用的话呢,最好是用 dna 加空闲中断,这个呢是我们后面介绍 dna 之后 会再来给大家来去讲解。那现在的话呢,大家主要是要理解一下我们怎么样来实现串口的空闲中断,我们接着这个历程来给大家来讲一下。接下来的话呢,我们来举个例子,这个例子的话呢,我们就利用串口中断加上我们的这个 汉口的空闲中段来实现数据包的接收,我们在上次课超时接收的数据包的这个程序的基础上来进行修改,把它改一下,我们改成这个地程六, 这个呢就是我们的这个串口的一个空前中段 接收数据包,这种数据包的话呢同样适用于就是我 我们这个设计包内部没有针头针尾的,我们没办法靠针头或针尾来判别一个设计包的一个完整性,这个时候的话呢,就可以利用我们这种超时,或者说利用这种空闲中断办法来实现。这个怎么来实现呢?实际上并不是特别难,我们只需要在 uit 点 c 这个文件当中,我们在这个地方要增加一个中断, 我们这边的话呢是使能的,是串口的接触中断,我们接下来要使能的就是空弦中断,那这个时候呢,我要把这个打开,把空弦中断,打开,那空弦中断的话,我们可以右键跟踪一下,找到这个呢是空弦中断,我们把空弦中断呢给它使能, 那这个时候呢啊?空闲中呢就是能的,对吧?这个地方我们可以去注视一下, 只能空前中断。实际上我们真正后面 在介绍 dna 的时候呢,我们可以把这边的串口接收中段给它关掉,然后呢打开 dna, 然后呢再加上这个只能空闲中断,我们就可以实现 dna 加空闲中段一个接收,这个呢我们后面讲到 dna 的时候再来反过来来讲,那我们现在呢先用串口接收中段加上空闲中段来实现我们数据包的接收, 这个地方呢初始化就完成了,对吧?其他的和我们上节课讲的都没有太大区别,我们就不再做过多的介绍了。接着的话呢就是说在我们的这个中段服务函数当中要做一个处理,那这边的话呢我们就不再用这个超时的办法了,那我们就把这些和定制计划器超时相关的把它都删掉,那这边的话呢我们都把它删掉, 那这个时候呢我保留这个框架,那这个时候呢这个框架保留好,然后的话呢我们把前面的超时的一些 相关的都把它删掉,那这两个呢计说器我们就不需要了,我们把它删掉,然后呢把点进去当中的这个地方呢也给它删掉,这两个我们就不要了, 然后的话呢我们把定制计算器,这个呢我们也不要了,定制计算器我们可以把它删除掉,我们把定制计算器的这个就不需要了,我们不需要再用超时了,我们把这个呢就删掉。 接着的话呢我们是这样子,我们在这个里面的话呢要做一个处理,对吧?就是说每来一个 串口中断的时候,因为我们现在没有 dmi 吗?所以呢每来一个串口中断的时候呢,我们就把这个数据呢给它接收到,把它保存到我们的缓腾区里面去,那我们这个地方呢就要做一个接收 这个里面,同样的我们可以用我们这个缩影来做这个接收的工作,就是每来一个自己的数据,我就把它接收到, 接收的话呢,我们有一个接收函数,对吧?我们可以看一下找到方向,找到我们的串口,点开这里面的话呢,我们有一个 received 这么一个函数,对吧?我们借助这个函数来接收数据,就是这个 receivedad, 我们把数据呢每来一个都把它接收到我们的这个数据缓冲区里面去, 这个呢还上节课是相同的,就是每来一个数据的话呢,我们就把它接收到这个里面去,当你没有新的数据来了,那就是说你你一开始的时候串口有一个数据包 来了,接收到我们这个缓冲区里面,就是来一个字接接收一个,又来一个字接又接收一个,又来一个字,接又接收。当你这个时候没有数据了,那这个地方会产生一个空闲中断,当然这个时间的话是一个自负时间,这个时间没有新的数据来产生空闲中断,我们需要在空闲中断当中呢做一个处理, 对吧?那这个时候你只要有新的时候就来,我就一直在接收,然后的话当然了你要去做一个判断,对吧?我们这个最大的话呢,我们这个最大的话只能接收到我们的开辟的那个缓冲区,如果说你用环形对立,那当然就不存在这个问题。如果说你没有环形对立,那我们这个直的话, 大于我这个最大的这个接收数据的一个缓冲区的值,那我们就不再去接收了,对吧?我就不再接收了,或者说我就直接呢再来新的数据,我就把它 从零开始重新接收。嗯,只能接收这么多,那我们可以这样子来处理一下,那这个呢?就是这个啊,串口的一个接收,串口接收之后我们还有一个呢,就是 lcf, 如果说你产生了空闲中断,那我这个地方呢可以用同样的办法, 我们产生一个空弦中断,那这个时候空弦中断的话呢?我们是用的这个标记, 如果说你产生了空闲中断,那我们这个时候呢要干什么呢?要治一个标志位,那我们把这个标志位给他治腰,就是接收标志位治腰, 然后的话呢我们要清除空闲标志位,清除空闲标志位,有同学可能会用这个函数,我们可以看一下这个函数,这个函数的话我们展开之后 可以看到他给的参数,一个是这个参数,一个是这个这个参数的话,我们在上面来找一个,看到这个里面 他并没有空闲中断,对吧?并没有空闲中断,那这个地方他会告诉我们空闲中断,你要想清除的话,那这边告诉我们这些中断, 包括我们这个空闲中呢?要想清除的话怎么清除呢?他是这样子的,他是首先的话你要有一个独操作,一个独操作的话是针对什么的? 是针对这个 sr 继承器,就是这状态继承器执行一个毒操作,然后的话呢 follow by 的, follow by 什么呢?再对一个低雅计算器执行一个独操作,这个时候呢就能够清除我们的这个空闲中断标志位, 所以呢我们并不能用这个函数去清除这个重大标志位,这个大家一定要注意。那怎么样清除他呢?我们可以去读这两个计算器就可以实现清除这个当然在手册当中我们也可以看一下,对吧?包括这个地方 用到空弦的一个针,空弦针的话呢,你看他的时间,在这个地方有一个提示,对吧?通过这张图也能看到这个空弦针实际上就是我们一个字符的时间,如果说你是十位的一不穿个东西,那就是我们刚才提到的,用你的步骤率分之一乘以这个比他位,他就是这个空弦针的一个时间差, 这个大家注意一下。另外一个呢,我们找到这边的一个 sr 集成器,这边呢有一个这个我们这个空闲中段位,这个位的话呢在这个地方有一个解释,我们可以看一下,对吧? 他是将到总线空闲的时候,会产生一个空闲中断,那这个空闲中断的话呢?他怎么样清除这个中断呢?他必须靠软件来清除, 那这边告诉我们必须有软件清除,怎么清除呢?就先读取 sr 寄存器,然后的话呢再读取低尔寄存器,这个时候呢就能够清除掉。那这边也提醒我们 要注意一个地方,就是这个空弦中段位他不会再次被制高,直到什么呢?直到阿 xn 也为被置气, 那就是什么意思?就是说只有在产生下一次的一个接收数据的时候,也就是我们在 pp 当中刚才提到过的,他实际上就是说你串口在无数据接收的情况下,他是不会一直产生空闲中的呢?他只有什么呢?只有是接收到第一个数据之后, 然后呢才会开始触发,也就是说他接收到一个数据之后,这个时候呢才会触发我们的空闲中断,并不是说你这个总线上一旦空闲,他就一直会产生空闲中断,这个一定要去理解,那这个地方呢,我们要把这个中断给他清除掉。怎么清除呢? 那我们就读这两个计算器,那这边的话我们可以再定一个变量,比如说我们叫一个清除变量, 我们进行这么一个变量,那我用这个变量的话呢,做一个中间变量,我们直接对我们这个 uirt, 也就是我们这个他当中的两个吸尘器执行一个毒操作,一个是我们的 sr 寄存器,先读 sr 寄存器, 然后的话呢再读低雅集成器,那就可以实现这个清除了,那这个地方你也可以去看好这个地方,这个地方也告诉我们了,对吧?他这边告诉我们了,这个地方 就是这个地方先读 sr 继承器,然后的话 follow 的,然后紧紧紧跟着再读取这个低尔继承器,就可以呢清除他的一个标志位,那这个时候呢就把标志位清除掉了,那这个时候呢就产生了一个空闲中段,那这个空闲中段的标志位,我们同样的在主行当中 呢,可以做一个处理的吧?这边判断他,判断他之后,那最后的话要把它再清除掉,那这个呢我们是不需要的,然后呢同样呢我这边的话可以把它发回来看一下,对吧?发回来之后我们这边的话呢,同样的我可以呢把这个 说句缓冲区呢,我们注意一下可以给它清零一下,就是你处理完之后我们可以呢把它清零,清零的话呢,我们可以用这么一个库函数 死重一点 h 当中有这么一个扩函数,我们可以用这个函数把我们这个缓能区当中的数据呢给它清成零, 这个时候呢就完成了,对吧?那这个时候我们就完成了,然后的话我们可以编一下,然后的话我们来看一下这个 urt 点一下大家理解 一下。当我们在一开始的时候,一开始的时候是没有空闲中的,当什么呢?当我们的串口接收到一个字节数据之后,比如说你发了一个数据, 然后紧接着又发一个数据,紧接着又发一个数据,比如说这一个数据包里面有这么四个字节的数据,你发这四个字节的数据,这个地方接着没有数据了, 这个时候的话他会产生贡献中的。但是呢你这边紧接着发这四个字节,每一个字节中段的时候都会进到这个中段符号当中,我们查询到这个标志位,会把它介绍到这个设计缓冲区里面去。 当你接到这个字节之后,后面没有数据了,超过了一个字节时间之后会产生这么一个空闲中段,在空闲中段里面的话呢,我们会把这个标志位给他治腰,是吧?那这个标志位一旦治腰了,我们在主行当中就能够查询到他,一旦他发现他围腰了,我们 把这个数据呢给他返回来,然后呢接着呢把数据清零,然后呢把标周位清零,这个时候呢就实现了空闲中断,加上我们的串孔中断,实现这么一根数据包的一个接收啊,这边有一个警告,我们看看是什么, 那他说这个变量的话没有用,那这个我们不管他,我们这边的话只是做一个局部的一个中间变量来用,那我们编译把它下载进来,我们来看一下, 我们看一下主行当中,那这个地方有没有问题啊?然后我下载, 下载完成之后我们打开我们的创口助手,那这边的话是康姆区幺幺五二零零的播测率,打开然后的话呢我们这边的话可以给他先敷一下,那个时候还是发了送一个海楼 stm 三二, 然后我打到嗨歌的模式,我把它清除掉,然后我发送这么一个八八,我发送这么一个吧,一二三四,看一下他能不能接收,如果能接收到他应该会返回这个数据,那我们看到他把这个数据返回过来了,然后呢我们可以增加数据, 然后呢同样呢他是可以接受到并且返回过来,对吧?那这个呢就是我们的一个串口中断加上一个空闲中断,当然你可以减少数据, 只要你两个说你包之间的时间间隔超过了一个字符时间,那都是没有问题的,对吧?然后的话呢你可以缩短,比如说缩短 也是没有问题,做成一个啊,这个时候也是没有问题,这样的话我们就实现类似我们上节课介绍这个超时接收的一个收细胞的一个实现的一个办法,对吧?那这种方法的话大家可以去了解一下,就是利用这个窗口中断加上呢我们的 这个空闲中段来实现说句包里接收。但是这个地方主要需要注意一下,如果说你这个连续发送数据针,比如说你两针,说句针两包数据相间隔的时间差比较短,你两包数据同时发过来的, 那这个时候的话,他会把它当成一包数据来进行处理,这是他的一个弊端,对吧?那就是说你两包数据之间必须有一定的时间差,这个时间差必须要大于一个字符的时间的一个时间,这个时间大家可以自己去算一下,对吧?当然也是非常短的一个时间, 那当然了,你如果说你是这种一问一答的这种模式,比如说你主机问从击答这种的话呢,肯定中间会有时间差,这种场合的话,我们用这种方式是没有问题的。这种方式唯一的一个缺点就是说他每一个数据包的一个接收过过程当中,每一个字节的接收都需要进中断,如果说 你的数据量比较大的话,那这样的话呢会影响你的 cpu, 你的 cpu 的话要一次一次的进中断,一次一次的进中断,这样的话呢就会加重我们 cpu 的一个负担, 所以呢我们一般的话空闲中断会和 dna 相结合,这样的话呢,只要产生空闲中断,我再去组成当中的话呢,去把 dna 保存的数据呢取出来去处理,这样的话呢能够减少我们 cpu 的一个负担, 这个大家去了解一下,但是这种方法的话,大家可以去理解一下,就是我们这个空闲中断到底是怎么一回事?知道这个空闲中断以后,你在学 dna 的时候,我们只需要把这边的这个接收中断 给它关掉,我们不需要用接收中断的,我们用 dna 用直接的存储器存储就可以了,这样的话加上我们这个空闲中断就完成任务了,这样的话你你理解了这个代码,你后面再理解这个代码的时候,就会相对来说是容易的多 的多,当然我们这种代码的话,实际上在一般的场合也是可以用的,对吧?这个大家要根据自己的实际情况去选择采用哪一种方式或是方法,这个呢就是所谓的这个空闲中断加上串口中断能够实现这种说你包里的接收,大家了解一下, 人家这种方法的话,就和我们前面介绍的超时的办法差不多了,只不过我们超时的话还需要占用一个硬件定时器,还要做一些软件的处理,对吧?那这边的话呢,你就不需要了,对吧?只要利用空闲中断就可以了,而且呢可以发现我们这个说句包的接收一般来讲是不会有什么太大的问题的,对吧? 你可以去任意增加这个数据,然后的话去测试,对吧?然后去测试只要你两包数据之间的时间差,但是如果你发动太快了,他可能会当成一包数据来进行处理,这个大家需要注意一下,就是说你不能连发, 你连发的话他会当成一包,但是他也能接收到。但是呢我们一般用的时候呢,肯定是要有一个断针,也就是说最好的适用的场合就是这种 数据包,数据包之间有一定的时间间隔的同时呢或者说是这种一问一答的这种模式就比较实用,大家了解一下这种方式。

这节课我们来讲解一下 project 如何仿真 hm 三二这个仿真软件呢?对于新手学习 mpm 三二还是挺不错的。这个是 mpm 三二芯片,这个是 oled 屏, 这个是独立按键。在运行仿真之前呢,我们双击单片机, 点中间像文件夹的东西,然后找到 h x 后缀的文件,双击导入点, ok, 就是这样,程序就导入单片机了。然后我们点左下角的运行按钮,仿真就可以开始运行了, 就是这么简单。已为这里分享不了仿真软件,需要软件的同学请留我的微信,联合二三八获取, 还赠送给你一些基础的 h m 三二仿真历程。就这样,我们下次再见。

各位同学大家好,我是铁头山羊,从今天开始呢,我们需要学习我们本套教程的第三章中段编程。中段编程呢,在 stm 三二编程里面是一个基本功,本节课呢,我们就来学习这个中段编程的原理。通过本节课的学习,我们对中段编程的概念有一个基本的认识。 本节课的第一个任务就是向大家介绍这个中断的概念,到底什么是中断呢?中断的这个概念呢,它比较抽象,如果直接向大家介绍中断是什么,可能这个理解起来会比较困难,那么我们需要举一些生活中的例子,以生活中的例子做类比,来推导出这个中断的概念。 在这里呢,我给大家列举了四个例子,帮助大家去理解这个中断的概念。首先我们来看第一个例子,我们假设自己是一名销售人员,我们在跟客户洽谈 谈业务,在洽谈业务的过程中呢,突然来了电话,这个时候你会告诉我这个客户,不好意思,我需要先接个电话,那么你就会中断跟客户的谈话,然后去接电话,接完电话之后,继续回到刚才的话题,接着跟客户谈。 那么第二个例子是在图书馆读书的这个例子,我们假设你在这个图书馆里面正在读书,这个时候呢,你发现了有一只蚊子, 你放下手中的图书去拍文字,拍完文字之后呢,我们接着刚才的进度,继续去读这个书。我们再来看第三个例子,一个玩游戏的例子, 某个周末呢,我们正在宿舍里边打游戏,那么在打游戏之前呢,我们已经给自己点好了外卖啊,打着打着游戏呢,这个外卖到了,外卖人员呢正在敲门,这个时候你需要停下手中的这个游戏,开门去取外卖,取完 外卖之后,你把这个外卖放下,继续去玩游戏。第四个例子,一个操场跑步的例子,某一天呢,我们正在操场上跑步锻炼身体,对吧?跑着跑着呢,我们突然发现自己的这个鞋带开了,我们需要停下来去系鞋带,系完鞋带之后啊,接着跑, 我们来观察这几个例子,这几个例子呢,都有一个共能点,就是我们一开始的时候在执行某项任务, 然后这些任务呢,会被一个突发的事件打断,比如说来电话呀,发现蚊子呀,外卖到了,或者鞋带开了,他会被一个突发的事件打断。 那么这个突发的事件发生之后呢,我们会中断当前的这个任务,转而呢去处理这个突发事件。突发事件处理完成之后,我们又会回到刚才的进度,继续去执行刚才被打断的这个任务。因此呢,我们就总结出来生活中 这个中断的一个概念。所谓中断呢,就是正在执行的事物被突发事件打断,我们转而去处理这个突发事件。突发事件处理完成之后,又会回到被打断的事物,继续执行。我们把这一个处理的过程叫做中断,我们来看这里有一个关键词叫做过程, 这个过程呢就是在强调这个中断,并不是啊,突发事件本身也不是我们处理突发事件的这个动作,而是从突发事件发生到我们停止当前执行的这个任务, 到我们处理中段,到中段处理完成之后,我们继续回到这个刚才被导弹的这个任务,这整一个过程里面的所有动作,我们才把它叫做中段。那么有了生活中关于中段的这个概念之后呢,我们可以在这个基础上进一步的去阐述单片机编程里面这个中段的概念。在了解单片机编 编程里面中断的概念之前呢,我们必须先认识一个名词,叫做常规程序。那么我们回忆一下这里下边这张图呢,是我们之前所写的一个闪灯的程序,我们就是使用这个 pc 十三银角去驱动这一颗 led, 让他去闪烁起来。 比如我们可以看到右边这一段代码呢,是在初始化这个 l 引角,也就是将 pc 十三设置成这个输出开漏模式。那么在下面的这个 y o 循环里面呢,是在不断的切换这个 pc 十三的呃高低电瓶,让这个 led 呢循环的点亮和熄灭,从而实现这个闪烁的效果。 我们可以看到这整段程序呢,都是写在这个闷方法的内部的,那么到现在为止呢,我们所写的所有程序,他要不然就是直接写在这个闷方法内部的,像这些代码,那么要不然就是闷方法 里边的一些函数,比如说这个 r c, c a p b, r prefer clock, c m d pair in it, 机票 read out put it a bit, 机票 right bit pair delay 等等这些方法,这些方法里内部的这个代码呢是被这个闷方法间接调用的。 那么不管是在闷方法内部直接书写的这些代码,还是由于这个闷方法的调用,而被间接调用的那部分代码都是由于这个闷方法的执行而得到执行的,我们把这部分代码呢叫做常规程序, 那么在我们的这个 s t m 三二单片机里边呢,还有另一部分程序,它不是由于这个问方法的执行而未得到执行的, 具体呢,我们来举一个例子,就是右边的这个图里面的例子,我们想象一下,在这个 s t m 三二里面呢,有一个片上外设,我们之前介绍过叫做串口,或者是说叫做 us art, 那么我们可以使用这 这个串口去连接一个 usb 转 ttl 的模块儿,这个模块儿的 usb 接口呢可以插到电脑上,这样呢我们就可以通过电脑向这个 stm 三二的串口发送数据了。 但是对于这个 stm 三二来说,只要电脑发来了数据,他必须马上进行处理,如果我们不及时去处理这个数据的话,那么电脑又新发来了这个数据,原来的数据就会被覆盖,这样就会造成这个数据的丢失,所以我们要及时的处理它。 在实际的这个 stm 三二编程里面呢,我们是这样做的,我们先写一个方法,然后在这个方法里边呢实现这个数据处理的过程。具体来说就是首先去接收串口发来的这个数据, 第二步呢是对这个数据进行具体的运算或者是处理。那么我们写的这个方法什么时候被调用呢?是这样的,比如说我们一直在执行 这个闪灯的程序,那么突然我们收到了串口发来的数据,这时候呢我们就会去调用我们刚才写的这个方法,对这个串口的数据呢进行处理,处理完成之后,我们又继续回到这个闪灯的程序去执行。 如果大家还是不明白这个图像的意思的话,我们通过一个具体的例子来给大家演示一下,我们来看左边这个位置,这是我们写的这个闪灯程序,假设现在呢这个闪灯程序正在执行 啊,代码在一条一条的往下走,当我们执行到这一行的时候呢,突然一个瞬间我们收到了这个电脑发来的数据,这个时候我们正在执行的这个程序呢,会被打断, cpu 转而会去处理这边的这个我们写的这个响应函数, 那么在这个响应函数里面,他首先会接收数据,然后呢会对收到的这个数据进行处理,那么执行完这个响应函数之后呢, 我们的程序又会回到我们刚才被打断的这个位置,继续的往下执行,这个就是中断处理一整个的过程。在实际的编程过程中呢,我们把这种突发的事件呢,我们叫做中断源, 而这种闪灯程序也就是被焖方法直接或者是间接调用的这部分程序呢,我们叫做常规程序,而 把上面处理这个呃串口数据的这一部分代码,我们叫做中断响应函数。那么由此呢,我们就总结出来了这个 stm 三二里边中断的概念, 所谓中断呢,就是由于中断源的触发,我们的常规程序被打断, cpu 转而去执行中断响应函数,然后呢处理完成之后又回到常规程序继续执行,我们把这个过程呢叫做 stm 三二里面的中断。那么讲到这里,大家已经清楚了什么叫做单飞机编程里面的 中断了,那么我们现在来讨论另一个问题,我们为什么要使用中断呢?那么这主要是因为我们的这个突发事件的两个特性,分别是这个突发性和紧急性。 所谓突发性呢,就是我们不知道这个突发事件会在什么时刻发生,它的发生呢是随机的,会在任意时刻, 我们的这个 s t m 三二呢,没有任何准备的时间。就比如说我们右边这个例子,通过电脑向 s t m 三二发数据,那么呃电脑什么时候向 s t m 三二发数据? s t m 三二不知道,所以呢他没办法提前做出准备。 那第二个特性呢,是由于紧急性,这个紧急性呢就是说这个突发事件需要马上被处理,他等不到这个呃常规程序一条一条执行完,轮到他,那么他需要打断这个常规程序的执行。比如说对于我们这个电 脑像 stm 三二发数据这个例子,那么电脑发来的这个数据,他发的速度很快,你一个数据到来了,如果不马上去处理,那么新的数据又发来,这个时候呢,旧的数据就会被覆盖掉,那么这就会造成数据的丢失,所以他没办法等到这个常规程序处理完成,再去处理它,这个常规程序呢需要被打断。 所以说有些情况下呢,这个中断是非用不可的,那么到此为止呢,我们一点一解,关于中断编程的一个概念,我们就解释清楚了。 再来看后边的这个中断处理的过程和术语,那么在刚才介绍这个中断概念的时候呢,我们曾经使用了这么几个箭头组成的一张图像来表示我们中断处理的每一个过程, 除去前后两个箭头,它是跟常规程序相关的,那么剩下的这四个箭头呢,都是跟我们中断处理的这个过程相关的。那么我们 通过这四个箭头就把我们中断处理的过程呢,分成了四个阶段,他们分别叫做中断触发、中断进入、中断响应和中断退出。其中这个中断触发呢,就是我们中断原发生的这个动作,也就是这个箭头 中断进入呢,表示我们斜向上的这个箭头,也就是说从中断源发生一直到中断响应这一段时间呢, 我们把它叫做中断进入,然后中断响应阶段呢,就是我们啊调用这个中断响应函数去处理这个中断的这个阶段,最后这个中断退出呢,就是我们中断处理完成之后,又回到常规程序执行,也就是斜向下的这个箭头。 那么我们来看右边的这些文字,其中在中断进入和中断退出的这两个阶段,我们分别要保存现场和还原现场。那么现在问题来了,什么叫做保存现场, 什么叫做还原现场呢?我们以下面的这个例子来解释一下这两个名词,这是我们刚才所说的那个销售的例子,我们在跟客户聊天的过程中来了电话,我们需要先去接听电话,接听完电话之后继续跟客户聊天。 大家来想象一下,我们在接电话之前,是不是需要先在脑子里面记录一下啊?问我跟客户谈到什么进度了,然后呢接完电话之后,我再沿着这个进度继续跟客户聊天,对吧? 我们在大脑里面去记忆聊天进度的这个过程呢,我们叫做保存现场,那么保存现场的目的呢?就是为了还原现场,也就是说当我们处理完成这个中断之后呢,再把原来的这个现场呢给他还原回来,我们沿着原来的进度 继续跟客户聊,这个就是所谓的保存现场和还原现场的一个概念。除此之外呢,我们再来看中断响应的这个 中断响应的这个阶段呢,我们要执行两个步骤,一个呢叫做清除中断源,另一个呢叫做调用中断响应函数。那么调用中断响应函数我们知道是什么意思,就是我们写了一个中断响应函数,然后在中断被响应的过程中,我们需要调用它,对吧?那这个我们刚才已经啊理解了, 但是这个轻收中断员是怎么一回事呢?我们还是以左下角的这个例子来进行说明。我们在在跟客户聊天的时候,突然来了电话,那么我们去接听电话,在接听电话的第一步,我们是不是需要去按一下这个接听按钮,把电话的这个铃声给它关闭掉呢? 那其实这个电话铃声才是我们真正的这个中断源,我们去关闭这个电话铃声的过程,其实就是清除中断源的过程,对吧?所以这就是所谓的清除中断源。 我们进行中断响应的第一步,就应该去清除这个中断源,然后再去调用这个中断响应函数。那么总结一下,我们中断处理的这个过程呢,分成了四个阶段,分别叫做中断触发、中断进入、中断响应和中断退出。 而在中断进入和中断退出的时候呢,我们需要进行保存现场和还原现场。在中断响应的过程中呢,我们需要庆祝中断员和调用中断响应函数,这个就是我们中断处理的一个全部的过程。了解完中断处理的过程和术语之后呢,我们再来看下一个话题,中断的优先级和中断排队。 那么首先来看一下,什么叫做中断的优先级呢?这里呢,我给大家举两个例子,我们先来看左边的这个例子,想象一下,你现在正在上自习,然后呢,同学假过来找你,因为他上课的时候呢,有一些东西没听懂,他 需要问你一些问题。然后呢,你必须中断这个自习的过程,转而给同学家解答问题。在给同学家解答问题的过程中呢,同学乙和同学丙也过来了,那么他们也是要向你请教这个问题,这个时候呢,同学乙和同学丙就得排队, 那么因为你跟这个同学丙关系更好一点,所以呢啊,你把这个同学丙排在前面,所以他们呃解答问题的顺序呢,就是先给同学甲解答问题,再给同学丙解答问题,最后给这个同学乙解答问题。 那么当这个三个过程处理完成之后呢,我们继续回到刚才的进度,进行这个自习,这是第一个例子,我们再来看第二个例子,也就是右边的这个例子,我们还是在自习,然后呢,同学甲过来来找你请教问题,那么这时候自习就中断了,我们去给同学甲解答问题啊,解答 答问题的过程中,哎,突然来了电话,我们需要先去接电话,接完电话再给这个同学讲讲解,那么讲解完成之后,再次回到这个之前自习的进度,继续自习。 从这两个例子里边,我们总结出来一个什么道理啊,就是说这个事情呢,他有轻重缓急。比如说我们解答问题的时候,我们为什么先给丙解答,再给乙解答呢?明明是乙先到的,这个是因为丙对你来说比乙更重要一点。 在给假解答问题的过程中,为什么我们需要中断掉给假解答问题的这个过程去接电话呢?这是因为 接电话这件事呢,比这个给同学解答问题更加紧急。所以呢,我们把这个中断处理过程中的这个轻重缓急的程度呢,我们叫做中断优先级。那么除此之外,还有两个概念对于我们来说非常重要,我们在这里来解 解释一下。其中第一个概念呢,叫做中断排队,第二个概念呢,叫做中断欠套。那么什么是中断排队呢?看左边的这个例子,我们在中断响应的过程中,就是我们响应同学假的这个过程中呢,他是一个中断响应,对吧?又有新的中断到来, 乙和丙这是新的中断,然后新的中断到来之后呢,他们必须进行排队,对吧?因为我在给同学贾解答问题,那么乙和丙得不到处理,他们俩就得排队。 在排队的过程中呢,我们需要根据这个中断优先级来决定排队的顺序,也就是说哪个人对我们重要,就排在前面,这个就是中断排队的一个概念。 那么我们再来介绍一下第二个概念,叫做中断嵌套。什么是中断嵌套呢?中断嵌套就是中断处理的过程被更紧急的中断源所打断,就比如说我们。
