原创 一个让人头痛而又有趣的软件bug

2020-6-11 22:56 13265 90 14 分类: MCU/ 嵌入式 文集: C语言
这是我前几天遇到的bug,RS485协议程序我已经做过无数次了,有无数个成功的先例。当开始做这个小程序的时候,我认为对我而言这只是小菜一碟,我挥挥手就可以把它搞定。
但是事情出乎我的意料,程序工作不正常!
先把有bug的代码贴出来:(代码很长,如果看起来眼睛脑壳痛,请直接跳过源代码,看后面的文字说明就好了,贴出代码是为了让人能感受到debug有时候是一件让人多么痛苦的事情)
void RS485_Poll(void)
  • {
  • uint8_t byte;
  • static uint8_t index = 0,len = 0;
  • static uint16_t check;
  • uint8_t i;
  • if(!BSP_RxFifoOut(&byte))
  • {
  • if(s_u8BusIdleFlag == 1)
  • {
  • if((s_u8RetryCount > 0) && (s_u16DelaySendPack_Timer_1ms == 0))
  • {
  • s_u8CollisionDetecting = 1;
  • s_u8DataVerifyIndex = 0;
  • len = s_u8OutPack[PROTOCOL_STATE_LEN] + 2;
  • for(i = 0;i < len;i++)
  • {
  • BSP_USART1Tx(s_u8OutPack[i]);
  • }
  • s_u8BusIdleFlag = 0;
  • s_u8Tick_64us = 32;
  • }
  • }
  • }
  • else
  • {
  • s_u8BusIdleFlag = 0;
  • s_u8Tick_64us = 32;
  • if(s_u8CollisionDetecting == 1)
  • {
  • if(byte == s_u8OutPack[s_u8DataVerifyIndex++])
  • {
  • if(s_u8DataVerifyIndex == s_u8OutPack[PROTOCOL_STATE_LEN] + 2)
  • {
  • s_u8CollisionDetecting = 0;
  • s_u8RetryCount = 0;
  • }
  • }
  • else
  • {
  • s_u8CollisionDetecting = 0;
  • if(s_u8RetryCount > 0)
  • {
  • s_u8RetryCount--;
  • s_u16DelaySendPack_Timer_1ms = GetPeseudoRandom();
  • }
  • }
  • }
  • else
  • {
  • switch(s_ProtocolState)
  • {
  • case PROTOCOL_STATE_HEAD0:
  • if(byte == 0xAA)
  • {
  • s_ProtocolState = PROTOCOL_STATE_HEAD1;
  • s_u8Reset_Timer_1ms = 0;
  • index = 0;
  • s_u8InPack[index++] = byte;
  • }
  • break;
  • case PROTOCOL_STATE_HEAD1:
  • if(byte == 0xAA)
  • {
  • s_ProtocolState = PROTOCOL_STATE_LEN;
  • s_u8InPack[index++] = byte;
  • }
  • else
  • {
  • s_ProtocolState = PROTOCOL_STATE_HEAD0;
  • }
  • break;
  • case PROTOCOL_STATE_LEN:
  • s_u8InPack[index++] = byte;
  • len = byte;
  • if((len <= (MAX_PACK_LEN - 2))
  • && (len >= (MIN_PACK_LEN - 2)))
  • {
  • s_ProtocolState = PROTOCOL_STATE_SRC_NET;
  • }
  • else
  • {
  • s_ProtocolState = PROTOCOL_STATE_HEAD0;
  • }
  • break;
  • case PROTOCOL_STATE_SRC_NET:
  • s_u8InPack[index++] = byte;
  • s_u8SrcNet = byte;
  • s_ProtocolState = PROTOCOL_STATE_SRC_DEV;
  • break;
  • case PROTOCOL_STATE_SRC_DEV:
  • s_u8InPack[index++] = byte;
  • s_u8SrcDev = byte;
  • s_ProtocolState = PROTOCOL_STATE_SRC_TYPE_H;
  • break;
  • case PROTOCOL_STATE_SRC_TYPE_H:
  • s_u8InPack[index++] = byte;
  • s_u16SrcType = ((uint16_t)byte)<<8;
  • s_ProtocolState = PROTOCOL_STATE_SRC_TYPE_L;
  • break;
  • case PROTOCOL_STATE_SRC_TYPE_L:
  • s_u8InPack[index++] = byte;
  • s_u16SrcType |= byte;
  • s_ProtocolState = PROTOCOL_STATE_CMD_H;
  • break;
  • case PROTOCOL_STATE_CMD_H:
  • s_u8InPack[index++] = byte;
  • s_u16Command = ((uint16_t)byte)<<8;
  • s_ProtocolState = PROTOCOL_STATE_CMD_L;
  • break;
  • case PROTOCOL_STATE_CMD_L:
  • s_u8InPack[index++] |= byte;
  • s_u16Command |= byte;
  • s_ProtocolState = PROTOCOL_STATE_DST_NET;
  • break;
  • case PROTOCOL_STATE_DST_NET:
  • s_u8InPack[index++] = byte;
  • s_u8DstNet = byte;
  • s_ProtocolState = PROTOCOL_STATE_DST_DEV;
  • break;
  • case PROTOCOL_STATE_DST_DEV:
  • s_u8InPack[index++] = byte;
  • s_u8DstDev = byte;
  • if(len > MIN_PACK_LEN)
  • {
  • s_ProtocolState = PROTOCOL_STATE_DAT;
  • }
  • else
  • {
  • s_ProtocolState = PROTOCOL_STATE_CRC_H;
  • }
  • break;
  • case PROTOCOL_STATE_DAT:
  • s_u8InPack[index++] = byte;
  • if(index >= len)
  • {
  • s_ProtocolState = PROTOCOL_STATE_CRC_H;
  • }
  • break;
  • case PROTOCOL_STATE_CRC_H:
  • s_u8InPack[index++] = byte;
  • check = ((uint16_t)byte)<<8;
  • s_ProtocolState = PROTOCOL_STATE_CRC_L;
  • break;
  • case PROTOCOL_STATE_CRC_L:
  • s_u8InPack[index++] = byte;
  • check |= byte;
  • if(check == CalcCRC16(s_u8InPack + 2,len - 2))
  • {
  • CommandHandle();
  • }
  • s_ProtocolState = PROTOCOL_STATE_HEAD0;
  • break;
  • default:
  • break;
  • }
  • }
  • }
  • }
  • static void CommandHandle(void)
  • {
  • if(((s_u8DstNet == s_u8LocalNet) && (s_u8DstDev == s_u8LocalDev))
  • || ((s_u8DstNet == 0xff) && (s_u8DstDev == 0xff)))
  • {
  • if(s_u16Command == 0xE3E0)
  • {
  • if((((s_u8InPack[PROTOCOL_STATE_DAT + 2] == 0) || (s_u8InPack[PROTOCOL_STATE_LEN] == 13))
  • &&(s_u8InPack[PROTOCOL_STATE_DAT] < 0x11))
  • || (s_u8InPack[PROTOCOL_STATE_DAT + 2] == 1))
  • {
  • if(s_u8InPack[PROTOCOL_STATE_DAT + 1] == 0)
  • {
  • Message_FifoIn(MSG_SERIAL_STOP);
  • }
  • else if(s_u8InPack[PROTOCOL_STATE_DAT + 1] == 1)
  • {
  • Message_FifoIn(MSG_SERIAL_OPEN);
  • }
  • else if(s_u8InPack[PROTOCOL_STATE_DAT + 1] == 2)
  • {
  • Message_FifoIn(MSG_SERIAL_CLOSE);
  • }
  • }
  • else if((((s_u8InPack[PROTOCOL_STATE_DAT + 2] == 0) || (s_u8InPack[PROTOCOL_STATE_LEN] == 13))
  • &&(s_u8InPack[PROTOCOL_STATE_DAT] >= 0x11))
  • || (s_u8InPack[PROTOCOL_STATE_DAT + 2] == 2))
  • {
  • if(s_u8InPack[PROTOCOL_STATE_DAT + 1] <= 0)
  • {
  • s_u8TargetPercent = s_u8InPack[PROTOCOL_STATE_DAT + 1];
  • Message_FifoIn(MSG_SERIAL_TP);
  • }
  • }
  • if(!((s_u8LocalNet == 0xff) && (s_u8LocalDev == 0xff)))
  • {
  • s_u8InPack[PROTOCOL_STATE_CMD_H] = 0xE3;
  • s_u8InPack[PROTOCOL_STATE_CMD_L] = 0xE1; // 注释掉此行后,可以连续接收命令
  • BuildInPack();
  • SendInPack();
  • }
  • }
  • else if(s_u16Command == 0xE3E2)
  • {
  • if((((s_u8InPack[PROTOCOL_STATE_DAT + 2] == 0) || (s_u8InPack[PROTOCOL_STATE_LEN] == 13))
  • &&(s_u8InPack[PROTOCOL_STATE_DAT] < 0x11))
  • || (s_u8InPack[PROTOCOL_STATE_DAT + 2] == 1))
  • {
  • s_u8InPack[PROTOCOL_STATE_DAT + 1] = GetCurtainControlState();
  • }
  • else if((((s_u8InPack[PROTOCOL_STATE_DAT + 2] == 0) || (s_u8InPack[PROTOCOL_STATE_LEN] == 13))
  • &&(s_u8InPack[PROTOCOL_STATE_DAT] >= 0x11))
  • || (s_u8InPack[PROTOCOL_STATE_DAT + 2] == 2))
  • {
  • s_u8InPack[PROTOCOL_STATE_DAT + 1] = Curtain_GetPercent();
  • }
  • if(!((s_u8LocalNet == 0xff) && (s_u8LocalDev == 0xff)))
  • {
  • s_u8InPack[PROTOCOL_STATE_CMD_H] = 0xE3;
  • s_u8InPack[PROTOCOL_STATE_CMD_L] = 0xE3;
  • BuildInPack();
  • SendInPack();
  • }
  • }
  • else if(s_u16Command == 0xF001)
  • {
  • if(CurtainController_IsProgState())
  • {
  • uint8_t i;
  • for(i = 0;i < 8;i++)
  • {
  • s_u8Mac[i] = s_u8InPack[PROTOCOL_STATE_DAT + i];
  • eeprom_write_byte(EEPROM_HDL_MAC + i,s_u8Mac[i]);
  • }
  • s_u8InPack[PROTOCOL_STATE_DAT] = 0xF8;
  • Message_FifoIn(MSG_SERIAL_LEAVE_LEARN);
  • }
  • else
  • {
  • s_u8InPack[PROTOCOL_STATE_DAT] = 0xF5;
  • }
  • s_u8InPack[PROTOCOL_STATE_LEN] = 12;
  • s_u8InPack[PROTOCOL_STATE_CMD_H] = 0xF0;
  • s_u8InPack[PROTOCOL_STATE_CMD_L] = 0x02;
  • BuildInPack();
  • SendInPack();
  • }
  • else if(s_u16Command == 0xF003)
  • {
  • uint8_t i;
  • for(i = 0;i < 8;i++)
  • {
  • s_u8InPack[PROTOCOL_STATE_DAT + i] = s_u8Mac[i];
  • }
  • s_u8InPack[PROTOCOL_STATE_DAT + i++] = s_u8LocalNet;
  • s_u8InPack[PROTOCOL_STATE_DAT + i++] = s_u8LocalDev;
  • s_u8InPack[PROTOCOL_STATE_DAT + i++] = 0x02;
  • s_u8InPack[PROTOCOL_STATE_DAT + i++] = 0xC1;
  • s_u8InPack[PROTOCOL_STATE_LEN] = 23;
  • s_u8InPack[PROTOCOL_STATE_CMD_H] = 0xF0;
  • s_u8InPack[PROTOCOL_STATE_CMD_L] = 0x04;
  • BuildInPack();
  • SendInPack();
  • }
  • else if(s_u16Command == 0x000E)
  • {
  • uint8_t i;
  • for(i = 0;i < 20;i++)
  • {
  • s_u8InPack[PROTOCOL_STATE_DAT + i] = s_u8Remark[i];
  • }
  • s_u8InPack[PROTOCOL_STATE_LEN] = 31;
  • s_u8InPack[PROTOCOL_STATE_CMD_H] = 0x00;
  • s_u8InPack[PROTOCOL_STATE_CMD_L] = 0x0F;
  • BuildInPack();
  • SendInPack();
  • }
  • else if(s_u16Command == 0x0010)
  • {
  • if((s_u8LocalNet == s_u8InPack[PROTOCOL_STATE_DST_NET]) && (s_u8LocalDev == s_u8InPack[PROTOCOL_STATE_DST_DEV]))
  • {
  • uint8_t i;
  • for(i = 0;i < 20;i++)
  • {
  • s_u8Remark[i] = s_u8InPack[PROTOCOL_STATE_DAT + i];
  • eeprom_write_byte(EEPROM_HDL_REMARK + i,s_u8Mac[i]);
  • }
  • s_u8InPack[PROTOCOL_STATE_LEN] = 12;
  • s_u8InPack[PROTOCOL_STATE_CMD_H] = 0x00;
  • s_u8InPack[PROTOCOL_STATE_CMD_L] = 0x11;
  • BuildInPack();
  • SendInPack();
  • }
  • }
  • else if(s_u16Command == 0xE5F5)
  • {
  • if(CurtainController_IsProgState())
  • {
  • s_u8InPack[PROTOCOL_STATE_DAT + 0] = s_u8LocalNet;
  • s_u8InPack[PROTOCOL_STATE_DAT + 1] = s_u8LocalDev;
  • s_u8InPack[PROTOCOL_STATE_LEN] = 13;
  • s_u8InPack[PROTOCOL_STATE_CMD_H] = 0xE5;
  • s_u8InPack[PROTOCOL_STATE_CMD_L] = 0xF6;
  • BuildInPack();
  • SendInPack();
  • Message_FifoIn(MSG_SERIAL_LEAVE_LEARN);
  • }
  • }
  • else if(s_u16Command == 0xE5F7)
  • {
  • if(CurtainController_IsProgState())
  • {
  • s_u8LocalNet = s_u8InPack[PROTOCOL_STATE_DAT + 0];
  • s_u8LocalDev = s_u8InPack[PROTOCOL_STATE_DAT + 1];
  • eeprom_write_byte(EEPROM_HDL_NET,s_u8LocalNet);
  • eeprom_write_byte(EEPROM_HDL_DEV,s_u8LocalDev);
  • s_u8InPack[PROTOCOL_STATE_LEN] = 13;
  • s_u8InPack[PROTOCOL_STATE_CMD_H] = 0xE5;
  • s_u8InPack[PROTOCOL_STATE_CMD_L] = 0xF8;
  • BuildInPack();
  • SendInPack();
  • Message_FifoIn(MSG_SERIAL_LEAVE_LEARN);
  • }
  • }
  • else if(s_u16Command == 0xE8F8)
  • {
  • if(CurtainController_IsProgState())
  • {
  • /* s_u8InPack[PROTOCOL_STATE_DAT] = 0xF8;
  • s_u8InPack[PROTOCOL_STATE_LEN] = 12;
  • s_u8InPack[PROTOCOL_STATE_CMD_H] = 0xE8;
  • s_u8InPack[PROTOCOL_STATE_CMD_L] = 0xF9;
  • BuildInPack();
  • SendInPack(); */
  • eeprom_write_byte(EEPROM_PROTOCOL_TYPE,PROTOCOL_TYPE_RAEX_485);
  • SerialProtocol_init();
  • Message_FifoIn(MSG_SERIAL_LEAVE_LEARN);
  • }
  • }
  • else if(s_u16Command == 0xFE05)
  • {
  • uint8_t i;
  • uint8_t flag = 1;
  • for(i = 0;i < 8;i++)
  • {
  • if(s_u8InPack[PROTOCOL_STATE_DAT + i] != s_u8Mac[i])
  • {
  • flag = 0;
  • }
  • }
  • if(flag == 1)
  • {
  • s_u8InPack[PROTOCOL_STATE_LEN] = 12;
  • s_u8InPack[PROTOCOL_STATE_CMD_H] = 0xFE;
  • s_u8InPack[PROTOCOL_STATE_CMD_L] = 0x06;
  • s_u8InPack[PROTOCOL_STATE_DAT] = 0xF8;
  • BuildInPack();
  • SendInPack();
  • }
  • }
  • else if(s_u16Command == 0xF005)
  • {
  • uint8_t i;
  • uint8_t flag = 1;
  • for(i = 0;i < 8;i++)
  • {
  • if(s_u8InPack[PROTOCOL_STATE_DAT + i] != s_u8Mac[i])
  • {
  • flag = 0;
  • }
  • }
  • if(flag == 1)
  • {
  • s_u8LocalNet = s_u8InPack[PROTOCOL_STATE_DAT + 8];
  • s_u8LocalDev = s_u8InPack[PROTOCOL_STATE_DAT + 9];
  • eeprom_write_byte(EEPROM_HDL_NET,s_u8LocalNet);
  • eeprom_write_byte(EEPROM_HDL_DEV,s_u8LocalDev);
  • s_u8InPack[PROTOCOL_STATE_DAT] = 0xF8;
  • s_u8InPack[PROTOCOL_STATE_LEN] = 12;
  • s_u8InPack[PROTOCOL_STATE_CMD_H] = 0xF0;
  • s_u8InPack[PROTOCOL_STATE_CMD_L] = 0x06;
  • BuildInPack();
  • SendInPack();
  • }
  • }
  • }
  • }
  • 复制代码

    第一个函数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点开始,午休也不休息,直忙到下午两点。
    这真的是挺折磨人的,要不是对编程有浓厚的兴趣,我想肯定无法正确找到原因。这个过程虽然折磨人,但是对困难的挑战,和挑战成功,却让人从中找到莫名的满足感。回顾整个过程,又觉得饶有趣味。
    其中有两点很值得深思:如何才能避免类似的录入错误,如何才能更快速的定位类似的错误?

    作者: Qeecoda, 来源:面包板社区

    链接: https://mbb.eet-china.com/blog/uid-me-1099225.html

    版权声明:本文为博主原创,未经本人允许,禁止转载!

    PARTNER CONTENT

    文章评论16条评论)

    登录后参与讨论

    海州.王 2020-12-31 09:30

    很多if()else(),逻辑上面看得人头疼。

    Qeecoda 2020-7-6 08:46

    追忆流年寻梦少年: 这种问题是比较烦;
    但对于解决问题、发现bug,过程可以优化,一般串口调试的第一步就是原发原收,或者是自发自收,看发送、接收情况,这样子就可以快速定位收端 ...
    我也是认为要遵循类似的思路,如果推理分析和凭经验都不能快速定位问题,就要把程序分拆成多个基本环节的组合,充分验证每个环节都是正确的,这样可确保“万无一失“?

    追忆流年寻梦少年 2020-6-30 13:34

    这种问题是比较烦;
    但对于解决问题、发现bug,过程可以优化,一般串口调试的第一步就是原发原收,或者是自发自收,看发送、接收情况,这样子就可以快速定位收端代码异常;然后根据收端的数据,再进一步设计发送0000,1111,1234等,根据接收数据异常分析,再进一步定位代码。
    当然,这一般都是事后的总结,发现前面浪费了时间,可以优化的。

    Qeecoda 2020-6-20 13:40

    allen_zhan: 很难有人会犯这种&quot;录入错误&quot;吧.
    这种代码移植, 工程师拿手的是 copy - paste.
    很多时候,单片机代码并没有一个‘原板’可供移植。

    Qeecoda 2020-6-20 13:39

    allen_zhan: 很难有人会犯这种&quot;录入错误&quot;吧.
    这种代码移植, 工程师拿手的是 copy - paste.
    即使已经做过的代码,有时候也难免手痒会重构代码的。

    allen_zhan 2020-6-19 17:10

    很难有人会犯这种"录入错误"吧.
    这种代码移植, 工程师拿手的是 copy - paste.

    Qeecoda 2020-6-16 21:04

    majunling606: 这个,折磨人了
    痛并快乐着吧

    Qeecoda 2020-6-16 21:02

    southcreek: 有一条原则,计算机总是对的。如果出错了,一定是人为因素。
    但如果计算机的设计原理使大多数的人总是出错,那么计算机的设计本身也需要改进。

    Qeecoda 2020-6-16 21:00

    southcreek: 有一条原则,计算机总是对的。如果出错了,一定是人为因素。
    绝大多数情况是这样!

    用户1515636 2020-6-15 19:35

    这个,折磨人了
    相关推荐阅读
    Qeecoda 2024-09-13 14:28
    秋夜偶书
          秋·月夜  玻色子  2023-9-13旧事依稀又月明,浮生若梦意难平。霜风十里江南夜,秋月无边故人情。...
    Qeecoda 2023-07-08 08:25
    电池快充标志引发的思考
            随着氮化镓技术的普及,快充功能特别是手机锂电池快充功能,在我们的生活中日益普及。快速充电显著提升了充电速度,给我们的生活带来巨大的便捷性。快充的...
    Qeecoda 2022-05-18 16:02
    MCP2515驱动代码
    [code]/* * @file mcp2515.h * @author TanQi * @version V1.0.0 * @date 2022-1-20 * @brief He...
    Qeecoda 2021-06-19 17:37
    实用可靠的干接点消抖滤波算法
    [code]/* * * 干接点常用于实现各种电气设备开关停控制的弱电接口,两个触点可以组合出无动作、开、停和关4种状态。 * 干接点信号可以由手控面板发出,也可以由中控设备发出。 * 在手动应用中常...
    Qeecoda 2020-05-17 16:02
    电子产品常见故障现象、原因分析及改进措施(一)
    1. 故障现象:通电无反应。原因分析:(1)接插件接不良;(2)470压敏电阻击穿;(3)开关电源的高压整流桥击穿;(4)开关电源的高压整理滤波电容损坏;(5)开关电源的开关管损坏;(6)开关电源的高...
    我要评论
    16
    90
    关闭 站长推荐上一条 /3 下一条