使用DMA中断规避或减轻单片机对通信快速响应的需求
可能在很多时候我们想到使用DMA只是为了处理大量数据接收的时候减轻对单片机的使用负荷,其实这在一定程度上也是可以认为对需要快速响应去做接收以及长时间接收的一种很好的处理方法。因为总会有遇到正在执行任务的时候单片机来不及去响应某一通信以及处理大量数据。因此我们可以使用DMA在脱离单片机内核的情况下,先响应通信接收完数据之后,然后再产生中断告诉单片机去处理DMA接收好的数据。
1.示意图:
个人觉得还是画个图来的直观,哈哈
2.代码实现
这里以串口通信为例:
(1)外围硬件初始化函数
void Hardware_Init(void)
{
delay_init(168); //初始化时钟
Usart1_Init(115200); //串口1初始化
DMA_Config_About_Rx(); //关于DMA接收配置
DMA_Config_About_Tx(); //关于DMA发送配置
}
(2)串口1初始化函数(需要看详细注释,可下载文末工程链接)
void Usart1_Init(unsigned int baud)
{
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_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA,&GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = baud;
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_Cmd(USART1, ENABLE);
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
}
(3)串口中断服务函数
void USART1_IRQHandler(void)
{
u16 Res;
if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)
{
DMA_Cmd(DMA2_Stream5, DISABLE);
Res = USART1->SR;
Res = USART1->DR;
Rx_Data_Lenth = BufferLen - DMA_GetCurrDataCounter(DMA2_Stream5);
if(Rx_Data_Lenth!=0)
{
rx_flag=true;
for(Res=0; Res < Rx_Data_Lenth; Res++)
{
SendBuffer[Res]= ReceiveBuffer[Res];
}
for(Res=0; Res < Rx_Data_Lenth; Res++)
{
ReceiveBuffer[Res]=0;
}
}
DMA_ClearFlag(DMA2_Stream5,DMA_FLAG_TCIF5 | DMA_FLAG_FEIF5 | DMA_FLAG_DMEIF5 | DMA_FLAG_TEIF5 | DMA_FLAG_HTIF5);
DMA_SetCurrDataCounter(DMA2_Stream5, BufferLen);
DMA_Cmd(DMA2_Stream5, ENABLE);
}
(4)DMA发送配置
void DMA_Config_About_Tx(void)
{
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);
DMA_DeInit(DMA2_Stream7);
while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE);
DMA_InitStructure.DMA_Channel = DMA_Channel_4;
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;
DMA_InitStructure.DMA_Memory0BaseAddr = (u32)SendBuffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_BufferSize = BufferLen;
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_Medium;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
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 = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
DMA_ITConfig(DMA2_Stream7,DMA_IT_TC,ENABLE);
}
(5)DMA接收配置
void DMA_Config_About_Rx(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);
DMA_DeInit(DMA2_Stream5);
while (DMA_GetCmdStatus(DMA2_Stream5) != DISABLE);
DMA_InitStructure.DMA_Channel = DMA_Channel_4;
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;
DMA_InitStructure.DMA_Memory0BaseAddr = (u32)ReceiveBuffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory ;
DMA_InitStructure.DMA_BufferSize = BufferLen;
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_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream5, &DMA_InitStructure);
DMA_Cmd(DMA2_Stream5, ENABLE);
}
(6)DMA中断服务函数
void DMA2_Stream7_IRQHandler(void)
{
if(DMA_GetFlagStatus(DMA2_Stream7,DMA_FLAG_TCIF7)!=RESET)
{
DMA_ClearFlag(DMA2_Stream7,DMA_FLAG_TCIF7);
DMA_Cmd(DMA2_Stream7,DISABLE);
DMA_ClearITPendingBit(DMA2_Stream7, DMA_IT_TCIF7);
// DMA_Config_About_Rx();
}
}
3.实现效果
这里实现的是,串口DMA接收以及将接收到的数据通过DMA发送出来。
4.工程链接(免费):
https://download.csdn.net/download/tiange1996/85031420
2022.03.24----ltt