这是我前几天遇到的bug,RS485协议程序我已经做过无数次了,有无数个成功的先例。当开始做这个小程序的时候,我认为对我而言这只是小菜一碟,我挥挥手就可以把它搞定。
但是事情出乎我的意料,程序工作不正常!
先把有bug的代码贴出来:(代码很长,如果看起来眼睛脑壳痛,请直接跳过源代码,看后面的文字说明就好了,贴出代码是为了让人能感受到debug有时候是一件让人多么痛苦的事情)
第一个函数void RS485_Poll(void)是用来解析数据包的,第二个函数static void CommandHandle(void)是用来处理数据包里面的命令的。
当我用串口工具向mcu发送控制命令的时候,总是第一个命令可以正常响应,随后的命令都不能正常响应。反复检查源代码,没有发现错误。这种代码我编写过无数此了,我想即使首次运行能不能通过,我也能极快找出bug,半小时之内一定能拿下这段代码的调试。好久没有遇到过让人头痛的bug了,我以为这个bug三五分钟也可以搞定。
我带着满满的信心,查看源代码。第一遍,看不出问题原因出自哪里。第二遍,更仔细的看,还是看不出来。第三、第四、第五......还是看不出来。
怎么办呢?一下子有点束手无策,我应该怎么办才能定位bug在哪里?
是不是数据包接收出错了?最有可能出错的就是crc校验吧?带着这个疑问,我注释掉void RS485_Poll(void)函数中对CommandHandle()函数的调用,并且在CommandHandle()函数原来的地方插入BSP_ToggleLed()。发现数据包接收没有任何错误。
到这里,又开始觉得束手无策了!
经过许久的煎熬后,不知道什么原因,我认为可以试试把应答数据包的代码注释掉再看看有没有什么线索。想到了就干,立马注释掉tatic void CommandHandle(void)中发送应答数据包对应的代码,再测试发现每次发送命令都可以正常执行了!如获至宝!我想应该离成功不远了,心情瞬间愉快了许多。
再逐行减少注释代码的函数,最后发现问题“位于”下面一行代码:
s_u8InPack[PROTOCOL_STATE_CMD_L] = 0xE1;
// 注释掉此行后,可以连续接收命令
根据以往的调试经验,一旦定位了错误在哪一行,改正这一行里面的错误,debug就通过。
可是翻来覆去的看这一行代码,却看不出一丁点的问题来!
调试再次进入胶着状态,漫长的调试让我的大脑极度疲劳,我感觉思维已经停止了,头脑一片空白,就这样束手无策了N久,才想到试试把接收到的数据包原封不动的返回到串口助手,看看能不能发现这行代码是如何影响程序的正确执行的。
想到就干,void RS485_Poll(void)函数中对调用函数CommandHandle()之后插入如下返回接收到的数据包的代码:
- for(i = 0;i < pack_len;i++)
- {
- Bsp_uart_send_byte(s_u8InPack[i]);
- }
发现第一次返回的数据包和串口助手发出的数据包相同,随后返回的数据包的s_u8InPack[PROTOCOL_STATE_CMD_L] 错误。
再次查看,void RS485_Poll(void)函数中写入s_u8InPack[PROTOCOL_STATE_CMD_L]那一行语句:
- case PROTOCOL_STATE_CMD_L:
- s_u8InPack[index++] |= byte;
- s_u16Command |= byte;
- s_ProtocolState = PROTOCOL_STATE_DST_NET;
- break;
发现代码录入出错了!正确的代码应该是“s_u8InPack[index++] = byte;”但错写成了“s_u8InPack[index++] |= byte;”至此终于找到了问题的“根源”!
|= 与=之间的差别再加上调试过程中一些凑巧,产生了bug位于其他代码段的假象,从而导致了一个初看起来让人无比困惑的bug!为了找出这个bug,我从中午11点开始,午休也不休息,直忙到下午两点。
这真的是挺折磨人的,要不是对编程有浓厚的兴趣,我想肯定无法正确找到原因。这个过程虽然折磨人,但是对困难的挑战,和挑战成功,却让人从中找到莫名的满足感。回顾整个过程,又觉得饶有趣味。
其中有两点很值得深思:如何才能避免类似的录入错误,如何才能更快速的定位类似的错误?
海州.王 2020-12-31 09:30
Qeecoda 2020-7-6 08:46
追忆流年寻梦少年 2020-6-30 13:34
但对于解决问题、发现bug,过程可以优化,一般串口调试的第一步就是原发原收,或者是自发自收,看发送、接收情况,这样子就可以快速定位收端代码异常;然后根据收端的数据,再进一步设计发送0000,1111,1234等,根据接收数据异常分析,再进一步定位代码。
当然,这一般都是事后的总结,发现前面浪费了时间,可以优化的。
Qeecoda 2020-6-20 13:40
Qeecoda 2020-6-20 13:39
allen_zhan 2020-6-19 17:10
这种代码移植, 工程师拿手的是 copy - paste.
Qeecoda 2020-6-16 21:04
Qeecoda 2020-6-16 21:02
Qeecoda 2020-6-16 21:00
用户1515636 2020-6-15 19:35