STM32使用ADC+电位器测电压

一、电位器

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

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

2.原理图:

这里写图片描述

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

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

硬件:STM32F103 系列,电位器:RVQ24YN03-20FB502 ,原博是WDD35D-4导电塑料电位器,亲测这个也可以

硬件连接:

VCC -----> 1
GND -----> 2
PA7 -----> 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对应表:

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;t<times;t++)
    {
        temp_val+=Get_Adc(ch);
        delay_us(200);
    }
    return temp_val/times;
}    
//#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);
        printf("adcx:%d\n",adcx);
        //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;
        printf("adcx>2:%f\n",adcx);
       // OLED_ShowNum(75,10,adcx,1,12);//显示电压值
        temp-=adcx;
        temp*=1000;
        printf("temp:%f\n",temp);
        //OLED_ShowString(80,10,".",12);
        //OLED_ShowNum(85,10,temp,3,12);
        //OLED_Refresh_Gram();
        //LED0=!LED0;
        delay_ms(250);  
    }                                               
}   

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

原文链接:https://blog.csdn.net/Zach_z/article/details/76651137

  • 9
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值