STM32
直播中

龙献益

7年用户 938经验值
私信 关注
[问答]

STM32串口接收不定长字节数据的方法

STM32串口接收不定长字节数据的方法

回帖(1)

李平

2021-12-9 10:18:44
1.程序设计
USART3 初始化函数代码如下:


/**
  * @name   RS485_Configuration(uint32_t baudrate, uint16_t wordlength,
  *                             uint16_t stopbits, uint16_t Parity)
  * @brief  Configure RS485(Usart2) clock, gpio and nvic:
  *         RS485_TX  USART2_TX  PB10
  *         RS485_RX  USART2_RX  PB11
  *         RS485_RE             PC4
  *         RS485_DE             PC5
  * @param  baudrate    9600  115200
  *         wordlength  USART_WordLength_8b/USART_WordLength_9b
  *         stopbits    USART_StopBits_1/USART_StopBits_2
  *         parity      USART_Parity_No/USART_Parity_Even
  * @retval None
  */
void RS485_Configuration(uint32_t baudrate, uint16_t wordlength, uint16_t stopbits, uint16_t parity)
{
        GPIO_InitTypeDef  GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;
        NVIC_InitTypeDef  NVIC_InitStructure;


        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);


        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOC, &GPIO_InitStructure);


        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_Init(GPIOB, &GPIO_InitStructure);


        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        GPIO_Init(GPIOB, &GPIO_InitStructure);


        RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART3,ENABLE);  // Start Reset USART2
        RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART3,DISABLE); // Stop  Reset USART2


        USART_InitStructure.USART_BaudRate = baudrate;
        USART_InitStructure.USART_WordLength = wordlength;
        USART_InitStructure.USART_StopBits = stopbits;
        USART_InitStructure.USART_Parity = parity;
        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;


        USART_Init(USART3, &USART_InitStructure);


        NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);


        USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);  // 开启接收中断(字节中断)
        USART_ITConfig(USART3, USART_IT_IDLE, ENABLE);  // 开启空闲中断(  帧中断)


        USART_Cmd(USART3, ENABLE);
       
        RS485_TX_DISABLE;  // Disable Tx Mode
}
USART3 中断函数代码如下:


uint8_t USART3_RX_BUF[80];  // 缓存最大80个字节,第1个字节为接收帧字节数量


/**
  * @name   USART3_IRQHandler
  * @brief  This function handles USART3 Handler
  * @param  None
  * @retval None
  */
void USART3_IRQHandler(void)
{
        uint8_t res;
        uint8_t clear = clear;      // 清除空闲中断标志位标志
        static uint8_t Rx_Sta = 1;  // 计数器
       
        if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)  // 接收到字节
        {
                res = USART3->DR;  // 读取接收到的字节,清除接收中断标志位
                USART3_RX_BUF[Rx_Sta++] = res;   // 缓存接收到的字节
        }
        else if(USART_GetITStatus(USART3, USART_IT_IDLE) != RESET)  // 检测到空闲
        {
                clear = USART3->SR;
                clear = USART3->DR;  // 清除空闲中断标志位(请参照芯片参考手册)
                USART3_RX_BUF[0] = Rx_Sta - 1;  // 一帧字节数计算
                Rx_Sta = 1;
        }
}
USART3_RX_BUF为接收缓存区,定义为80个字节,第一个字节USART3_RX_BUF[0]为接收到的字节个数,后面为接收到的数据。


  • USART3_RX_BUF[0]可以作为数据帧字节长度的判断。
  • res = USART3->DR清除接收中断标志位。
    参考STM32F10xxx英文参考手册,当PDR移位寄存器中的数据转移到USART_DR寄存器中,该位被硬件置位。如果USART_CR1寄存器中的RXNE=1,则产生中断。对USART_DR进行读取操作可以将该标志位清除。也可以通过写入0来清除,但这种方式只推荐用于多缓存通讯。




  • clear = USART3->SR;
    clear = USART3->DR;清除空闲中断标志位。
    参考STM32F10xxx英文参考手册,当检测到总线空闲,该位被硬件置位。如果USART_CR1寄存器中的IDLEIE=1,则产生中断。使用软件序列可以清除该标志位(先对USART_SR读取,再对USART_DR读取)。IDLE标志位不会再次被置高直到RXNE标志位被置高,即又检测到一次空闲总线。
    通俗地讲:
    空闲中断检测到一次空闲后,会自动失能,清除标志位后也不会再次触发;
    当接收到新的数据时,空闲中断会自动使能,检测到空闲就产生中断。
    空闲中断的使用是基于接收中断的,必须开启接收中断才能正常使用。





举报

更多回帖

发帖
×
20
完善资料,
赚取积分