STM32F407使用USART2外设进行DMA1发送以及接收未知长度的数据

1、STM32的串口接收数据有三种方式可以选择:

1.1 轮询接收
       在主循环中一直判断串口接收完成标志位是否置位,如果置位则读取收到的数据。该种模式一般不会使用,其缺点很明显,当主函数在做其他工作时接收数据标志位置位,此时将得不到及时响应,从而错过后续数据的接收。

1.2 中断接收
       将串口接收配置为中断模式,当有数据收到时,进入到串口接收中断中读取数据。这种方式使用最多,好处是可以处理收到的每一字节数据,数据不会有漏掉,适合一般数据量少、接收频率低的场合。但是当频繁接收数据且串口使用多(STM32F4有六路串口)的情况下,会频繁的进入串口中断处理接收到的数据,会影响系统的性能。

1.3 空闲中断接收
       严格来说,空闲中断接收模式也是一种中断接收模式,只不过稍加改进,当一帧数据接收完成之后,串口会进入到空闲中断中去,然后在空闲中断中处理收到的数据。这种模式对处理不定长数据帧带来很大的便利,我们不必频繁的进入接收中断处理数据,但是弊端也是明显的,由于每次都要接收完一个完整的数据帧后才空闲中断,所以当一帧数据出错时,我们也不得不接收这帧错误的数据。在通讯可靠的场合,使用空闲中断接收模式接收串口数据,将会大大提高系统的性能。

2 空闲中断接收原理及使用方法
2.1空闲中断接收的原理
       其实,空闲中断接收的原理非常简单,比如我们在使用波特率为115200 8 N 1模式接收数据时,接收每个bit和每个byte需要的时间是固定的,当我们发送一帧数据,如:0x55 0xaa 0x00 0x01 0x02 0x03 时,发送是连续的,也就是说如果使用串口接收中断,那么就会进入六次接收中断里,直到收到最后一byte数据0x03为止,但是我们使用空闲中断接收模式时,在收到最后一byte数据0x03后的一个byte时间段后没有收到下一byte数据,串口就认为此时处于空闲模式,然后就触发了空闲中断,进入到空闲中断接收服务函数中了。

2.2 空闲中断使用方法
      我们使用DMA来暂存接收到的串口数据,然后在空闲中断中取出数据。整个操作比较简单。接下来谈谈整个实现过程。

3、串口的配置

这里我们使用的时USART2-----这里我们分模块进行配置

3.1 串口USART2的配置

u8 USART2_RX_BUF[USART2_REC_LEN]={0};     //接收缓冲,最大USART_REC_LEN个字节.

u16 USART2_RX_STA=0;       //接收状态标记	

u16 USART2_RX_CNT=0;
//初始化IO 串口2   bound:波特率	
void RS422_Init(u32 bound)
{  	 
    GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//使能USART2时钟
	
  //串口2引脚复用映射
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_USART2); //GPIOA2复用为USART2
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_USART2); //GPIOA3复用为USART2
	
	//USART2    
   GPIO_InitStr
下面是一个使用STM32F407标准库和DMAUSART2循环接收示例代码。该代码使用DMA接收USART2传输的数据,并将其存储在一个缓冲区中,然后在接收到特定字符时将缓冲区中的数据打印出来。 ```c #include "stm32f4xx.h" #include <stdio.h> #include <string.h> #define BUFFER_SIZE 50 #define RX_COMPLETE_FLAG (1 << 6) volatile uint8_t buffer[BUFFER_SIZE]; volatile uint8_t rx_index = 0; volatile uint8_t rx_complete = 0; void USART2_Init(void); void DMA1_Stream5_IRQHandler(void); int main(void) { USART2_Init(); while (1) { if (rx_complete) { printf("Received: %s\n", buffer); rx_index = 0; rx_complete = 0; memset(buffer, 0, sizeof(buffer)); } } } void USART2_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; USART_InitTypeDef USART_InitStruct; NVIC_InitTypeDef NVIC_InitStruct; DMA_InitTypeDef DMA_InitStruct; // Enable clock for GPIOA and USART2 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); // Configure GPIO pins for USART2 transmit and receive GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOA, &GPIO_InitStruct); // Connect GPIO pins to USART2 alternate function GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2); GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2); // Configure USART2 USART_InitStruct.USART_BaudRate = 115200; USART_InitStruct.USART_WordLength = USART_WordLength_8b; USART_InitStruct.USART_StopBits = USART_StopBits_1; USART_InitStruct.USART_Parity = USART_Parity_No; USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART2, &USART_InitStruct); // Enable USART2 receive interrupt USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); // Configure NVIC for USART2 NVIC_InitStruct.NVIC_IRQChannel = USART2_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStruct); // Configure DMA1 Channel 4 Stream 5 for USART2 receive RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); DMA_InitStruct.DMA_Channel = DMA_Channel_4; DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&USART2->DR; DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)buffer; DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStruct.DMA_BufferSize = BUFFER_SIZE; DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; DMA_InitStruct.DMA_Priority = DMA_Priority_High; DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA1_Stream5, &DMA_InitStruct); // Enable DMA1 Stream 5 transfer complete interrupt DMA_ITConfig(DMA1_Stream5, DMA_IT_TC, ENABLE); // Configure NVIC for DMA1 Stream 5 NVIC_InitStruct.NVIC_IRQChannel = DMA1_Stream5_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStruct); // Enable USART2 and DMA1 Channel 4 Stream 5 USART_Cmd(USART2, ENABLE); DMA_Cmd(DMA1_Stream5, ENABLE); } void USART2_IRQHandler(void) { if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) { USART_ClearITPendingBit(USART2, USART_IT_RXNE); } } void DMA1_Stream5_IRQHandler(void) { if (DMA_GetFlagStatus(DMA1_Stream5, RX_COMPLETE_FLAG) != RESET) { DMA_ClearFlag(DMA1_Stream5, RX_COMPLETE_FLAG); // Copy the contents of the buffer up to the delimiter to a local buffer uint8_t temp_buffer[BUFFER_SIZE]; uint8_t delimiter = '\n'; for (uint8_t i = 0; i < BUFFER_SIZE; i++) { temp_buffer[i] = buffer[i]; if (buffer[i] == delimiter) { temp_buffer[i] = '\0'; rx_complete = 1; break; } } } } ``` 在此示例中,我们使用DMA1的通道4和流5来接收USART2传输的数据使用DMA实现循环接收的好处是,可以避免在中断中处理大量数据,从而提高系统的响应能力。在DMA配置中,我们将USART2数据寄存器作为DMA外设地址,并将缓冲区作为DMA的内存地址。我们还启用了循环模式,以便在接收缓冲区溢出时重新开始接收。 在DMA传输完成时,我们将使用DMA传输完成中断处理程序来检查接收到的数据。由于我们在接收到特定字符时才打印缓冲区中的数据,因此我们需要在此处检查缓冲区中是否存在特定字符。如果找到特定字符,则将缓冲区中的数据复制到临时缓冲区中,并将rx_complete标志设置为1,以便在主循环中打印数据。在打印缓冲区中的数据之后,我们需要清空缓冲区以便接收新的数据
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值