×
单片机 > 单片机程序设计 > 详情

STM32 ADC转换

发布时间:2020-08-26 发布时间:
|
STM32具有1~3个ADC。这些ADC可以相互独立使用,也可以使用双重模式。STM32的ADC是12位逐次逼近型的模拟/数字转换器。它有18个通道,可测量16个外部和2个内部信号源。各通道可以单次、连续、扫描或间断模式执行。
ADC其实检测的是电压信号,然后在将它转换数字信号。在我使用开发板上,ADC能检测的电压范围为0~3.3v,其转换成数字信号后对应的数字量范围为:0~4095。
下面就讲讲STM32 ADC转换功的实现。还是基于我自己的规范工程上修改!!
1、工程的修改
1)由于要使用ADC功能,必须使用到库文件stm32f10x_adc.c,所以将是stm32f10x_adc.c文件添加到STM32F10x_StdPeriod_Driver工程组中。
2)打开stm32f10x_conf.h文件,将原先屏蔽的:#include "stm32f10x_adc.h"语句的屏蔽去掉。
3)新建ADConvert.c与ADConvert.h两个文件分别保存到BSP文件夹下的src与inc两个文件中。并将ADConvert.c文件添加到BSP工程组中。
 
2、ADConvert.c与ADConvert.h两个文件的编写。
首先当然是ADC对应的引脚的初始化了。我使用的是stm32f10xzet6芯片,它自带有3个ADC,ADC不同的通道都有对应的芯片引脚,通道与引脚的对应关系如下图所示:
 本次工程,我使用ADC1的通道0与通道1,所以对应的两个引脚是:PA0与PA1。由于它们要用于检测电压值,所以需要将引脚配置成模拟输入模式,代码如下:

/*************************************************************
Function : ADConvert_GPIO_Init
Description: ADC的引脚配置
Input : none
return : none
*************************************************************/
static void ADConvert_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0| GPIO_Pin_1;//ADC通道0与通道1对应的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚
GPIO_Init(GPIOA, &GPIO_InitStructure);
}

然后是ADC的配置。在这个工程里,我并没有借助DMA来来实现ADC的转换,本来想着不用DMA来实现ADC的多路转换,但是经过好几次试验发现:这样做似乎不行。于是大胆得出这样的结论:不使用DMA无法实现多路ADC同时转换。在没有使用DMA的情况下,实现多路的ADC转换(当然不是同时转换的),只能一路一路轮流 地转换。ADC的设置代码如:

/*************************************************************
Function : ADConvert_ADC1_Init
Description: ADC1初始化
Input : none
return : none
*************************************************************/
static void ADConvert_ADC1_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

ADC_DeInit(ADC1);//将外设 ADC1 的全部寄存器重设为缺省值
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//ADC工作模式:ADC1和ADC2工作在独立模式
ADC_InitStructure.ADC_ScanConvMode =ENABLE;//模数转换工作在扫描模式
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//模数转换工作在连续转换模式
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);//根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器
ADC_Cmd(ADC1, ENABLE);//打开ADC1
ADC_ResetCalibration(ADC1); //开启复位校准
while(ADC_GetResetCalibrationStatus(ADC1));//等待复位校准结束
ADC_StartCalibration(ADC1);//开始AD校准
while(ADC_GetCalibrationStatus(ADC1));//等待校准结束
}

上面的代码配置ADC为连续转换模式、数据右对齐、设置转换通道为1路,并进行复位校准与AD校准。
接下去需要编写一个总函数:ADConvert_Init(),将DAC配置相关的代码都包含进去,代码如下:

/*************************************************************
Function : ADConvert_Init
Description: ADC初始化
Input : none
return : none
*************************************************************/
void ADConvert_Init(void)
{
ADConvert_GPIO_Init();
ADConvert_ADC1_Init();
}

最后还需要编写一个获取转换后的AD值的函数:ADC_GetADValue(),它的代码如下:

/*************************************************************
Function : ADC_GetADValue
Description: 获取转换后的数字量
Input : channel-ADC1的通道
return : 转换后的数字量
*************************************************************/
u16 ADC_GetADValue(u8 channel)
{
//ADC1,ADC通道为channel,规则采样顺序值为1,采样时间为239.5周期
ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_239Cycles5);
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定得到ADC1的软件转换功能
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));//等待转换结束
return ADC_GetConversionValue(ADC1); //返回最近一次ADC1 规则组的转换结果
}

其中ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_239Cycles5);这句话比较重要。它的功能是:指定ADC1的通道1的转换顺序为1即最先转换(这里只设置了1路测量),采样的时间为239.5周期。采样的时间的话自己设置,可以有下面的选择:
ADC_SampleTime_1Cycles5: 1.5 周期 ADC_SampleTime_7Cycles5: 7.5 周期 ADC_SampleTime_13Cycles5: 13.5 周期 ADC_SampleTime_28Cycles5: 28.5 周期 ADC_SampleTime_41Cycles5: 41.5 周期 ADC_SampleTime_55Cycles5: 55.5 周期 ADC_SampleTime_71Cycles5: 71.5 周期 ADC_SampleTime_239Cycles5: 239.5 周期
设置完采用配置后,需要发送一个软件启动信号,表示开始准换,转换王弼后,在将转换后的结构返回。
下面的ADConvert.h的代码,非常简单,仅仅声明了可能会其他文件调用的:ADConvert_Init()与ADC_GetADValueADC_GetADValue()这两个函数:

#ifndef __ADCONVERT_H__
#define __ADCONVERT_H__
#include "stm32f10x.h"

void ADConvert_Init(void);
u16 ADC_GetADValue(u8 channel);

#endif

3、main函数的编写
在main函数首先需要定义两个变量:in0Value与in1Value,分别保存ADC1通道1的转换值与通道2的转换值。然后在while(1)循环中每隔1s采集一次,并打印出来。它的代码如下:

/*************************************************************
Function : main
Description: main入口
Input : none
return : none
*************************************************************/
int main(void)
{
u16 in0Value = 0;
u16 in1Value = 0;

BSP_Init();
ADConvert_Init();
PRINTF("\nmain() is running!\r\n");
while(1)
{
LED1_Toggle();
in0Value = ADC_GetADValue(ADC_Channel_0);
PRINTF("ADC1_IN0: AD=%d Volt=%1.1f\r\n", in0Value, 3.3*in0Value/4096);
in1Value = ADC_GetADValue(ADC_Channel_1);
PRINTF("ADC1_IN1: AD=%d Volt=%1.1f\r\n", in1Value, 3.3*in1Value/4096);
Delay_ms(1000);
}
}

用ADC_GetADValue()测得转换后的数字量,接下去再将它换算成电压值,换算的公式如下;
测得的电压值 = 转换后的数字量 * 3.3 / 4096
这样就可以算出ADC测量的电压值了。
 
4、测试
这里需要使用到一个电位器,电位器连接着开发板的电源,将可阻值的脚连接到PA0上,用螺丝刀旋转电位器改变其阻值,可以在看到串口调试软件不断地有数据输出,上面显示着ADC1通道0的采样的转换值与其对应的电压值,如下图所示;
在将电位器可变电阻端的引脚连接到PA1上,然后旋转电位器,串口调试软件就会输出ADC1通道1 的转换值与对应的电压值,如下图所示:
最后,将PA0与PA1的引脚短接,然后在连接电位器的可变电阻的引脚上,并旋转电位器,在串口调试助手上输出的信息中可以看到ADC1的通道0 与通道1的转换值与对应的电压,如图所示:



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
如何升级STM32单片机的代码