STM32串口:字节中断与帧中断不同导致的BUG

2023-11-05

  在使用STM32F207这一款单片机调试串口的时候,使用两种不同的中断接收方式:帧中断IDLE和字节中断RXNE,会出现一些神奇的事情,只要我们认真地分析是可以揭开BUG后面隐藏的真相。其中IDLE中断也叫作串口空闲中断

一、问题背景

1.1 硬件连接框图

  如图1所示是简化的硬件连接框图,本来有18个SLAVE设备,问题的复现只需要两个所以只画了两个SLAVE设备。MASTER和SLAVE1、SLAVE2使用485总线进行通信,其中MONITOR是一个监听设备,用于监听所有在总线上的数据,监听数据并分析是在调试各类总线型通信时常用的手段,两个120欧电阻是首尾匹配电阻所以485总线的阻抗是60欧。

  其中SLAVE1、SLAVE2、MONITOR都是使用STM32F207+ADM2682扩展出来485,接收方式是使用帧中断;MASTER是对方设计的所以不清楚使用的主控芯片、中断方式是帧中断接收还是字节中断接收,通过图6可以分析出来应该是字节中断,因为MASTER反应时间t2是远小于SLAVE的反应时间t1。

  双方约定命令主要有两种:①、MASTER会定时20ms向SLAVE发送取数指令,SLAVE向MASTER返回传感器测试值Y;②、如果MASTER解析出来传感器测试值Y在[-X,X]范围内,MASTER会向SLAVE发送清零指令,SLAVE需要将Y值清零,SLAVE不需要返回任何数据。

图1 硬件连接框图

1.2 玄学的BUG

  前期自测:因为没有MASTER设备,所以使用USB-485模块模拟MASTER设备,使用XCOM串口软件作为上位机发送取数据指令以及清零指令。单独测试读数据命令时,定时20ms,SLAVE每次都回返回数据无丢帧。

  因为MSATER和SLAVE之间的数据交互都是一包数据10个字节的,所以使用了串口的USART_IT_IDLE中断就是帧中断,它是当串口收到一帧数据或者说一包数据后产生的中断。以MASTER发送给SLAVE2的取数据指令包含10个字节:AA 01 52 00 00 00 00 00 52 85,当接收完0xAA时,会触发一次USART_IT_RXNE字节中断,而不会触发USART_IT_IDLE帧中断,当接收完0x85后,会触发USART_IT_RXNE字节中断和USART_IT_IDLE帧中断,所以这个命令会触发10次USART_IT_RXNE字节中断和1次USART_IT_IDLE帧中断

  中期联调:当SLAVE传感器值Y不在[-X,X]范围时(蓝色部分),无异常现象;当SLAVE传感器值Y在[-X,X]范围时(蓝色部分),预期现象时会出现清零,即Y值会显示为0。但是实测出现了如图3所示的不清零情况,-0.7因为在[-X,X]范围内,所以-0.7会瞬间变成0,但是一直在0.7停留,并且状态灯一直是绿色的,所以通信是没有断掉的【有一次没有返回数据就会绿灯变成红色,并且通过MONITOR记录下的数据发现是每次都会返回数据的,所以MONITOR是很有必要的,用以BUG调试时的数据记录回看】,即MASTER的取数据命令都得到了SLAVE的反应。

在这里插入图片描述

图2 传感器值与阈值范围

在这里插入图片描述

图3 错误现象

  因为出现了玄学现象,为了复现BUG所以通过改变传感器的状态使传感器值反复经过[-X,X]红色线部分看看能不能复现故障。复现的一次情况是SLAVE1设备的角度在1.3度停止不动,并且不会清零。通过在线Debug查看MONITOR接收到的数据,发现一个帧中断接受到了30个数据,前十个字节数据是SLAVE1回的数据(其中解析出来的数据是1.3,属于红色线范围,会被MASTER清零),中间十个字节是SLAVE向SLAVE1发出的清零指令,后面十个字节是MASTER向SLAVE2发出的读角度指令。

  这里有个问题为什么不Debug SLAVE1设备呢?其实是Debug了的,只不过没有有效的收获,因为导致这个BUG的原因是SLAVE1+MASTER+SLAVE2一起导致的,如果Debug这三个中的任何一个单个设备,均不能复现这个BUG。

  • BB 00 52 01 66 66 A6 3F 68 EF 是SLAVE1MASTER设备的数据指令,10个字节

  • AA 09 53 00 00 00 00 00 22 05 是MASTER发送给SLAVE1的清零指令,10个字节

  • AA 01 52 00 00 00 00 00 52 85 是MASTER发送给SLAVE2的取数据指令,10个字节

  使用Debug发现了一次帧中断出现了“三包数据”(这里的“三包数据”指的是本应该是三包数据的,但是却被识别成了一包数据,所以这里带引号的三包数据实际上按照一包数据接收的,同理“两包数据”),本来是一包数据就会触发一次帧中断的,也就是说本应该触发三次帧中断的只触发了一次帧中断如图4所示。也有出现一次帧中断接收“两包数据”的,当时只保存了示波器抓到一次帧中断接收“两包数据”的波形,没有Debug时的RS485_RX_BUF截图。

在这里插入图片描述

图4 一个帧中断接收“三帧数据”

1.3 帧中断触发条件

  中断产生条件:STM32的帧中断是IDLE中断,当接收到一帧数据,就会产生IDLE中断。帧中断常被用于接收不定长度字节数据。
  优点:因为IDLE中断是一帧数据/一包数据产生一次中断,然后读取寄存器里面存取的数据可以获得本次帧中断所接收的数据长度与数据内容,即使某一帧由于未知原因增加一个字节或者减小一个字节,可以根据接收到的数据长度和约定的不一致所以不采用这一帧数据,但是下一帧数据是不受前面错误帧数据的影响,这个是下面使用字节中断可能会出现的问题。
  缺点:当使用帧中断时,因为判断帧结束的标志需要默认电平持续的时间>发送一个字节所需要的时间,所以对于一帧数据的响应时间一定是大于一个字节数据信号的时间,即下文的 t Byre t_{\text {Byre}} tByre

1.4 字节中断触发条件

  中断产生条件:STM32的字节中断是RXNE中断,当接收到1个字节,就会产生RXNE中断。字节中断可以用来接收定长字节数据,比如针对上面的AA 09 53 00 00 00 00 00 22 05命令,每接收到一个字节数据,触发一次RXNE中断,RxCount++、保存接收到的这一字节数据到RXBuffer并指针加1,当接收到的数据计数到10(10时约定好的命令)时,判断RXBuffer是否是约定的命令,如果是则进行Response。
  缺点:使用RXNE中断的缺点显而易见,因为没有按照一帧数据一帧数据接收,一旦某一帧因为未知原因增加一个字节或者减小一个字节就会导致后续接收到的数据包是错位的,所以相应地需要增加相应措施解决这个问题。
  优点:这个优点是相对于帧中断来讲的,因为按照字节来接收到的,而单片机对于一个字节数据产生中断所需要的时间与 t Byte t_{\text {Byte}} tByte暂时没有发现有关系(不知道与发送一位数据所需要的时间是否有关, t bit t_{\text {bit}} tbit),所以其响应时间相比着帧中断会快很多。本文为了将“两包数据”中包含的命令解析出来,最后就是将帧中断改为了字节中断去接收,然后循环判断是否是约定的命令。
后面需要查找资料:485总线上数据格式,如何判定一位,一位数据与中间电平是否有关系

二、解决问题

2.1 复现BUG:一个帧中断“2包数据”?

  发现了是帧中断导致的一个帧中断接收了多帧数据,我们从事故的一开始分析一个帧中断是如何导致接收到“两包数据”的,首先是MASTER发送给SLAVE1的读数据命令为事件的起始点,从MASTRE、SLAVE1、SLAVE2、MONITOR四个角度看485总线上都发生了,因为MONITOR是不参与命令交互的,所以以MONITOR为视角看到的485总线上的信号时序图是出现在485总线上的所有信号的真实时序,如图5所示,其中

  • t1大小的影响因素:SLAVE1对M→S1读数据命令的反应时间
  • t2大小的影响因素:MASTER对S1→M回数据命令的反应时间,判定在阈值范围的红色曲线上,所以需要清零,如果是蓝色区域,则没有这一步。
  • t3大小的影响因素:因为t3位于M→S1清零和与M→S2读数据这两个命令之间,这两个命令都是由MASTER发送的,中间应该是没有时间差的。
  • t4大小的影响因素:SLAVE2对M→S2读数据命令的反应时间
  • 过渡电平是485总线上没有数据时总线的默认电平,等于(Vh+Vl)/2,485的空闲是差分的所以应该是中间值同CAN与CANFD,TTL的空闲电平是逻辑高电平。
  • 图6中t1前面的信号为一帧数据,记为第1帧;t1后面的信号为一帧数据,记为第2帧。对于图5,t1后面t3前面,“2+t2+3”是第2帧;t1前面即“1”是第1帧。

在这里插入图片描述

图5 两包数据合为一包时序图

  使用示波器捕捉的“两包数据”合为一帧的波形如图6所示,此时示波器的时间刻度是2.5ms(没拍好所以看不清楚了)。串口的波特率是9600,单片机经过芯片ADM2682将TTL电平转化为485电平,因为只是电平的转换,所以转换后的485信号的波特率依旧是9600,所以发送一位需要的时间是1s/9600。对于串口除了设置波特率外,我们还要设置停止位(1)、数据位(8)、奇偶校验位(无),所以发送一个字节需要 t Byte = ( 1 s / 9600 ) ⋅ 9 = 0.9375 m s t_{\text {Byte}}=(1 s / 9600) \cdot 9=0.9375 \mathrm{ms} tByte=(1s/9600)9=0.9375ms,所以要区分开来两帧数据如第1帧和第2帧,那么两帧数据之间过渡电平的持续时间t1应该大于 t Byte t_{\text {Byte}} tByte,这样才能识别为两帧数据;按照这个来发送一位数据需要时间 t bit = ( 1 s / 9600 ) = 0.1042 m s t_{\text {bit}}=(1 s / 9600)=0.1042 \mathrm{ms} tbit=(1s/9600)=0.1042ms,怎么区分是两个字节数据(查资料后补充)。
  使用下面的代码测试串口在一包数据出现多久可以以触发IDLE中断,测试的结果如图7所示。代码示例如下,可以发现一包数据需要等待1ms的时间才会触发IDLE中断,后面可以通过改变波特率验证,波特率越高,等待时间越小
  在MODBUS通信协议帧数据之间的停顿间隔**“3.5字符”定义:MODBUS通讯规定主机发送完一组命令必须间隔3.5个字符再发送下一组新命令,这个3.5字符主要用来告诉其他设备这次命令已经结束,3.5个字符的定义在波特率为9600的情况下,只要大于4.01ms即可,计算方法同上,只不过发送一个字节按照最大时间来计算所以发送一个字节需要 t Byte = ( 1 s / 9600 ) ⋅ 11 = 1.1458333 m s t_{\text {Byte}}=(1 s / 9600) \cdot 11=1.1458333 \mathrm{ms} tByte=(1s/9600)11=1.1458333ms,即停止位2、数据位8、有奇/偶检验一共11位**。

void USART1_IRQHandler(void)
{
	if(USART_GetFlagStatus(USART1,USART_FLAG_IDLE)!=Bit_RESET)//如果接收到1帧数据
	{
       	PA10_High();//拉高GPIO PA10
        clear=USART1->SR;//读SR寄存器
        clear=USART1->DR;//读DR寄存器(先读SR寄存器再读DR,就是为了清除IDLE中断)						
		PA10_Low();//拉低GPIO PA10
    }	
} 
图6 示波器捕捉的两帧数据合为一帧
图7 发送一包数据多久可以触发IDLE中断

  根据两包数据合为一包数据的原因,推测三包数据合为一包数据的485总线上的时序图如图8所示,因为没有捕捉到波形,所以这里只是猜测,没有得到验证,后续想办法模拟验证吧。推测是t2和t3太短,导致S1→M回数据M→S1清零M→S2读数据这三帧数据合并为了一帧数据。因为SLAVE设备是使用帧中断进行接收的,所以t1=t4> t Byte t{\text {Byte}} tByte即反应比较慢,他们回数据信号不会和前面的读数据信号混到一起成为一帧数据,即1和2是不会混为一帧数据,4和5不会混为一帧数据,只有使用字节中断的会导致反应比较快如t2< t Byte t{\text {Byte}} tByte,即2+3+4合为了一帧数据。

在这里插入图片描述

图8 假设的三包数据合为一包时序图

2.2 项目总结思考

  因为不知道对方MASTER设备的接收中断方式使用的是帧中断还是字节中断,所以提前确认好对方设备或者说项目中的测试设备及对接设备的通信具体形式等细节是十分有必要的,否则单独测试时双方都是OK的,等到联调的时候就会出现一些玄学的BUG。
  我们要做到首先遇到BUG不要慌,BUG不会凭空产生,而是许多关键事件的连锁反应。其次判断BUG是人为失误还是设计有瑕疵,就需要我们去剖析那些BUG的细节,寻找线索。
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32串口:字节中断与帧中断不同导致的BUG 的相关文章

  • 2023华为od机试C++ 目录与考试说明(B卷+A卷)

    本专栏使用C 语言解题 常见问题 1 进入机考网页之后如果链接上写着 B卷 就表示是B卷题库 对应着目录中的时间这一列 2023Q2 在2023年5月10日之后 大多数同学收到的应该是B卷题库 2 2022年的题库已经废弃 如果时间紧迫 建

随机推荐

  • 程序员自曝接私活:10个月时间接了30多个单子,纯收入40万

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 随着互联网的发展 对于程序员的需求也日益增多 一些程序员在按部就班的同时 也会在外接一些私活增加收入 无独有偶 有一名程序员无意间发现了商机 开始了全职接私活 在10个月时
  • oVirt:数据中心的开源虚拟化

    oVirt 数据中心的开源虚拟化 通过标记 发布 2019年1月30日 更新 2019年2月27日 oVirt是基于Linux Libvirt和KVM的完整的开源虚拟化解决方案 它旨在成为VMware vSphere的替代产品 让我们看看它
  • PyTorch深度学习实践概论笔记8练习-kaggle的Titanic数据集预测(一)数据分析

    刘老师在第8讲PyTorch深度学习实践概论笔记8 加载数据集中留下一个练习 对kaggle上的Titanic数据集 使用DataLoader类进行分类 训练目标是预测某位乘客是否活下来 Survived 本篇文章先读取数据和做一些简单的数
  • QT编译安装QtMqtt子模块,WIN平台

    QT安装QtMqtt子模块 下载源代码编译 添加库文件到QT安装目录 测试工程 最终效果 2021 10 15 补充 将配置文件添加到安装目录 完整文件下载 系统 Windows10 环境 QT5 12 9 下载源代码编译 GitHub上下
  • 【Qt Quick】Android环境配置及第一个Hello World

    Android环境配置及第一个Hello World 安装Java jdk 安装Android studio 安装手机模拟器 配置Qt 第一个Hello World 常见错误 安装Java jdk 1 下载 链接 link Java1 8
  • Java数据库开发之Hibernate框架(4)Hibernate的查询

    占位 下周补充
  • kettle定时调度

    简单版 https blog csdn net hzp666 article details 107841754 详细版 1 场景介绍 根据不同的操作系统定时调度kettle资源库中的job 1 1Windows系统的定时调度 我的是 ve
  • 网络IO模型

    网络IO的本质是对socket的读取 在网络IO的过程中 有两个重要角色 分别是系统内核和用户进程 首先要等系统内核准备好数据 然后将数据从系统内核拷贝至用户进程空间 这样才算完成了一次IO 如果在系统内核没有准备好数据时 用户IO线程在此
  • Gimpel Software推出C和C ++的首选静态分析工具 PC-lint Plus,不再维护PC-lint/FlexeLint。

    Gimpel Software已不再维护PC lint FlexeLint版本9 最终更新是2014年发布的版本9 00L Gimpel Software在2018年底之前为PC lint FlexeLint提供技术支持 Gimpel So
  • Qt头文件中的QT_BEGIN_NAMESPACE

    在源代码中是这样定义的 1 define QT BEGIN NAMESPACE namespace QT NAMESPACE 2 define QT END NAMESPACE 也就是说 如果你定义以下内容 1 QT BEGIN NAMES
  • 数据结构-链式队列

    link queue node h ifndef LINK QUEUE NODE H define LINK QUEUE NODE H include
  • 串口通信协议概述——针对面试

    串口通信 串口通信 Serial Communications 的概念非常简单 串口按位 bit 发送和接收字节的通信方式 重要参数 1 数据位 2 停止位 3 奇偶校验位 4 波特率 其中 数据位 停止位 奇偶校验位又是数据格式 数据格式
  • PyWebIo

    Part1什么是 PyWebIo PyWebIO 提供了一系列命令式的交互函数来在浏览器上获取用户输入和进行输出 将浏览器变成了一个 富文本终端 可以用于构建简单的 Web 应用或基于浏览器的 GUI 应用 使用 PyWebIO 开发者能像
  • 数据库项目代码生成工具V1.18.08.18.0(RIO)

    下载 1 第一步 2 第二步 3 第三步 结果
  • ios10.3之CoreData的详细教程

    首先如果要使用CoreData可以选择在初创项目时选择添加coredata 也可以选择自己添加coredata文件 系统添加coredata后会在Appdelegate类中自动添加一个persistentContainer属性 和一个sav
  • 苹果系统与win10连接到服务器,苹果手机怎么连接win10电脑详细步骤

    使用苹果手机的朋友们你们知道苹果手机如何连接win10电脑吗 不知道的就往下看看怎么操作吧 说不定以后你可能就会用到这个方法 1 用苹果手机正品数据线连接到电脑上的 USB 端口 电脑系统会自动识别出苹果手机的内部存储器 内部存储器包括包括
  • Ai-Bot RPA自动化框架

    Ai Bot是Android Windows平台上的node js自动化框架 1 跟python的区别 跟uipaht uibot 其他框架的区别 1 VS python 相同点 Ai Bot基于node js语言的一款自动化框架 和pyt
  • 关于网络连接Network的使用

    开发一个局域网连接 代码 using UnityEngine using System Collections public class all MonoBehaviour private int serverPort public int
  • Python模拟超级大乐透随机选号

    看了一下体彩超级大乐透规则 前区号码由01 35共三十五个号码组成 后区号码由01 12共十二个号码组成 由此可以使用random模拟体彩超级大乐透随机选号 import random import time class Lottery 一
  • STM32串口:字节中断与帧中断不同导致的BUG

    文章目录 一 问题背景 1 1 硬件连接框图 1 2 玄学的BUG 1 3 帧中断触发条件 1 4 字节中断触发条件 二 解决问题 2 1 复现BUG 一个帧中断 2包数据 2 2 项目总结思考 在使用STM32F207这一款单片机调试串口