Skip to content

第七章 ADC

7.1 ADC模拟-数字转换器

7.1.1 ADC简介

  • ADC(Analog-Digital Converter)模拟-数字转换器
  • ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁
  • 12位逐次逼近型ADC,1us转换时间
  • 输入电压范围:03.3V,转换结果范围:04095
  • 18个输入通道,可测量16个外部和2个内部信号源
  • 规则组和注入组两个转换单元
  • 模拟看门狗自动监测输入电压范围

STM32F103C8T6 ADC资源:ADC1、ADC2,10个外部输入通道

7.1.2 逐次逼近法ADC

逐次逼近法:即 二分比较确定电压值

12 位最大值为 4095(即1111111111) ,先去一半 2048 与待测电压比较,若小于 2048 则记 0 ,然后与 2048 的一半 1024 比较,若待测电压大于 1024 ,则记作 1 ,依次比较 12 次, 得到一个 16 位的二进制数,按比例与 3.3V 换算得到待测电压的实际值。

image-20241226152637577

如下图中比较器的位置即为逐次逼近法实现的电路,一路为外部输入的待测电压,一路为内部参考电压,并经过DAC(数字模拟转换器)转换进行比较。

image-20241226153511469

7.1.3 ADC框图

  • 规则组: 十六个通道,所以可以一次接16个GPIO;但是只有一个数据寄存器所以只能存储一个数据,即只会保留最后一个通道数据。
  • 注入组: 四个通道,可以一次接4个GPIO;而且有四个数据寄存器,可以同时存储四个数据。
Danger

由于规则组只有一个数据寄存器,当使用多通道时最好配合 DMA (数据搬运小助手)。

STM32的ADC的总框图如下:

image-20241226203038872

ADC开始转换的触发源如下,主要是一些定时器触发,其中需要注意的是TIM4_TRGO可以用于触发主模式实现硬件的全自动触发ADC,避免频繁进中断触发ADC。

image-20241226203145626

关于ADC的转换通道:

image-20241226204051325

Danger

需要注意的是:ADCCLK最高频率为 14MHZ ,所以ADC预分频器最小应为 6 分频;REF参考电平一般是和ADC的供电引脚相连的。

7.1.4 ADC基本结构

image-20241226210531078

Note

EOC即转换结束或注入转换结束的标志位;这里的模拟看门狗是用于监控转换结果的范围是否超出阈值,若超过阈值则可以申请中断控制。

7.2 输入通道与转换模式

7.2.1 输入通道

GPIO的 16 个输入通道:

通道 ADC1 ADC2 ADC3
通道0 PA0 PA0 PA0
通道1 PA1 PA1 PA1
通道2 PA2 PA2 PA2
通道3 PA3 PA3 PA3
通道4 PA4 PA4 PF6
通道5 PA5 PA5 PF7
通道6 PA6 PA6 PF8
通道7 PA7 PA7 PF9
通道8 PB0 PB0 PF10
通道9 PB1 PB1
通道10 PC0 PC0 PC0
通道11 PC1 PC1 PC1
通道12 PC2 PC2 PC2
通道13 PC3 PC3 PC3
通道14 PC4 PC4
通道15 PC5 PC5
通道16 温度传感器
通道17 内部参考电压
Note

ADC1和ADC2的引脚完全相同,可以用于配置双ADC模式,仅作为了解即可。

7.2.2 转换模式

主要的转换模式有四种,是单次转换、连续转换和非扫描模式、扫描模式的四种组合。

  • 单次转换 :即完成一次输入通道序列的模数转换后,触发EOC标志位,需要再次触发才会再进行输入通道序列的模数转换。
  • 连续转换 :即完成一次输入通道序列的模数转换后,触发EOC标志位,紧接着继续进行输入通道序列的模数转换,依次循环不会中断,要获取ADC值读取数据寄存器即可。
  • 非扫描模式 :即输入通道序列中仅有一个输入通道。
  • 扫描模式 :即输入通道序列中仅有多个输入通道。
Danger

使用扫描模式时,为避免数据覆盖,应结合DMA使用。

  1. 单次转换非扫描模式

image-20241226212934097

  1. 连续转换,非扫描模式

image-20241226212946750

  1. 单次转换,扫描模式

image-20241226213028025

  1. 连续转换,扫描模式

image-20241226213055108

7.3 其他相关知识点

7.3.1 触发控制源

分为软件和硬件触发:

image-20241226214501204

7.3.2 ADC数据对齐

  • 右对齐

image-20241226214625133

  • 左对齐

image-20241226214629455

7.3.4 转换时间

AD转换的步骤:采样,保持,量化,编码

  • 采样保持,即接一个采用开关,在量化编码前收集电压,量化编码开始后断开采样开关,防止电压连续跳变影响转换结果
  • 量化编码,即逐次逼近测电压值

STM32 ADC的总转换时间为: TCONV = 采样时间 + 12.5个ADC周期

12.5个ADC周期就是量化编码时间

例如:当ADCCLK=14MHz,采样时间为1.5个ADC周期 TCONV = 1.5 + 12.5 = 14个ADC周期 = 1μs

7.3.4 ADC校准

  1. ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差。

  2. 建议在每次上电后执行一次校准。

  3. 启动校准前, ADC必须处于关电状态超过至少两个ADC时钟周期

7.4 STM32CubeMX参数

image-20241226225441144

Danger

stm32f103c8t6的外部信号源仅引出了 10 个,需注意。

image-20241226225713790

  1. ADC模式一般使用单ADC,使用多ADC则需要同时打开ADC1和ADC2(多ADC不常用)
  2. ADC设置,依次为ADC数据对齐,扫描模式,连续转换,非连续转换
  3. ADC规则组转换模式,依次为规则组转换使能,转换通道数量,外部触发源(这里的参数一般默认即可)
    • 需注意Number Of Conversions参数,当采用扫描模式 需要将其数值提高至选用通道的数量,然后就会出现多个Rank
    • Rank表示一个通道,下属参数有所属通道,采用周期,一般需参考手册调整采用周期,默认也可以。
  4. 模拟开门狗

7.5 ADC读取电压值

均采用单ADC

电位计接线图,参考江协科技资料,将GPIO引脚按情况修改:

7-1 AD单通道

7.5.1 单次转换非扫描模式

image-20241226222017580

image-20241226222057543

配置串口输出电压值

image-20241226222231023

定义串口,模拟值,电压变量

C
/* USER CODE BEGIN 2 */
uint32_t value = 0;
double voltage = 0.0;
char message[20] = "";
/* USER CODE END 2 */

主要功能代码

C
/* USER CODE BEGIN WHILE */
while (1) {
    // 打开ADC转换
    HAL_ADC_Start(&hadc1);
    //等待ADC转换,防止第一次读取默认值
    HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
    //读取ADC数据寄存器的值
    value = HAL_ADC_GetValue(&hadc1);
    //电压换算
    voltage = (value / 4095.0) * 3.3 ;

    sprintf(message, "ADC: %lu   %.2fV", value, voltage);
    //串口发送函数
    HAL_UART_Transmit(&huart1, message, strlen(message), HAL_MAX_DELAY);
    HAL_Delay(500);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */

HAL_MAX_DELAY为一直等待,关于串口发送函数可以去第九章瞄一眼,也可以先不管就用就可以。

image-20241226223855311

不难看出即使电位计旋转到最大,ADC值也不是最大的 4095 ,是因为我们缺少了校准的一步:

C
/* USER CODE BEGIN 2 */
uint32_t value = 0;
double voltage = 0.0;
char message[20] = "";
//ADC校准
HAL_ADCEx_Calibration_Start(&hadc1);
/* USER CODE END 2 */

7.5.2 连续转换非扫描模式

打开连续转换即可:

image-20241226224615787

代码只需要把开启转换和等待转换的函数放在循环前即可

C
/* USER CODE BEGIN 2 */
uint32_t value = 0;
double voltage = 0.0;
char message[20] = "";
HAL_ADCEx_Calibration_Start(&hadc1);
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
/* USER CODE END 2 */

7.5.3 扫描模式说明

由于规则组多通道会有数据覆盖问题,故在DMA章节在实现ADC的多通道扫描模式。