赞
踩
DMA 传输将数据从一个 地址空间复制到另外一个地址空间。当 CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器 来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的 内存区。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工 作。DMA 传输方式无需 CPU 直接 控制传输,通过硬件为 RAM 与 I/O 设备 开辟一条直接传送数据的通路,能使 CPU 的效率大为提高。
“搬运”,将外部数据搬运进MCU,这件事不需要CPU去做,CPU可以去处理别的事情。
其中主要配置前三个标红的框,第四个紫色框根据一次搬运的长度选择,有一个8位、16位、32位。
u16 ADC1_Value[C_Channel_Sample][C_ADC_Channel] = { 0 }; // DMA搬运数据存放处(数组)
DMA的配置:
- void DMA_Init_JX(void)
- {
- DMA_InitTypeDef DMA_InitStructure;
- //NVIC_InitTypeDef NVIC_InitStructure;
-
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // 使能DMA时钟
-
-
- // DMA_CH1(ADC1)参数设置
- //--------------------------------------------------------------------------------------------------------------------------
- DMA_DeInit(DMA1_Channel1); // 将DMA的通道1寄存器重设为缺省值
- DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->DR; // DMA外设ADC基地址
- DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADC1_Value; // DMA内存基地址
- DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // 内存作为数据传输的目的地
- DMA_InitStructure.DMA_BufferSize = C_ADC_Channel * C_Channel_Sample; // DMA通道的DMA缓存的大小
- DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址寄存器不变
- DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 内存地址寄存器递增
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 数据宽度为16位
- DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // 数据宽度为16位
- DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 工作在循环缓存模式
- DMA_InitStructure.DMA_Priority = DMA_Priority_High; // DMA通道 x拥有高优先级
- DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // DMA通道x没有设置为内存到内存传输
- DMA_Init(DMA1_Channel1, &DMA_InitStructure); // 根据DMA_InitStruct中指定的参数初始化DMA的通道
- //--------------------------------------------------------------------------------------------------------------------------
-
- DMA_Cmd(DMA1_Channel1, ENABLE); // 启动DMA通道
-
- }
ADC通道的配置:
- void ADC1_Rocker_Init(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- ADC_InitTypeDef ADC_InitStructure;
- // NVIC_InitTypeDef NVIC_InitStructure;
-
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1, ENABLE); // 使能PA端口和ADC1时钟
-
-
- // 模拟输入:PA1、PA2、PA3、PA6
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_6;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; // 模拟输入引脚
- //GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; // 输入模式无需设置端口速度
- GPIO_Init(GPIOA, &GPIO_InitStructure);
-
-
- // 配置ADC1_CH1、ADC1_CH2、ADC1_CH3、ADC1_CH6
- // ADC工作条件:ADC的时钟频率<=14MHz && ADC采样频率<=1MHz
- // ADC的总转换周期(必须>=1us) = (采样周期(1.5~239.5) + 12.5(固定转换周期)) / ADC时钟频率
- // 当:ADC的时钟频率==12MHz、采样周期==1.5,ADC转换周期≈1.17us
- //---------------------------------------------------------------------------------------------------------------------
- RCC_ADCCLKConfig(RCC_PCLK2_Div6); // ADC时钟6分频:72M/6=12M
-
- ADC_DeInit(ADC1); // 复位ADC1
-
- // 设置ADC1的工作模式
- ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // ADC工作模式:ADC1和ADC2工作在独立模式
- ADC_InitStructure.ADC_ScanConvMode = ENABLE; // "扫描转换模式"使能。即:ADC工作在多通道模式
- ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // "连续转换模式"失能。即:ADC工作在单次转换模式
- ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 转换由软件启动(也可以设置为外部触发)
- ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // ADC数据对齐方式:右对齐
- ADC_InitStructure.ADC_NbrOfChannel = C_ADC_Channel; // 设置顺序进行规则转换的ADC通道的数目
- ADC_Init(ADC1, &ADC_InitStructure); // 初始化ADC1
-
-
- // 为了能够正确地配置每一个 ADC 通道,用户在调用 ADC_Init()之后,
- // 必须调用ADC_xxxChannelConfig()来配置每个所使用通道的转换次序和采样时间。
- //--------------------------------------------------------------------
- ADC_RegularChannelConfig(ADC1, N_ADC_Channel_1, 1, ADC_SampleTime_239Cycles5); // 参数:ADC1,要设置的ADC通道序号,规则组采样顺序,采样周期
- // 此函数:配置的是"ADC1"的通道"1",它在规则组中的采样顺序是"1",采样周期是"ADC_SampleTime_239Cycles5"
-
- ADC_RegularChannelConfig(ADC1, N_ADC_Channel_3, 2, ADC_SampleTime_239Cycles5);
- // 此函数:配置的是"ADC1"的通道"3",它在规则组中的采样顺序是"2",采样周期是"ADC_SampleTime_239Cycles5"
- //---------------------------------------------------------------------------------------------------------------------
-
-
- /*
- //ADC1的中断NVIC设置
- //---------------------------------------------------------------------------------
- NVIC_InitStructure.NVIC_IRQChannel = ADC1_2_IRQn; // ADC1中断
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; // 抢占优先级3级
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // 子优先级3级
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能ADC1_2_IRQn中断
- NVIC_Init(&NVIC_InitStructure); // 初始化NVIC寄存器
-
- ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE ); // 允许ADC1的EOC中断
- //---------------------------------------------------------------------------------
- */
-
-
- // 开启ADC的DMA支持
- ADC_DMACmd(ADC1, ENABLE); // 要实现DMA功能,还需独立配置DMA通道等参数
-
-
- ADC_Cmd(ADC1, ENABLE); // 使能ADC1
-
-
- ADC_ResetCalibration(ADC1); // 使能ADC1复位校准
-
- while(ADC_GetResetCalibrationStatus(ADC1)); // 等待ADC1复位校准结束
-
- ADC_StartCalibration(ADC1); // 开启ADC1校准
-
- while(ADC_GetCalibrationStatus(ADC1)); // 等待ADC1校准结束
-
- }
ADC采集:
在配置时,配置为软件触发方式。在使用ADC时,使用程序使能ADC1转换,也就是第一句。
搬运时DMA一次搬运16位数据,前8位为ADC1通道1的值,放在二维数组的第一列
后8位为ADC1通道3的值,放在二维数组的第二列
- void ADC1_Value_average(void)
- {
- // 摇杆检测
- //------------------------------------------------------------------------
- ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 软件使能ADC1转换
-
- // 转换完成后,DMA自动将数据搬运到指定位置
- //while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC )); // 等待转换结束
-
- AM_ADC_Channel1_Sample += ADC1_Value[C_ADC_Sample][0]; // 得到
-
- AM_ADC_Channel3_Sample += ADC1_Value[C_ADC_Sample][1];
-
- C_ADC_Sample++ ; // ADC实际采样次数
-
- // 判断是否已经采样10次
- if(C_ADC_Sample >= C_Channel_Sample)
- {
- C_ADC_Sample = 0;
-
- AV_ADC_Channel1_Sample = AM_ADC_Channel1_Sample / C_Channel_Sample; // 求通道1的平均值
-
- AM_ADC_Channel1_Sample = 0 ;
-
-
- AV_ADC_Channel3_Sample = AM_ADC_Channel3_Sample / C_Channel_Sample; // 求通道3的平均值
-
- AM_ADC_Channel3_Sample = 0 ;
- }
-
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。