前言:
最近项目中需要用到串口及网口输出大量的数据给上位机,先调试串口。发现CPU花蛮多时间来传输数据,太浪费了。所以想到了用DMA来传输串口数据,一搜资料,库函数里还真的有DMA来实现USART数据的传输的,真的。遂有以下学习笔记:
我以前使用串口都是简单的通过重构putchar函数,调用printf函数来给上位机PC传输数据的,数据格式通常是ASCII码,然而这次数据帧格式是十六进制,所以得用USART_SendData()函数了,由于数据量大,有3000多字节数据,除了发送数据外,CPU还得做其他事情,所以这里用DMA来传数据。
(1)建立发送数据缓冲区:uint32_t SendBuff[3000];
(2)宏定义串口的DMA基地址:#define USART1_DR_Base 0x40013804
(3)开启USART1、GPIOA、AFIO、DMA1的时钟,并且初始化USART的GPIO:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9; //tx
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10; //rx
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);
USART_InitStructure.USART_BaudRate=256000; //波特率256000bit/s
USART_InitStructure.USART_WordLength=USART_WordLength_8b; //8 bit data
USART_InitStructure.USART_StopBits=USART_StopBits_1; // stop bit 1
USART_InitStructure.USART_Parity=USART_Parity_No; //no parity bit
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx; //双工模式
USART_Init(USART1,&USART_InitStructure);
(4)使能串口1的发送和接收中断;使能串口1:
//enable USART1's interruput
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
//enable USART1
USART_Cmd(USART1,ENABLE);
(5)USART中断优先级配置:
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
(6)DMA对USART1的配置:
void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
DMA_DeInit(DMA1_Channel4);
DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;//在(2)中已经宏定义了,内存地址&串口数据寄存器地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff; //要发送的数组,注意此处发送的是32位的, 即四个字节的数据。
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 3000; //传输数据大小
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模式一次传输,不循环
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//优先级中
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel4, &DMA_InitStructure);
}
(7)主函数:
int main(void)
{
SystemInit();
USART_Config();
NVIC_Configuration();
DMA_Configuration();
LED_Config();
Data_init();
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);//将USART1配置成DAM方式工作,
DMA_Cmd(DMA1_Channel4, ENABLE);//使能DMA通道,开始传输数据
while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET)//此时DMA正在传输数据,传输结束则跳出while
{
LED1_ON; //当DMA在传输数据时,CPU在此可以干其他事情,这里是举例点灯
LED2_OFF;
delay_ms(50);
LED1_OFF;
LED2_ON;
delay_ms(50);
}
printf("\r\nDMA transmission successful!\r\n");
while(1);
}
(8)还有USART中断尚未弄明白,后续补充。
文章评论(0条评论)
登录后参与讨论