1)编写adc.c文件
编写adc.c文件,里面放以下三个函数
1. Adc_Init (void):用于ADC的初始化,需要在main()中调用一次。
(需要根据具体情况修改,在第四节会讲如何修改)
2.Get_Adc(ch):读取某个通道的AD采样值。传递参数直接填通道名,例如通道1:ADC_Channel_1
(需要根据具体情况修改,在第五节会讲如何修改)
3.Get_Adc_Average(ch,times):也是读取某个通道的AD采样值,只不过取多次的平均值,提高准确度
#include "adc.h"
#include "delay.h"
//初始化 ADC
//这里我们仅以规则通道为例
//我们默认将开启通道 0~3
void Adc_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |
RCC_APB2Periph_ADC1 , ENABLE ); //使能 ADC1 通道时钟
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置 ADC 分频因子 6
//72M/6=12,ADC 最大时间不能超过 14M
//PA1 作为模拟通道输入引脚
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//模拟输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.1
ADC_DeInit(ADC1); //复位 ADC1,将外设 ADC1 的全部寄存器重设为缺省值
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC 独立模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //单通道模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //单次转换模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//转换由
//软件而不是外部触发启动
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC 数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1; //顺序进行规则转换的ADC通道的数目
ADC_Init(ADC1, &ADC_InitStructure); //根据指定的参数初始化外设 ADCx
ADC_Cmd(ADC1, ENABLE); //使能指定的 ADC1
ADC_ResetCalibration(ADC1); //开启复位校准
while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束
ADC_StartCalibration(ADC1); //开启 AD 校准
while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束
}
//获得 ADC 值
//ch:通道值 0~3
u16 Get_Adc(u8 ch)
{
//设置指定 ADC 的规则组通道,设置它们的转化顺序和采样时间
ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );
//通道 1,规则采样顺序值为 1,采样时间为 239.5 周期
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能软件转换功能
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
return ADC_GetConversionValue(ADC1); //返回最近一次 ADC1 规则组的转换结果
}
u16 Get_Adc_Average(u8 ch,u8 times)
{
u32 temp_val=0;
u8 t;
for(t=0;t<times;t++)
{
temp_val+=Get_Adc(ch);
delay_ms(5);
}
return temp_val/times;
}
2)编写adc.h文件
只需声明adc.c中三个函数即可
#ifndef __ADC_H
#define __ADC_H
#include "sys.h"
void Adc_Init(void);
u16 Get_Adc(u8 ch);
u16 Get_Adc_Average(u8 ch,u8 times);
#endif
3)在main()使用ADC
(1)ADC初始化
直接调用adc.c中的初始化函数即可
Adc_Init(); //ADC 初始化
(2)读取ADC值
调用adc.c中的Get_Adc_Average(ch,times)
u16 adcx
...
adcx=Get_Adc_Average(ADC_Channel_1,10);
将ADC值赋给了16位变量adcx
(3)转换为电压值
STM32的ADC为12位,参考电压为Vref
因此电压值为:V = adcx * (Vref / 4096)
但有一个需要注意的地方,前面定义的 adcx 是一个16位整型变量,而电压值是有小数的,因此需要一个float型变量来保存电压值,并通过一定技巧得到整数部分和小数部分。代码如下:
float temp
...
temp=(float)adcx*(3.3/4096); //转换后得到的电压值
adcx=temp; //电压值的整数部分 float型赋给整型,结果是保留了整数部分
temp-=adcx; //电压值的小数部分
temp*=1000; //小数部分*1000变为整型,方便LCD显示
adcx为电压值的整数部分,temp为电压值的小数部分
4)根据配置情况修改Adc_Init (void)
stm32有多个ADC,每个ADC又有多个通道,要根据具体使用情况进行相关配置
上文代码使用了ADC1的通道1,对应的GPIO是PA1,因此GPIO的配置是按照PA1来设置的。若使用了其他通道,则需要改成对应的GPIO。
STM32F103的ADC通道与GPIO对应表如下(其余型号自己翻datesheet找下)
需要修改的代码在下面列出了
//这里用的是PA1,根据具体GPIO修改
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |
RCC_APB2Periph_ADC1 , ENABLE ); //使能 ADC1 通道时钟
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_1;
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.1
//这里用的是ADC1,根据具体情况改成ADCx
ADC_DeInit(ADC1); //复位 ADC1,将外设 ADC1 的全部寄存器重设为缺省值
ADC_Init(ADC1, &ADC_InitStructure); //根据指定的参数初始化外设 ADCx
ADC_Cmd(ADC1, ENABLE); //使能指定的 ADC1
ADC_ResetCalibration(ADC1); //开启复位校准
while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束
ADC_StartCalibration(ADC1); //开启 AD 校准
while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束
5)根据配置情况修改Get_Adc(ch)
参见上面修改Adc_Init (void)的方法,把ADC1都改为ADCx