没志青年
发布于 2025-06-13 / 37 阅读
0

32单片机 - ADC

以 STM32F407 为例

STM32F407VET6 标准库 模板

STM32F407VET6 HAL 模板

PY32:

一、ADC 极限值

时钟频率

采样和转换时间

二、ADC 配置

ADC 数值转换

STM32的ADC为 12 位,可以将模拟信号转换为 0~4095 之间的数值。

假设ADC的位数为 N

电压V=Vref2N1ADC电压V=\frac{V_{ref}}{2^N-1}*ADC值

前半部分是计算一位数代表多少电压

为什么减1?

因为有个0,要的是。

比如你使用 2 位数表示,则有0、1、2、3,参考电压为3V

那应该1表示1V,2表示2V,就是 3V/3,如果是3V/4,那就不对了。

3 * 3/4 不等于 3V了,。

ADC 采集通道

首先,需要知道某个ADC对应哪些通道:

(一)第一种方法就是看数据手册上的引脚复用:

例如 ADC12_IN6 这种是指 ADC 1 和 2 共用。

内部的通道:

内部通道的说明:

(二)使用 CubeMX,更直观,但是仅限于 STM32 单片机

右下角搜索,对应的引脚会闪烁。

(三)通过库文件

ADC通道可以分为规则组和注入组:

  • 规则组:规则组就是正常的按顺序转换,最多有16个转换。

  • 注入组:把注入组理解为高优先级的中断,规则组理解为低优先级的中断,注入组可抢占规则组的转换,插队提前转换。注入组最多有4个转换。

如图,规则组在第一个转换后被注入组抢占了,注入组转换完了,才能轮到规则组。

结构体:

// F1



// F4




// G4
typedef struct
{
  uint32_t Channel;       // 通道
  uint32_t Rank;          // 
  uint32_t SamplingTime;
  uint32_t SingleDiff;
  uint32_t OffsetNumber;
  uint32_t Offset;
  uint32_t OffsetSign;
  FunctionalState OffsetSaturation;
} ADC_ChannelConfTypeDef;

ADC_ChannelConfTypeDef sConfig = {0};
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) 
{
    while (1);
}

ADC 事件与中断

ADC 触发方式

事件:

事件

方向

触发时机

中断

DMA 请求

ADC -> DMA

每个通道转换完成后生成一个 DMA 请求

DMA 溢出

DMA已经完成了预设的数据传输量,但又来了个DMA请求。(如果DMA配置的是循环模式,则不会产生该事件。)

规则组转换结束 EOC

可变?

注入组转换结束 JEOC

注入组整组转换完成

模拟看门狗事件

模拟看门狗:

模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。

采集模式:

  • 单次、连续:决定是否重复。注入组不支持连续转换(要支持的话,规则组就无法工作了,那就废了。)

  • 扫描:决定是否多通道

  • 不连续模式

模式

对象

说明

单次

一个通道

单次 + 扫描

一个序列

序列的每个通道依次转换1次,所有通道转换完成后停止。

连续

一个通道

连续 + 扫描

一个序列

序列的每个通道依次转换1次,所有通道转换完成后开始新的一轮。

连续是无限的意思,就是硬件不支持“连续3次 / 连续10次”这种,但是软件上可以实现(1、手动触发n次,常用 2、在中断中计数 3、DMA自带的计数,在搬运n次产生TC中断停止)。

扫描 + 不连续模式:一组的通道分多次转换。

规则组:

n = 3,要转换的通道 = 0、1、2、3、6、7、9、10

第 1 次触发:转换序列 0、1、2

第 2 次触发:转换序列 3、6、7

第 3 次触发:转换序列 9、10 并生成 EOC 事件

第 4 次触发:转换序列 0、1、2

注入组:

n = 1,要转换的通道 = 1、2、3

第 1 次触发:转换通道 1

第 2 次触发:转换通道 2

第 3 次触发:转换通道 3 并生成 EOC 和 JEOC 事件

第 4 次触发:通道 1

ADC 时钟

ADC时钟是有上限的。

打开数据手册,搜索【Analog-to-digital converter characteristics】或【12-bit ADC characteristics】,找到关于ADC参数的表。

Range1、Range2:采集范围,Range1为默认范围,即0~Vref(3.3V),range2为拓展范围,需要通过内部分压器,精度较低。

绝大多数情况适用的是 Range1,。

官方文档中只指出了一个或所有ADC工作的情况,没说明2个、3这些中间数的频率范围,所以,保险起见,使用所有ADC同时工作,52MHz。

ADC 采样和转换时间

采样和转换时间 TCONVT_{CONV}=采样时间 + 转换时间

转换时间为固定的 12.5 个周期:

有的手册中会这样写,但其实还是12.5个周期(ADC位数12 + 0.5),我猜测都是固定的 12.5 个周期。

采样时间是可以设置的,

三、双 ADC 模式

两个ADC同时工作可提高效率,但是协要调它们如何工作。

默认为独立模式,两个 ADC 各干各的,常用。

触发信号由 ADC1 产生。

因此只能是ADC1+ADC2组合,或ADC1+ADC3组合,不能是ADC2+ADC3组合。

规则组同步模式

用于规则通道组。

此模式下,ADC1的外部触发不仅能触发ADC1,还能同时触发ADC2。

注入组同步模式

用于注入通道组。

  • 转换的数据存储在每个ADC接口的ADC_JDRx寄存器中

  • 当所有ADC1/ADC2注入通道都被转换时,产生JEOC中断

注意事项上:

  • 不要在2个ADC上转换相同的通道(两个ADC在同一个通道上的采样时间不能重叠)。

  • 在同步模式中,必须转换具有相同时间长度的序列,或保证触发的间隔比2个序列中较长的序列 长,否则当较长序列的转换还未完成时,具有较短序列的ADC转换可能会被重启。

交替模式

只用于规则组的一个通道。

ADC1触发,过一段时间,ADC2自动触发。

也就是转换两次仅需要一个触发信号。


一些型号的等待周期是可以设置的,因此可分为快速交替模式和慢速交替模式。

交替触发模式

只用于注入组。

每个转换需要一次触发信号。

此模式下,外部触发信号来自ADC1,这个信号指导 ADC1 和 ADC2 交替触发。

四、双 ADC 混合模式

规则组同步模式 + 注入组同步模式

就是单ADC下的注入组抢占规则组,只不过这里实现的是,同时使用两个ADC采集两个通道。

规则组同步模式 + 交替触发模式

规则组正常工作,注入组轮流执行。

第1次注入触发 → ADC1注入转换

第2次注入触发 → ADC2注入转换

图中看到两个重复的通道,比如第一次触发那里的两个CH2,但并不是真的搞两个在那里,其实这图想表达的是CH0抢占了CH2,CH0转换完后CH2再开始转换。

内部温度传感器

支持的温度范围:—40 °C 到 125 °C

精度:±1.5 °C

ADC 多模式

某些ADC作为一组,共享资源,比如G474RBT3的 ADC12和ADC345

  • 共享同一个时钟

  • 共用校准电路,必须先校准 ADC1 再校准 ADC2,因为 ADC1 校准会覆盖掉 ADC2 的校准

  • 双重模式下,共享触发信号,即触发了ADC1采样,ADC2也会采样,可实现同步采样。

  • 同步模式下会共享采样时间和转换序列???这啥玩意,待明确

ADC 多模式配置结构体:

typedef struct
{
  uint32_t Mode;             
  uint32_t DMAAccessMode;    
  uint32_t TwoSamplingDelay; 
} ADC_MultiModeTypeDef;

比如:

ADC_MultiModeTypeDef multimode = {0};
multimode.Mode = ADC_MODE_INDEPENDENT;    // 配置为独立模式
if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
{
    while (1);
}

ADC前电阻分压

VrealV_{real}为真正的电压,设VinV_{in}为输入到ADC的电压。

1、求电压放大倍数,假设为

Vreal=Vin100+5.15.1V_{real}=V_{in}*\frac{100+5.1}{5.1}

2、求 ADC 电压换算公式,设 ADC 值为 val

Vin=3.34095valV_{in}=\frac{3.3}{4095}*val

3、求真实电压和ADC值的关系

Vreal=3.34095val100+5.15.1=val346.8320884.5=val0.01660705......(V)  =  val16.607  (mV)V_{real}=\frac{3.3}{4095}*val*\frac{100+5.1}{5.1}=val*\frac{346.83}{20884.5}=val*0.01660705......(V)\;=\;val*16.607\;(mV)