1+X 传感网中级备考实例解析:异步串行通信的接收中断(1)

RXNE中断响应过程方法(1)

在USART1串口控制流水灯的实验中,https://www.jianshu.com/p/48817b329231,串口助手发送“mode_1#”命令字后,STM32的USART1 DR寄存器接收到1个字符之后,就会进入到中断服务函数;总结中断执行的过程:

(1)使能中断标志位,CR1寄存器的标志位RXNEIE被置1; 此函数调用之后,会直接配置CR1寄存器的RXNEIE=1;

__HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE);

图1:RXNE事件使能
图2:STM32的USART支持的中断事件

(2)响应中断的入口函数

在使能了中断之后,DR数据寄存器只要接收到1个字符,例如,发送命令字“mode_1#”,DR寄存器先接收到一个字符“m”,就会产生中断;USART1_IRQHandler()函数是USART1中断服务的入口,其中&huart1是访问串口句柄UART_HandleTypeDef,可以通过huart1.TxXferSize,调用结构体定义的成员,

void USART1_IRQHandler(void)//中断响应的入口
{
 
    USER_UART_IRQHandler(&huart1);

}

串口句柄的定义内容,包含了(发送或接收的)数据缓存、数据指针、串口 DMA 相关的变量、各种标志位等等要在整个项目流程中都要设置的各个成员。还有中断服务程序中的回调函数;这样我们在整个程序中就可以方便调用;

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)用户重写中断服务函数
此次项目中,我们注释掉了HAL库原本的HAL_UART_IRQHandler(&huart1);然后重新定义了USER_UART_IRQHandler(&huart1);在中断入口响应函数 USART1_IRQHandler(void)执行以后,我们就直接调用USER_UART_IRQHandler(&huart1);在main.c中对函数进行定义;

void USER_UART_IRQHandler(UART_HandleTypeDef *huart)
    
{
    if((__HAL_UART_GET_FLAG(&huart1,UART_FLAG_RXNE) != RESET))//接收一个字节就会产生中断
    {
          __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))//接收一组数据/一帧数据就会中断
        
    {   
           __HAL_UART_DISABLE_IT(&huart1,UART_IT_IDLE);
             uart1RxState = 1;
    }

}

这种方式与我们之前学习的标准库方法比较相似,在中断服务入口函数里,判断标志位,然后做读/写操作,最后清除标志位;没有使用调用HAL库的回调函数,程序代码思路比较简洁;
(4)判断标志位,将数据寄存器DR中接收的低8位字符读取到自己定义的数组中;同时,完成清除标志位RXNE;代码中uart1RxBuff是我们在C语言代码中定义好的数组,准备将DR寄存器的数值读入到数组中;通过在线调试,我们可以看到变化;
从DR寄存器读取数据之后,RXNE会自动被清零

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

图3:单步运行查看数组是否接收到字符

图4:RXNE置1和清零的条件

当RDR移位寄存器中的数据被转移到USART_DR寄存器中,该位被硬件置位。如果USART_CR1寄存器中的RXNEIE为1,则产生中断。对USART_DR的读操作可以将该位清零。

(5)使能IDLE中断,本次项目在RXNE中断响应函数中,开启了IDLE中断,IDLE是空闲线路检测标志位,当一帧数据发送完,下一帧数据还没有发送之前,会有空闲状态;IDLE标志位用于检测一帧数据是否发送完成;在本例中,IDLE使能的代码是:

 __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);

在中断服务函数中又使能了一个新的中断,可能对于初学者有很多疑问;这里注意不属于中断嵌套,IDLE标志位也只有在接收数据的状态下,才可能发生,因为RXNE接收一个字符就会发生中断,而IDLE是接收一帧数据才会发生中断,这里两个状态是可以在一次接收数据的过程中按代码顺序先后发生;所以不存在中断嵌套问题;如果初学者对这里觉得难以理解,也可以将IDLE的使能,在main.c全局变量中进行使能;

(6)产生IDLE中断
当检测到总线空闲时,IDLE位被硬件置位,因为已经开启了USART_CR1中的IDLEIE为’1’,则产生中断;条件判断成立,接收数据状态字置uart1RxState=1;

if((__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) != RESET))//接收一组数据/一帧数据就会中断
        
    {       
           __HAL_UART_DISABLE_IT(&huart1,UART_IT_IDLE);
             uart1RxState = 1;
    }

IDLE的状态位受到RXNE状态位的影响,先有RXNE状态位置1,检测到IDLE状态情况下,才会进入IDLE的中断响应;表示一帧数据已经接收完成;

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

总结:通过此篇分析,是帮助同学们理解串口接收中断函数的执行流程;使能函数__HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE) 与用户自定义的中断服务函数 USER_UART_IRQHandler(UART_HandleTypeDef *huart),配合使用。完成数据接收;此篇没有用到接收中断的回调函数。我们在下篇方法二中进行介绍。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,635评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,628评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,971评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,986评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,006评论 6 394
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,784评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,475评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,364评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,860评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,008评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,152评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,829评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,490评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,035评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,156评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,428评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,127评论 2 356