本人本科在读,就是课下总结自己瞎写,能帮上就帮上!
1、什么是DMA?
Direct Memory Access 将数据从一个地址空间复制到另一个地址空间。
先配置中断引脚和中断NVIC
#define bSize 512
uint8_t TperBuf[bSize];
uint8_t RperBuf[bSize];
void usart_gpio_ini()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|
RCC_APB2Periph_USART1|
RCC_APB2Periph_GPIOB|
RCC_APB2Periph_AFIO, ENABLE) ;
GPIO_InitTypeDef gpio_Ini;
gpio_Ini.GPIO_Pin = GPIO_Pin_9; //PA.9
gpio_Ini.GPIO_Speed = GPIO_Speed_50MHz;
gpio_Ini.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &gpio_Ini);//初始化GPIOA.9
gpio_Ini.GPIO_Pin = GPIO_Pin_10;//PA10
gpio_Ini.GPIO_Speed = GPIO_Speed_50MHz;
gpio_Ini.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &gpio_Ini);//初始化GPIOA.10
NVIC_InitTypeDef nvic_Ini;
nvic_Ini.NVIC_IRQChannel=USART1_IRQn;
nvic_Ini.NVIC_IRQChannelCmd=ENABLE;
nvic_Ini.NVIC_IRQChannelPreemptionPriority=1;
nvic_Ini.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&nvic_Ini);
USART_InitTypeDef usart_Ini;
usart_Ini.USART_BaudRate=9600;
usart_Ini.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
usart_Ini.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
usart_Ini.USART_Parity=USART_Parity_No;
usart_Ini.USART_StopBits=USART_StopBits_1;
usart_Ini.USART_WordLength=USART_WordLength_8b;
USART_Init(USART1,&usart_Ini);
USART_DMACmd(USART1,USART_DMAReq_Rx|USART_DMAReq_Tx,ENABLE);
USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);//空闲中断
USART_Cmd(USART1,ENABLE);
}
DMA通道4和5配置
数据长度是一个字节,寄存器内存增量,外设不可以增量。
void dma_ini()
{
DMA_InitTypeDef dma_Ini;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
dma_Ini.DMA_BufferSize=bSize;
dma_Ini.DMA_M2M=DMA_M2M_Disable;
dma_Ini.DMA_DIR=DMA_DIR_PeripheralSRC;
dma_Ini.DMA_MemoryBaseAddr=(uint32_t)RperBuf;
dma_Ini.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
dma_Ini.DMA_MemoryInc=DMA_MemoryInc_Enable;
dma_Ini.DMA_Mode=DMA_Mode_Normal;
dma_Ini.DMA_PeripheralBaseAddr=USART1_BASE+0x04;
dma_Ini.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
dma_Ini.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
dma_Ini.DMA_Priority=DMA_Priority_Medium;//DMA某通道具有优先级
DMA_Init(DMA1_Channel5,&dma_Ini);
dma_Ini.DMA_BufferSize=bSize;
dma_Ini.DMA_DIR=DMA_DIR_PeripheralDST;
dma_Ini.DMA_M2M=DMA_M2M_Disable;
dma_Ini.DMA_MemoryBaseAddr=(uint32_t)TperBuf;
dma_Ini.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
dma_Ini.DMA_MemoryInc=DMA_MemoryInc_Enable;
dma_Ini.DMA_Mode=DMA_Mode_Normal;
dma_Ini.DMA_PeripheralBaseAddr=USART1_BASE+0x04;
dma_Ini.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
dma_Ini.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
dma_Ini.DMA_Priority=DMA_Priority_Medium;
DMA_Init(DMA1_Channel4,&dma_Ini);
DMA_Cmd(DMA1_Channel4,DISABLE);
DMA_Cmd(DMA1_Channel5,ENABLE);//使能DMA传输完成通道
}
串口1的配置,
void USART1_IRQHandler()
{
if(USART_GetITStatus(USART1,USART_IT_IDLE)==SET)//通道传输完成标志
{
USART_ClearITPendingBit(USART1,USART_IT_IDLE);
uint16_t ls=USART_ReceiveData(USART1);
DMA_Cmd(DMA1_Channel5,DISABLE);
uint16_t size=bSize-DMA_GetCurrDataCounter(DMA1_Channel5);//总的减去当前有的内存空间
for(int i=0;i<size;i++)
TperBuf[i]=RperBuf[i];
DMA_SetCurrDataCounter(DMA1_Channel5,bSize);//
DMA_Cmd(DMA1_Channel5,ENABLE);
DMA_Cmd(DMA1_Channel4,DISABLE);
DMA_SetCurrDataCounter(DMA1_Channel4,size);
DMA_Cmd(DMA1_Channel4,ENABLE);
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
for(int i=0;i<10000;i++);
GPIO_SetBits(GPIOB,GPIO_Pin_5);
for(int i=0;i<10000;i++);
}
}
什么是IDLE中断
IDLE就是串口收到一帧数据后,超过1个Byte的时间没有收到数据,就发生的中断。
通道x传输数量寄存器
清除IDLE标志位,CurrdataCounter寄存器大于0并且使能开启就会自动发数据。
只能在通道停止时设置,通道启动后变为只读,指示剩余的待传输字节数;
寄存器内容变成0并配置成自动重加载模式时,会自动装载上次配置的值;
数值为0时,不进行数据传输;