概述
想必看到这篇博客的你已经知道了DMA的好处了吧,所以这儿就不过多地讲述DMA对于缓解MCU压力有多么重要的用途,DMA在很多方面都可以使用,如IIC,SPI,USART等,这儿主要给出DMA在USART上面的一个实例。
代码实现
主要代码直接在一个程序中实现
全局变量以及宏定义
#define DEFAULT_BAUD 115200
#define UART_RX_LEN 128
/*串口接收DMA缓存*/
uint8_t Uart_Rx[UART_RX_LEN] = {0};
/*串口发送DMA缓存*/
uint8_t Uart_Send_Buffer[100]={0};
uint8_t Data_Receive_Usart=0;
DMA和USART的初始化的函数
void usart_dma_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* 配置GPIO的模式和IO口 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9; //TX
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化串口输入IO
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10; //RX
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //模拟输入
GPIO_Init(GPIOA,&GPIO_InitStructure);
/*初始化串口接收和发送函数*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE);
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_InitStructure.USART_BaudRate = DEFAULT_BAUD;
/*初始化串口*/
USART_Init(USART1,&USART_InitStructure);
/*中断配置*/
USART_ITConfig(USART1,USART_IT_TC,DISABLE);
USART_ITConfig(USART1,USART_IT_RXNE,DISABLE);
USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);
//配置UART1中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //通道设置为串口1中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //中断占先等级0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //中断响应优先级0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //打开中断
NVIC_Init(&NVIC_InitStructure);
/*DMA发送中断设置*/
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/*DMA1通道4配置发送*/
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_DeInit(DMA1_Channel4);
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Uart_Send_Buffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 100;
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_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel4,&DMA_InitStructure);
DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);
//DMA_Cmd(DMA1_Channel4, ENABLE);//使能通道4,一般发送的时候再使能
/*DMA1通道5配置接收*/
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_DeInit(DMA1_Channel5);
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Uart_Rx;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = UART_RX_LEN;
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_VeryHigh;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel5,&DMA_InitStructure);
/*使能通道5*/
DMA_Cmd(DMA1_Channel5,ENABLE);
//采用DMA方式发送
USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
//采用DMA方式接收
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
//启动串口
USART_Cmd(USART1, ENABLE);
}
DMA发送使能函数
/**@ brief 使能发送数据
*
* 启动DMA数据发送功能
*
* @param size表示需要发送的DMA中数据的个数
*/
void uart_dma_send_enable(uint16_t size)
{
DMA1_Channel4->CNDTR = (uint16_t)size;
DMA_Cmd(DMA1_Channel4, ENABLE);
}
串口接收的中断函数
/**@ brief串口1接收中断
*
* 收到一帧数据进入一次,进行DMA的读取
*
*/
void USART1_IRQHandler(void)
{
uint32_t temp = 0;
uint16_t i = 0;
if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)
{
//USART_ClearFlag(USART1,USART_IT_IDLE);
temp = USART1->SR;
temp = USART1->DR; //清USART_IT_IDLE标志
DMA_Cmd(DMA1_Channel5,DISABLE);
temp = UART_RX_LEN - DMA_GetCurrDataCounter(DMA1_Channel5);
for (i = 0;i < temp;i++)
{
Data_Receive_Usart = Uart_Rx
;
//+++对收到的数据加一后回发出去
Uart_Send_Buffer=Data_Receive_Usart+1;
uart_dma_send_enable(temp);
//+++
}
//设置传输数据长度
DMA_SetCurrDataCounter(DMA1_Channel5,UART_RX_LEN);
//打开DMA
DMA_Cmd(DMA1_Channel5,ENABLE);
}
}
DMA发送中断
/**@ brief DMA发送中断
*
* 发送数据,将DMA中的数据发送出去
*
*/
void DMA1_Channel4_IRQHandler(void)
{
if(DMA_GetITStatus(DMA1_FLAG_TC4)==SET)
{
DMA_ClearFlag(DMA1_FLAG_GL4);
DMA_Cmd(DMA1_Channel4, DISABLE);
}
}
到此为止主要代码就已经结束了,基本上能够满足测试要求
概述
想必看到这篇博客的你已经知道了DMA的好处了吧,所以这儿就不过多地讲述DMA对于缓解MCU压力有多么重要的用途,DMA在很多方面都可以使用,如IIC,SPI,USART等,这儿主要给出DMA在USART上面的一个实例。
代码实现
主要代码直接在一个程序中实现
全局变量以及宏定义
#define DEFAULT_BAUD 115200
#define UART_RX_LEN 128
/*串口接收DMA缓存*/
uint8_t Uart_Rx[UART_RX_LEN] = {0};
/*串口发送DMA缓存*/
uint8_t Uart_Send_Buffer[100]={0};
uint8_t Data_Receive_Usart=0;
DMA和USART的初始化的函数
void usart_dma_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* 配置GPIO的模式和IO口 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9; //TX
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化串口输入IO
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10; //RX
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //模拟输入
GPIO_Init(GPIOA,&GPIO_InitStructure);
/*初始化串口接收和发送函数*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE);
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_InitStructure.USART_BaudRate = DEFAULT_BAUD;
/*初始化串口*/
USART_Init(USART1,&USART_InitStructure);
/*中断配置*/
USART_ITConfig(USART1,USART_IT_TC,DISABLE);
USART_ITConfig(USART1,USART_IT_RXNE,DISABLE);
USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);
//配置UART1中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //通道设置为串口1中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //中断占先等级0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //中断响应优先级0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //打开中断
NVIC_Init(&NVIC_InitStructure);
/*DMA发送中断设置*/
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/*DMA1通道4配置发送*/
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_DeInit(DMA1_Channel4);
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Uart_Send_Buffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 100;
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_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel4,&DMA_InitStructure);
DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);
//DMA_Cmd(DMA1_Channel4, ENABLE);//使能通道4,一般发送的时候再使能
/*DMA1通道5配置接收*/
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_DeInit(DMA1_Channel5);
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Uart_Rx;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = UART_RX_LEN;
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_VeryHigh;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel5,&DMA_InitStructure);
/*使能通道5*/
DMA_Cmd(DMA1_Channel5,ENABLE);
//采用DMA方式发送
USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
//采用DMA方式接收
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
//启动串口
USART_Cmd(USART1, ENABLE);
}
DMA发送使能函数
/**@ brief 使能发送数据
*
* 启动DMA数据发送功能
*
* @param size表示需要发送的DMA中数据的个数
*/
void uart_dma_send_enable(uint16_t size)
{
DMA1_Channel4->CNDTR = (uint16_t)size;
DMA_Cmd(DMA1_Channel4, ENABLE);
}
串口接收的中断函数
/**@ brief串口1接收中断
*
* 收到一帧数据进入一次,进行DMA的读取
*
*/
void USART1_IRQHandler(void)
{
uint32_t temp = 0;
uint16_t i = 0;
if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)
{
//USART_ClearFlag(USART1,USART_IT_IDLE);
temp = USART1->SR;
temp = USART1->DR; //清USART_IT_IDLE标志
DMA_Cmd(DMA1_Channel5,DISABLE);
temp = UART_RX_LEN - DMA_GetCurrDataCounter(DMA1_Channel5);
for (i = 0;i < temp;i++)
{
Data_Receive_Usart = Uart_Rx;
//+++对收到的数据加一后回发出去
Uart_Send_Buffer=Data_Receive_Usart+1;
uart_dma_send_enable(temp);
//+++
}
//设置传输数据长度
DMA_SetCurrDataCounter(DMA1_Channel5,UART_RX_LEN);
//打开DMA
DMA_Cmd(DMA1_Channel5,ENABLE);
}
}
DMA发送中断
/**@ brief DMA发送中断
*
* 发送数据,将DMA中的数据发送出去
*
*/
void DMA1_Channel4_IRQHandler(void)
{
if(DMA_GetITStatus(DMA1_FLAG_TC4)==SET)
{
DMA_ClearFlag(DMA1_FLAG_GL4);
DMA_Cmd(DMA1_Channel4, DISABLE);
}
}
到此为止主要代码就已经结束了,基本上能够满足测试要求
举报