实验介绍:
在使用UART接收数据时,通常中断的频率时比较快的,八个字节的数据就会有八次中断来接受数据,会影响主程序。这里就引用到了DMA的使用,DMA不会影响主程序,当我的UART接收端有数据时,会自动将数据搬运到内存。此时,cpu只需要判断是否内存中是否接收到了数据即可。
在接收数据时,是如何判断将一包数据保存到缓存中? 当检测到RX引脚空闲(高电平)时间超过传输一个字符帧所需的时间时,就会产生空闲中断标志LDLEF。当一包数据发送过来时字节与字节之间的空闲时间是可以忽略不记的,但是,包与包之间的空闲时间就长了,可以利用这个来判断接收到了一包数据。
实验过程:
配置DMA:
/**
************************************************************
* @brief DMA配置
* @param
* @return
************************************************************
*/
static void usbComDmaInit(void)
{
//使能DMA时钟
RCC_AHBPeriphClockCmd(uartInfo.dmaPeriphClock, ENABLE);
//复位该通道的DMA设置
DMA_DeInit(uartInfo.dmaCh);
//DMA配置结构体
DMA_InitTypeDef dmaConfig;
//搬运的内存基地址(数组)
dmaConfig.DMA_MemoryBaseAddr = (uint32_t)ricvBuf;
//外设的基地址(USART的数据寄存器,基地址+0x04)
dmaConfig.DMA_PeripheralBaseAddr = USART1_DATA_ADDR;
//设置方向为外设为源地址
dmaConfig.DMA_DIR = DMA_DIR_PeripheralSRC;
//最大搬运长度
dmaConfig.DMA_BufferSize = MAX_BUFF_SIZE;
//设置外设不为自增,因为数据寄存器地址是固定的
dmaConfig.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
//设置内存缓冲区地址为增量(数组)
dmaConfig.DMA_MemoryInc = DMA_MemoryInc_Enable;
//这里有三种:字节、半字、字,这里选择字节
dmaConfig.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
dmaConfig.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
//这是内存到内存标志,使用的是外设到内存,选择失能
dmaConfig.DMA_M2M = DMA_M2M_Disable;
//模式为接收一次即可,还有一种为循环模式
dmaConfig.DMA_Mode = DMA_Mode_Normal;
//优先级设置为高,有四种:低、中等、高、非常高
dmaConfig.DMA_Priority = DMA_Priority_High;
//初始化
DMA_Init(uartInfo.dmaCh, &dmaConfig);
//使能USART DMA
USART_DMACmd(uartInfo.uartNu, USART_DMAReq_Rx, ENABLE);
//使能DMA通道
DMA_Cmd(uartInfo.dmaCh, ENABLE);
}
配置中断服务函数:
/**
************************************************************
* @brief UART中断服务函数
* @param
* @return
************************************************************
*/
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(uartInfo.uartNu, USART_IT_IDLE) == SET)
{
USART_ClearITPendingBit(uartInfo.uartNu, USART_IT_IDLE); //清空中断
USART_ReceiveData(uartInfo.uartNu); //清空中断
//获取接收数据查看是否为接收到的数据长度 DMA_GetCurrDataCounter 标志位是做递减所以做差值运算
if (PACKET_DATA_LEN == (MAX_BUFF_SIZE - DMA_GetCurrDataCounter(uartInfo.dmaCh)))
{
g_pktRcvd = true;
}
DMA_Cmd(uartInfo.dmaCh, DISABLE); //关闭使能通道 否则设置不生效
DMA_SetCurrDataCounter(uartInfo.dmaCh, MAX_BUFF_SIZE); //重新配置dma搬运最大次数 没有重新配置就结束搬运
DMA_Cmd(uartInfo.dmaCh, ENABLE); //打开使能通道
}
}
中断服务函数清空中断,需使用USART_ClearITPendingBit清除中断并且调用一次USART_ReceiveData函数方可清除成功,否则会一直触发。
标志位是做递减操作所以如果递减次数为0就会结束搬运,所以,要重新设置最大搬运次数。需要注意的是设置最大搬运次数时需要关闭通道使能否则设置不成功。