1. 从轮询到中断
许多学习者更倾向于使用轮询方式而非中断方式来操作。
这是否与我们的天性有关呢?每个人都希望掌控一切,肯定不愿被打断。我们通常都有这样的经历:正在谈论一件事情,突然电话响起,电话结束后却忘记刚才说了什么!这种糟糕的体验对我们影响深刻,以至于我们或许会认为机器也会遇到类似困扰,频繁的中断会不会导致混乱呢?幸运的是,尽管机器大部分时间比人类笨拙一些,但在处理这类情况时却能够精确无误。机器在接收中断时总是会先诚实地记录下当前工作状态,然后处理中断事件,最后恢复原始工作状态,毫不含糊。
仔细思考一下,我们在接电话前为何不先用小本子记录正在谈论的事情呢?或许是因为手边没有笔,又或许是因为我们过于自信以为自己比机器更聪明,当然最有可能的原因是我们通常所谈论的内容都十分无聊,哈哈。
打开Keil后,进入以下工程路径:
STM32Cube_FW_F0_V1.11.0\Projects\STM32F030R8-Nucleo\Examples\UART\UART_TwoBoards_ComIT\MDK-ARM\Project.uvprojx
此时,如果不仔细查看,几乎无法发现与轮询操作的代码有何不同。特别是在初始化部分,几乎完全相同。那么约定的中断模式呢?
好吧,往下看一下,终于能够发现一些微小区别:
在这里我们发现串口发送调用了一个不同的函数。秘密就在这个函数里:
HAL_UART_Transmit_IT 这个函数有三个参数:
UART_HandleTypeDef *huart, 让函数知道处理的是哪个串口
uint8_t *pData, 需要发送的数据首地址
uint16_t Size 发送数据的大小(长度)
这个函数的三个步骤:
Step1: 把待发送数据区的首地址,长度赋给串口的 Handle。
Step2: 根据参数(8B还是9B),挂载不同的处理函数。
Step3: 开中断(串口发送寄存器空将产生中断)。
HAL_UART_Transmit_IT 函数执行完这些任务就退出了,主程序可以继续执行其它的操作。这是和轮询完全不同的。我们回头看一下轮询方式的 HAL_UART_Transmit 就会发现这个函数一直要等到所有数据都发送完才退出,在此期间MCU被100%占用,没有办法做其它的事情。轮询方式发送函数里有个参数 5000,这是一个发送超时参数,不管有没有发送完,5秒以后强制退出此函数,防止由于硬件或其它原因卡死在这个函数里。
2.再谈Handle
对于 Handle 这个词,我们没有用”句柄”这种翻译,因为”句柄”这个词本身也是生造出来的,这个词本身就不太好理解,容易把人引入歧途。所以我们认为 Handle 这个词不翻译为好。Handle 是一个重要的概念,所以我们需要反复体会用它来管理硬件模块的好处。
我们可以把它想象成一个负责装卸货船的办事处,类型声明(如 UART_HandleTypeDef ) 是一个创建办事处的模板。如果有五个码头,那就创建五个办事处,这些办事处是相似的,但每个办事处又不同,它们建在不同的码头,有不同的人员,可以调用不同的车队。这个办事处可以等待中央机构(MCU)的命令,也可以用更好的办法。
中断的方式就像我们给这个办事处建立一个自动处理流程,码头来了一个空货船,则自动触发办事处中的一些办事员调动车队把货物运到船上。而轮询方式就像所有的事情都要等待中央指挥中心(MCU)下达命令,即使办事处一堆人员正无所事事。
下面的 Handle 就好比是一个这样的办事处,初始化的过程就是告知它建在 USART1,以及波特率,有无奇偶校验,停止位等信息。
HAL_UART_Transmit_IT 函数告知此办事处有一堆 8BIT 货物在仓库 aTxBuffer 存放,并通过把 TxISR 指向适合的车队( 函数 UART_TxISR_8BIT ),建立了一个自动处理流程。
3.中断产生,执行的流程
我们从下图中可以看到从中断产生到执行的过程,一个是发送寄存器空产生中断时,一个是发送完成产生中断时。
以上就是良许教程网为各位朋友分享的Linu系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你 !