gd32F303串口接收的几种方式

一、串口接受到换行符停止

cpp 复制代码
#include "usart.h"

UCHAR arr_rxData[1024]={0};//存储串口接收的数据
UINT arr_len=0;//串口已经接收数据的字节数个数
USART_RX_FLAG rxFlg=FLASE;//默认串口未接收到数据

void USART2_Init(void)
{
	rcu_periph_clock_enable(RCU_GPIOB); //enable GPIO clock 
	rcu_periph_clock_enable(RCU_USART2);// enable USART clock

	gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10); // USARTx_Tx 
	gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_11);//USARTx_Rx

	usart_deinit(USART2); //USART configure 
	usart_baudrate_set(USART2, 115200);                //设置波特率
	usart_word_length_set(USART2, USART_WL_8BIT);      //设置数据位
	usart_parity_config(Uusart_hardware_flow_rts_config(USART2, USART_RTS_DISABLE); 
	usart_hardware_flow_cts_config(USART2, USART_CTS_DISABLE); //无硬件数据流控制
	usart_receive_config(USART2, USART_RECEIVE_ENABLE);        //使能接收器
	usart_transmit_config(USART2, USART_TRANSMIT_ENABLE);      //使能发送器
	
	nvic_irq_enable(USART2_IRQn, 1, 0);//配置NVIC分组,初始化NVIC分组4
	usart_interrupt_enable(USART2, USART_INT_RBNE);//使能接收中断
	usart_enable(USART2);//使能串口
}

int fputc(int ch, FILE *f) 
{
    while(RESET == usart_flag_get(USART2, USART_FLAG_TBE));
    usart_data_transmit(USART2, (uint8_t)ch);
    return ch;
}

/****************************************************************************
1、如果使能接收中断但是还是没有进入中断处理函数,可能是硬件接线比较松,导致出现问题
2、接收数据代码书写
	if(rxFlg==TRUE)//表示接受一次数据完成
	{
		printf("receive data:%s\r\n",arr_rxData);
		
		//将接收数据的标志位,数据长度,存储数据数组都清0
		rxFlg=FLASE;
		arr_len=0;
		memset(arr_rxData,0,sizeof(arr_rxData));
	}
******************************************************************************/
void USART2_IRQHandler(void) 
{
	if(RESET != usart_interrupt_flag_get(USART2, USART_INT_FLAG_RBNE)){
        arr_rxData[arr_len++]=usart_data_receive(USART2);
		if(arr_rxData[arr_len-1]==0x0a)
		{
			rxFlg=TRUE;
			arr_len--;
			arr_rxData[arr_len]='\0';
		}
    }
    //usart_interrupt_flag_clear(USART2, USART_INT_FLAG_RBNE);
	/*清除中断标志位,不用手动清除中断标志位,因为不管是直接读寄存器还是通过DMA,只要是对USART_DATA寄存器的一个读操作都可以硬件自动清除RBNE位*/
}

二、使用空闲中断实现串口接收

对于串口接收到的数据,还有很重要的一点就是不确定长度,这样就不知道何时该停止接收,这个时候,串口的空闲中断就体现出他的重要性了,那么什么是空闲中断呢?

空闲中断是在检测到有数据接收后,总线上在一个字节的时间内没有再接收到数据时,从而产生中断。即串口的RXNE位被置位之后才开始检测,检测到空闲之后,串口的CR1寄存器的IDLE位被硬件置1。

cpp 复制代码
#include "usart.h"

UCHAR arr_rxData[1024]={0};//存储串口接收的数据
UINT arr_len=0;//串口已经接收数据的字节数个数
USART_RX_FLAG rxFlg=FLASE;//默认串口未接收到数据

void USART2_Init(void)
{
	rcu_periph_clock_enable(RCU_GPIOB); //enable GPIO clock 
	rcu_periph_clock_enable(RCU_USART2);// enable USART clock

	gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10); // USARTx_Tx 
	gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_11);//USARTx_Rx

	usart_deinit(USART2); //USART configure 
	usart_baudrate_set(USART2, 115200);                //设置波特率
	usart_word_length_set(USART2, USART_WL_8BIT);      //设置数据位
	usart_parity_config(Uusart_hardware_flow_rts_config(USART2, USART_RTS_DISABLE); 
	usart_hardware_flow_cts_config(USART2, USART_CTS_DISABLE); //无硬件数据流控制
	usart_receive_config(USART2, USART_RECEIVE_ENABLE);        //使能接收器
	usart_transmit_config(USART2, USART_TRANSMIT_ENABLE);      //使能发送器
	
	nvic_irq_enable(USART2_IRQn, 1, 0);//配置NVIC分组,初始化NVIC分组4
	usart_interrupt_enable(USART2, USART_INT_RBNE);//使能接收中断
	usart_enable(USART2);//使能串口
}

int fputc(int ch, FILE *f) 
{
    while(RESET == usart_flag_get(USART2, USART_FLAG_TBE));
    usart_data_transmit(USART2, (uint8_t)ch);
    return ch;
}

void USART2_IRQHandler(void) 
{
	if(RESET != usart_interrupt_flag_get(USART2, USART_INT_FLAG_RBNE)){
        arr_rxData[arr_len++]=usart_data_receive(USART2);
    }
	if(RESET != usart_interrupt_flag_get(USART2, USART_INT_FLAG_IDLE))
	{
		usart_interrupt_flag_clear(USART2,USART_INT_FLAG_IDLE);	/* 清除空闲中断标志位 */
		usart_data_receive(USART2);		
		rxFlg=TRUE;
		arr_len--;
		arr_rxData[arr_len]='\0';
	}
}

三、使用DMA转运数据实现串口接收

对于串口的数据接收来说,和发送一样,如果采用传统的接收中断模式接收数据,同样的会因为频繁中断而导致消耗大量CPU资源,所以也使用DMA进行串口数据的接收。

cpp 复制代码
#define USART2_ADDR (uint32_t)&USART_DATA(USART2)
UCHAR UART2_RX_BUF[UART2_RX_LEN*2]; 		/* 双接收缓冲区 */
USART_RX_FLAG UART2_RX_STAT = FLASE;	
UINT UART2_RX_NUM = 0;					/* 接收到的数据个数 */

void USART2_DMA_Init(void)
{
	dma_parameter_struct dma_init_struct;	/* DMA配置参数结构体 */
	
	rcu_periph_clock_enable(RCU_GPIOB); //enable GPIO clock 
	rcu_periph_clock_enable(RCU_USART2);// enable USART clock
	rcu_periph_clock_enable(RCU_DMA0);		/* 使能 DMA0 时钟 */

	gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10); 
	gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_11);

	usart_deinit(USART2); //USART configure 
	usart_baudrate_set(USART2, 115200);                //设置波特率
	usart_word_length_set(USART2, USART_WL_8BIT);      //设置数据位
	usart_parity_config(USART2, USART_PM_NONE);        //设置奇偶校验位
	usart_stop_bit_set(USART2, USART_STB_1BIT);        //设置停止位
	usart_hardware_flow_rts_config(USART2, USART_RTS_DISABLE); //禁用rts
	usart_hardware_flow_cts_config(USART2, USART_CTS_DISABLE); //无硬件数据流控制
	usart_receive_config(USART2, USART_RECEIVE_ENABLE);        //使能接收器
	usart_transmit_config(USART2, USART_TRANSMIT_ENABLE);      //使能发送器
	
	/* USART0 DMA 接收配置*/
    dma_deinit(DMA0, DMA_CH2);/*USART2_RX:CH2 USART0_RX:CH4*/
	dma_struct_para_init(&dma_init_struct);
    dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;		/* 外设到存储器方向 */
    dma_init_struct.memory_addr = (uint32_t)UART2_RX_BUF;		/* 存储器基地址 */
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;	/* 存储器地址自增 */
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;		/* 存储器位宽为8位 */
   dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;			/* 软件优先级为极高*/
    dma_init(DMA0, DMA_CH2, &dma_init_struct);

    dma_circulation_disable(DMA0, DMA_CH2);/* DMA循环模式配置,不使用循环模式 */
    usart_dma_transmit_config(USART2, USART_DENT_ENABLE);
	usart_dma_receive_config(USART2, USART_DENR_ENABLE);
	nvic_irq_enable(DMA0_Channel2_IRQn, 0, 0);/* DMA0 通道2 中断优先级设置并使能 */
    dma_channel_enable(DMA0, DMA_CH2);/* 使能 DMA0 通道2 */
	
	nvic_irq_enable(USART2_IRQn, 1, 0);//配置NVIC分组,初始化NVIC分组4
	usart_interrupt_enable(USART2, USART_INT_IDLE);/* 使能USART0空闲中断 */
	usart_enable(USART2);//使能串口
}

/*
如果接收完毕,那么将数据打印出来
if(UART2_RX_STAT == TRUE)
{
	UART2_RX_STAT = FLASE;
	printf("RECEIVE %d data:%s \r\n", UART2_RX_NUM, UART2_RX_BUF);
}
*/
void USART2_IRQHandler(void)	
{
    if(RESET != usart_interrupt_flag_get(USART2, USART_INT_FLAG_IDLE)) //空闲中断
	{
		usart_interrupt_flag_clear(USART2,USART_INT_FLAG_IDLE);	/* 清除空闲中断标志位 */
		usart_data_receive(USART2);								/* 清除接收完成标志位 */
		dma_channel_disable(DMA0, DMA_CH2);						/* 关闭DMA传输 */
		
		UART2_RX_NUM = sizeof(UART2_RX_BUF) - dma_transfer_number_get(DMA0,DMA_CH2);
		UART2_RX_BUF[UART2_RX_NUM] = '\0';	/* 添加字符串结束符 */
		UART2_RX_STAT = TRUE;/* 接收完成 */				
		
		/* 重新设置DMA传输 */
		dma_memory_address_config(DMA0,DMA_CH2,(uint32_t)UART2_RX_BUF);
		dma_transfer_number_config(DMA0,DMA_CH2,sizeof(UART2_RX_BUF));
		dma_channel_enable(DMA0, DMA_CH2);		/* 开启DMA传输 */
    }
}
相关推荐
学习日记hhh10 分钟前
STM32G431RBT6(蓝桥杯)串口(发送)
stm32·单片机·嵌入式硬件
老李的森林10 分钟前
嵌入式开发--STM32延时函数重构
stm32·单片机·嵌入式硬件·重构·延时
OH五星上将2 小时前
OpenHarmony(鸿蒙南向开发)——小型系统内核(LiteOS-A)【内核通信机制】上
linux·嵌入式硬件·harmonyos·openharmony·鸿蒙开发·liteos-a·鸿蒙内核
爱桥代码的程序媛2 小时前
鸿蒙OpenHarmony【轻量系统内核通信机制(互斥锁)】子系统开发
嵌入式硬件·harmonyos·鸿蒙·openharmony··鸿蒙开发·子系统开发
c10638915149 小时前
STM32外设之LTDC/DMA2D—液晶显示(野火)
stm32·单片机·嵌入式硬件
LongRunning9 小时前
【快速笔记】freeRTOS
单片机
唯创知音10 小时前
电子烟智能化创新体验:WTK6900P语音交互芯片方案,融合频谱计算、精准语音识别与流畅音频播报
人工智能·单片机·物联网·音视频·智能家居·语音识别
MGT_979610 小时前
基于51单片机的台灯控制(Proteus仿真)
嵌入式硬件·51单片机·proteus
夜间去看海10 小时前
基于51单片机的倒计时音乐播放系统设计
单片机·嵌入式硬件·51单片机
aqymnkstkw12 小时前
2024年【电气试验】考试题库及电气试验模拟试题
大数据·c语言·人工智能·嵌入式硬件·安全