使用HAL库开发STM32:基于ADC的入门指南

文章目录

  • 目的
  • 基础说明
  • 基础使用
  • 配置选项说明
  • 轮询 单通道 单次
  • 轮询 单通道 连续
  • 轮询 多通道 扫描
  • 中断 单通道
  • 中断 多通道 扫描
  • DMA 单通道 单轮
  • DMA 单通道 连续
  • DMA 多通道 连续
  • 自校准
  • 总结
  • 目的

    ADC(模拟数字转换器)是现在单片机上基本都有的外设,可以把一个模拟的电压转换成数据。这篇文章将以 STM32F405RG 为基础介绍通过HAL库来使用ADC的一些基础功能。

    基础说明

    STM32的单片机通常都有多个ADC,每个ADC具有多个通道连接到外部的GPIO口。不同的ADC部分通道可能共用GPIO口。

    引脚数量大于等于100的封装上通常会有 VREF 引脚,ADC可转换的电压不大于 VREF 上的电压;引脚数量小于100的封装其 VREF 直接就是在芯片内部连接到 VDDA 的。

    和其他外设一样ADC工作需要时钟,STM32中ADC的时钟通常由PCLK2(ABP2外设时钟)分频得来,在 STM32F405RG 中最大可以达到36MHz。

    STM32的ADC通常最大精度是12位,使用时也可以配置成10位、8位或6位等。精度会影响转换速度和数据计算。

    ADC每处理一次数据分为 采样转换 两个过程。 采样时间可以配置,比如 STM32F405RG 中最小为3个ADC时钟周期;转换时间和精度有关,12位精度下为12个ADC时钟周期、10位精度下为10个ADC时钟周期,依此类推。

    所以每采样一个数据所需的时间为 (采样周期 + 转换周期) / ADC时钟频率。比如当ADC时钟频率为30MHz,采样周期选最小值3,精度为12位时,每处理一次数据耗时为 (3+12)/30/1000000 (秒) = 0.5微秒。

    ADC工作最后得到的数据换算成真实电压的时候主要和 VREF 以及精度有关。比如12位精度下 真实电压 = 数据 * VREF / (4096 - 1) ,10位精度下 真实电压 = 数据 * VREF / (1024 - 1) ,依此类推。但这里还有点争议,比如那个 -1 要不要?

    这里主要考虑两个问题:ADC因为工作原理关系本身有1个分辨率的误差;单片机在除以4096、1024等这些数值的时候可以用右移的方式提高效率。所以通常可以不要 -1 ,即12位精度下 真实电压 = 数据 * VREF / 4096

    基础使用

    HAL库对很多外设的使用设计了 轮询中断DMA 三种方式。STM32的ADC采样转换有 单次 / 连续 转换模式 。另外每个ADC每次处理时只能处理一个通道,所以多通道时还涉及 扫描 模式 。这些模式一组和就产生非常多的情况,下面主要以示例演示方式进行使用说明。

    STM32的ADC还有规则转换(Regular)和注入转换(Injected),注入就相当于在正常规则转换过程中插入中断,优先进行注入转换,通常挺少用的,这里不进行演示。

    下图是这里演示用到的电路图:

    在上面电路下PA0上的电压为2.2V,PA1上的电压为1.1V,ADC在12位精度采样时数据分别为 2730 和 1365 左右。

    配置选项说明

  • ADCs_Common_Settings 所有ADC公共设置
    本文只介绍ADC工作于独立模式,所以这里不用调整;
  • ADC_Settings 当前ADC设置
  • Clock Prescaler PCLK2时钟分频系数,分频后就是ADC时钟;
  • Resolution 分辨率;
  • Data Alignment 数据对齐方式,通常默认左对齐就行;
  • Scan Conversion Mode 扫描模式,多通道时强制开启扫描模式;
  • Continuous Conversion Mode 连续转换模式;
  • Discontinuous Conversion Mode
  • DMA Continuous Requests DMA连续请求;
  • End Of Conversion Selection
  • ADC_Regular_ConversionMode 规则转换模式
  • Number Of Conversion 要转换的通道数目
  • External Trigge rConversion Source 转换触发源
  • External Trigge rConversion Edge 转换触发规则
  • Rank 通道转换序号
  • Channel 该序号通道编号
  • Sampling Time 该序号采样时间
  • ADC_Injected_ConversionMode 注入转换模式
    挺少使用的,本文不涉及;
  • WatchDog 模拟看门狗
    输入通道上电压超出某个阈值时触发,本文不涉及;
  • 轮询 单通道 单次


    上面是个最基本的使用,只转换一个通道 ch0,单次转换模式。每次启动ADC转换一次数据,启动转换后等待转换完成,完成后读取结果。需要再次转换时就再来一遍这样的流程。

    上面演示中的ch0接的就是PA0引脚,采样转换后的数据与预测的数据接近。

    上面演示中主要用到了下面一些函数:

  • HAL_ADC_Start (ADC_HandleTypeDef *hadc) 启动ADC
  • HAL_ADC_PollForConversion(ADC_HandleTypeDef * hadc, uint32_t Timeout) 等待规则通道转换完成
  • uint32_t HAL_ADC_GetValue (ADC_HandleTypeDef * hadc) 获取数据
  • 过程中如果想要改变通道可以使用下面方式:

      ADC_ChannelConfTypeDef sConfig;
      sConfig.Channel = ADC_CHANNEL_1;
      sConfig.Rank = 1;
      sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
      HAL_ADC_ConfigChannel(&hadc1, &sConfig);
    

    轮询 单通道 连续


    连续转换下只要启动ADC后就会不停的工作直到使用 HAL_ADC_Stop (ADC_HandleTypeDef *hadc) 函数手动停止ADC。

    连续情况下可以不使用 HAL_ADC_PollForConversion ,需要时去读取数据即可。

    轮询 多通道 扫描


    上面就是多通道轮询扫描处理了,需要注意的是采样转换顺序是依据 Rank 编号,而不是通道编号。

    中断 单通道


    上面演示中开启了ADC中断,重写 void HAL_ADC_ConvCpltCallback (ADC_HandleTypeDef *hadc) 函数,使用 HAL_ADC_Start_IT(ADC_HandleTypeDef* hadc) 函数启动ADC。每次转换完成将触发 HAL_ADC_ConvCpltCallback ,在该函数中读取数据。

    中断方式下也可以使用前面的方式改变采样通道。

    这里需要注意的是——如果打断点调试,断点千万别打在 HAL_ADC_Start_IT(ADC_HandleTypeDef hadc) 后。*

    中断 多通道 扫描

    DMA 单通道 单轮


    使用 HAL_ADC_Start_DMA(ADC_HandleTypeDef * hadc, uint32_t * pData, uint32_t Length) 方法可以启动ADC DMA方式,完成一轮采集后会触发 HAL_ADC_ConvCpltCallback

    DMA 单通道 连续


    DMA连续采样需要注意的是DMA模式必须设定为Circular,启动转换后会持续不断的转换,每完成一轮就会触发一次 HAL_ADC_ConvCpltCallback 。可以使用 HAL_ADC_Stop_DMA(ADC_HandleTypeDef * hadc) 函数停止ADC工作。

    DMA 多通道 连续

    自校准

    对于大多数系列的STM32单片机来说在启动ADC采样前需要进行校准,以提高采样准确性。通常自校准方式如下:
    HAL_ADCEx_Calibration_Start (ADC_HandleTypeDef * hadc)
    上面函数需要在ADC启动前使用。

    总结

    STM32用HAL库的情况下使用ADC基本功能还是挺简单的。比较常见的做法就是需要采样的通道由DMA在后台不停的采集到一个数组中,需要使用的时候再从这个数组中取数据。

    物联沃分享整理
    物联沃-IOTWORD物联网 » 使用HAL库开发STM32:基于ADC的入门指南

    发表评论