天天看點

困擾一周的奇葩bug:重複相似代碼多,導緻單片機程式跑飛

今天是個好日子,困擾一周的bug終于解決了,迫不及待将這個奇葩問題分享給各位朋友~

硬體環境:

國産MCU:華大HC32L130

問題描述:

最近做一款基于Modbus協定的三通道溫度采集子產品,程式設計是移植之前驗證過的兩通道溫度、壓力采集子產品的程式,完成後,三通道溫度采集程式可正常運作。

最後需要對三通道溫度采集子產品添加二次校準算法功能,新功能寫好後,也可正常采集和通信,但是使用IAP功能時,flash扇區擦除失敗,無法跳轉到更新程式,且程式跑飛。

問題分析和解決:

嘗試1:修改新增加的二次校準算法功能程式。

将二次校準算法功能屏蔽,更新程式可正常使用,估計是這裡的問題,進行修改:變量定義、指針位址、記憶體管理等一系列操作下來,問題沒有解決。

此時我的排查側重點是資料記憶體或者位址溢出方面。

嘗試2:檢視flash配置是否存在問題。

既然是flash扇區擦除失敗,會不是是配置存在問題?通過檢視寄存器,修改時隙間隔等方面,還是無法解決問題,主要是之前運作一直沒問題,排除這點。

那麼會不會新添加的二次校準算法功能和已經存在的功能沖突呢?或者是使用的全局結構體變量有問題?

嘗試3:整體研讀項目代碼,重點排查二次校準算法功能中全局變量、全局結構體變量的使用。

并沒有變量使用不合理或者邏輯錯誤的地方。

嘗試4:按照功能子產品屏蔽代碼,是否是程式中某部分功能與二次校準算法功能程式沖突。

通過一點點屏蔽程式,發現在二次校準算法功能程式正常運作前提下,屏蔽主循環的Modbus顯示功能、Modbus配置UART功能、傳感器GPIO配置等多個部分均可正常使用IAP功能。

通過仔細分析,這些功能子產品中變量定義和使用均不存在問題,此時心态很郁悶了,這些子產品功能基本沒有關聯。

嘗試5:通過修改某個功能子產品代碼,是否可使程式正常運作。

此時項目整體功能是不存在邏輯問題和bug的,是否可以通過将以上那些存在未知沖突故障的代碼換種寫法,讓程式正常運作呢?

經過了一系列操作和嘗試,将主循環的Modbus顯示功能代碼換種更簡潔的寫法,程式可以完美運作~

原程式如下所示:

if(nModbusCalRegs[Modbus_RegCalChan-Modbus_RegCalChan] == TEMP1_CHANNEL_ID)
 {
   ///< 初始化溫度傳感器:校準量程、零點偏移、靈敏度、零點偏移系數和靈敏度偏移系數
   nModbusCalRegs[Modbus_CalChanIndex] = strDeviceParamSave.temp1_range;
   memcpy((uint8_t *) &ltemp,(uint8_t *) &strDeviceParamSave.temp1_bias1, 4);
   ntemp = (uint16_t) ltemp;
   nModbusCalRegs[Modbus_CalZeroIndex] = ntemp;
   ntemp = (uint16_t) (ltemp >> 16);
   nModbusCalRegs[Modbus_CalZeroIndex+1] = ntemp;
   memcpy((uint8_t *) &ltemp,(uint8_t *) &strDeviceParamSave.temp1_kate1, 4);
   ntemp = (uint16_t) ltemp;
   nModbusCalRegs[Modbus_CalKateIndex] = ntemp;
   ntemp = (uint16_t) (ltemp >> 16);
   nModbusCalRegs[Modbus_CalKateIndex+1] = ntemp;
   memcpy((uint8_t *) &ltemp,(uint8_t *) &strDeviceParamSave.temp1_bias2, 4);
   ntemp = (uint16_t) ltemp;
   nModbusCalRegs[Modbus_CalKZeroIndex] = ntemp;
   ntemp = (uint16_t) (ltemp >> 16);
   nModbusCalRegs[Modbus_CalKZeroIndex+1] = ntemp;
   memcpy((uint8_t *) &ltemp,(uint8_t *) &strDeviceParamSave.temp1_kate2, 4);
   ntemp = (uint16_t) ltemp;
   nModbusCalRegs[Modbus_CalKSensiIndex] = ntemp;
   ntemp = (uint16_t) (ltemp >> 16);
   nModbusCalRegs[Modbus_CalKSensiIndex+1] = ntemp;
 }
 else if(nModbusCalRegs[Modbus_RegCalChan-Modbus_RegCalChan] == TEMP2_CHANNEL_ID)
 {
   ///< 初始化溫度傳感器:校準量程、零點偏移、靈敏度、零點偏移系數和靈敏度偏移系數
   nModbusCalRegs[Modbus_CalChanIndex] = strDeviceParamSave.temp2_range;
   memcpy((uint8_t *) &ltemp,(uint8_t *) &strDeviceParamSave.temp2_bias1, 4);
   ntemp = (uint16_t) ltemp;
   nModbusCalRegs[Modbus_CalZeroIndex] = ntemp;
   ntemp = (uint16_t) (ltemp >> 16);
   nModbusCalRegs[Modbus_CalZeroIndex+1] = ntemp;
   memcpy((uint8_t *) &ltemp,(uint8_t *) &strDeviceParamSave.temp2_kate1, 4);
   ntemp = (uint16_t) ltemp;
   nModbusCalRegs[Modbus_CalKateIndex] = ntemp;
   ntemp = (uint16_t) (ltemp >> 16);
   nModbusCalRegs[Modbus_CalKateIndex+1] = ntemp;
   memcpy((uint8_t *) &ltemp,(uint8_t *) &strDeviceParamSave.temp2_bias2, 4);
   ntemp = (uint16_t) ltemp;
   nModbusCalRegs[Modbus_CalKZeroIndex] = ntemp;
   ntemp = (uint16_t) (ltemp >> 16);
   nModbusCalRegs[Modbus_CalKZeroIndex+1] = ntemp;
   memcpy((uint8_t *) &ltemp,(uint8_t *) &strDeviceParamSave.temp2_kate2, 4);
   ntemp = (uint16_t) ltemp;
   nModbusCalRegs[Modbus_CalKSensiIndex] = ntemp;
   ntemp = (uint16_t) (ltemp >> 16);
   nModbusCalRegs[Modbus_CalKSensiIndex+1] = ntemp;
 }
 else if(nModbusCalRegs[Modbus_RegCalChan-Modbus_RegCalChan] == TEMP3_CHANNEL_ID)
 {
   ///< 初始化溫度傳感器:校準量程、零點偏移、靈敏度、零點偏移系數和靈敏度偏移系數
   nModbusCalRegs[Modbus_CalChanIndex] = strDeviceParamSave.temp3_range;
   memcpy((uint8_t *) &ltemp,(uint8_t *) &strDeviceParamSave.temp3_bias1, 4);
   ntemp = (uint16_t) ltemp;
   nModbusCalRegs[Modbus_CalZeroIndex] = ntemp;
   ntemp = (uint16_t) (ltemp >> 16);
   nModbusCalRegs[Modbus_CalZeroIndex+1] = ntemp;
   memcpy((uint8_t *) &ltemp,(uint8_t *) &strDeviceParamSave.temp3_kate1, 4);
   ntemp = (uint16_t) ltemp;
   nModbusCalRegs[Modbus_CalKateIndex] = ntemp;
   ntemp = (uint16_t) (ltemp >> 16);
   nModbusCalRegs[Modbus_CalKateIndex+1] = ntemp;
   memcpy((uint8_t *) &ltemp,(uint8_t *) &strDeviceParamSave.temp3_bias2, 4);
   ntemp = (uint16_t) ltemp;
   nModbusCalRegs[Modbus_CalKZeroIndex] = ntemp;
   ntemp = (uint16_t) (ltemp >> 16);
   nModbusCalRegs[Modbus_CalKZeroIndex+1] = ntemp;
   memcpy((uint8_t *) &ltemp,(uint8_t *) &strDeviceParamSave.temp3_kate2, 4);
   ntemp = (uint16_t) ltemp;
   nModbusCalRegs[Modbus_CalKSensiIndex] = ntemp;
   ntemp = (uint16_t) (ltemp >> 16);
   nModbusCalRegs[Modbus_CalKSensiIndex+1] = ntemp;
 }
 else
 {
   nModbusCalRegs[Modbus_CalChanIndex] = 0;
 
   nModbusCalRegs[Modbus_CalZeroIndex] = 0;
   nModbusCalRegs[Modbus_CalZeroIndex+1] = 0;
 
   nModbusCalRegs[Modbus_CalKateIndex] = 0;
   nModbusCalRegs[Modbus_CalKateIndex+1] = 0;
 
   nModbusCalRegs[Modbus_CalKZeroIndex] = 0;
   nModbusCalRegs[Modbus_CalKZeroIndex+1] = 0;
 
   nModbusCalRegs[Modbus_CalKSensiIndex] = 0;
   nModbusCalRegs[Modbus_CalKSensiIndex+1] = 0;
 }      

優化後程式如下所示:

if(nModbusCalRegs[Modbus_RegCalChan-Modbus_RegCalChan] == TEMP1_CHANNEL_ID)
  {
    temp_range = strDeviceParamSave.temp1_range;
    temp_bias1 = strDeviceParamSave.temp1_bias1;
    temp_kate1 = strDeviceParamSave.temp1_kate1;
    temp_bias2 = strDeviceParamSave.temp1_bias2;
    temp_kate2 = strDeviceParamSave.temp1_kate2;
  }
  else if(nModbusCalRegs[Modbus_RegCalChan-Modbus_RegCalChan] == TEMP2_CHANNEL_ID)
  {
    temp_range = strDeviceParamSave.temp2_range;
    temp_bias1 = strDeviceParamSave.temp2_bias1;
    temp_kate1 = strDeviceParamSave.temp2_kate1;
    temp_bias2 = strDeviceParamSave.temp2_bias2;
    temp_kate2 = strDeviceParamSave.temp2_kate2;   
  }
  else if(nModbusCalRegs[Modbus_RegCalChan-Modbus_RegCalChan] == TEMP3_CHANNEL_ID)
  {
    temp_range = strDeviceParamSave.temp3_range;
    temp_bias1 = strDeviceParamSave.temp3_bias1;
    temp_kate1 = strDeviceParamSave.temp3_kate1;
    temp_bias2 = strDeviceParamSave.temp3_bias2;
    temp_kate2 = strDeviceParamSave.temp3_kate2;
  }
 
  ///< 初始化溫度傳感器:校準量程、零點偏移、靈敏度、零點偏移系數和靈敏度偏移系數
  nModbusCalRegs[Modbus_CalChanIndex] = temp_range;
  memcpy((uint8_t *) &ltemp,(uint8_t *) &temp_bias1, 4);
  ntemp = (uint16_t) ltemp;
  nModbusCalRegs[Modbus_CalZeroIndex] = ntemp;
  ntemp = (uint16_t) (ltemp >> 16);
  nModbusCalRegs[Modbus_CalZeroIndex+1] = ntemp;
  memcpy((uint8_t *) &ltemp,(uint8_t *) &temp_kate1, 4);
  ntemp = (uint16_t) ltemp;
  nModbusCalRegs[Modbus_CalKateIndex] = ntemp;
  ntemp = (uint16_t) (ltemp >> 16);
  nModbusCalRegs[Modbus_CalKateIndex+1] = ntemp;
  memcpy((uint8_t *) &ltemp,(uint8_t *) &temp_bias2, 4);
  ntemp = (uint16_t) ltemp;
  nModbusCalRegs[Modbus_CalKZeroIndex] = ntemp;
  ntemp = (uint16_t) (ltemp >> 16);
  nModbusCalRegs[Modbus_CalKZeroIndex+1] = ntemp;
  memcpy((uint8_t *) &ltemp,(uint8_t *) &temp_kate2, 4);
  ntemp = (uint16_t) ltemp;
  nModbusCalRegs[Modbus_CalKSensiIndex] = ntemp;
  ntemp = (uint16_t) (ltemp >> 16);
  nModbusCalRegs[Modbus_CalKSensiIndex+1] = ntemp;      

哎,淚奔,回頭想想,可能是重複代碼過多,導緻編譯過程存在問題,硬體開發工程師的程式bug往往出其不意,切忌先入為主,始終要保持質疑的态度呀~

繼續閱讀