STM32ADC模数转换实验

本章所要实现的功能是:通过 ADC1 通道 1 采样外部电压值,将采样的 AD 值和转换后的电压值通过串口打印出来,同时 DS0 指示灯闪烁,提示系统正常运 行。程序框架如下: (1)初始化 ADC1_IN1 相关参数,开启 ADC1 (2)编写获取 ADC1_IN1 的 AD 转换值函数 (3)编写主函数

开发步骤

(1)使能端口时钟和 ADC 时钟,设置引脚模式为模拟输入 我们知道 ADCx_IN0-ADCx_IN15 属于外部通道,每个通道都会对应芯片的一 个引脚,比如 ADC1_IN1 对应 STM32F103ZET6 的 PA1 引脚,所以首先要使能 GPIOA 端口时钟和 ADC1 时钟,如下: RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1,E NABLE); 然后将 PA1 引脚配置为模拟输入模式,代码如下: GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AN; //模拟输入模式 GPIO 的初始化在前面很多章节中都介绍过,这里就不多说。 (2)设置 ADC 的分频因子 开启 ADC1 时钟之后,我们就可以通过 RCC_CFGR 设置 ADC 的分频因子。分 频因子要确保 ADC 的时钟( ADCCLK)不要超过 14Mhz。 这个我们设置分频因 子为 6, 因此 ADC 时钟为 72/6=12MHz,库函数的实现方法如下: RCC_ADCCLKConfig(RCC_PCLK2_Div6); (3)初始化 ADC 参数,包括 ADC 工作模式、规则序列等 我们知道要使用 ADC,需要配置 ADC 的转换模式、触发方式、数据对齐方式、 规则序列等参数,这些参数是通过库函数 ADC_Init 函数实现。函数原型如下: void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct); 函数中第一个参数是用来选择 ADC,例如 ADC1;第二个参数是一个结构体指 针变量,结构体类型是 ADC_InitTypeDef,其内包含了 ADC 初始化的成员变量。 下面我们就来简单介绍下这个结构体: 1. typedef struct 2. { 3. uint32_t ADC_Mode; // ADC 工作模式选择 4. FunctionalState ADC_ScanConvMode; /* ADC 扫描(多通道)或者单次(单通道)模 式选择 */ 5. FunctionalState ADC_ContinuousConvMode; // ADC 单次转换或者连续转换选择 6. uint32_t ADC_ExternalTrigConv; // ADC 转换触发信号选择 7. uint32_t ADC_DataAlign; // ADC 数据寄存器对齐格式 8. uint8_t ADC_NbrOfChannel; // ADC 采集通道数 9. } ADC_InitTypeDef; ADC_Mode:ADC 模式选择,有独立模式、双重模式,在双重模式下还有很多 细分模式可选,具体由 ADC_CR1:DUALMOD 位配置。 ADC_ScanConvMode:ADC 扫描模式选择。可选参数为 ENABLE 或 DISABLE,用 来设置是否打开 ADC 扫描模式。如果是单通道 AD 转换,选择 DISABLE;如果是 多通道 AD 转换,选择 ENABLE。 ADC_ContinuousConvMode:ADC 连续转换模式选择。可选参数为 ENABLE 或 DISABLE,用来设置是连续转换还是单次转换模式。如果为 ENABLE,则选择连续 转换模式;如果为 DISABLE,则选择单次转换模式,转换一次后停止,需要手动 控制才能重新启动转换。 ADC_ExternalTrigConv:ADC 外部触发选择。ADC 外部触发条件有很多,在 前面介绍框图时已列出,根据需要选择对应的触发条件,通常我们使用软件自动 触发,所以此成员可以不用配置。 ADC_DataAlign:ADC 数据对齐方式。可选参数为右对齐 ADC_DataAlign_Right 和左对齐 ADC_DataAlign_Left。 ADC_NbrOfChannel:AD 转换通道数目,根据实际设置。具体的通道数和通 道的转换顺序是配置规则序列或注入序列寄存器。 了解结构体成员功能后,就可以进行配置,本章实验 ADC 初始化配置代码如 下: 1. ADC_InitTypeDef ADC_InitStructure; 2. ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; 3. ADC_InitStructure.ADC_ScanConvMode = DISABLE;//非扫描模式 4. ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//关闭连续转换 5. ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//禁止触发 检测,使用软件触发 6. ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐 7. ADC_InitStructure.ADC_NbrOfChannel = 1;//1 个转换在规则序列中 也就是只转换规则序 列 1 8. ADC_Init(ADC1, &ADC_InitStructure);//ADC 初始化 (4)使能 ADC 并校准 前面几个步骤已经将 ADC 配置好,但还不能正常使用,只有开启 ADC 并且复 位校准了才能让它正常工作,开启 ADC 的库函数如下: void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState); 开启 ADC1 代码如下: ADC_Cmd(ADC1, ENABLE);//开启 AD 转换器 执行复位校准的方法是: ADC_ResetCalibration(ADC1); 执行 ADC 校准的方法是: ADC_StartCalibration(ADC1); //开始指定 ADC1 的校准状态 记住,每次进行校准之后要等待校准结束。 这里是通过获取校准状态来判 断是否校准是否结束。 下面我们一一列出复位校准和 AD 校准的等待结束方法: while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束 while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束 (5)读取 ADC 转换值 通过上面几步配置,ADC 就算准备好了,接下来我们要做的就是设置规则序 列里面的通道,采样顺序以及通道的采样周期,然后启动 ADC 转换。在转换结 束后,读取转换结果值就可以了。 设置规则序列通道以及采样周期的库函数是: void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel,uint8_t Rank, uint8_t ADC_SampleTime); 参数 1 用来选择 ADC,参数 2 用来选择规则序列里面的通道,参数 3 用来设 置转换通道的数量,参数 4 用来设置采样周期。例如本实验中 ADC1_IN1 单次转 换,采样周期为 239.5,代码如下: ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5 ); 设置好规则序列通道及采样周期,接下来就要开启转换,由于我们采用的是 软件触发,库函数如下: void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState); 例如要开启 ADC1 转换,调用函数为: ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的 ADC1 的软件转 换启动功能 开启转换之后,就可以获取 ADC 转换结果数据,调用的库函数是: uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx); 同样如果要获取 ADC1 转换结果,调用函数是: ADC_GetConversionValue(ADC1); 同时在 AD 转换中,我们还要根据状态寄存器的标志位来获取 AD 转换的各 个状态信息。获取 AD 转换的状态信息的库函数是: FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG); 例如我们要判断 ADC1 的转换是否结束,方法是: while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束 将以上几步全部配置好后,我们就可以正常使用 ADC 执行转换操作了。

adc.h+adc.c

#ifndef _adc_H
#define _adc_H

#include "system.h"
void     ADCx_Init();
u16 Get_ADC_Value(u8 ch, u8 times);
#endif
#include "adc.h"
#include "SysTick.h"

void     ADCx_Init()
{
    GPIO_InitTypeDef GPIO_InitStructure;
    ADC_InitTypeDef ADC_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
    
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);
    
    ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;// ADC 单次转换disable或者连续转换选择enable
    ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;// ADC 数据寄存器对齐格式
    ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;// ADC 转换触发信号选择,未使用外部触发
    ADC_InitStructure.ADC_Mode=ADC_Mode_Independent ;// ADC 工作模式选择
    ADC_InitStructure.ADC_NbrOfChannel=1;// ADC 采集通道0x1-0x10
    ADC_InitStructure.ADC_ScanConvMode=DISABLE;; /* ADC 扫描enable(多通道)或者单次disable(单通道)模
式选择 */

    ADC_Init( ADC1, &ADC_InitStructure);
    
    ADC_Cmd( ADC1, ENABLE);
    ADC_ResetCalibration(ADC1);//复位校准
    while(ADC_GetResetCalibrationStatus(ADC1));//检测到复位校准状态完成之后退出循环
    
    ADC_StartCalibration(ADC1);//开始指定adc1的校准状态
    while(ADC_GetCalibrationStatus( ADC1));//原理同上
    
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);//开启ad转换,软件触发模式
    
}
u16 Get_ADC_Value(u8 ch, u8 times)//得到ADC的值,ch通道值,times循环多次取平均值得次数
{
    ADC_RegularChannelConfig( ADC1, ch,1, ADC_SampleTime_239Cycles5 );
    u8 i=0;
  u32 temp_val=0;
    for(i=0;i<times;i++)
    {
        ADC_SoftwareStartConvCmd(ADC1, ENABLE);//因为选择的是单次转换
        //每采集一次就结束,采集关闭,所以要开启转换,从而多次开启取平均值
        while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==0);//转换完成返回1
        temp_val+=ADC_GetConversionValue(ADC1);
        delay_ms(5);
    }
    return temp_val/times;

}

main.c

#include "stm32f10x.h"
#include "led.h"
#include "system.h"
#include "SysTick.h"
#include "beep.h"
#include "key.h"
#include "exti.h"
#include "time.h"
#include "pwm.h"
#include "usart.h"
#include "stdio.h"
#include "iwdg.h"
#include "wwdg.h"
#include "input.h"
#include "touch_key.h"
#include "wkup.h"
#include "adc.h"
int main()
{
    u16 i=0;
    u16 val=0;
    float V;//将AD值转换为电压值
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置优先级分组
  SysTick_Init(72);
    LED_Init();
    USART1_Init(115200);//波特率115200
    ADCx_Init();
    while(1)
    {
        i++;
        if(i%20==0)LED1=!LED1;
        delay_ms(10);
        
        if(i%100==0)
        {
            val=Get_ADC_Value(ADC_Channel_1, 20);
            printf("检测的AD值为:%d\r\n",val);
            V=(float)val*(3.3)/4096;//电压转换公式,AD值*3.3/2的12次方(4096)
            printf("电压值为: %.2fV\n",V);
        }
    
    
    }
    
}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值