STM32F407使用标准库,串口USART2通过DMA进行数据接收,接收缓冲区使用乒乓缓冲的实例
时间: 2023-06-25 10:06:54 浏览: 99
以下是一个使用标准库在STM32F407上使用DMA接收USART2数据的例子,其中接收缓冲区使用乒乓缓冲:
```c
#include "stm32f4xx.h"
#include <string.h>
#define BUFFER_SIZE 512
uint8_t rxBuffer[BUFFER_SIZE][2]; // 乒乓缓冲区
volatile uint8_t rxIndex = 0; // 当前读取的缓冲区索引
volatile uint16_t rxCounter = 0; // 接收的数据长度
void USART2_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;
DMA_InitTypeDef DMA_InitStruct;
// 使能GPIOA和DMA1时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
// 使能USART2时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
// 初始化GPIOA
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// 将PA2的复用功能映射到USART2上
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);
// 初始化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_Init(USART2, &USART_InitStruct);
USART_Cmd(USART2, ENABLE);
// 初始化DMA
DMA_InitStruct.DMA_Channel = DMA_Channel_4;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t) &USART2->DR;
DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t) &rxBuffer[0][0];
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_VeryHigh;
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);
// 使能USART2的DMA接收
USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);
// 使能DMA流
DMA_Cmd(DMA1_Stream5, ENABLE);
}
void DMA1_Stream5_IRQHandler(void) {
if (DMA_GetITStatus(DMA1_Stream5, DMA_IT_TCIF5)) {
// 清除中断标志
DMA_ClearITPendingBit(DMA1_Stream5, DMA_IT_TCIF5);
// 切换缓冲区
rxIndex = (rxIndex + 1) % 2;
// 计算接收到的数据长度
if (rxCounter < BUFFER_SIZE) {
rxCounter += BUFFER_SIZE / 2;
}
}
}
int main(void) {
USART2_Init();
while (1) {
// 等待接收到数据
while (rxCounter == 0) {}
// 处理接收到的数据
for (uint16_t i = 0; i < rxCounter; i++) {
uint8_t data = rxBuffer[(rxIndex + 1) % 2][i];
// TODO: 处理接收到的数据
}
// 清空接收缓冲区
rxCounter = 0;
memset(rxBuffer[(rxIndex + 1) % 2], 0, BUFFER_SIZE);
}
}
```
在上述代码中,我们使用了双缓冲技术,即接收缓冲区使用两个相同大小的缓冲区(乒乓缓冲)。当DMA传输完成时,我们通过切换缓冲区的方式将数据存储到另一个缓冲区中,同时计算接收到的数据长度。在主循环中,我们等待接收到数据,处理接收到的数据,然后清空接收缓冲区。在处理接收到的数据时,我们需要注意缓冲区的索引,因为DMA传输可能正在写入其中一个缓冲区。