概述
12 位 ADC 是逐次趋近型模数转换器。它具有多达 19 个复用通道,可测量来自 16 个外部 源、两个内部源和 VBAT 通道的信号。这些通道的 A/D 转换可在单次、连续、扫描或不连续 采样模式下进行。ADC 的结果存储在一个左对齐或右对齐的 16 位数据寄存器中。 ADC 具有模拟看门狗特性,允许应用检测输入电压是否超过了用户自定义的阈值上限或下限。
ADC基本结构
ADC供电
时钟
用于模拟电路的时钟:ADCCLK,所有 ADC 共用 此时钟来自于经可编程预分频器分频的 APB2 时钟,该预分频器允许 ADC 在 fPCLK2/2、 /4、/6 或 /8 下工作
用于数字接口的时钟(用于寄存器读/写访问) 此时钟等效于 APB2 时钟。可以通过 RCC APB2 外设时钟使能寄存器 (RCC_APB2ENR) 分别为每个 ADC 使能/禁止数字接口时钟。
ADC通道
外部输入通道
有 16 条复用通道。可以将转换分为两组:规则转换和注入转换。每个组包含一个转换序列,该序列可按任意顺序在任意通道上完成。
内部通道
对于 STM32F40x 和 STM32F41x 器件,温度传感器内部连接到通道 ADC1_IN16。内部参考电压 VREFINT 连接到 ADC1_IN17。
对于 STM23F42x 和 STM32F43x 器件,温度传感器内部连接到与 VBAT 共用的通道 ADC1_IN18。一次只能选择一个转换(温度传感器或 VBAT)。同时设置了温度传感器和 VBAT 转换时,将只进行 VBAT 转换。
VBAT 通道连接到通道 ADC1_IN18。该通道也可转换为注入通道或规则通道
注:温度传感器、VREFINT 和 VBAT 通道只在主 ADC1 外设上可用。
规则通道和注入通道
规则通道最多有16个转换构成、一个规则转换组规定了多路复用转换的顺序。
注入通道就是可以在规则通道转换过程中插入进行转换的通道。数量最多为4个。
ADC触发模式
软件启动:直接控制寄存器,启动ADC外设,一般为轮询方式进行ADC转换
内部定时器触发:
外部IO触发:
ADC转换时序
ADC开始精确转换之前,需要一定的稳定时间 tstab。稳定时间以后,才可以启动ADC进行转换。ADC 开始转换并经过 15 个
时钟周期后,EOC 标志置 1,转换结果存放在 16 位 ADC 数据寄存器中。
ADC 会在数个 ADCCLK 周期内对输入电压进行采样,可使用 ADC_SMPR1 和 ADC_SMPR2
寄存器中的 SMP[2:0] 位修改周期数。每个通道均可以使用不同的采样时间进行采样。
总转换时间的计算公式如下:
Tconv = 采样时间 + 12 个周期
示例:
ADCCLK = 30 MHz 且采样时间 = 3 个周期时:
Tconv = 3 + 12 = 15 个周期 = 0.5 μs(APB2 为 60 MHz 时)
由于规则通道组只有一个数据寄存器,因此,对于多个规则通道的转换,使用 DMA 非常有帮助。这样可以避免丢失在下一次写入之前还未被读出的 ADC_DR 寄存器中的数据。如果数据没有被读出,之后的ADC数据会覆盖前面的ADC数据。
例1:规则通道
- 规则通道
- 时钟配置 略
- ADC配置
使用软件方式触发,开启单个ADC检测通道 生成代码
HAL_ADC_Start() 采用软件方式启动ADC。
在软件方式启动ADC以后,需要使用函数HAL_ADC_PollForConversion()判断转换是否完成。
然后使用HAL_ADC_GetValue()将32位寄存器中保存的数据读取出来
uint32_t ADC_Value=0; HAL_ADC_Start(&hadc1); if(HAL_ADC_PollForConversion(&hadc1, 100)==HAL_OK) { ADC_Value=HAL_ADC_GetValue(&hadc1); }
可以使用串口或者LCD显示,将数据进行显示。
例2 使用定时器触发ADC转换
ADC触发方式有3种:软件触发,内部定时器触发和外部IO触发
内部定时器触发,通过定时器的TRGO事件来激活ADC进行电压采集
注:单个ADC使用多个通道时候使用中断时,扫描模式会被强制打开。如果在使用扫描模式的情况下使用中断,会在最后一个通道转换完毕后才会产生中断。因此只能使用DMA进行多通道数据搬运。
- 时钟设定略
- 定时器设定
配置定时器时钟
配置触发事件选择(trigger event selection) 定时器的全局中断可以不打开 不影响事件发生
- ADC设置
在配置ADC通道时,需要将定时器时钟映射到ADC的触发条件上
单通道的情况下 模式似乎不影响定时器触发ADC
打开ADC的中断,在中断回调函数中可以进行数据处理等操作
生成代码
- 代码补充
在主函数中,启动定时器和ADC中断
HAL_TIM_Base_Start_IT(&htim2);
HAL_ADC_Start_IT(&hadc1);
在adc.c中添加通道结束后的中断回调函数,来获得ADC转换后中寄存器的值
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { if(hadc->Instance==ADC1) { uint32_t val=HAL_ADC_GetValue(hadc); } }
DMA 多通道 定时器
在使用多通道时,必须使用扫描模式,cubemx 会强制开启(scan conversion mode)ADC完成转换换后会立刻转换下一个通道,知道整个组里面的通道序列转换完成,如果中断被允许,此时才会发生中断。
因此,使用DMA来对数据进行自动存储到缓存区中,在一个通道组完成转换后,触发中断,再对数据进行处理。
- 时钟配置 略
- 定时器配置
根据触发需求进行定时器配置,配置触发事件选择(trigger event selection) 定时器的全局中断可以不打开 不影响事件发生
- ADC配置
选择多个通道进行扫描模式scan conversion mode
修改需要采集的通道数量(Number of Conversion)将通道(channel)对应到Rank中
开启DMA连续触发请求,关闭后 DMA只触发一次
将ADC的触发方式映射到TRGO上
打开DMA传输 将ADC映射到DMA上 修改DMA的模式为循环模式(正常模式只触发一次)
修改传输数据的长度
注:TIM和ADC的中断都可以不开。在外设使用DMA是,建议尽量不要开启外设中断,若必须开,也要禁止外设主要事件源产生硬件中断。因为HAL中DMA的中断回调函数会映射到外设的回调函数中,这样可能导致多次进入中断回调函数中。
- 补充代码
在主函数中开启定时器和ADC的DMA
HAL_TIM_Base_Start(&htim2);
HAL_ADC_Start_DMA(&hadc1, dmaDataBuffer, DATA_LEN);
在adc.c中添加回调函数处理
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { }