论STM32 USART串口中断配置函数USART_ITConfig()的编程思路

void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState)

函数参数列表中,USART的有效范围为:

#define IS_USART_ALL_PERIPH(PERIPH) (((PERIPH) == USART1) || \
                                     ((PERIPH) == USART2) || \
                                     ((PERIPH) == USART3) || \
                                     ((PERIPH) == UART4) || \
                                     ((PERIPH) == UART5))

USART_IT的有效范围为:

#define IS_USART_CONFIG_IT(IT) (((IT) == USART_IT_PE) || ((IT) == USART_IT_TXE) || \
                               ((IT) == USART_IT_TC) || ((IT) == USART_IT_RXNE) || \
                               ((IT) == USART_IT_IDLE) || ((IT) == USART_IT_LBD) || \
                               ((IT) == USART_IT_CTS) || ((IT) == USART_IT_ERR))

STATE用于表征寄存器的使能状态,只有两种有效值,DISABLE(0)和ENABLE (1)

#define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE))

下面的判断语句用于判断中断源是否为 CTS,因为只有在USART1-3中才存在CTS中断,所以这里要对USART进行参数有效性判断!

 if (USART_IT == USART_IT_CTS)
  {
    assert_param(IS_USART_123_PERIPH(USARTx));
  }   

将对应的USART串口的基地址赋值给usartbase变量:

  usartxbase = (uint32_t)USARTx;

 找到对应串口中的寄存器编号:

 usartreg = (((uint8_t)USART_IT) >> 0x05);

为什么要将USART_IT的低八位右移五位呢?这是STM32那些编程大聪明想到的骚操作,注意USART_IT中各参数的宏定义:

#define USART_IT_PE                          ((uint16_t)0x0028)
#define USART_IT_TXE                         ((uint16_t)0x0727)
#define USART_IT_TC                          ((uint16_t)0x0626)
#define USART_IT_RXNE                        ((uint16_t)0x0525)
#define USART_IT_IDLE                        ((uint16_t)0x0424)
#define USART_IT_LBD                         ((uint16_t)0x0846)
#define USART_IT_CTS                         ((uint16_t)0x096A)
#define USART_IT_ERR                         ((uint16_t)0x0060)
#define USART_IT_ORE                         ((uint16_t)0x0360)
#define USART_IT_NE                          ((uint16_t)0x0260)
#define USART_IT_FE                          ((uint16_t)0x0160)

再取(uint8)强制类型转换以后,注意PE、TXE、TC、RXNE、IDLE中断都是0010 XXXX

而且他们都存在于CR1寄存器中:

 PE、TXE、TC、RXNE、IDLE在右移五位以后,结果均为0x01,所以就用0x01用于表征CR1寄存器。

同样推理(uint8)LBD右移五位以后为0x02,所以是否用0x02表征CR2寄存器呢?查看一下LBD是否在CR2寄存器中就知道了~

 事实证明没毛病嗷老铁~

再看CTS、ORE、ERR、NE、FE在(uint8)并右移五位以后为0x03,用于表征CR3寄存器。注意在CR3寄存器中,ORE(过载错误)、NE(噪声错误)、FE(帧错误)均由bit0 EIE(可以理解为ERR)表示。

 

这一步解决了,继续看代码,IT_Mask宏定义为0x001F,与USART相与以后保留低5位,其数值换算为十进制正好就是表征了对应的中断源在对应寄存器中的位置!

 itpos = USART_IT & IT_Mask;     
 itmask = (((uint32_t)0x01) << itpos);

 举个栗子,比如RXNE中断:

#define USART_IT_RXNE                        ((uint16_t)0x0525)

 itpos = 0x0005;0000 0000 0000 0000 0000 0000 0001 0000

再看CR1中RXNE位在哪里捏?

哎没毛病嗷老铁!

继续看下面的代码,这一步就是根据刚才确定寄存器的编号,将地址再USARTx的基地址基础上进行相应的偏移。

if (usartreg == 0x01) /* The IT is in CR1 register */
  {
    usartxbase += 0x0C;  
  }
  else if (usartreg == 0x02) /* The IT is in CR2 register */
  {
    usartxbase += 0x10;
  }
  else /* The IT is in CR3 register */
  {
    usartxbase += 0x14; 
  }

 最后就是按部就班的使能或者失能对应的中断:

 if (NewState != DISABLE)
  {
    *(__IO uint32_t*)usartxbase  |= itmask;    //寄存器相应位置上的中断使能位置1
  }
  else
  {
    *(__IO uint32_t*)usartxbase &= ~itmask;    //中断使能位置0,其他位保持
  }

最后做一个小节,学习一下编程技巧:

        对于寻找某个寄存器中的具体某一位,可以采取“分段策略”,某一位段用于表征寄存器的编号,其他某一位段用于表征该位在特定寄存器中的具体的位置。

寻找寄存器编号可以采取位移的方法,寻找位可以采取位移+根据位移值对0x1进行反位移操作。

附stm32f10x_usart.c中USART_ITConfig()完整代码:

 

void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState)
{
  uint32_t usartreg = 0x00, itpos = 0x00, itmask = 0x00;
  uint32_t usartxbase = 0x00;
  /* Check the parameters */
  assert_param(IS_USART_ALL_PERIPH(USARTx));
  assert_param(IS_USART_CONFIG_IT(USART_IT));
  assert_param(IS_FUNCTIONAL_STATE(NewState));
  /* The CTS interrupt is not available for UART4 and UART5 */
  if (USART_IT == USART_IT_CTS)
  {
    assert_param(IS_USART_123_PERIPH(USARTx));
  }   
  
  usartxbase = (uint32_t)USARTx;

  /* Get the USART register index */
  usartreg = (((uint8_t)USART_IT) >> 0x05);

  /* Get the interrupt position */
  itpos = USART_IT & IT_Mask;     //取USART_IT低五位,然而所有的USART_IT的bit4均为0,所以实质上是取低4为,提取了相应中断在寄存器中的位置
  itmask = (((uint32_t)0x01) << itpos);
    /* 在对应的USARTx的基地址基础上找到各自的CR1-3 地址 */
  if (usartreg == 0x01) /* The IT is in CR1 register */
  {
    usartxbase += 0x0C;  
  }
  else if (usartreg == 0x02) /* The IT is in CR2 register */
  {
    usartxbase += 0x10;
  }
  else /* The IT is in CR3 register */
  {
    usartxbase += 0x14; 
  }
  if (NewState != DISABLE)
  {
    *(__IO uint32_t*)usartxbase  |= itmask;    //寄存器相应位置上的中断使能位置1
  }
  else
  {
    *(__IO uint32_t*)usartxbase &= ~itmask;    //中断使能位置0,其他位保持
  }
}

物联沃分享整理
物联沃-IOTWORD物联网 » 论STM32 USART串口中断配置函数USART_ITConfig()的编程思路

发表评论