本帖最后由 mmik 于 2018-6-14 16:51 编辑
最近在做一个STM32单片机的项目,用到串口通信功能。但是目前网上的帖子比较零碎现在整理一份完整的代码发到论坛中。希望能帮到用到的朋友。
关键步骤:
1、初始化串口。
2、初始化DMA通道。
3、配置串口中断,当发生IDLE中断时处理一次DMA数据。
4、配置DMA中断,当发生DMA接收完成时处理一次DMA数据。
上代码:
初始化串口:
// 通用端口初始化参数
GPIO_InitTypeDef GPIO_InitStructure;
// 串口初始化参数
USART_InitTypeDef USART_InitStructure;
// 中断向量初始化参数
NVIC_InitTypeDef NVIC_InitStructure;
// 启用GPIO总线时钟
// STM32F1系列GPIO时钟都在APB2总线
RCC_APB2PeriphClockCmd(uartDef->portAPBxParam, ENABLE);
// 启用串口总线时钟
// uart1 在APB2总线,uart2~5 在APB1总线
if (APB1 == uartDef->uartAPBx)
{
RCC_APB1PeriphClockCmd(uartDef->uartAPBxParam, ENABLE);
}
else if (APB2 == uartDef->uartAPBx)
{
RCC_APB2PeriphClockCmd(uartDef->uartAPBxParam, ENABLE);
}
// 设置串口TX发送口
GPIO_InitStructure.GPIO_Pin = uartDef->txPin;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //推挽输出
GPIO_Init(uartDef->txGPIO, &GPIO_InitStructure); //初始化GPIOA.9
// 设置串口RX接收口
GPIO_InitStructure.GPIO_Pin = uartDef->rxPin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(uartDef->rxGPIO, &GPIO_InitStructure);
//USART 初始化设置
USART_InitStructure.USART_BaudRate = uartDef->uartDcb.baudrate; //串口波特率,一般设置为9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长为8位数据格式
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(uartDef->port, &USART_InitStructure); //初始化串口
USART_ITConfig(uartDef->port, USART_IT_RXNE, ENABLE); //开启接收中断
USART_ITConfig(uartDef->port, USART_IT_IDLE, ENABLE); //开启空闲中断
//USART NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = uartDef->NVIC_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; //抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
USART_Cmd(uartDef->port, ENABLE); //使能串口
// 配置DMA收发
DMA_Configuration(port);
//// 配置DMA
DMA_InitTypeDef DMA_InitStructure;
//使能DMA传输
//
if((0x0400 & (u32)DMA_CHx))
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
}
else
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
}
DMA_Cmd(DMA_CHx, DISABLE);
DMA_DeInit(DMA_CHx); //将DMA的通道寄存器重设为缺省值
DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; //DMA外设ADC基地址
DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA内存基地址
DMA_InitStructure.DMA_DIR = dmaDir; //数据传输方向,从内存读取发送到外设
DMA_InitStructure.DMA_BufferSize = bufferSize; //DMA通道的DMA缓存的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //数据宽度为8位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为8位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常缓存模式
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有高优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输
DMA_Init(DMA_CHx,&DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器
DMA_ITConfig(DMA_CHx, DMA_IT_TC, ENABLE);
DMA_Cmd(DMA_CHx, ENABLE);
// 根据端口选择DMA监听
switch(port)
{
case UART_PORT1:
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;
break;
case UART_PORT2:
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel6_IRQn;
break;
case UART_PORT3:
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel3_IRQn;
break;
case UART_PORT4:
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel3_IRQn;
break;
default:
break;
}
// 串口5 不支持DMA
switch(port)
{
case UART1:
case UART2:
case UART3:
case UART4:
// 开启DMA 发送
USART_DMACmd(uartDef->port,USART_DMAReq_Tx,ENABLE);
USART_DMA_Config(uartDef->txChannel,
0,DMA_DIR_PeripheralDST,
(u32)&uartDef->port->DR,(u32)(uartDef->txBuffer));
// 开启DMA 接收
USART_DMACmd(uartDef->port,USART_DMAReq_Rx,ENABLE);
USART_DMA_Config(uartDef->rxChannel,
uartDef->rxMaxLen,DMA_DIR_PeripheralSRC,
(u32)&uartDef->port->DR,(u32)(uartDef->rxBuffer));
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
break;
default:
break;
}
DMA 中断处理(DMA1_IT_TC6 是指通道6的中断标志)
if( DMA_GetITStatus(DMA1_IT_TC6)==SET)
{
DMA_ClearITPendingBit(DMA1_IT_GL6);
DMA_Cmd(uartDef->rxChannel,DISABLE);
uartDef->rxLen = uartDef->rxMaxLen - DMA_GetCurrDataCounter(uartDef->rxChannel);
if (NULL != uartDef->callback)
{
uartDef->callback(UART_PORT2,EVENT_UART_READY_TO_READ,uartDef->customizePara);
}
DMA_SetCurrDataCounter(uartDef->rxChannel,uartDef->rxMaxLen);
DMA_Cmd(uartDef->rxChannel,ENABLE);
}
USART 中断处理
if(USART_GetITStatus(uartDef->port, USART_IT_IDLE) != RESET)
{
res = uartDef->port->SR;
res = uartDef->port->DR;
DMA_Cmd(uartDef->rxChannel,DISABLE);
uartDef->rxLen = uartDef->rxMaxLen - DMA_GetCurrDataCounter(uartDef->rxChannel);
if (NULL != uartDef->callback)
{
uartDef->callback(port,EVENT_UART_READY_TO_READ,uartDef->customizePara);
}
DMA_SetCurrDataCounter(uartDef->rxChannel,uartDef->rxMaxLen);
DMA_Cmd(uartDef->rxChannel,ENABLE);
}
|