文章目录

  • ADC的基本了解
  • ADC原理
  • 逐次型ADC转换原理
  • 电阻分压电路
  • Cube配置外设
  • ADC内部电压的使用
  • ADC采样相关函数
  • 代码编写
  • 最终编写的代码
  • 参考资料
  • ADC的基本了解

  • ADC,即模数转换器

  • 在单片机中的传输信号为数字信号,通过离散的高低电平表示数字逻辑1和0,但是日常生活中我们常见的信号为模拟信号,即连续变化的信号,但是我们可以把这些信号转换为电信号,再通过ADC将模拟信号转化为数字信号进行处理

  • ADC原理

  • 一般工作流程为:采样,比较,转换

  • 采样:指采集某一时刻的模拟电压
  • 比较:指将采样的电压在比较电路中进行比较
  • 转换:指将比较电路中结果转换成数字量
  • STM32F4采用12位逐次逼近型ADC(SAR-ADC)

    首先会对模拟信号进行采样,采样值为Vin

    然后进行比较该3位ADC有3种比较过程,如下图

    该图表示,对不同位数赋予不同的权值

  • 与1/2Vref进行比较,Vin大于1/2Vref时,将第一位赋值为1
  • 与3/4Vref进行比较,Vin小于3/4Vref时,将第二位赋值为0
  • 与5/8Vref进行比较,Vin小于5/8Vref时,将第三位赋值为0
  • 然后将各值按照1/2,1/4,1/8按权进行计算,例如以上比较后输出结果为100,则转换结果为1 * 1/2+0 * 1/4+0 * 1/8=1/2,则最终转换结果为1/2Vref.
  • STM32最高支持12位ADC,一般ADC的位数越多则转换精度越高,但与此同时转换的速度也会变慢

    STM32内部有一个校准电压VREFINT,电压为1.2V,当供电电压不为3.3V时可以使用内部的vrefint通道采集1.2V电压作为Vref,以提高精度(STM32的校准电压Vrefint在ADC1中)。

    逐次型ADC转换原理

    整个电路由比较器,D/A转换器,缓冲寄存器和若干控制逻辑电路构成

  • 比较器:用于输入电压值与D/A转换器输出电压进行比较,当输入电压大于该转换器电压时输出1,反之输出0
  • D/A转换器:ADC的逆向过程,将缓冲寄存器的记录数字量转换成模拟量
  • 缓冲寄存器:记录当前转换的数字量
  • 转换的过程如下:

    1. 将缓冲寄存器清零
    2. 将逐次逼近寄存器最高位置1
    3. 将数字值传入D/A转换器,经D/A转换后的模拟量传入比较器,为V0
    4. V0与比较器的待转换的模拟量V1比较,若V0<V1,该位保留,否则清0
    5. 再置寄存器次高位为1,将寄存器中新的数字量送D/A转换器
    6. 输出的V0再与V1进行比较,若若V0<V1,该位保留,否则清0
    7. 一直循环该过程,直至寄存器最低位,得到数字量的输出

    电阻分压电路

    由于电池提供的电源是24V的高电压,但是单片机引脚的耐压只有0-3.3V所以需要通过分压电路来进行处理

    首先,利用200KΩ和22KΩ的分压电路将24V电压进行分压

    分压后的电压送至次级电路

    在次级电路中,通过100nF的电容进行滤波,使输出的电压更加稳定

    接着用二极管保护电路将电压限制在0-3.3V(当电压大于3.3V时,二极管正向导通,电压被限制在3.3V;当电压小于0V时,二极管正向导通,电压被限制在0V)

    Cube配置外设

    在原理图中找到ADC对应的引脚

    可以看到该ADC对应PF10引脚,使用ADC3的通道8

    在Cube中对ADC1和ADC3进行如下配置

    ADC1用于内部1.2V的Vrefint通道读取

    ADC3用于电池电压ADC3通道8的读取

    在ADC_Settings中对ADC1和ADC3都进行如下配置

    这样就配置好了Cube

    ADC内部电压的使用

    由于外部供电电压不一定为 3.3V

    为了在这种情况提高ADC精度,我们需要使用单片机内部的参照电压

    使用ADC采样该电压来提高ADC的精度

    ADC内部参照电压VREFINT为1.2V

    将采样内部参照电压1.2V的ADC值和Vref的加权值进行比较,进而得到ADC的输出值

    STM32的ADC采用Vcc作为Vref,但为了防止Vcc存在波动较大导致Vref不稳定,进而导致采样值的比较结果不准确,STM32可以通过内部已有的参照电压VREFINT来进行校准

    接着以VREFINT为参照来比较ADC的采样值,从而获得比较高的精度

    即可以通过一个函数对1.2V的电压进行多次采样,并计算其平均值,然后将其与ADC采样的数据进行比较得到单位数字电压的模拟电压值voltage_vrefint_proportion,设采样得到的数字值为average_adc,公式如下

    ADC采样相关函数

    1. HAL_ADC_ConfigChannel()

      HAL_StatusTypeDef HAL_ADC_ConfigChannel(ADC_HandleTypeDef* hadc, ADC_ChannelConfTypeDef* sConfig)
      

      作用:设置ADC通道的各个属性值,包括转换通道,序列排序,采样时间等

      返回值:为HAL_StatusTypeDef类型,即表示状态,如成功则返回HAL_OK

      参数:a. TIM_HandleTypeDef * hadc,即输入&hadc1等

      ​ b.ADC_ChannelConfTypeDef* sConfig,即ADC的参数设置结构体需要先对sConfig结构体进行赋值

    1. HAL_ADC_Start()

      HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef* hadc)
      

      作用:开启ADC的采样

      返回值:同样是HAL_StatusTypeDef类型

      参数:ADC_HandleTypeDef* hadc,即&hadc1等

    2. HAL_ADC_PollForConversion()

      HAL_StatusTypeDef HAL_ADC_PollForConversion(ADC_HandleTypeDef* hadc, uint32_t Timeout)
      

      作用:等待ADC转换结束

      返回值:同样是HAL_StatusTypeDef类型

      参数:1.ADC_HandleTypeDef* hadc;2.uint32_t Timeout,即等待的最大时间

    1. HAL_ADC_GetValue()

      uint32_t HAL_ADC_GetValue(ADC_HandleTypeDef* hadc)
      

      作用:获取ADC值

      返回值:HAL_StatusTypeDef类型

      参数:TIM_HandleTypeDef* hadc类型

    代码编写

    程序流程如下:

    获得基准电压值

    首先要对内部电压VREFINT进行采样,并将其作为校准值

    通过init_vrefint_reciprocal函数执行以上过程

    void init_vrefint_reciprocal(void) 
    {
        uint8_t i = 0; 
        uint32_t total_adc = 0; 
        for(i = 0; i < 200; i++) //对电压VREFINT进行200次采样
        { 
            total_adc += adcx_get_chx_value(&hadc1, ADC_CHANNEL_VREFINT);
        }
        voltage_vrefint_proportion = 200 * 1.2f / total_adc;//使VREFINT的电压值1.2V除以采样得到的均值,后面ADC采样到的电压值与这个voltage_vrefint_proportion相乘就可以计算出内部参考电压做过校准的ADC值
    }
    

    获得电池电压

    然后对ADC的电压值进行采样,再将该采样值与voltage_vrefint_proportion(模拟电压值)相乘得到ADC的采样值

    得到ADC采样值后,我们可以根据这个值反算出电压的值,分压的电压阻值为200KΩ,22KΩ,则(22K Ω + 200K Ω) / 22K Ω = 10.09,把采样值乘以该值后所得即为电池电压值

    该求电压的代码实现如下:

    fp32 get_battery_voltage(void)
    { 
        fp32 voltage; 
        uint16_t adcx = 0; 
        adcx = adcx_get_chx_value(&hadc3, ADC_CHANNEL_8);
        //(22KΩ+200KΩ)/22KΩ=10.090909090909090909090909090909 
        voltage = (fp32)adcx * voltage_vrefint_proportion * 10.090909090909090909090909090909f; 
        return voltage;
    }
    

    获取温度

    通过ADC获得板载温度传感器的温度值

    先经过ADC值进行采样

    然后将采样结果通过公式计算出温度值

    temperate = (adc – 0.76f) * 400.0f + 25.0f

    fp32 get_temprate(void)
    { 
        uint16_t adcx = 0;
        fp32 temperate; 
        adcx = adcx_get_chx_value(&hadc1, ADC_CHANNEL_TEMPSENSOR);//先进行ADC采样 
        temperate = (fp32)adcx * voltage_vrefint_proportion;
        temperate = (temperate - 0.76f) * 400.0f + 25.0f; //使用公式计算出温度值 
        return temperate; 
    }
    

    最终编写的代码

    /* USER CODE BEGIN PV */
    float Batvalt=0;//电池电压
    float Vrefint=0;//单位数字电压的模拟电压值
    float Temperate=0;//板载温度传感器的温度值
    /* USER CODE END PV */
    
      /* USER CODE BEGIN WHILE */
      while (1)
      {
        /* USER CODE END WHILE */
    
        /* USER CODE BEGIN 3 */
        HAL_ADC_Start(&hadc1);//启动ADC1采样
        while(!HAL_ADC_PollForConversion(&hadc1,1));//等待ADC1进行1s的转换
        /*当该函数成功运行后输出成功的状态(1)
        故我们这里需要取非(“!”),即让该函数成功运行后就结束循环*/
        Vrefint=1.2/HAL_ADC_GetValue(&hadc1);
        /*HAL_ADC_GetValue(&hadc1),获取内部电压的采样值
          Vrefint,单位数字电压的模拟电压值
        */
    
        HAL_ADC_Start(&hadc3);//启动ADC3采样
        while(!HAL_ADC_PollForConversion(&hadc3,1));//等待ADC3进行1s的转换
        Batvalt=HAL_ADC_GetValue(&hadc3)*Vrefint*10.090909090909090909090909090909f;
        //HAL_ADC_GetValue(&hadc3),即获取ADC3的采样值
        //Vrefint,内部电压的基准值(单位数字电压的模拟电压值)
        //10.090909090909090909090909090909f,由(22KΩ+200KΩ)/22KΩ计算所得,分压比
      
        HAL_ADC_Start(&hadc1);//启动ADC1采样
        while(!HAL_ADC_PollForConversion(&hadc1,1));//等待ADC1进行1s的转换
        Temperate=(HAL_ADC_GetValue(&hadc1)-0.76f)*400.0f+25.0f;
        /*HAL_ADC_GetValue(&hadc1),获取内部电压的采样值
          根据公式计算出板载温度传感器的温度值
        */ 
      }
      /* USER CODE END 3 */
    

    结果如图所示:

    参考资料

    从零开始制作RoboMaster步兵机器人-11.ADC采样电池电压
    ADC数模转换
    《RoboMaster开发板 C 型嵌入式软件教程文档》
    《Description of STM32F4 HAL and low-layer drivers》

    物联沃分享整理
    物联沃-IOTWORD物联网 » 电池电压ADC采样

    发表评论