ADC 即模拟数字转换器,英文详称 Analog-to-digital converter,可以将外部的模拟信号转换为数字信号。 STM32F103 系列芯片拥有 3 个ADC(C8T6 只有 2 个),这些ADC可以独立使用,其中ADC1和ADC2还可以组成双重模式(提高采样率)。
STM32 的 ADC 是 12 位逐次逼近型的模拟数字转换器。它有18个通道,可测量16个外部和2个内部信号源,其中ADC3根据CPU引脚的不同其通道数也不同,一般有8个外部通道。ADC 中的各个通道的 A/D 转换可以单次、 连续、扫描或间断模式执行。ADC的结果可以以左对齐或者右对齐存储在 16 位数据寄存器中。
ADC输入电压:要求在ADC供电电压的正负极之间变化(0~3.3V)。
ADC的分辨率:用位数表示,位数越高,量化结果越精细,对应分辨率就越高。如:12位的AD值量化结果的范围:0~2^12-1(0~4095)。(电压范围:0~3.3v,实际电压值与量化结果成正比)
转换频率/转换时间:如:1MHz/1us(STM32的最快转换时间)
ADC的通道数:ADC1/2有18个通道,18个通道:16个外部通道,2个内部通道(一个接内部温度传感器(可测量CPU的温度),一个是内部参考电压(1.2V左右的基准电压,不随外部电压的变化而变化。作用:如果你的芯片供电电压不是标准的3.3V,测量外部引脚的电压可能不准,就可以读取基准电压来校准,就能得到正确的电压值了)) ADC3根据CPU引脚的不同其通道数也不同,一般有8个外部通道。
规则组与注入组:ADC可以一次性转换一个组,转换完结束。
模拟看门狗:自动检测输入电压范围,可用于当某模拟量(如光照/电压)大于某阈值时,就执行一些操作,当AD值高于/低于设定的阈值时,它就会申请中断。
STM32可选择多个通道:一般的ADC(如之前讲解的ADC0809芯片), 多路开关只能选一个通道,开始转换,等待转换完成,取出结果。而对应STM32的ADC可以同时选多个通道,还分成了两个组(规则组和注入组),规则组一次性最多可以选16个通道,注入组一次性可选择4个通道。规则组只有一个数据寄存器,当ADC有多个通道需要转换时,每个通道转换完成后,可以用DMA及时将数据转运到其他存储器上,防止数据被覆盖。注入组有4个数据寄存器,注入组不需要担心数据覆盖的问题。
左下角的开始触发与ADC0809的START类似:
触发ADC开始转换的信号有两种:
1.软件触发
2.硬件触发(ADC框图的左下角,上面是注入组触发,下面是规则组触发,定时器可以通向DAC或ADC用于触发转换。
实际问题:ADC需要经常过一段时间转换一次,例如隔1ms转换一次。
①.使用中断:用定时器,每隔1ms申请中断一次,在中断里手动开启一次转换。 用中断会影响主程序的执行,并且不同中断之间优先级不同,有时会导致一些中断不能及时响应,如果触发ADC的中断不能及时响应,那ADC的转换频率就会受到影响。
②.使用硬件触发:对于这些需要频繁进中断,而只在中断中只做一些简单工作的,一般都有硬件的支持(触发输出使ADC开始工作,不需要中断),对于上面的实际问题就可以使用硬件触发的方法。
注入组和ADC3的外部触发详见参考手册
例如:用TIM3定时1ms,并选择TIM3的更新事件选择为TRGO输出,然后在ADC这里选择开始触发信号为TIM3的TRGO,这样TIM3的更新事件就可以通过硬件来触发ADC开始转换了。也可以用外部中断引脚来触发转换。
VREF+/VREF-:DAC的参考电压,DAC的参考电压也决定了ADC的输入电压范围,所以他也是ADC的参考电压
VDDA(3.3V)与VSSA(0V):内部模拟部分(ADC、RC震荡器、锁相环等)的电源,一般情况下VDDA接VREF+,VSSA接VREF-。
ADCCLK:ADC的时钟,ADC预分频器是来自RCC的,一般我们设置 PCLK2 为 72MHz。为了不超过 ADC 的最大输入时钟频率 14MHz,我们设置 ADC 的预分频器分频系数为 6,就可以得到 ADC 的输入时钟频率为 72MHz/6,即12MHz。
中断相关:
如果开启了模拟看门狗,并指定了看门狗的通道,那么看门狗就会关注这个通道,一旦超过阈值范围,就会申请模拟看门狗的中断,最后通向NVIC。
对于规则组与注入组转换完成之后也会产生一个EOC/JEOC转换完成的信号,这两个信号会在状态寄存器置一个标志位,读取这个标志位就可以知道是否转换完成了,这两个标志位也可以去NVIC申请中断,如果开启了NVIC相应通道就可以触发中断。
总结ADC的基本结构:
图片选自B站江科大STM入门教学PPT
原理图上的引脚PA0上的ADC12_IN0说明ADC1和ADC2的外部输入引脚IN0都在PA0上,ADC1/ADC2的输入引脚在同一个引脚上可用于开启双ADC模式 。
图片选自B站江科大STM入门教学PPT
图片选自B站江科大STM入门教学PPT
小结:
非扫描模式和扫描模式:是否要扫描多个ADC通道,若只有一个通道,就可以使用非扫描模式。若有多个通道模拟值需要采集,就可以使用扫描模式。扫描模式相当于有多个ADC通道需要转换,非扫描模式就默认只有一个通道。
单次转换模式和连续转换模式:若有1个通道,单次转换就是ADC转换一次这个通道就停下来。连续转换就是ADC转换一次这个通道后,继续将最新的通道值转换出来(模拟量转数字量,转换频率由ADC转换频率决定,可以设置ADC采样时间)。若有多个ADC通道,单次转换就是ADC转换一次这多个通道(按照一定的顺序,可以设置)就停下来。连续转换就是ADC转换一次这多个通道后,继续将最新的多个通道值转换出来,继续按照之前设置好的通道顺序进行转换。
图片选自B站江科大STM入门教学PPT
ADC数据的左对齐与右对齐:
数据寄存器是16位的,而ADC的转换结果是12位,那么数据就有左对齐和右对齐(常用)。
二进制数的特点:左移n位,数据增大2^n倍 左对齐直接读的话会比实际值大16倍。
左对齐的用途:如果你不想要这么高的分辨率,可以选择左对齐,然后把高八位取出来,这样就舍弃了后面4位精度。
图片选自B站江科大STM入门教学PPT
量化编码:就是逐次比较的过程,位数越多花的时间越长。
采样保持电路:量化编码是需要一小段时间的,这段时间输入电压不允许变化,故需要一个电容来收集采样后外部的电压,收集完之后再关闭采样与电容之间的通道。
ADC的采样时间是可以设置的,ADC周期可通过设置ADCCLK(通过RCC设置分频系数)来设置,而STM32 ADC的转换时间=采样时间+12.5个ADC周期,故可通过程序设置采样时间和ADCCLK来设置实际需要的ADC转换时间。
ADC使用一般步骤:
校准-->通道配置-->启动ADC --> 等待 ADC 转换完成--> 获取转换值
ADC:非扫描模式,单次转换模式,由软件触发。
ADC_CR1寄存器(模式选择寄存器):
模式选择:双模式选择(此实验单通道选择独立模式)和扫描模式(此实验选择非扫描模式)
ADC_CR2寄存器:
EXTSEL[2:0]位用于选择规则组启动转换的外部事件触发源,本实验使用的是软件触发(SWSTART),所以这三个位置为 111。EXTTRIG 位必须置 1,EXTSEL[2:0]位才能选择软件触发(SWSTART),别漏了这步,否则设置软件触发会不成功。SWSTART 位用于启动一次规则组通道的转换。
ADC 采样事件寄存器x:
一般每个要转换的通道,采样时间建议尽量长一点,以获得较高的准确度,但是这样会降低 ADC 的转换速率。
1.用于初始化 ADC
HAL_StatusTypeDef HAL_ADC_Init(ADC_HandleTypeDef *hadc);
typedef struct { uint32_t DataAlign; /* 设置数据的对齐方式 */
uint32_t ScanConvMode; /* 扫描模式 */
FunctionalState ContinuousConvMode; /* 开启连续转换模式/单次转换模式 */
uint32_t NbrOfConversion; /* 设置转换通道数目 */
FunctionalState DiscontinuousConvMode; /* 是否使用规则通道组间断模式 */
uint32_t NbrOfDiscConversion; /* 配置间断模式的规则通道个数 */
uint32_t ExternalTrigConv; /* ADC 外部触发源选择 */ 、
} ADC_InitTypeDef;
1) DataAlign:用于设置数据的对齐方式,这里可以选择右对齐或者是左对齐,该参数可选为: ADC_DATAALIGN_RIGHT 和 ADC_DATAALIGN_LEFT。
2) ScanConvMode:配置是否使用扫描。如果是单通道转换使用 ADC_SCAN_DISABLE,如果是多通道转换使用 ADC_SCAN_ENABLE。
3) ContinuousConvMode:可选参数为 ENABLE 和 DISABLE,配置自动连续转换还是单次转换。 使用 ENABLE 配置为使能自动连续转换;使用 DISABLE 配置为单次转换,转换一次后停止 需要手动控制才重新启动转换。
4) NbrOfConversion:指定规则组转换通道数目,范围是:1~16。
5) DiscontinuousConvMode:配置是否使用规则通道组间断模式,比如要转换的通道有 1、2、 5、7、8、9,那么第一次触发会进行通道 1 和 2,下次触发就是转换通道 5 和 7,这样不连续的转换,依次类推。此参数只有将 ScanConvMode 使能,还有 ContinuousConvMode 失能的情况下才有效,不可同时使能。
6) NbrOfDiscConversion:配置间断模式的通道个数,禁止规则通道组间断模式后,此参数忽略。
7) ExternalTrigConv:外部触发方式的选择,如果使用软件触发,那么外部触发会关闭。 本实验就使用软件触发的方式
2.首先调用 HAL_ADC_Init 函数配置了相关的功能后,再调用此函数进行 ADC 自校准功能
HAL_StatusTypeDef HAL_ADCEx_Calibration_Start(ADC_HandleTypeDef *hadc);
3.调用了 HAL_ADC_Init 函数配置了相关的功能后,就可以调用此函数配置 ADC 具体通道。
HAL_StatusTypeDef HAL_ADC_ConfigChannel(ADC_HandleTypeDef *hadc, ADC_ChannelConfTypeDef *sConfig);
4.当配置好 ADC 的基础的功能后,就调用此函数启动 ADC。
HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef *hadc);
5.一般先调用 HAL_ADC_Start 函数启动转换,再调用该函数等待转换完成,然后再调用 HAL_ADC_GetValue 函数来获取当前的转换值。
HAL_StatusTypeDef HAL_ADC_PollForConversion(ADC_HandleTypeDef *hadc, uint32_t Timeout);
6.一般先调用 HAL_ADC_Start 函数启动转换,再调用 HAL_ADC_PollForConversion 函数等 待转换完成,然后再调用 HAL_ADC_GetValue 函数来获取当前的转换值
uint32_t HAL_ADC_GetValue(ADC_HandleTypeDef *hadc);
ADC句柄、ADC时钟结构体(用于设置ADC时钟)、GPIO句柄声明
1.开启ADCx时钟、开启GPIO(模拟量输入引脚)时钟
2.设置ADC时钟,GPIO引脚初始化(1.Pin 2.模拟模式)
3.ADC初始化
4.ADC校准
5.ADC通道配置(可自己写一个函数)
6.开启ADC、等待转换结束、获取转换结果
7.编写通道 ch 的转换值的平均函数
ADC:非扫描模式,连续转换模式,由软件触发。
DMA:正常模式,由软件触发。
ADC、GPIO、DMA句柄声明
1.开启ADCx时钟、开启GPIO(模拟量输入引脚)时钟、DMA时钟
2.设置ADC时钟,GPIO引脚初始化(1.Pin 2.模拟模式)
3.DMA初始化 将DMA与外设连接起来(软件层面)
__HAL_LINKDMA(&g_adc_dma_handle, DMA_Handle, g_dma_adc_handle);
4.ADC初始化
5.ADC校准
6.ADC通道配置
7.设置ADC中断优先级(配置DMA数据流请求中断优先级,ADC_ADCX_DMACx_IRQn表示DMA1通道1的中断,如下面第一张图)
8.开启ADC和DMA(设置传输个数为0,实际开启由adc_dma_enable用寄存器开启),开启DMA中断(如下图)
9.使能一次DMA传输函数(用寄存器操作)
10.中断服务子函数的编写
DMA1通道1传输完成后产生中断,中断标志由相关寄存器判断,如上第二张图。本实验采用判断标志位(传输指定个数数据后DMA中断)的方式,即DMA转运完成一次(传输ADC_DMA_BUF_SIZE个数据到目的数组g_adc_dma_buf[ADC_DMA_BUF_SIZE]中去,传输完成后产生中断,标记g_adc_dma_sta为1),再对原始数据进行平均,显示,再清零标志位g_adc_dma_sta = 0,再次开启DMA转运,循环往复。
使用DMA采集与没有使用DMA采集的区别:
没有使用DMA而采用函数获取转换值,每次获取(获取之前已经设置好了ADC_init和ADC校准)都要设置ADC通道、开启ADC、等待ADC转换结束、获取转换值(如下图)。 根本区别在于不使用DMA转运每次要等待ADC转换结束后才可以用HAL_ADC_GetValue(&g_adc_handle)来获取ADC转换值,而使用DMA转运数据,ADC_DMA初始化(包括DMA_init,DMA与ADC连接,ADC_init,ADC校准,设置ADC通道,开启ADC,开启DMA)之后,ADC每转换完成一次就触发一次DMA转运,不需要考虑ADC是否已经转换完成。
ADC:扫描模式(有多个通道),连续转换模式,由软件触发。
DMA:正常模式,由软件触发。
1.因为是ADC多组通道,ADC模式是扫描模式。
2.DMA目的数组元素个数均为要采集通道数的整数倍。
1.DMA的传输计数器个数是通过对函数adc_dma_enable()传递参数cndtr来实现的 adc_dma_enable():使能一次ADC DMA传输。回顾一下DMA启动传输的条件:DMA_ENABLE,传输计数器不为0,有触发源。
2.DMA只使用了一个通道,ADC使用了6个通道。
3.DMA的数据源地址与目的地址是通过HAL_DMA_Start_IT()函数传递的。
4.该DMA传输是软件触发的(没有通过硬件触发),ADC启停同步,保证数据的正确性。
江科大ADC+DMA具体实验步骤:
AD多通道DMA配合转运数据
1.
ADC:扫描模式,单次转换,由软件触发
DMA:正常模式(非循环模式),触发源为ADC1,DMA的通道不能任意选择(由相应硬件决定)
ADC启动之前就将DMA初始化以及将DMA的硬件触发通道打开,ADC转运完成一次就触发DMA一次
调用该函数,ADC开始转换,连续扫描4个通道,DMA也同步开始转运,转换数据依次存放在ADvalue数组。
主函数:
2.
ADC:扫描模式,连续转换,软件触发
DMA:循环模式,触发源为ADC1的硬件触发
ADC触发之后,ADC连续转换,DMA循环转运,两者一直工作,始终把最新的转换结果,刷新到SRAM数组里。
主函数:
本实验HAL库版本代码已更新。
3.
完全硬件自动化
定时器触发ADC--->ADC触发DMA转运。
欢迎提问讨论,共同进步,望诸君共勉!