STM32F429标准库使用DMA实现串口收发
自己使用的代码
全局变量
uint8_t USART1SendBuff[128];
uint8_t USART1ReceiveBuff[128];
uint8_t USART1ReceiveBuffSize;//串口接收数据的长度
uint8_t USART1_Tx_Flage = 0;//串口使用DMA发送数据标志位,1:正在通信;0:通信结束
uint8_t USART1_Rx_Flage = 0;//串口使用DMA接收数据标志位,1:收到数据;0:没有数据
串口初始化
void USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
//配置GPIO口为复用功能
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//选择具体的复用功能
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
//配置USART参数
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
//配置中断
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); //开启检测串口空闲状态中断,用在接收不定长数据
USART_ClearITPendingBit(USART1, USART_IT_TC);
USART_Cmd(USART1, ENABLE);
//配置NVIC
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//优先级低于对应的DMA优先级(1)
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
对应的DMA初始化
void USART_DMA_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
//USART1_TX
DMA_DeInit(DMA2_Stream7);
while(DMA_GetCmdStatus(DMA2_Stream7) != DISABLE);//确保DMA数据流复位完成
DMA_InitStructure.DMA_Channel = DMA_Channel_4;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;//设置DMA源为串口数据寄存器地址
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)USART1SendBuff;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_BufferSize = sizeof(USART1SendBuff);
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream7, &DMA_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream7_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
DMA_ITConfig(DMA2_Stream7, DMA_IT_TC, ENABLE);
DMA_ClearFlag(DMA2_Stream7, DMA_IT_TC);
USART1_Tx_Flage = 0;
//USART1_RX
DMA_DeInit(DMA2_Stream2);
while(DMA_GetCmdStatus(DMA2_Stream2) != DISABLE);//确保DMA数据流复位完成
DMA_InitStructure.DMA_Channel = DMA_Channel_4;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;//设置DMA源为串口数据寄存器地址
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)USART1ReceiveBuff;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = sizeof(USART1ReceiveBuff);
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream2, &DMA_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
DMA_Cmd(DMA2_Stream2, ENABLE);//初始时打开
while(DMA_GetCmdStatus(DMA2_Stream2) != ENABLE);
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
USART1_Rx_Flage = 0;
}
串口重定向
void USART1_Printf(char *format, ...)
{
uint32_t length;
va_list arg_ptr;
while(USART1_Tx_Flage);//等待上一次传输结束
va_start(arg_ptr, format);
length = vsnprintf((char*)USART1SendBuff, sizeof(USART1SendBuff)+1, (char*)format, arg_ptr);
va_end(arg_ptr);
DMA_SetCurrDataCounter(DMA2_Stream7, length);//设置DMA传输的长度
USART1_Tx_Flage = 1;
DMA_Cmd(DMA2_Stream7, ENABLE);//开始DMA传输,触发DMA的TC中断
while(DMA_GetCmdStatus(DMA2_Stream7) != ENABLE);
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
}
串口发送的DMA传输完成中断函数
void DMA2_Stream7_IRQHandler(void)
{
if(DMA_GetITStatus(DMA2_Stream7, DMA_IT_TCIF7) == SET)
{
DMA_Cmd(DMA2_Stream7, DISABLE);//关闭DMA通道
while(DMA_GetCmdStatus(DMA2_Stream7) != DISABLE);//DMA只有在关闭的时候才能设置一些参数
DMA_ClearITPendingBit(DMA2_Stream7, DMA_IT_TCIF7 | DMA_IT_HTIF7);
USART_DMACmd(USART1, USART_DMAReq_Tx, DISABLE);
USART1_Tx_Flage = 0;
}
}
串口接收完成中断函数
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_IDLE) == SET)//接收不定长数据,需要保证接收的数据长度小于DMA的设置长度
{
USART_ReceiveData(USART1);
USART_ClearITPendingBit(USART1, USART_IT_IDLE);//这个中端标志位清除比较特殊,看手册
DMA_Cmd(DMA2_Stream2, DISABLE);//要先关闭DMA才能触发DMA的标志位
while(DMA_GetCmdStatus(DMA2_Stream2) != DISABLE);//等待关闭完成
DMA_ClearITPendingBit(DMA2_Stream2, DMA_IT_TCIF2 | DMA_IT_HTIF2);
USART1ReceiveBuffSize = sizeof(USART1ReceiveBuff) - DMA_GetCurrDataCounter(DMA2_Stream2);//计算获取数据点长度
USART1_Rx_Flage = 1;
DMA_SetCurrDataCounter(DMA2_Stream2, sizeof(USART1ReceiveBuff));
DMA_Cmd(DMA2_Stream2, ENABLE);
while(DMA_GetCmdStatus(DMA2_Stream2) != ENABLE);//等待打开完成
}
}