今天是個好日子,困擾一周的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 *) <emp,(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 *) <emp,(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 *) <emp,(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 *) <emp,(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 *) <emp,(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 *) <emp,(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 *) <emp,(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 *) <emp,(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 *) <emp,(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 *) <emp,(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 *) <emp,(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 *) <emp,(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 *) <emp,(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 *) <emp,(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 *) <emp,(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 *) <emp,(uint8_t *) &temp_kate2, 4);
ntemp = (uint16_t) ltemp;
nModbusCalRegs[Modbus_CalKSensiIndex] = ntemp;
ntemp = (uint16_t) (ltemp >> 16);
nModbusCalRegs[Modbus_CalKSensiIndex+1] = ntemp;
哎,淚奔,回頭想想,可能是重複代碼過多,導緻編譯過程存在問題,硬體開發工程師的程式bug往往出其不意,切忌先入為主,始終要保持質疑的态度呀~