:数据帧及标志位的收发机制与寄存器深度剖析)
目录前言一、USART模块地址空间1.1 STM32统一编址机制1.2 USART1地址范围详解1.3 各串口模块地址清单二、USART寄存器结构2.1 寄存器列表与偏移量2.2 寄存器权限标识说明三、数据寄存器 USART_DR3.1 TDR与RDR的双重角色3.2 DR寄存器的位结构四、数据帧格式4.1 数据帧结构组成4.2 以发送0x55为例的波形分析4.3 起始位与停止位的电平本质五、USART发送机制5.1 从TDR到发送移位寄存器的数据流转5.2 数据覆盖问题——为什么不能盲目连续写入5.3 TXE与TC——衡量发送状态的两个核心标志位5.3.1 TXETransmit Data Register Empty发送数据寄存器空5.3.2 TCTransmission Complete发送完成5.3.3 TXE与TC的区别5.4 USART_SR状态寄存器全景六、USART带标志位的数据发送原理6.1 用户视角什么时候可以写入数据6.2 USART硬件视角TXE标志的翻转时机七、三字节完整发送流程剖析0x00 → 0xFF → 0x557.1 第一阶段发送 0x007.2 第二阶段发送 0xFF7.3 第三阶段发送 0x557.4 发送完毕TC标志位的翻转八、阻塞式发送模式九、时钟域的并行操作十、USART 详细接收过程10.1 数据帧格式回顾10.2 接收过程的逐步拆解10.2.1 第一阶段检测起始位10.2.2 第二阶段逐位接收数据位10.2.3 第三阶段接收校验位10.2.4 第四阶段检测停止位10.2.5 第五阶段校验与数据平移10.3 RXNE 标志位——接收就绪的信号10.3.1 RXNE 位的定义10.3.2 RXNE 的硬件置位机制10.3.3 RXNE 的清除机制10.4 阻塞式读取机制10.4.1 轮询检测 RXNE10.4.2 形象比喻10.4.3 责任边界10.4.4 读取后自动清零10.5 连续接收的时序关系结语 云泽Q个人主页 专栏传送入口: 《C语言》《数据结构》《C》《Linux》《蓝桥杯系列》《笔试算法》《AI赋能》《STM32》《Python》⛺️遇见安然遇见你不负代码不负卿~前言大家好啊我是云泽Q欢迎阅读我的文章一名热爱计算机技术的在校大学生喜欢在课余时间做一些计算机技术的总结性文章希望我的文章能为你解答困惑~一、USART模块地址空间1.1 STM32统一编址机制在STM32F103ZET6这款MCU内部所有片上外设——包括SRAM、Flash以及各类外设模块——都处于CPU的统一编址空间之下完成地址映射。换句话说每一个外设、每一个寄存器最终都对应着一个明确的物理地址。CPU通过对这些物理地址的读写操作来实现对外设的控制和数据交互。具体到USART模块STM32F103ZET6内部总共包含了5个串口接口USART1、USART2、USART3、UART4、UART5。每一个串口都是一个独立的硬件单元拥有自己专属的地址空间。只要搞清楚其中一个串口的硬件结构和寄存器组其余所有串口的原理完全一致可以直接举一反三。1.2 USART1地址范围详解以USART1为例它的物理地址范围是0x4001 3800 ~ 0x4001 3BFF这个地址空间的大小可以通过公式计算结束地址 - 起始地址 1 0x4001 3BFF - 0x4001 3800 1 0x3FF 1 0x400十六进制将0x400转换为十进制1024字节即1KB。也就是说CPU内核为USART1分配了1KB的地址空间。但实际使用中只有最开头的很少一部分地址被真正使用到了后续的大部分地址是保留的访问它们可能产生不可预知的行为。USART1中一共有7个寄存器每一个寄存器都有一个偏移量地址。访问任何一个寄存器的方式都是USART1基地址(0x4001 3800) 寄存器偏移量1.3 各串口模块地址清单外设所在总线起始地址结束地址地址空间大小类型USART1APB20x4001 38000x4001 3BFF1 KB高级同步/异步串行接口USART2APB10x4000 44000x4000 47FF1 KB通用同步/异步串行接口USART3APB10x4000 48000x4000 4BFF1 KB通用同步/异步串行接口UART4APB10x4000 4C000x4000 4FFF1 KB通用异步串行接口UART5APB10x4000 50000x4000 53FF1 KB通用异步串行接口可以看到USART1挂载在APB2总线上而其余串口均挂载在APB1总线上。这也说明USART1的性能和时钟频率与其他串口有所不同。二、USART寄存器结构2.1 寄存器列表与偏移量USART1的7个寄存器及其偏移量如下寄存器偏移量(Offset)地址计算过程最终地址USART_SR0x000x4001 3800 0x000x4001 3800USART_DR0x040x4001 3800 0x040x4001 3804USART_BRR0x080x4001 3800 0x080x4001 3808USART_CR10x0C0x4001 3800 0x0C0x4001 380CUSART_CR20x100x4001 3800 0x100x4001 3810USART_CR30x140x4001 3800 0x140x4001 3814USART_GTPR0x180x4001 3800 0x180x4001 3818这里我们重点关注前几个核心寄存器USART_SR状态寄存器偏移量0x00用于存放各种状态标志位包括我们后面重点讲解的TXE和TC。USART_DR数据寄存器偏移量0x04是发送和接收数据的核心寄存器。2.2 寄存器权限标识说明在参考手册的寄存器位描述中你会看到类似rc、w0、r这样的标识这些代表了每一位的读写权限rRead Only只读该位只能读取不能写入。从编程角度你可以直接读取寄存器的值来获取状态。rcRead Clear读后清零该标志位由硬件自动置位当你在软件中读取该寄存器或对应位后硬件会自动将该位清零。这是一个典型的读即清机制。w0Write 0 to Clear写0清零该位可以通过软件写0来清零。写入1通常不影响该位的状态。这些权限标识反映了硬件对各个标志位的管理方式。很多情况下标准库或HAL库已经帮我们处理了这些底层的读写操作不需要我们手动去操作。但了解这些底层机制有助于在遇到异常时进行深度调试。三、数据寄存器 USART_DR3.1 TDR与RDR的双重角色USART_DR是串口通信中最核心的寄存器之一它的偏移量为0x04对于USART1来说其物理地址为0x4001 3804。从数据手册的描述来看USART_DR被标注为一个寄存器但实际上它由两个逻辑寄存器组成TDRTransmit Data Register发送数据寄存器用于发送数据。当CPU向USART_DR写入数据时数据被写入TDR。RDRReceive Data Register接收数据寄存器用于接收数据。当CPU从USART_DR读取数据时数据来自RDR。TDR和RDR共享同一个物理地址0x4001 3804通过总线控制信号中的读写方向来区分写操作→ 访问TDR发送方向读操作→ 访问RDR接收方向TDR寄存器提供了内部总线APBx和输出移位寄存器之间的并行接口RDR寄存器提供了输入移位寄存器和内部总线之间的并行接口。3.2 DR寄存器的位结构USART_DR是一个32位寄存器但实际只使用了低9位位段名称说明位31:9保留位硬件强制为0位8:0DR[8:0]数据值Data value共9位DR[8:0]共9位意味着USART最多支持9位数据的传输。如果配置为9位数据位则无法启用奇偶校验功能。工程中更常见的配置是8位数据 1位奇偶校验如8N1、8E1、8O1。当使能校验位USART_CR1中PCE位被置位进行发送时写到MSB的值根据数据长度不同MSB是第7位或第8位会被后来的校验位所取代。也就是说硬件会自动用计算出的校验位覆盖最高数据位用户无需手动计算校验值。四、数据帧格式4.1 数据帧结构组成串口通信的数据是以**帧Frame**为单位进行传输的。一个完整的数据帧由以下部分组成[起始位] [数据位] [校验位(可选)] [停止位]以最常见的配置为例起始位1位固定为低电平0用于通知接收方数据开始传输数据位8位或9位实际要传输的数据LSB最低有效位先发校验位1位奇校验或偶校验由硬件自动生成停止位1位或1.5位、2位固定为高电平1用于标识一帧结束所以一帧完整的帧包含1 8 1 1 11位。4.2 以发送0x55为例的波形分析以发送数据0x55为例来直观理解数据帧的传输过程0x55 的二进制 0101 0101由于串口通信是LSB先发最低有效位优先所以实际发送顺序为起始位 → 数据位(LSB→MSB) → 校验位 → 停止位 0 → 1 0 1 0 1 0 1 0 → 奇校验位 → 1完整帧为0起始 10101010数据LSB先发 1奇校验 1停止 11位波形图上各阶段的含义阶段名称电平说明①空闲状态高电平无数据传输时TX线保持高电平②起始位低电平拉低电平触发接收方开始采样③数据位高低交替8位数据逐位发送LSB先发④校验位由数据决定奇校验位硬件自动填充⑤停止位高电平拉高电平标识一帧结束回到空闲状态4.3 起始位与停止位的电平本质起始位和停止位虽然可以用逻辑0和逻辑1来理解但更好的理解方式是从电平角度起始位本质上就是USART硬件发现有数据要发送时主动拉低TX引脚的电平形成低电平触发信号通知接收端准备接收数据。停止位本质上就是USART硬件发现数据发送完成时主动拉高TX引脚的电平形成高电平恢复信号表示这一帧结束了回到空闲状态。接收端收到的是一串高低电平交替的方波最终形成的波形就是我们在示波器上看到的样子。起始位可以理解为逻辑0但更好的方式是理解成低电平停止位可以理解为逻辑1但更好的方式是理解成高电平。五、USART发送机制5.1 从TDR到发送移位寄存器的数据流转整个发送过程涉及两个关键的寄存器层次CPU通过APB总线→ 写入 → TDR发送数据寄存器→ 硬件转移 → 发送移位寄存器 → 逐位输出到TX引脚具体流程如下用户程序将要发送的数据写入USART_DR实际写入TDR。USART硬件检测到TDR中有数据后将TDR中的数据一次性并行转移到发送移位寄存器中。发送移位寄存器在USART时钟驱动下将数据逐位串行输出到TX引脚LSB先发。硬件自动在数据帧前后添加起始位和停止位并根据配置自动填充校验位。注意发送移位寄存器对用户是不可见的用户只能通过TDR来操作发送数据。5.2 数据覆盖问题——为什么不能盲目连续写入假设USART底层正在发送数据发送移位寄存器中还有数据未发完。此时如果用户再次向TDR写入新数据会发生什么while(cnt){TDRcnt;cnt--;}如果第一次写入时USART正在忙数据暂存在TDR中等待转移到移位寄存器。如果在USART还没完成转移和发送之前用户第二次又往TDR写入数据那么新数据会直接覆盖TDR中尚未发送的旧数据导致数据丢失。这就好比你一边在说话别人一边往你嘴里塞新的台词——你根本来不及把之前的话说完。因此在发送数据之前必须确认TDR是否为空即上一次的数据是否已经被转移到移位寄存器中。这正是TXE标志位存在的意义。5.3 TXE与TC——衡量发送状态的两个核心标志位USART_SR状态寄存器中有两个极其重要的标志位专门用来衡量发送过程的状态5.3.1 TXETransmit Data Register Empty发送数据寄存器空位置USART_SR的位7含义当TDR中的数据被硬件转移到发送移位寄存器后该位被硬件置1。取值说明0数据还没有被转移到移位寄存器TDR非空此时不能写入新数据。1数据已经被转移到移位寄存器TDR已空可以写入下一帧数据。清零方式对USART_DR进行写操作时该位自动清零因为写入新数据后TDR不再为空。应用场景主要用于单缓冲器传输中判断是否可以写入下一字节数据。5.3.2 TCTransmission Complete发送完成位置USART_SR的位6含义当包含有数据的一帧发送完成后并且TXE1时由硬件将该位置1。取值说明0发送还未完成。1发送已完成整个数据帧包括停止位已全部从TX引脚发出。清零方式软件序列清除先读USART_SR然后写入USART_DR。或者直接写入’0’来清除仅在多缓冲器通讯中推荐。应用场景用于判断整帧数据是否彻底发送完毕。5.3.3 TXE与TC的区别这两个标志位经常被混淆它们的本质区别在于衡量的阶段不同标志位衡量的是什么何时置1TXETDR寄存器是否为空数据从TDR转移到移位寄存器后立即置1TC整帧数据是否发送完毕移位寄存器中最后一位含停止位发完后置1简单来说TXE1意味着TDR空了你可以写下一字节了但当前这一帧可能还在移位寄存器中慢慢发。TC1意味着不仅TDR空了移位寄存器也空了整个数据帧已经全部从TX引脚发出去了。5.4 USART_SR状态寄存器全景USART_SR状态寄存器位于偏移量0x00处复位值为0x00C0。其关键位段如下位名称权限说明位7TXEr发送数据寄存器空位6TCrc w0发送完成位5RXNErc w0读数据寄存器非空接收数据就绪位4IDLErc w0空闲线检测位3OREr溢出错误位2NEr噪声错误标志位1FEr帧错误位0PEr校验错误其中我们当前阶段重点关注的是**TXE位7和TC位6**这两个发送相关的标志位。后续进入接收阶段后RXNE位5将成为核心关注点。六、USART带标志位的数据发送原理当我们把两个核心标志位——TXE和TC——引入到USART的发送流程中后串口发送就进入了真正意义上的实战阶段。在用户代码层面进行数据帧发送时真实情况下的每一次发送都是要携带标志位来判断状态的。我们要发送三个字节的数据分别是0x00、0xFF和0x55。这一次不只是一个数据而是连续三个。数据帧的格式设定为1位起始位 8位数据位 1位奇校验位 1位停止位总共11位。这个帧格式是我们之前一直沿用的此处不再赘述。6.1 用户视角什么时候可以写入数据站在用户的角度理解TXE和TC的状态变化逻辑至关重要当TXE 1时说明TDR是空的。此时如果用户还有数据要发送就可以放心地继续写入下一个字节。如果用户的数据已经全部写完了那就什么都不用做静等USART硬件把剩余数据发完。当TC变成1时意味着TXE 1 TC 1表示本轮数据全部发送完毕。如果数据没发完只要TXE 1用户就可以继续往TDR里写新数据。用户判断逻辑就是TXE 1 自己还有数据要发那么就继续发送。6.2 USART硬件视角TXE标志的翻转时机从USART硬件模块的角度来看它的运作逻辑是这样的USART必须先把当前移位寄存器里的数据全部串行发送完毕。发送完成后USART才会把TDR寄存器中的数据平移到发送移位寄存器。只有TDR中的数据成功平移到发送移位寄存器之后USART才会将TXE设置为1表示TDR已空允许用户再次写入。这就是TXE的本质——USART硬件模块用来指导用户写入数据的指挥棒。它告诉用户现在TDR空了你可以写了或者TDR还被占着你必须等。如果用户无视TXE标志位在TXE 0TDR不空时强行写入数据就会导致自己覆盖了自己的数据。这时候锅要用户自己背因为USART已经通过TXE标志告诉你TDR不为空了你还要往里写。所以用户要写TDR必须先对TXE进行判定只有TXE 1用户才能再写入。七、三字节完整发送流程剖析0x00 → 0xFF → 0x55下面我们以发送0x00、0xFF、0x55这三个字节为例从时序角度逐步拆解整个发送过程。7.1 第一阶段发送 0x00初始状态下TDR为空TXE 1TC 1。用户将第一个数据0x00写入TDR。此时TDR被占用TXE被USART自动设置为0。TC也被设置为0因为发送尚未完成。USART硬件自动将TDR中的数据1-0-0-0-0-0-0-0-0含起始位和校验位平移到发送移位寄存器。TDR重新变为空TXE恢复为1。发送移位寄存器开始按位串行输出数据到TX引脚。此时TC仍为0因为移位寄存器中还有数据正在发送。7.2 第二阶段发送 0xFFUSART硬件在自身时钟驱动下继续从移位寄存器逐位输出0x00的数据帧。同时由于上一阶段TDR已经变空TXE 1用户代码检测到TXE 1后将第二个数据0xFF写入TDR。此时TDR再次被占用TXE被设置为0。注意如果此时USART硬件中上一次0x00的数据还没有从移位寄存器发送完毕那么TDR内部的0xFF就无法被平移到移位寄存器。因此TDR一直被占用TXE保持为0。用户必须等待TXE变回1才能写入下一个数据。当USART把0x00的所有位11位全部发送完毕后硬件会将TDR中的0xFF平移到移位寄存器。平移完成后TDR重新变空TXE被USART设置为1。移位寄存器开始串行输出0xFF加上奇校验位后为1-1-1-1-1-1-1-1-1。7.3 第三阶段发送 0x55此时TXE 1用户检测到后将第三个数据0x55写入TDR。TDR被占用TXE被设置为0。USART继续从移位寄存器输出0xFF的数据帧。当0xFF的数据帧全部输出完毕后USART将TDR中的0x55平移到移位寄存器。TDR变空TXE被设置为1。移位寄存器开始输出0x55的数据帧。此时用户已经没有更多数据要发送了。TDR保持为空TXE 1。7.4 发送完毕TC标志位的翻转当最后一个数据0x55的所有位也从移位寄存器全部串行输出到TX引脚后TDR为空TXE 1移位寄存器也为空两个条件同时满足USART硬件将TC标志位置为1宣告本次多字节数据发送全部完成。此时TXE 1 TC 1整个发送流程结束。八、阻塞式发送模式在实际编程中用户发送数据时必须对TXE标志位进行检测如果TXE 0表示TDR中的数据还没有被平移到发送移位寄存器TDR被占用。此时用户必须阻塞在检测TXE标志位的位置进行等待直到TXE变为1。这种模式的写入方式就叫做阻塞式发送。在时序图上可以清晰地看到数据寄存器TDR中依次装入数据1、数据2、数据3。每当一个数据从TDR平移到发送移位寄存器时TXE标志从低电平跳变为高电平标记为时刻①、②。用户只有在TXE变高的时刻才能写入下一个数据。当最后一个数据全部发送完毕TDR和发送移位寄存器都为空时TC标志被置为1标记为时刻③。所以如果使用阻塞模式进行数据发送一个或多个数据之后要知道USART是否彻底把数据全部发送出去了就看TC标志位。当TC 1时表示要发送的数据已全部发送完成。九、时钟域的并行操作需要特别注意的是CPU和USART模块是在各自的时钟域下独立运行的CPU通过APBx总线时钟向TDR写入数据。USART模块通过自身的波特率时钟从移位寄存器逐位串行输出数据。这意味着在时间维度上用户向TDR写入下一个数据和USART从移位寄存器发送当前数据是可以并行进行的。只要TDR是空的TXE 1用户就可以提前把下一个数据写好放进去等USART发完当前数据后硬件会自动把TDR中的新数据搬运到移位寄存器继续发送。这种硬件层面的自动平移机制使得串口发送在效率上远高于CPU逐位模拟的方式。十、USART 详细接收过程前面我们完成了 STM32 USART 发送的详细过程数据帧格式和标志位都已经搞定了。接下来进入下一个话题——USART 详细的接收过程。之前我们聊接收的时候只是站在 8 位数据位的角度并没有谈任何数据帧格式。所以这一次我们要带着完整的帧格式来理解接收的全貌。10.1 数据帧格式回顾以发送端发送0x55为例对应的二进制为0101 0101。我们约定的帧格式为组成部分位数说明起始位1 位低电平拉低标记一帧数据的开始数据位8 位实际有效数据校验位1 位奇校验位停止位1 位高电平拉高标记一帧数据的结束总共 11 位比特位构成一帧完整的数据。需要特别注意的是发送端是从低位向高位逐位发送的。0x55的二进制0101 0101我们人眼阅读时是从高位到低位读的但在物理线路上发送端先发最低位的1再发0、1、0……依此类推。所以线路上实际传输的比特流顺序为起始位(0) → 1 → 0 → 1 → 0 → 1 → 0 → 1 → 0 → 校验位(1) → 停止位(1)接收端按这个顺序依次接收到自己的接收移位寄存器中。10.2 接收过程的逐步拆解10.2.1 第一阶段检测起始位接收端的 RX 引脚平时处于空闲的高电平状态。当接收控制器检测到一个拉低的电平低电平时就知道对方开始发送数据了。这个低电平仅仅用于 USART 内部判断对方开始发了不需要保存更不需要被用户读取。起始位由硬件自动识别和处理。收到这个拉低的电平后接收移位寄存器准备好接收对面的数据第一个进入接收移位寄存器的就是起始位。10.2.2 第二阶段逐位接收数据位起始位之后发送端开始逐位发送 8 位数据。接收端按照约定的波特率时钟节拍一位一位地把数据从 RX 引脚读入接收移位寄存器中。以0x55为例实际进入接收移位寄存器的顺序为第1位进入1 第2位进入0 第3位进入1 第4位进入0 第5位进入1 第6位进入0 第7位进入1 第8位进入0数据在接收移位寄存器中逐位右移填充最终填满 8 个有效数据位。10.2.3 第三阶段接收校验位8 位数据位之后接下来进入的是 1 位校验位。在我们的奇校验配置下0x55的二进制0101 0101中1的个数为 4 个偶数为了满足奇校验总1个数为奇数校验位为1。这个校验位同样被接收移位寄存器接收进来。10.2.4 第四阶段检测停止位在收到约定的 9 位数据8 位数据位 1 位校验位之后接收端继续检测线路电平。当读到拉高的电平时就说明对方发完了这就是停止位。这个高电平同样仅仅是 USART 内部判断对方发完了的信号不需要保存更不需要被用户读取。停止位由硬件自动识别。10.2.5 第五阶段校验与数据平移当 11 位完整帧全部接收完毕后USART 模块自己进行校验校验通过 → 有效数据8 位从接收移位寄存器平移到接收数据寄存器RDR。校验不通过 → 数据无效可能触发错误标志位。在这个过程中起始位和停止位已经被硬件自动丢弃它们只起到帧边界的标记作用不会进入 RDR。10.3 RXNE 标志位——接收就绪的信号数据从接收移位寄存器平移到 RDR 的过程中状态寄存器USART_SR中的RXNE 位会被硬件自动置 1。10.3.1 RXNE 位的定义RXNE 全称为Read Data Register Not Empty读数据寄存器非空位于 USART_SR 状态寄存器的位 5位编号名称含义位 5RXNE读数据寄存器非空RXNE 0数据没有收到RDR 为空不可读取。RXNE 1收到数据RDR 非空可以读出。10.3.2 RXNE 的硬件置位机制当 RDR 移位寄存器中的数据被转移到 USART_DR 寄存器中时RXNE 位被硬件自动置位。如果 USART_CR1 寄存器中的 RXNEIE接收中断使能位为 1则同时会产生中断。10.3.3 RXNE 的清除机制正常读取清除对 USART_DR即 RDR执行读操作RXNE 位会被硬件自动清零。手动清除RXNE 位也可以通过写入 0 来清除但只有在多缓存通讯中才推荐这种清除方式。10.4 阻塞式读取机制有了 RXNE 标志位之后用户就可以安全地读取数据了。具体做法是10.4.1 轮询检测 RXNE在读取 RDR 之前必须检测 RXNE 标志位while((USART_SR0x0020)0);// 轮询等待 RXNE 置 1// RXNE 为 1 后安全读取数据uint8_treceived_dataUSART_DR;// 读取数据同时硬件清零 RXNE标志位为 0 表示没有数据程序通过while循环不断轮询检测。只要标志位一直为 0程序就卡在那里等待。10.4.2 形象比喻这个等待过程就像去食堂打饭阿姨还没把饭菜端上来的时候你只能站在点菜的位置上等待阿姨把菜放上来了RXNE 变 1你这个时候才能拿到菜。10.4.3 责任边界这种机制明确了硬件和软件之间的责任边界USART 模块的责任负责接收数据、校验数据、将有效数据放入 RDR并置位 RXNE 通知用户数据准备好了。用户的责任在 RXNE 置 1 之后去读取数据。只要标志位为 1用户读数据读出错了就和 USART 模块没关系了——“我把我该做的工作做了要后面读数据出错这个锅我不背。”10.4.4 读取后自动清零只要用户把数据读走了RXNE 标志位就会被 USART 硬件自动清零回到 0 状态准备接收下一帧数据。10.5 连续接收的时序关系当连续接收多帧数据时时序关系如下每一帧数据接收完成并校验通过后RXNE 被置 1图中①②③标记处用户读取后 RXNE 自动清零等待下一帧。结语