說起這個bug,讓我想到了前幾個月一個入職的實習生小夥伴。小夥伴被安排了一個小任務,做一個小工裝,按照公司的私有協議實現一些數據的讀取、轉發,用的是最常用的串口通訊。
小伙子也是滿懷鬥志,計劃使用cubemx和HAL庫開發,底層勾勾點點,只把應用層移植過來,簡單快速。但有時候,理想和現實總是差一點「運氣」和細心....
一切準備就緒,代碼移植過來,呵,不出意外的話肯定有意外...不但通訊沒成功,點個燈都滅了,然後開始仿真、屏蔽代碼,一部分一部分排除法...最終定位在了串口中斷上,不管有沒有數據來,都會瘋狂的進中斷。
繼續仿真,進入到了這個錯誤,來看看是什麼錯誤。
校驗位錯誤,看起來很奇怪,外部串口已經斷開了,理論上不會再進中斷了才是,現在還報了個校驗位錯誤,然後開始瘋狂百度,找不到頭緒了,可把孩子急壞了。
然後開始新建工程,先驗證串口收發,自己寫的基本的驗證收發都沒問題呀,怎麼就移植過來別人的代碼就跑崩了呀,費解...
最後實在是沒辦法了,就幫小伙子調試一下吧,不調不信,一調差點給我整崩潰了,這不最近調藍牙模組,突然又遇到這個問題了,忽然想起來這個事情,就簡單記錄一下,希望可以幫助一些小夥伴排憂解難,特別是用hal庫的小夥伴
嵌入式物聯網需要學的東西真的非常多,千萬不要學錯了路線和內容,導致工資要不上去!
無償分享大家一個資料包,差不多150多G。裡面學習內容、面經、項目都比較新也比較全!某魚上買估計至少要好幾十。
點擊這裡找小助理0元領取:加微信領取資料
一般我們使用cubemx配置串口的時候,僅僅是配置了一些參數、IO等,串口號名稱不能像IO口一樣定義label。
然後初始化代碼如下:
void MX_USART2_UART_Init(void)
{
/* USER CODE BEGIN USART2_Init 0 */
/* USER CODE END USART2_Init 0 */
/* USER CODE BEGIN USART2_Init 1 */
/* USER CODE END USART2_Init 1 */
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART2_Init 2 */
/* USER CODE END USART2_Init 2 */
}
結構體句柄採用的是系統自定義的:
UART_HandleTypeDef huart2;
然後中斷是這樣的:
/**
* @brief This function handles USART2 global interrupt / USART2 wake-up interrupt through EXTI line 26.
*/
void USART2_IRQHandler(void)
{
/* USER CODE BEGIN USART2_IRQn 0 */
#if 1
/* USER CODE END USART2_IRQn 0 */
HAL_UART_IRQHandler(&huart2);
/* USER CODE BEGIN USART2_IRQn 1 */
#else
HAL_UART_IRQHandler(&BluetoothUart);
#endif
/* USER CODE END USART2_IRQn 1 */
}
這樣全採用HAL庫的配置是完全沒有問題的,那麼為什麼會出現上面所說的那個問題呢?且往下看
相信不少同學在開發的時候,對於一些定義命名都喜歡「顧名思義」,也是變量命名的一種最基本要求,加入用了4個串口,各自負責不同的功能,這樣命名,誰看得出來哪個串口是幹什麼用的:
UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;
UART_HandleTypeDef huart3;
UART_HandleTypeDef huart4;
一般都會命名為具體的功能描述:
UART_HandleTypeDef ble_uart;
UART_HandleTypeDef print_uart;
UART_HandleTypeDef gsm_uart;
UART_HandleTypeDef gps_uart;
然後串口在初始化的時候,就會重新初始化,寫成自己的函數:
static void BluetoothUartInit(void)
{
BluetoothUart.Instance = USART2;
BluetoothUart.Init.BaudRate = 115200;
BluetoothUart.Init.WordLength = UART_WORDLENGTH_8B;
BluetoothUart.Init.StopBits = UART_STOPBITS_1;
BluetoothUart.Init.Parity = UART_PARITY_NONE;
BluetoothUart.Init.Mode = UART_MODE_TX_RX;
BluetoothUart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
BluetoothUart.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&BluetoothUart) != HAL_OK)
{
Error_Handler();
}
HAL_UART_Receive_IT(&BluetoothUart, &ble_com.recbyte, 1);
}
這時候我們開始運行代碼,看一下huart2和BluetoothUart的值。
BluetoothUart->Instance = 0x400044000;
huart2->Instance = 0;
再來看下USART2對應的值是多少,加起來不正是上面的值嗎,也就是說huart2實際上是沒有被賦予正確的值的:
#define PERIPH_BASE (0x40000000UL) /*!< Peripheral base address */
#define APBPERIPH_BASE (PERIPH_BASE)
#define USART2_BASE (APBPERIPH_BASE + 0x00004400UL)
當然,其他值也是沒有被正確賦值的:
至於為什麼仿真會報PE錯誤,繼續看看報這個錯誤的原因:
uint32_t isrflags = READ_REG(huart->Instance->ISR);
uint32_t cr1its = READ_REG(huart->Instance->CR1);
uint32_t cr3its = READ_REG(huart->Instance->CR3);
uint32_t errorflags;
uint32_t errorcode;
主要看ISR、CR1和USART_ISR_PE、USART_CR1_PEIE這幾個寄存器。
#define USART_ISR_PE_Pos (0U)
#define USART_ISR_PE_Msk (0x1UL << USART_ISR_PE_Pos) /*!< 0x00000001 */
#define USART_ISR_PE USART_ISR_PE_Msk /*!< Parity Error */
#define USART_CR1_PEIE_Pos (8U)
#define USART_CR1_PEIE_Msk (0x1UL << USART_CR1_PEIE_Pos) /*!< 0x00000100 */
#define USART_CR1_PEIE USART_CR1_PEIE_Msk /*!< PE Interrupt Enable */
CR1 = 0x20001160;
ISR = 0;
//最終計算
isrflags & USART_ISR_PE = 0&1 = 0;
cr1its & USART_CR1_PEIE = 0x20001160&(1<<8) = 0x100;
觸發PE錯誤條件是,當然滿足了,我覺得觸發這個錯誤可能純屬偶然...
/* UART parity error interrupt occurred -------------------------------------*/
if (((isrflags & USART_ISR_PE) != 0U) && ((cr1its & USART_CR1_PEIE) != 0U))
{
__HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_PEF);
huart->ErrorCode |= HAL_UART_ERROR_PE;
}
最終如何解決呢,很簡單,還是上面說到的,你用cubemx配套生成的,肯定不會出問題,當然了,你改為自己的,肯定也不會出問題,一個用一半顯然是不行的啦~
為了不受cubemx生成代碼影響,可以採取宏定義的方法:
void USART2_IRQHandler(void)
{
/* USER CODE BEGIN USART2_IRQn 0 */
#if 0
/* USER CODE END USART2_IRQn 0 */
HAL_UART_IRQHandler(&huart2);
/* USER CODE BEGIN USART2_IRQn 1 */
#else
HAL_UART_IRQHandler(&BluetoothUart);
#endif
/* USER CODE END USART2_IRQn 1 */
}
問題就到這裡了,問題不大,卻需要多多留心!
原文連結:https://mp.weixin.qq.com/s/96OQS5Id_iiZUTTFL552YQ
轉載自:嵌入式微處理器
原文連結:解決了個bug,想說點啥卻又難以啟齒
本文來源網絡,免費傳達知識,版權歸原作者所有。如涉及作品版權問題,請聯繫我進行刪除。