使用HAL库开发STM32:ADC基础使用

Posted Naisu Xu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用HAL库开发STM32:ADC基础使用相关的知识,希望对你有一定的参考价值。

目的

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

以上是关于使用HAL库开发STM32:ADC基础使用的主要内容,如果未能解决你的问题,请参考以下文章

STM32学习(31)STM32通过ADC实现多按键功能(标准库和HAL库实现)

stm32f103ve+光电传感器使用教程+oled(HAL库)

正点原子STM32(基于HAL库)4

使用HAL库开发STM32:使用Timer输出PWM信号

STM32HAL ADC+TIM+DMA采集交流信号 基于cubemx

STM32深入实践教程目录