如何使用USART(编程理论讲解)
如下是串口发送信息的原理图,CPU将数据写入TDR寄存器,然后串口外设将寄存器中的数据发送出去 这就是串口发送的全部流程 (图中所有图片均来自博主 铁头山羊)
在这个发送流程的过程中,我们涉及一种转换思想叫做串并转换,为什么要进行串并转换呢?很简单,我们的数据写入寄存器的时候是并行写入的,但是我们的寄存器向外发送这个信号的时候却是串行发送的,所以这个过程就涉及串并转换
在这之前我们先补充移位寄存器
移位寄存器顾名思义其作用就是将这个寄存器里面的每一个数据一位一位的移出这个寄存器 同时也满足低位先行
USART基本模型
USART的完整框图
接下来我们讲如何具体配置其相关寄存器
首先是数据帧格式设置(借此我们也来复习一下如何看懂数据手册)
如下这张图中的CR寄存器就是我们控制数据帧的寄存器,我们只需要向这个寄存器相应的位写入1或0就能使能寄存器,或者关闭寄存器。
我们以具体的参考手册为例
在参考手册中我们是可以找到该寄存器的每一位代表了什么,对每一位置0或者置1,我们就能配置相应的模式,就比如CR1寄存器的第13位(虽然写着12 但是我们的寄存器是从0开始的),它控制的就是我们的数据长度,如果我们将此位置为1 那么我们的数据长度就为9,如果我们将此位置位0 那么我们的数据长度就为8
了解了串口的基本组成原理之后,我们现在来实现串口发送的功能
在串口的发送过程中,我们的数据是以双缓存的方式进行存储和发送的分,双缓存顾名思义就是我们要发送的数据会存储到两个不同的寄存器中 由这两个不同的寄存器进行相互作用来发送数据
双缓存的数据发送模式会带来两个问题 1.数据发送过快导致的覆盖问题 2.数据什么时候发送完成的问题
1.就比如我们的第一组数据仍在移位寄存器中未发送完成,我们的第二个数据此时已经存储到TDR寄存器中,但是第三个数据也被搬运到TDR寄存器中 这样就会导致数据二与数据三的数据混淆或者说数据二的数据被数据三给覆盖
2.数据什么时候发送完成的问题,就比如此时我们的第一组数据仍在移位寄存器中还没有彻底发送成功 我们就将TDR寄存器中的数据二写入到移位寄存器中,这样就会导致数据一的发送被混淆
所以为了解决第一个数据覆盖的问题,我们加入了寄存器TXE,当TXE标志位为0时就代表了TDR寄存器中有数据存在,当TDR寄存器为1的时候就代表了TDR寄存器中没有数据存在,所以我们就可以通过读取TXE寄存器的数值来判断TDR寄存器中是否有数据,具体的编程如下用while循环来判断TXE寄存器的数值是否为零,若为零我们会一直在while循环中等待 因为TXE为零就代表了我们的TDR寄存器中此时有数据存在,若不满足TXE==的条件 我们就会跳出while循环 执行接下来的操作 也就是给TDR寄存中写入下一组数据
我们在数据手册中看一下关于TXE的简介 参考手册中的 禁止产生中断就代表了 我们的TDR寄存器中此时仍有数据存在
而为了解决第二个问题 我们引入第二个寄存器 TC寄存器 ,TC寄存器的数值就代表了在移位寄存器中的数据是否成功发送 如果TC标志位为0就代表了我们的移位寄存器中仍有数据未发送成功,若TC标志位为1就代表了我们的移位寄存器中数据已经发送成功 此时我们可以将TDR寄存器中的数据写入移位寄存器(补充一下 TDR寄存器中的数据更新到移位寄存器中的这个过程是硬件自动填充的 不需要我们手动来填充 而之所以要判断移位寄存器中的数据是否发送完成 是为了给我们程序员一个信号 告诉我们数据发送完成 可以开始进行下一步操作)
有了上面对发送的补充,我们现在来看一下单个数据的发送
数据的连续发送
我们的连续发送有如下两种书写方式,我们分别展开来讲
第一种写法如下 我在旁边打了错误符号就代表这种书写方法是错误的,为什么这么说呢 因为第一种书写方式最后表达出来并不是真正的连续发送 而是先发送一个数据保证这个数据彻底发送完成之后我们才会发送第二组数据,可以理解为 第一组数据先写入 TDR寄存器中 然后从TDR寄存器中写入到移位寄存器中 然后等待移位寄存器中这组数据向外发送完成之后我们才会重新向TDR寄存器中写入数据 那么这里就有一个问题 就是我们在等待移位寄存器中的数据发送完成的这个过程中 我们的TDR寄存器中是没有数据的 我们必须要等到移位寄存器中的数据发送完成之后我们才能向TDR寄存器中写入数据,这明显不是连续发送
而第二种书写方式是 我们先将第一组数据写入TDR寄存器中 然后等待第一组数据转移到移位寄存器中,一旦第一组数据从TDR寄存器中转移到移位寄存器中 我们就将第二组数据写入 TDR寄存器中,这样的书写方式满足了连续发送的规律
下面我们来讲如何接收数据
还是跟接收的时候同样的思路 我们先提出问题 然后在去试着解决这些问题
1.问题一 何时读取数据
因为我们的RX引脚是接的发送方的TX引脚 我们不知道 对方何时发送完成 就会导致两种情况的出现
第一种情况就是对方的数据还没发送完成 我们接收方的TDR寄存器只存储了发送发发送的前几个数据 我们就将这个数据直接搬运到接收方的RDR寄存器中 这样就会导致接收的数据有纰漏
第二种情况就是发送方给我们连续发送数据就比如发送方发送的第一组数据刚到我们接收方的移位寄存器中 还没完全写入RDR寄存器中 我们就将第二组数据写入到移位寄存器中
我们引入RXNE标志位来解决这个问题
RXNE寄存器(也可以叫标志位)为1时代表我们的RDR标志位有数据 此时我们可以读取里面的数据,而当RDR为0时代表RDR寄存器无数据 此时我们需要等待 (反映到程序层面就是卡死在while循环中)
接收单个数据
接收多个数据