一、ADC参考手册学习
A/D转换可以按单次、连续设置采样;可以一一扫描或间断的对多个ADC通道进行采集。ADC的结果有左对齐和右对齐。
ADC的输入时钟不得超过14Mhz,它是由PCLK2经分频产生。
二、ADC通道选择
16个多路通道,可以分成:规则组和注入组。规则组:可以设定任意的顺序进行的通道排列。(最多16个)
注入组:可以像中断一样优先进行转换。(最多4个)
三、数据对齐
四、外部触发事件
当外部触发信号被选中时,只有上升沿(外部触发的)可以启动转换。在手册中详细写了计时器触发对应ADC的触发源时哪些。
五、DMA请求
当转换多个规则通道时需要使用DMA,这可以避免对视已经存储在ADC_DR寄存器中的数据。只有在规则通道的转换结束时才产生DMA请求。
只有ADC1和ADC3拥有DMA功能。ADC2转化的数据可以通过双ADC模式,利用ADC1的DMA功能传输。
六、代码部分
adc.c:-
#include "adc.h"
-
#include "usart.h"
-
#include "systick.h"
-
-
vu16 ADC_ConvertedValue[4];
-
#define ADC1_DR_Address ((u32)&ADC1->DR)
-
-
//left ADC1_2: PA2
-
// ADC1_3: PA3
-
//right ADC1_0: PA0
-
// ADC1_1: PA1
-
void ADC_GPIO_Config(void)
-
{
-
GPIO_InitTypeDef GPIO_InitStructure;
-
/*配置ADC和GPIOA、DMA的时钟*/
-
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
-
/*配置GPIOA0~4为输入模式*/
-
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
-
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
-
GPIO_Init(GPIOA, &GPIO_InitStructure);
-
}
-
-
void ADC_DMA_Config(void)
-
{
-
DMA_InitTypeDef DMA_InitStructure; // 注:ADC为12位模数转换器,只有ADCConvertedValue的低12位有效
-
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//使能DMA时钟
-
DMA_DeInit(DMA1_Channel1);//开启DMA1的第一通道
-
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;//DMA对应的外设基地址
-
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_ConvertedValue; //内存存储基地址
-
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //DMA的转换模式为SRC模式,由外设搬移到内存
-
DMA_InitStructure.DMA_BufferSize = 4;//DMA缓存大小,1个
-
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; //DMA搬移数据尺寸,HalfWord就是为16位
-
DMA_InitStructure.DMA_Mode =DMA_Mode_Circular;//循环转换模式
-
DMA_InitStructure.DMA_Priority = DMA_Priority_High;//DMA优先级高
-
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//M2M模式禁用
-
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
-
DMA_ITConfig(DMA1_Channel1,DMA_IT_TC, ENABLE);//使能传输完成中断
-
}
-
-
void ADC_Config(void)
-
{
-
ADC_InitTypeDef ADC_InitStructure;
-
ADC_GPIO_Config();
-
ADC_DMA_Config();
-
NVIC_EnableIRQ(DMA1_Channel1_IRQn); //打开NVIC中对应的DMA通道
-
-
/* Enable DMA1 channel1 */
-
DMA_Cmd(DMA1_Channel1, ENABLE);
-
/* ADC1 configuration ------------------------------------------------------*/
-
ADC_DeInit(ADC1); //先复位一下
-
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //各通道独立模式
-
ADC_InitStructure.ADC_ScanConvMode = ENABLE; //打开扫描
-
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //关闭连续转换
-
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T4_CC4; //使用TIM4的CC4(外部触发)
-
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据右对齐
-
ADC_InitStructure.ADC_NbrOfChannel = 4; //一共要采样的通道数
-
ADC_Init(ADC1, &ADC_InitStructure);
-
-
ADC_Cmd(ADC1, ENABLE); //开启ADC
-
ADC_DMACmd(ADC1, ENABLE); //开启ADC--DMA数据传输通道
-
-
RCC_ADCCLKConfig(RCC_PCLK2_Div8); //配置ADC采样参考时钟的预分频值
-
-
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_71Cycles5); //71.5个ADC时钟
-
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_71Cycles5);
-
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_71Cycles5);
-
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_71Cycles5);
-
-
ADC_ResetCalibration(ADC1); //重置ADC采样校准器
-
while(ADC_GetCalibrationStatus(ADC1)); //等待校准成功
-
ADC_StartCalibration(ADC1); //开启ADC采样状态
-
while(ADC_GetCalibrationStatus(ADC1)); //等到开启成功
-
-
ADC_ExternalTrigConvCmd(ADC1, ENABLE); //使能外部触发ADC采样
-
-
}
-
-
void DMA1_Channel1_IRQHandler(void)
-
{
-
u8 i=0;
-
if(DMA_GetITStatus(DMA1_IT_TC1) == SET)
-
{
-
for(i=0;i<4;i++)
-
printf("adc value is %d .
",ADC_ConvertedValue[i]);
-
DMA_ClearITPendingBit(DMA1_IT_TC1);
-
}
- }
-
#include "tim.h"
-
-
//利用定时器TIM4的通道4输出比较功能,给ADC1提供采样触发信号,这里触发周期为:100ms
-
//公式: psc/72*period/1000000 (单位为秒)
-
//psc 是预分频的值
-
-
void TIM_OCTigrConfig(void)
-
{
-
TIM_TimeBaseInitTypeDef TIM_timeBaseStructure;
-
TIM_OCInitTypeDef TIM_ocInitStructure;
-
-
u16 period = 60000; //设置周期值
-
u16 pluse = 30000; //设置CRR值
-
-
//失能TIM4的时钟,TIM4时挂在APB1总线上的,注意TIM4的时钟是72M的
-
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
-
-
TIM_timeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //预分频因子
-
TIM_timeBaseStructure.TIM_Prescaler = 120-1; //预分频
-
TIM_timeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
-
TIM_timeBaseStructure.TIM_Period = period; //设置周期,给ARR赋值
-
TIM_TimeBaseInit(TIM4, &TIM_timeBaseStructure);
-
-
//配置TIM4通道4的输出比较
-
TIM_ocInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //PWM输出模式为PWM1
-
TIM_ocInitStructure.TIM_OCNPolarity = TIM_OCPolarity_High; //设置有效电平的极性
-
TIM_ocInitStructure.TIM_OutputState = TIM_OutputState_Enable; //使能通道输出
-
TIM_ocInitStructure.TIM_Pulse = pluse; //设置PWM的脉冲宽度值,即CRR值
-
TIM_OC4Init(TIM4, &TIM_ocInitStructure);
-
-
TIM_ARRPreloadConfig(TIM4, ENABLE); //使能TIM4寄存器ARR的预装载功能
-
TIM_OC4PreloadConfig(TIM4, TIM_OCPreload_Enable); //使能TIM4通道1的CCR的预装载功能
-
-
//使能TIM4定时器
-
TIM_Cmd(TIM4, ENABLE);
- }
教训总结:在设置DMA时钟时错把 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//使能DMA时钟
写成了 RCC_APB1PeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//使能DMA时钟
DMA是AHB上的外设。。。。