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

先点赞,再看博客,顺便点个关注鼓励一下。
如果文章看完,觉得不错的话可以点个收藏,日后不迷路。

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

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;
	}
}
  1. USART3_RX_BUF为接收缓存区,定义为80个字节,第一个字节USART3_RX_BUF[0]为接收到的字节个数,后面为接收到的数据。
  2. USART3_RX_BUF[0]可以作为数据帧字节长度的判断。
  3. res = USART3->DR清除接收中断标志位。
    参考STM32F10xxx英文参考手册,当PDR移位寄存器中的数据转移到USART_DR寄存器中,该位被硬件置位。如果USART_CR1寄存器中的RXNE=1,则产生中断。对USART_DR进行读取操作可以将该标志位清除。也可以通过写入0来清除,但这种方式只推荐用于多缓存通讯。
    RXNE
  4. clear = USART3->SR;
    clear = USART3->DR;清除空闲中断标志位。
    参考STM32F10xxx英文参考手册,当检测到总线空闲,该位被硬件置位。如果USART_CR1寄存器中的IDLEIE=1,则产生中断。使用软件序列可以清除该标志位(先对USART_SR读取,再对USART_DR读取)。IDLE标志位不会再次被置高直到RXNE标志位被置高,即又检测到一次空闲总线。
    通俗地讲:
    空闲中断检测到一次空闲后,会自动失能,清除标志位后也不会再次触发;
    当接收到新的数据时,空闲中断会自动使能,检测到空闲就产生中断。
    空闲中断的使用是基于接收中断的,必须开启接收中断才能正常使用。

    IDLE

2. 最后

    本教程由 Brendon Tan 原创发布,版权所有。该文档仅供个人学习交流使用,不得用于其他用途,禁止商用, 转载或公开使用请联系作者授权。
    此教程由本人独立整理,如有不当之处,欢迎指正。

猜你喜欢

转载自blog.csdn.net/Brendon_Tan/article/details/89716628