一、库函数
1、void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT, FunctionalState NewState)
核心功能:配置 DMA 通道的中断使能 / 失能(开启或关闭某个 DMA 中断类型)。
2、void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber)
核心功能:设置 DMA 通道的当前剩余传输数据个数(DMA 的核心计数器,传输 1 个数据,计数器自动减 1)。
3、uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx)
核心功能:获取 DMA 通道的当前剩余传输数据个数(读取计数器的实时值),返回值为剩余个数。
4、FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG)
核心功能:查询 DMA 的状态标志位是否置 1(即某个事件是否发生,如传输完成、半传输、错误),返回标志位状态。
5、void DMA_ClearFlag(uint32_t DMAy_FLAG)
核心功能:手动清除 DMA 的状态标志位(将置 1 的标志位清零)。
6、ITStatus DMA_GetITStatus(uint32_t DMAy_IT)
核心功能:查询 DMA 的中断挂起位是否置 1(即某个中断事件是否发生,且该中断已开启),返回中断状态。
7、void DMA_ClearITPendingBit(uint32_t DMAy_IT)
核心功能:清除 DMA 的中断挂起位(将置 1 的中断挂起位清零)。
二、数据转换
将数组A中的数据转换到数组B中
uint8_t DataA[] = {0x01, 0x02, 0x03, 0x04};
uint8_t DataB[] = {0, 0, 0, 0};
1、初始化配置
void MyDMA_Init(uint32_t AddrA, uint32_t AddrB, uint16_t Size)
{
MyDMA_Size = Size;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr = AddrA;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
DMA_InitStructure.DMA_MemoryBaseAddr = AddrB;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure .DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = Size;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
DMA_Init(DMA1_Channel1,&DMA_InitStructure);
DMA_Cmd(DMA1_Channel1,DISABLE);
}
站点地址
将要转换数组的地址和数据个数传入。
void MyDMA_Init(uint32_t AddrA, uint32_t AddrB, uint16_t Size)
打开DMA时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
配置外设站点
配置外设站点地址,数据宽度:以字节传输,地址是否自增:是。
DMA_InitStructure.DMA_PeripheralBaseAddr = AddrA;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
配置存储器站点
配置存储器站点地址,数据宽度:以字节传输,地址是否自增:是。
DMA_InitStructure.DMA_MemoryBaseAddr = AddrB;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure .DMA_MemoryInc = DMA_MemoryInc_Enable;
配置传输方向和数据个数
配置为从外部站点传输到存储器站点,数据个数Size。
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = Size;
配置重装,触发、优先级
配置为不重装,软件触发,中等优先级(在这个程序中可任意配置)
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
关闭DMA1
DMA_Cmd(DMA1_Channel1,DISABLE);
2、再次启动DMA
当数组A的数据变化后,再次启动DMA转换数据到数组B。
void MyDMA_Transfer(void)
{
DMA_Cmd(DMA1_Channel1,DISABLE);
DMA_SetCurrDataCounter(DMA1_Channel1,MyDMA_Size);
DMA_Cmd(DMA1_Channel1,ENABLE);
while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);
DMA_ClearFlag(DMA1_FLAG_TC1);
}
再次启动DMA要重装计数器,重装计数器要先关闭DMA,MyDMA_Size在前面Init 中有被执行MyDMA_Size = Size;
DMA_Cmd(DMA1_Channel1,DISABLE);
DMA_SetCurrDataCounter(DMA1_Channel1,MyDMA_Size);
DMA_Cmd(DMA1_Channel1,ENABLE);
等待DMA通道1转换完成标志位置1,然后手动清除标志位。
while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);
DMA_ClearFlag(DMA1_FLAG_TC1);
3、调用
让数组A的元素++,显示两个数组的元素值,延时一段时间,然后在显示更新后的值。
int main(void)
{
OLED_Init();
MyDMA_Init((uint32_t)DataA,(uint32_t)DataB,4);
OLED_ShowString(1,1,"DataA");
OLED_ShowString(3,1,"DataB");
OLED_ShowHexNum(1,8,(uint32_t)DataA,8);
OLED_ShowHexNum(3,8,(uint32_t)DataB,8);
OLED_ShowHexNum(2,1,DataA[0],2);
OLED_ShowHexNum(2,4,DataA[1],2);
OLED_ShowHexNum(2,7,DataA[2],2);
OLED_ShowHexNum(2,10,DataA[3],2);
OLED_ShowHexNum(4,1,DataB[0],2);
OLED_ShowHexNum(4,4,DataB[1],2);
OLED_ShowHexNum(4,7,DataB[2],2);
OLED_ShowHexNum(4,10,DataB[3],2);
while(1)
{
DataA[0] ++;
DataA[1] ++;
DataA[2] ++;
DataA[3] ++;
OLED_ShowHexNum(2,1,DataA[0],2);
OLED_ShowHexNum(2,4,DataA[1],2);
OLED_ShowHexNum(2,7,DataA[2],2);
OLED_ShowHexNum(2,10,DataA[3],2);
OLED_ShowHexNum(4,1,DataB[0],2);
OLED_ShowHexNum(4,4,DataB[1],2);
OLED_ShowHexNum(4,7,DataB[2],2);
OLED_ShowHexNum(4,10,DataB[3],2);
Delay_ms(1000);
MyDMA_Transfer();
OLED_ShowHexNum(2,1,DataA[0],2);
OLED_ShowHexNum(2,4,DataA[1],2);
OLED_ShowHexNum(2,7,DataA[2],2);
OLED_ShowHexNum(2,10,DataA[3],2);
OLED_ShowHexNum(4,1,DataB[0],2);
OLED_ShowHexNum(4,4,DataB[1],2);
OLED_ShowHexNum(4,7,DataB[2],2);
OLED_ShowHexNum(4,10,DataB[3],2);
Delay_ms(1000);
}
}
三、DMA+AD多通道
1、接线图

2、初始化配置
配置ADC:单ADC工作、数据右对齐、软件触发、关闭连续转换、扫描模式、扫描通道数目4
配置DMA:
外部站点:地址是ADC1的DR寄存器(ADC转化结果存放在这个寄存器)、数据带宽16位、地址不递增。
存储器站点:地址是全局数组AD_Value、数据带宽16位、地址递增。
搬运方向外设→内存、搬运次数4次、单次搬运、ADC硬件触发、DMA优先级:中等(无其他DMA时随意)
void AD_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
GPIO_InitTypeDef GPIO_Initstructure;
GPIO_Initstructure.GPIO_Mode = GPIO_Mode_AIN;//此时GPIO口只受到ADC的控制
GPIO_Initstructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1| GPIO_Pin_2 | GPIO_Pin_3;
GPIO_Initstructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_Initstructure);
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1,ADC_Channel_1,2,ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1,ADC_Channel_2,3,ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1,ADC_Channel_3,4,ADC_SampleTime_55Cycles5);
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_NbrOfChannel = 4;
ADC_Init(ADC1,&ADC_InitStructure);
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 4;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
DMA_Init(DMA1_Channel1,&DMA_InitStructure);
DMA_Cmd(DMA1_Channel1,ENABLE);
ADC_DMACmd(ADC1, ENABLE);
ADC_Cmd(ADC1,ENABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1) == SET);
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1) == SET);
}
打开ADC和DMA的通道
开启ADC1的DMA请求(ADC转换完成后,主动通知DMA搬运)
ADC_DMACmd(ADC1, ENABLE);
3、再启动
需要采集数据时,在主函数中调用一次就执行一次 4 通道扫描,采集完成后结果自动存入AD_Value数组
void AD_GetValue(void)
{
DMA_Cmd(DMA1_Channel1,DISABLE);
DMA_SetCurrDataCounter(DMA1_Channel1,4);
DMA_Cmd(DMA1_Channel1,ENABLE);
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);
DMA_ClearFlag(DMA1_FLAG_TC1);
}
4、调用
int main(void)
{
OLED_Init();
AD_Init();
OLED_ShowString(1,1,"AD0:");
OLED_ShowString(2,1,"AD1:");
OLED_ShowString(3,1,"AD2:");
OLED_ShowString(4,1,"AD3:");
while(1)
{
AD_GetValue();
OLED_ShowNum(1,5,AD_Value[0],4);
OLED_ShowNum(2,5,AD_Value[1],4);
OLED_ShowNum(3,5,AD_Value[2],4);
OLED_ShowNum(4,5,AD_Value[3],4);
Delay_ms(100);
}
}
网硕互联帮助中心





评论前必须登录!
注册