STM32的ADC是12位的,且采样时钟速度不能超过14M.
单独使用AD:
1:初始化相关GPIO,(看手册的ADC引脚配置)
2:初始化ADC
3;配置采样时钟
函数:RCC_ADCCLKConfig(RCC_PCLK2_Div8);//采样时钟 最大14M时钟
4:ADC通道选择
函数:ADC_RegularChannelConfig();ADC几/通道几/转换顺序/采样频率
5:ADC_CMD
6:进行ADC效准
ADC_ResetCalibration(ADC1);//初始化效准寄存器,ADC效验初始化
while(ADC_GetResetCalibrationStatus(ADC1));//是否效验初始化完成
ADC_StartCalibration(ADC1);//开始效准
while(ADC_GetCalibrationStatus(ADC1));//效准完成 手册有描述
7:开启软件转换
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//不要 ADC_SoftwareStartInjectedConvCmd这个函数以为是启动函数哇,
GPIO初始化:
static void ADC_GPIOC_INIT(void)
{ GPIO_InitTypeDef ADC1_GPIOC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
ADC1_GPIOC_InitStruct.GPIO_Mode=GPIO_Mode_AIN;
ADC1_GPIOC_InitStruct.GPIO_Pin|=GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
ADC1_GPIOC_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&ADC1_GPIOC_InitStruct);
}
ADC初始化:
static void adc1_init(void)
{
ADC_InitTypeDef ADC1_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//开启ADC外设时钟
ADC1_InitStruct.ADC_ContinuousConvMode=ENABLE; //是否连续转换 就是时间到了就更新新的数据不靠软件在去触发
ADC1_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;//数据对齐
ADC1_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None; //触发源选择 为软件
ADC1_InitStruct.ADC_Mode=ADC_Mode_Independent;//独立模式1 很多模式看手册描述 这里是独立
ADC1_InitStruct.ADC_NbrOfChannel=3;//几个通道
ADC1_InitStruct.ADC_ScanConvMode=ENABLE;//通道扫描模式一个一个去采 采集完后是不是去下一个通道采,一般用于多通道
ADC_Init(ADC1, &ADC1_InitStruct);//初始化结构体
RCC_ADCCLKConfig(RCC_PCLK2_Div8);//采样时钟 最大14M时钟
ADC_RegularChannelConfig(ADC1,ADC_Channel_11,1,ADC_SampleTime_55Cycles5); //选择采集通道,转换顺序1,和采样时钟
ADC_RegularChannelConfig(ADC1,ADC_Channel_12,2,ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1,ADC_Channel_13,3,ADC_SampleTime_55Cycles5);
ADC_DMACmd(ADC1, ENABLE);//开启DMA
// ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE);
ADC_Cmd(ADC1,ENABLE);//开启ADC
//也可以开中断 DMA 但是ADC的EOC的标志位是要把通道转完了就产生中断 用DMA搬运好多了
ADC_ResetCalibration(ADC1);//初始化效准寄存器,ADC效验初始化
while(ADC_GetResetCalibrationStatus(ADC1));//是否效验初始化完成
ADC_StartCalibration(ADC1);//开始效准
while(ADC_GetCalibrationStatus(ADC1));//效准完成 手册有描述
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//不要 ADC_SoftwareStartInjectedConvCmd这个函数以为是启动函数哇,
//要多通道必须是中断或DMA直接用会3个乱掉
}
ADC_SoftwareStartConvCmd启动ADC转换:
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);可以获取ADC的值
中断就判断EOC位;
//static void nvic_init(void)
//{
// NVIC_InitTypeDef NVIC_ADC1_InitStruct;
// NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2);
// NVIC_ADC1_InitStruct.NVIC_IRQChannel= ADC1_2_IRQn;
// NVIC_ADC1_InitStruct.NVIC_IRQChannelCmd= ENABLE;
// NVIC_ADC1_InitStruct.NVIC_IRQChannelPreemptionPriority=2;
// NVIC_ADC1_InitStruct.NVIC_IRQChannelSubPriority=2;
// NVIC_Init(&NVIC_ADC1_InitStruct);
//}
//__IO u16 adc_value1[4]={0};
//__IO u16 adc_value1_temp[4]={0};
//u8 temp=0;
//void ADC1_2_IRQHandler(void)
//{
//
// if(ADC_GetITStatus(ADC1,ADC_IT_EOC))
// {
// adc_value1_temp[temp]=ADC1->DR;
// if(temp++>=2)
// temp=0;
// }
// ADC_ClearITPendingBit(ADC1,ADC_IT_EOC);
//}
这里是DMA搬运ADC
ADC_DMA:
void adc1_out3_init(void)
{
//nvic_init();
ADC_GPIOC_INIT();
adc1_init();
}
static void ADC_GPIOC_INIT(void)
{ GPIO_InitTypeDef ADC1_GPIOC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
ADC1_GPIOC_InitStruct.GPIO_Mode=GPIO_Mode_AIN;
ADC1_GPIOC_InitStruct.GPIO_Pin|=GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
ADC1_GPIOC_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&ADC1_GPIOC_InitStruct);
}
static void adc1_init(void)
{
ADC_InitTypeDef ADC1_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//开启ADC外设时钟
ADC1_InitStruct.ADC_ContinuousConvMode=ENABLE; //是否连续转换 就是时间到了就更新新的数据不靠软件在去触发
ADC1_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;//数据对齐
ADC1_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None; //触发源选择 为软件
ADC1_InitStruct.ADC_Mode=ADC_Mode_Independent;//独立模式1 很多模式看手册描述 这里是独立
ADC1_InitStruct.ADC_NbrOfChannel=3;//几个通道
ADC1_InitStruct.ADC_ScanConvMode=ENABLE;//通道扫描模式一个一个去采 采集完后是不是去下一个通道采,一般用于多通道
ADC_Init(ADC1, &ADC1_InitStruct);//初始化结构体
RCC_ADCCLKConfig(RCC_PCLK2_Div8);//采样时钟 最大14M时钟
ADC_RegularChannelConfig(ADC1,ADC_Channel_11,1,ADC_SampleTime_55Cycles5); //选择采集通道,转换顺序1,和采样时钟
ADC_RegularChannelConfig(ADC1,ADC_Channel_12,2,ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1,ADC_Channel_13,3,ADC_SampleTime_55Cycles5);
ADC_DMACmd(ADC1, ENABLE);//开启DMA
// ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE);
ADC_Cmd(ADC1,ENABLE);//开启ADC
//也可以开中断 DMA 但是ADC的EOC的标志位是要把通道转完了就产生中断 用DMA搬运好多了
ADC_ResetCalibration(ADC1);//初始化效准寄存器,ADC效验初始化
while(ADC_GetResetCalibrationStatus(ADC1));//是否效验初始化完成
ADC_StartCalibration(ADC1);//开始效准
while(ADC_GetCalibrationStatus(ADC1));//效准完成 手册有描述
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//不要 ADC_SoftwareStartInjectedConvCmd这个函数以为是启动函数哇,
//要多通道必须是中断或DMA直接用会3个乱掉
}
DMA配置:
#define ADC1_ADDR 0x4001244C
__IO u16 adc_value1[3]={0};
__IO float adc_value1_temp[4]={0};
void dma1_adc1_init(void)
{
DMA_InitTypeDef DMA1_line1_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA1_line1_InitStruct.DMA_PeripheralBaseAddr=(u32)ADC1_ADDR; //有坑 尽量不要用ADC->DR数据有问题 外饰地址
DMA1_line1_InitStruct.DMA_MemoryBaseAddr=(u32)adc_value1; //变量地址
DMA1_line1_InitStruct.DMA_DIR=DMA_DIR_PeripheralSRC;//方向 外设-》变量
DMA1_line1_InitStruct.DMA_BufferSize=3;//DMA一次循环菜几次
DMA1_line1_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord ;//变量宽度
DMA1_line1_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;////外设宽度
DMA1_line1_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;//变量地址是不是自增
DMA1_line1_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设地址是不是自增
DMA1_line1_InitStruct.DMA_Priority=DMA_Priority_High ;//优先级
DMA1_line1_InitStruct.DMA_M2M=DMA_M2M_Disable;//是不是内存到内存
DMA1_line1_InitStruct.DMA_Mode=DMA_Mode_Circular;//循环搬运
DMA_Init(DMA1_Channel1,&DMA1_line1_InitStruct);//通道选择,看手册
DMA_Cmd(DMA1_Channel1,ENABLE); //开启DMA
}
这样子就可以通过DMA获取ADC的值了
备注:
//电压计算公式
//ADC=采来的值/4096*3.3 或采来的值*3.3/4096+补偿 3.3为VREF+和VREF-的引脚值 以实际为主
//ADC放大就成倍
//ADC显示比例 ADC=实际电压/VREF+和VREF-的引脚值(3.3)*要的比例 例100 实际电压3.3/3.3*100
int main(void)
{
dma1_adc1_init();
adc1_out3_init();//调用
while(1)
{
}
}