STM32使用ADC+电位器测电压

一、WDD35D-4导电塑料电位器

1. 电位器

电位器是具有三个引出端、阻值可按某种变化规律调节的电阻元件。电位器通常由电阻体和可移动的电刷组成。当电刷沿电阻体移动时,在输出端即获得与位移量成一定关系的电阻值或电压。

电位器既可作三端元件使用也可作二端元件使用。后者可视作一可变电阻器,由于它在电路中的作用是获得与输入电压(外加电压)成一定关系得输出电压,因此称之为电位器。

2. WDD35D-4导电塑料电位器

导电塑料电位器使用时一般按分压器原理以电压输出或转换电流输出(4~20mA)与轴旋转角度或直线位移成高精度的线性关系,电信号引出一般采用接线柱形式。
参数:

参数 数值
电阻值 5K
总阻公差 ±15%
独立线性 0.1%
电气旋角 345°±2°
额定功耗 2W,at70℃

3. 接线方法及原理

原理图:

STM32使用ADC+电位器测电压_第1张图片

三根接线柱由标记1、2、3分别表示。1是输入端,2是输出端,3接地。轴从1端到3端角度旋转或直线位移时阻值发生变化,由2端按线性规律高精度输出,同时通过变换电路将阻值变化转换为信号显示。

使用电压说明: 电位器使用直流电压,加载1、3端的额定电压

二、 ADC

1. 模数变换器(ADC)

模数变换器(ADC)。把模拟量转换为数字量的装置。在计算机控制系统中,须经各种检测装置,以连续变化的电压或电流作为模拟量,随时提供被控制对象的有关参数(如速度、压力、温度等)而进行控制。计算机的输入必须是数字量,故需用模数转换器达到控制目的

2. STM32的ADC

STM32 拥有 1~3 个 ADC ( STM32F101/102系列只有1个ADC),这些ADC可以独立使用,也可以使用双重模式(提高采样率)。STM32 的 ADC 是 12 位逐次逼近型的模拟数字转换器。它有18个通道,可测量16个外部和2个内部信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中。模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值

STM32 的 ADC 最大的转换速率为 1Mhz,也就是转换时间为 1us(在 ADCCLK=14M,采样周期 1.5 个 ADC 时钟下得到),不要让 ADC 的时钟超过 14M,否则将导致结果准确度下降

STM32 将 ADC 的转换分为 2 个通道组:规则通道组和注入通道组。规则通道相当于你正常运行的程序,而注入通道呢,就相当于中断。在你程序正常执行的时候,中断是可以打断你的执行的。同这个类似,注入通道的转换可以打断规则通道的转换,在注入通道被转换完成之后,规则通道才得以继续转换

STM32的ADC通道与GPIO对应表:

STM32使用ADC+电位器测电压_第2张图片

3. ADC设置步骤

  1. 开启IO口时钟和ADC时钟,设置GPIO口为模拟输入
  2. 复位ADC,设置ADC分频因子,ADC最大时钟不能超过14M,否则将导致ADC准确度下降
  3. 初始化ADC参数uu,设置ADC的工作模式以及规则序列的相关信息
  4. 使能ADC并校准
  5. 读取ADC值

  6. 通过ADC1的通道7(PA7)来捕获ADC的值:
#include "adc.h"

void Adc_Init(void)//ADC初始化
{
    GPIO_InitTypeDef GPIO_InitStructure;
    ADC_InitTypeDef ADC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1,ENABLE);//RCC->APB2ENR|=1<<2;RCC->APB2ENR|=1<<9;使能PORTA口和ADC1时钟 

    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);//GPIOA->CRL&=0X0FFFFFFF PA7模拟输入

    RCC_ADCCLKConfig(RCC_PCLK2_Div6);//RCC->CFGR&=~(3<<14);RCC->CFGR|=2<<14; 6分频ADC时钟为12M

    ADC_DeInit(ADC1);//RCC->APB2RSTR|=1<<9; ADC1复位

    ADC_InitStructure.ADC_Mode=ADC_Mode_Independent; //ADC1->CR1&=0XF0FFFF;ADC1->CR1|=0<<16; 独立工作模式
    ADC_InitStructure.ADC_ScanConvMode=DISABLE;//ADC1->CR1&=~(1<<8); 非扫描模式
    ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;//ADC1->CR2=~(1<<1); 单次转换模式
    ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//ADC1->CR2&=~(7<<17);ADC1->CR2|=7<<17;软件控制转换 ADC1->CR2|=1<<20; 使用外部触发
    ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//ADC1->CR2&=~(1<<11);右对齐
    ADC_InitStructure.ADC_NbrOfChannel=1;//ADC1->SQR1&=~(0XF<<20); ADC1->SQR1|=0<<20;//顺序进行规则转换的ADC通道的数目1
    ADC_Init(ADC1,&ADC_InitStructure);//根据ADC_InitStructure中指定的参数初始化外设ADC的寄存器

    ADC_Cmd(ADC1,ENABLE);//ADC1->CR2|=0;使能ADC1
    ADC_ResetCalibration(ADC1); //ADC1->CR2|=1<<3;使能复位校准
    while(ADC_GetResetCalibrationStatus(ADC1));//while(ADC1->CR2&1<<3)等待复位校准结束
    ADC_StartCalibration(ADC1);//ADC1->CR2|=1<<2;开启AD校准
    while(ADC_GetCalibrationStatus(ADC1));//while(ADC1->CR2&1<<2)等待校准结束
}

//获得ADC值
//ch:通道值 0~3
u16 Get_Adc(u8 ch)   
{
    //设置指定ADC的规则组通道,一个序列,采样时间
    //ADC1->SMPR2&=~(7<<21);ADC1->SMPR2|=7<<21;ADC1,ADC通道,采样时间为239.5周期
    //ADC1->SQR3&=0XFFFFFFE0;ADC1->SQR3|=ch;
    ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );  

    //ADC1->CR2|=1<<22;                 
  //使能指定的ADC1的软件转换启动功能
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);     //使能指定的ADC1的软件转换启动功能    

    //while(!(ADC1->SR&1<<1)); 
    //等待转换结束
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));

    //return ADC1->DR
    //返回最近一次ADC1规则组的转换结果
    return ADC_GetConversionValue(ADC1);
}

u16 Get_Adc_Average(u8 ch,u8 times)
{
    u32 temp_val=0;
    u8 t;
    for(t=0;t200);
    }
    return temp_val/times;
}    

三、测量外部电压值

1. 硬件连接

VCC -----> 1
GND -----> 2
PA7 -----> 3

2.代码

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "oled.h"
#include "adc.h"
int main(void)
 { 
    u16 adcx;
    float temp;
    delay_init();            //延时函数初始化    
    uart_init(9600);        //串口初始化为9600
    LED_Init();             //初始化与LED连接的硬件接口
    OLED_Init();
    Adc_Init();             //ADC初始化             
    while(1)
    {
        adcx=Get_Adc_Average(ADC_Channel_7,10);
        OLED_ShowString(00,00,"ADC_CH0_VAL:",12);
        OLED_ShowNum(75,00,adcx,4,12);
        OLED_ShowString(00,10,"ADC_CH0_VOL:",12);
        temp=(float)adcx*(3.3/4096);
        adcx=temp;
        OLED_ShowNum(75,10,adcx,1,12);//显示电压值
        temp-=adcx;
        temp*=1000;
        OLED_ShowString(80,10,".",12);
        OLED_ShowNum(85,10,temp,3,12);
        OLED_Refresh_Gram();
        LED0=!LED0;
        delay_ms(250);  
    }                                               
}   

转动电位器,可以看到外部电压数值在OLED上显示的变化,由此可以引申出来测量角度和角速度。

你可能感兴趣的:(嵌入式)