STM32学习:ADC模数转换
ADC简介
adc模数转换器
模拟电压转化为数字变量
转化方式:12位逐次逼近型ADC,1us转换时间
输入范围:0-3.3V,转换范围:0-4095
共有18个输入通道,可以测量16个外部和两个内部信号源
规则组和注入组两个转换单元
模拟看门狗自动执行检测输入电压范围,当电压高于或者低于某一范围将跳转进入中断函数中进行操作的执行。
逐次逼近型ADC
主要采用二分法进行编码
ADC数据比较的功能框图
ADC0809来类比STM32单片机中的ADC转换,通过ALE对选中的地址进行锁存,ADDA-ADDC进行对通道的选择,STM32中具有12位的通道,对相应的位置1将选择相应的通道,之后再选择的通道中注入相应的电压,通过和DAC的数值进行比较,采用二分法进行逐次逼近从而从而将相应的比较数值传输进入三态锁存缓冲器中输出比较好的数据,即为转换好的adc数值。
ADC分频
由于使用的时钟为APB2上的72MHZ的时钟因此在使用之前需要进行时钟的预分频因为ADCCLK只支持最大为14MHZ频率的时钟。
ADC功能框图
1、vssa,vdda,vref+,vref-主要为电源供电以及基准电压。
2、ADCx_IN0-15 为ADC的16为输入的通道。
其中最多4位为注入通道:可以同时对4路的通道数据进行转换传入注入通道寄存器,之后进行保存和输出。
最多16位为规则通道:规则通道中每次只能进行对一路通道数据的转换和保存,存入规则通道数据寄存器。
3、规则通道和注入通道数据转换完成之后都会将EOC标志位进行置1之后可以进行对中断函数的跳转。
而在注入通道的转换过程完成后会将JEOC位进行置1
4、也可以进行对阈值进行设定从而进入模拟看门狗的配置,当数据超出了我们所设置好的阈值之后看门狗将会被触发从而设置进入中断函数中。
ADC单通道转换的具体配置流程
1、创建一个ADC的初始化函数这里创建为void AD_Init()并在函数中打开对本次用到的ADC和GPIO的时钟。
void AD_Init()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE );
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//对apb2的时钟进行6分频
2、对GPIO进行初始化配置
而在GPIO的配置中引脚要配置为模拟输入模式
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AIN;//将GPIOA0的引脚设置为模拟输入模式,这时候GPIOA0是无效的
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);
3、进行对ADC规则组的通道进行配置
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_1Cycles5);//ADC规则组通道配置
本次使用到的通道主要为ADC1的通道0,共用一个通道,最后一个参数为本次转换所需要花费的时间。
4、之后进行对ADC进行初始化配置
ADC_InitTypeDef ADC_InitStruct;
ADC_InitStruct.ADC_ContinuousConvMode=DISABLE;//连续转换的模式设置
ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;//配置ADC存储模式为右对齐
ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//是否配置硬件的中断函数,选择none
ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;//配置模式为独立模式,其余模式都是双ADC模式
ADC_InitStruct.ADC_NbrOfChannel=1;//通道数目
ADC_InitStruct.ADC_ScanConvMode=DISABLE;//ADC的扫描模式关闭
ADC_Init(ADC1,&ADC_InitStruct);
5、使能ADC
ADC_Cmd(ADC1,ENABLE);//使能配置好的ADC
6、在用户手册中建议我们在使用ADC之前进行对代码的校准
校准的过程分为两步,第一步为复位校准,第二次为正式开始校准;
ADC_ResetCalibration(ADC1);//复位校准
while(ADC_GetResetCalibrationStatus(ADC1) == SET);//获得校准复位的状态 获取的是CR2中的RSTCAL的数值
ADC_StartCalibration(ADC1);//ADC1开始校准
while(ADC_GetCalibrationStatus(ADC1) == SET);
7、校准完成之后我们便可以进行对ADC数值读取的函数进编写。
在函数中我们需要先将相应的ADC1数值转换进行开启,之后对转换标志位EOC进行判断从而得知转化是否完成,在完成之后我们在进行对数据的读取。并将读取到的数值进行返回。(而在执行了读取ADC_DR数据存储寄存器过后将会自动对EOC标志进行清除)
uint16_t GetADCval(void)
{
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//开启ADC的转换
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);//读取ADC的EOC标志位 没有转换好的情况下进行循环等待
return ADC_GetConversionValue(ADC1);//获取ADC1数值转化的结果
}
以下为完整的adc.c adc.h代码
本来就是以学习为目的写的,我直接公开供大家一起交流学习,一起进步(ps:俺比较反感vip,收费)
adc.c
#include "stm32f10x.h"
void AD_Init()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE );
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//对apb2的时钟进行6分频
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AIN;//将GPIOA0的引脚设置为模拟输入模式,这时候GPIOA0是无效的
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_1Cycles5);//ADC规则组通道配置
//ADC_RegularChannelConfig(ADC1,ADC_Channel_1,2,ADC_SampleTime_55Cycles5);//ADC规则组进行选择,
//ADC_RegularChannelConfig(ADC1,ADC_Channel_2,3,ADC_SampleTime_1Cycles5);//如果用到了别的通道,
//ADC_RegularChannelConfig(ADC1,ADC_Channel_3,4,ADC_SampleTime_1Cycles5);//可以继续对其进行定义
//ADC_RegularChannelConfig(ADC1,ADC_Channel_4,5,ADC_SampleTime_1Cycles5);
ADC_InitTypeDef ADC_InitStruct;
ADC_InitStruct.ADC_ContinuousConvMode=DISABLE;//连续转换的模式设置
ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;//配置ADC存储模式为右对齐
ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//是否配置硬件的中断函数,选择none
ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;//配置模式为独立模式,其余模式都是双ADC模式
ADC_InitStruct.ADC_NbrOfChannel=1;//通道数目
ADC_InitStruct.ADC_ScanConvMode=DISABLE;//ADC的扫描模式关闭
ADC_Init(ADC1,&ADC_InitStruct);
ADC_Cmd(ADC1,ENABLE);//开启adc的电源 开始转换
/*接下来时ADC的校准*/
ADC_ResetCalibration(ADC1);//复位校准
while(ADC_GetResetCalibrationStatus(ADC1) == SET);//获得校准复位的状态 获取的是CR2中的RSTCAL的数值
ADC_StartCalibration(ADC1);//ADC1开始校准
while(ADC_GetCalibrationStatus(ADC1) == SET);
}
uint16_t GetADCval(void)
{
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//开启ADC的转换
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);//读取ADC的EOC标志位 没有转换好的情况下进行循环等待
return ADC_GetConversionValue(ADC1);//获取ADC1数值转化的结果
}
adc.h
#ifndef __ADC__H
#define __ADC__H
uint16_t GetADCval(void);
void AD_Init();
#endif
芜湖