1+X 傳感網(wǎng)中級備考實例解析:異步串行通信的接收中斷(1)

RXNE中斷響應(yīng)過程方法(1)

在USART1串口控制流水燈的實驗中,http://www.itdecent.cn/p/48817b329231,串口助手發(fā)送“mode_1#”命令字后,STM32的USART1 DR寄存器接收到1個字符之后,就會進入到中斷服務(wù)函數(shù);總結(jié)中斷執(zhí)行的過程:

(1)使能中斷標(biāo)志位,CR1寄存器的標(biāo)志位RXNEIE被置1; 此函數(shù)調(diào)用之后,會直接配置CR1寄存器的RXNEIE=1;

__HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE);

圖1:RXNE事件使能
圖2:STM32的USART支持的中斷事件

(2)響應(yīng)中斷的入口函數(shù)

在使能了中斷之后,DR數(shù)據(jù)寄存器只要接收到1個字符,例如,發(fā)送命令字“mode_1#”,DR寄存器先接收到一個字符“m”,就會產(chǎn)生中斷;USART1_IRQHandler()函數(shù)是USART1中斷服務(wù)的入口,其中&huart1是訪問串口句柄UART_HandleTypeDef,可以通過huart1.TxXferSize,調(diào)用結(jié)構(gòu)體定義的成員,

void USART1_IRQHandler(void)//中斷響應(yīng)的入口
{
 
    USER_UART_IRQHandler(&huart1);

}

串口句柄的定義內(nèi)容,包含了(發(fā)送或接收的)數(shù)據(jù)緩存、數(shù)據(jù)指針、串口 DMA 相關(guān)的變量、各種標(biāo)志位等等要在整個項目流程中都要設(shè)置的各個成員。還有中斷服務(wù)程序中的回調(diào)函數(shù);這樣我們在整個程序中就可以方便調(diào)用;

UART_HandleTypeDef huart1;

typedef struct __UART_HandleTypeDef
{
  USART_TypeDef                 *Instance;        /*!< UART registers base address        */

  UART_InitTypeDef              Init;             /*!< UART communication parameters      */

  uint8_t                       *pTxBuffPtr;      /*!< Pointer to UART Tx transfer Buffer */

  uint16_t                      TxXferSize;       /*!< UART Tx Transfer size              */

  __IO uint16_t                 TxXferCount;      /*!< UART Tx Transfer Counter           */

  uint8_t                       *pRxBuffPtr;      /*!< Pointer to UART Rx transfer Buffer */

  uint16_t                      RxXferSize;       /*!< UART Rx Transfer size              */

  __IO uint16_t                 RxXferCount;      /*!< UART Rx Transfer Counter           */

  DMA_HandleTypeDef             *hdmatx;          /*!< UART Tx DMA Handle parameters      */

  DMA_HandleTypeDef             *hdmarx;          /*!< UART Rx DMA Handle parameters      */

  HAL_LockTypeDef               Lock;             /*!< Locking object                     */

  __IO HAL_UART_StateTypeDef    gState;           /*!< UART state information related to global Handle management
                                                       and also related to Tx operations.
                                                       This parameter can be a value of @ref HAL_UART_StateTypeDef */

  __IO HAL_UART_StateTypeDef    RxState;          /*!< UART state information related to Rx operations.
                                                       This parameter can be a value of @ref HAL_UART_StateTypeDef */

  __IO uint32_t                 ErrorCode;        /*!< UART Error code                    */

#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
  void (* TxHalfCpltCallback)(struct __UART_HandleTypeDef *huart);        /*!< UART Tx Half Complete Callback        */
  void (* TxCpltCallback)(struct __UART_HandleTypeDef *huart);            /*!< UART Tx Complete Callback             */
  void (* RxHalfCpltCallback)(struct __UART_HandleTypeDef *huart);        /*!< UART Rx Half Complete Callback        */
  void (* RxCpltCallback)(struct __UART_HandleTypeDef *huart);            /*!< UART Rx Complete Callback             */
  void (* ErrorCallback)(struct __UART_HandleTypeDef *huart);             /*!< UART Error Callback                   */
  void (* AbortCpltCallback)(struct __UART_HandleTypeDef *huart);         /*!< UART Abort Complete Callback          */
  void (* MspInitCallback)(struct __UART_HandleTypeDef *huart);           /*!< UART Msp Init callback                */
  void (* MspDeInitCallback)(struct __UART_HandleTypeDef *huart);         /*!< UART Msp DeInit callback              */
#endif  /* USE_HAL_UART_REGISTER_CALLBACKS */

} UART_HandleTypeDef;

(3)用戶重寫中斷服務(wù)函數(shù)
此次項目中,我們注釋掉了HAL庫原本的HAL_UART_IRQHandler(&huart1);然后重新定義了USER_UART_IRQHandler(&huart1);在中斷入口響應(yīng)函數(shù) USART1_IRQHandler(void)執(zhí)行以后,我們就直接調(diào)用USER_UART_IRQHandler(&huart1);在main.c中對函數(shù)進行定義;

void USER_UART_IRQHandler(UART_HandleTypeDef *huart)
    
{
    if((__HAL_UART_GET_FLAG(&huart1,UART_FLAG_RXNE) != RESET))//接收一個字節(jié)就會產(chǎn)生中斷
    {
          __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
            uart1RxBuff[uart1RxCounter] = (uint8_t)(huart1.Instance->DR & (uint8_t)0x00ff);
           uart1RxCounter++;
       
          __HAL_UART_GET_FLAG(&huart1,UART_FLAG_RXNE);

    }
    if((__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) != RESET))//接收一組數(shù)據(jù)/一幀數(shù)據(jù)就會中斷
        
    {   
           __HAL_UART_DISABLE_IT(&huart1,UART_IT_IDLE);
             uart1RxState = 1;
    }

}

這種方式與我們之前學(xué)習(xí)的標(biāo)準(zhǔn)庫方法比較相似,在中斷服務(wù)入口函數(shù)里,判斷標(biāo)志位,然后做讀/寫操作,最后清除標(biāo)志位;沒有使用調(diào)用HAL庫的回調(diào)函數(shù),程序代碼思路比較簡潔;
(4)判斷標(biāo)志位,將數(shù)據(jù)寄存器DR中接收的低8位字符讀取到自己定義的數(shù)組中;同時,完成清除標(biāo)志位RXNE;代碼中uart1RxBuff是我們在C語言代碼中定義好的數(shù)組,準(zhǔn)備將DR寄存器的數(shù)值讀入到數(shù)組中;通過在線調(diào)試,我們可以看到變化;
從DR寄存器讀取數(shù)據(jù)之后,RXNE會自動被清零;

if((__HAL_UART_GET_FLAG(&huart1,UART_FLAG_RXNE) != RESET))
uart1RxBuff[uart1RxCounter] = (uint8_t)(huart1.Instance->DR & (uint8_t)0x0i0ff);
           uart1RxCounter++;

圖3:單步運行查看數(shù)組是否接收到字符

圖4:RXNE置1和清零的條件

當(dāng)RDR移位寄存器中的數(shù)據(jù)被轉(zhuǎn)移到USART_DR寄存器中,該位被硬件置位。如果USART_CR1寄存器中的RXNEIE為1,則產(chǎn)生中斷。對USART_DR的讀操作可以將該位清零。

(5)使能IDLE中斷,本次項目在RXNE中斷響應(yīng)函數(shù)中,開啟了IDLE中斷,IDLE是空閑線路檢測標(biāo)志位,當(dāng)一幀數(shù)據(jù)發(fā)送完,下一幀數(shù)據(jù)還沒有發(fā)送之前,會有空閑狀態(tài);IDLE標(biāo)志位用于檢測一幀數(shù)據(jù)是否發(fā)送完成;在本例中,IDLE使能的代碼是:

 __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);

在中斷服務(wù)函數(shù)中又使能了一個新的中斷,可能對于初學(xué)者有很多疑問;這里注意不屬于中斷嵌套,IDLE標(biāo)志位也只有在接收數(shù)據(jù)的狀態(tài)下,才可能發(fā)生,因為RXNE接收一個字符就會發(fā)生中斷,而IDLE是接收一幀數(shù)據(jù)才會發(fā)生中斷,這里兩個狀態(tài)是可以在一次接收數(shù)據(jù)的過程中按代碼順序先后發(fā)生;所以不存在中斷嵌套問題;如果初學(xué)者對這里覺得難以理解,也可以將IDLE的使能,在main.c全局變量中進行使能;

(6)產(chǎn)生IDLE中斷
當(dāng)檢測到總線空閑時,IDLE位被硬件置位,因為已經(jīng)開啟了USART_CR1中的IDLEIE為’1’,則產(chǎn)生中斷;條件判斷成立,接收數(shù)據(jù)狀態(tài)字置uart1RxState=1;

if((__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) != RESET))//接收一組數(shù)據(jù)/一幀數(shù)據(jù)就會中斷
        
    {       
           __HAL_UART_DISABLE_IT(&huart1,UART_IT_IDLE);
             uart1RxState = 1;
    }

IDLE的狀態(tài)位受到RXNE狀態(tài)位的影響,先有RXNE狀態(tài)位置1,檢測到IDLE狀態(tài)情況下,才會進入IDLE的中斷響應(yīng);表示一幀數(shù)據(jù)已經(jīng)接收完成;

(7)禁用IDLE中斷;__HAL_UART_DISABLE_IT(&huart1,UART_IT_IDLE);

總結(jié):通過此篇分析,是幫助同學(xué)們理解串口接收中斷函數(shù)的執(zhí)行流程;使能函數(shù)__HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE) 與用戶自定義的中斷服務(wù)函數(shù) USER_UART_IRQHandler(UART_HandleTypeDef *huart),配合使用。完成數(shù)據(jù)接收;此篇沒有用到接收中斷的回調(diào)函數(shù)。我們在下篇方法二中進行介紹。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容