stm32 网口 串口模块通信丢帧、死机问题的解决

7 篇文章 0 订阅
2 篇文章 0 订阅

首先描述问题,是我一同事而非我本人遇到的,公司让我协助他查找问题。

客户是卫通地面站,主控电脑使用的是麒麟系统,通过UDP和我们的设备进行网络通信,客户每间隔一秒钟发送一次状态查询指令,一天的时间内会出现3到5次设备不响应指令的状态,客户判定为丢帧。通过查看客户的通讯日志,发现不响应的时间竟然差不多都是40秒钟以上,40秒后恢复了响应。

情况诡异。一开始同事怀疑是网口模块的问题,毕竟客户那里发的比较频繁,有可能说是模块收发的数据太多,导致了硬件异常,模块接收发送失败。还有某研究所的一哥们提醒说他觉得moxa的网口模块和麒麟系统不兼容,容易出问题。。。对这样的提议我表示怀疑,首先moxa的网口芯片肯定都是经过大量的测试的,不会说有问题就生产销售了。对麒麟的操作系统我虽然不了解但是我知道你网络通信出了你的网关就和你本身没关系了,跟你接什么样子的网口模块还有关系,真是让人不禁莞尔。

对未知故障的猜测人们往往会向对自己有利,与自己无关的一方面想,这是人的弱点也是本性但是抱着胡乱猜疑的态度去撇清自己的关系,实在不是科研人员的素养。

继续进行问题分析,我找了一块板子进行测试用,用网口助手给板子发数据,时间是1s发一次,短时间内并没有看到什么异常现象,于是加快发送的速度,改为500ms发一次,现象暴露了,出现了丢帧问题,一分钟的时间内都丢了几帧,这个丢帧率也是真的太高了吧。但是并没有出现客户所说的连续四十秒无响应的问题。

那么首先查找这个丢帧的问题吧。其实问题很隐蔽,所以在我调快发送速度的时候也就很容易出现了。

我同事他在中断里接收数据,收到数据后计数变量index增加,当接收数据为帧尾标志的时候(0x7E),便会产生一个标志位,一帧的长度最短在24个字节。他在主程序里判断到这个标志位后呢,便把index变量清零。

这样的操作方式在低频率通信时一点问题也没有,但是当通信数据增多,这样带来的问题就是,当接收完一帧数据后,主程序里还没来得及判断,又来了数据,index在之前的基础上自增,这样这一帧数据他看第【0】字节不是帧头,第【23】字节不是帧尾,帧头不对帧尾也不对就不做反应,直到index大于缓存区长度64后,再清零。

为了解决这个问题,我让他开辟了一个FIFO,数据来了,先存进FIFO了,这样不管来多少帧数据,主程序里都能一一判断到,无非是实时性不好,但是不会丢帧。

这个问题解决了,那么客户反应的40多秒无响应是怎么回事呢?

其实在找第一个bug的过程中,我就发现了一些端倪,就是每次我给板子重启,网口模块一般在30s左右的时候才能正常接收到数据并能够发送,于是我不得不猜测,是什么问题导致了网口模块发生了硬件故障从而重启了么?是第一个BUG引起了网口模块硬件异常从而重启了吗?未必不可能,但有些牵强,因为在上面的测试过程中我确实没有遇见过客户说的现象,也即网口模块重启的现象。而且时间似乎也并不能够对的上。

阴谋论的迷雾再次笼罩了我的大脑。会不会真的是客户那里有问题呢?这时候我们和客户进行了一次通话,客户说他们是两个线程在发数据,一个线程发查询状态,一个线程发控制命令。我问,如果两个发送命令撞帧了呢,会产生什么后果吗?

客户思考了一会说,有可能,但我们站上其他厂商的设备没有出现问题,我还很忙,先挂了。

大写的尴尬。冷静下来思考一下,从TCP/IP协议的多层结构开看,从一个电脑出来的数据,即便是两个线程发,协议栈也不会把两个数据揉在一起,因为网络协议栈只有一个,一个线程在发的时候另一个一定会阻塞。不可能两个同时调用,因此从技术层面来说撞帧实现不了。

此时怀疑是stm32产生了硬件异常,进入了中断,从而导致了看门狗超时让设备重启,这样的话,时间就能够对的上了。

那就在所有可能出现硬件异常中断的地方打上断点。然而让程序运行了一段时间后就是不见进硬件异常中断。

再次压力测试,加快发送数据的频率,我提高到了每100ms发送一帧查询指令。一个不经意间一看,竟然出现了只发不回的情况!我激动的看程序的调试界面,赶紧在数据接收这里打了一个断点,咦,这数据也正在接收啊,那就很匪夷所思了:

1. 程序没有进入异常中断,证明不是看门狗引起的硬件异常从而导致重启;

2. 在出现问题后我赶紧用cmd去ping板子,发现一开始能ping通,但是过一会就故障了,然后又能ping通;

2. 程序能够接收到,但是好像没有发出来,还没等我去查为啥没发的原因,网口已经恢复正常了。又开始发了(40s时间过去了)

好不容易复现的现象稍纵即逝。怀疑是不是网口模块出现故障,只能收不能发,然后自己重启了呢?

我又陷入了不断的自我怀疑和相互怀疑之中。

“再加点压力!”我想。我直接把发送时间改成了5ms一次,结果现象非常容易复现了,这时候打断点,发现了根本问题:

网口模块根本没有重启,是单片机的重启带动了网口模块的复位,而且单片机也根本没有进入异常中断,而是说不断地进入了一个中断!

不断进入中断的原因被我发现了,第一个判断条件根本就没有通过,原因是定时器竟然是DISABLE的?

同事在接收到帧头数据的时候关闭了定时器2,(可能是想接收数据不被打断...)即调用了STOP_TIME这个宏;

但是关定时器的操作有点迷:

#define START_TIME  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);TIM_Cmd(TIM2, ENABLE)
#define STOP_TIME   TIM_Cmd(TIM2, DISABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , DISABLE)

使能/失能定时器的时候,干嘛还给RCC时钟树使能/失能呢?这样导致的问题就是,我在执行START_TIME时,被STOP_TIME中断,导致时钟树是关闭的,但定时是开启的,开启定时产生了计时,溢出后产生中断,但是被判断定时器是失能 的,这就导致中断清除不掉 ,但是串口又能接收数据(串口优先级比定时器高),同时看门狗一直喂不了狗,导致重启。。。。

问题找到后,同事去给客户重新烧录了程序,经过了一天的观察,问题再也没有复现,悬着的心终于落下了...

  • 14
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
STM32作为一款功能强大的微控制器,可以通过串口与4G模块进行通信。下面我将阐述如何实现STM32与4G模块串口通信。 首先,我们需要连接STM32和4G模块串口引脚。通常情况下,STM32会有多个串口可供使用,我们需要选择其中一个串口的引脚进行连接。通常,将4G模块的RX(接)引脚连接到STM32的TX(送)引脚,同时将4G模块的TX引脚连接到STM32的RX引脚。此外,还需要将两者的地线(GND)相连。 接下来,我们需要在STM32的代码中配置串口通信。首先,我们需要初始化所选串口,设置通信参数,如波特率、数据位、停止位和校验位等。然后,通过使用STM32提供的串口相关函数,我们可以送和接数据。例如,使用串口送函数可以向4G模块送AT指令,而使用串口函数可以接4G模块返回的响应。 需要注意的是,由于串口通信是一种异步通信协议,送方和接方之间需要使用相同的通信参数来进行正确的数据传输。在配置串口参数时,请务必确保STM32和4G模块使用相同的波特率、数据位、停止位和校验位等。 在实际应用中,我们可以使用STM32的定时器和中断功能来实现更稳定和高效的串口通信。例如,我们可以使用定时器中断来定时送和接数据,以确保数据传输的准确性和时效性。 综上所述,通过合理连接串口引脚并正确配置串口通信参数,我们可以实现STM32与4G模块之间的串口通信。这种通信方式可以让STM32与4G模块进行数据交互,从而实现更多功能和应用场景。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值