12位ADC是一种逐次逼近型模拟数字转换器。它有多达18个通道,可测量16个外部和2个内部信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中。
模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。
ADC的输入时钟不得超过14MHz
通过设置ADC_CR2寄存器的ADON位可给ADC上电。当第一次设置ADON位时,它将ADC从断电状态下唤醒。
ADC上电延迟一段时间后(tSTAB),再次设置ADON位时开始进行转换。
tSTAB可查询数据手册
一般来说是1us
通过清除ADON位可以停止转换,并将ADC置于断电模式。在这个模式中,ADC几乎不耗电(仅几个μA)。
也就是 启动ADC,第一次置位ADON位后,等待tSTAB时间后,硬件将ADON置位,如果这时候软件第二次置位ADON位,则ADC开始转换
寄存器ADCx_CR2的ADON位如下:
我们应该通过寄存器ADCx_CR2的SWSTART/JSWSTART位来启动ADC的转换,而不是置位ADON来启动转换。(在通过软件触发启动ADC转换的情况下)
将ADC从断电模式中唤醒的HAL库的代码如下:
函数ADC_Enable()
可通过寄存器ADCx_CR2的CONT位来选择是单次转换还是连续转换
此模式用来扫描一组模拟通道。
扫描模式可通过设置ADC_CR1寄存器的SCAN位来选择。一旦这个位被设置,ADC扫描所有被A**DC_SQRX寄存器(对规则通道)或ADC_JSQR(对注入通道)**选中的所有通道。
在每个组的每个通道上执行单次转换。在每个转换结束时,同一组的下一个通道被自动转换。如果设置了CONT位,转换不会在选择组的最后一个通道上停止,而是再次从选择组的第一个通道继续转换。
如果设置了DMA位,在每次EOC后,DMA控制器把规则组通道的转换数据传输到SRAM中。而注入通道转换的数据总是存储在ADC_JDRx寄存器中
注入通道没有DMA搬运数据的功能。
ADC最大时钟频率为14MHz,最小采样时间为1.5周期 + 12.5固定周期 = 14个周期,即1us。
通过寄存器ADC_SMPRx的位SMPx设置采样时间。
因为规则通道转换的值储存在一个仅有的数据寄存器中,所以当转换多个规则通道时需要使用DMA,这可以避免丢失已经存储在ADC_DR寄存器中的数据。
只有在规则通道的转换结束时才产生DMA请求,并将转换的数据从ADC_DR寄存器传输到用户指定的目的地址。
注入通道没有DMA请求
但是注入通道有4个数据寄存器ADC 注入数据寄存器x (ADC_JDRx) (x= 1…4) 和4个数据偏移寄存器ADC注入通道数据偏移寄存器x (ADC_JOFRx)(x=1…4)
只有ADC1和ADC3拥有DMA功能。由ADC2转化的数据可以通过双ADC模式,利用ADC1的DMA功能传输。
注入通道有4个数据寄存器ADC 注入数据寄存器x (ADC_JDRx) (x= 1…4)
4个数据偏移寄存器ADC注入通道数据偏移寄存器x (ADC_JOFRx)(x=1…4)
不同于规则转换序列,如果JL[1:0]的长度小于4,则转换的序列顺序是从(4-JL)开始
采用STM32F103C8T6单片机,KeilMDK5.32版本
ADC1开启3个规则通道,转换序列为:通道0(PA0),通道1(PA1),通道2(PA2)
在规则通道每个通道转换完成之后,DMA负责将转换的数据从ADC_DR寄存器传输到用户指定的目的地址
开启3个注入通道,转换序列为:通道0(PA0),通道1(PA1),通道2(PA2)
注入通道触发选择为自动注入(当规则通道的所有通道转换完成之后开始转换注入通道)
开启注入转化完成中断。
注入转换完成之后在注入通道转换完回调函数中串口输出转换的数据
规则通道所有通道共享一个数据寄存器,而注入通道各有一个数据寄存器
配置过程
规则和注入通道配置
ADC的DMA配置
ADC的中断
使能ADC和DMA
DMA传输
定义一个数组adc1Value
独立ADC模式下只用到低16位,故只定义uint16_t类型
ADC初始化函数添加用户代码
开启注入通道转换完成中断(在中断函数中HAL库会关闭该中断,我们可以根据需要再次开启该中断)
注入通道转换完成(所有通道都转换完成)回调函数void HAL_ADCEx_InjectedConvCpltCallback(ADC_HandleTypeDef *hadc)
通过串口发送数据
这里再给出规则通道转换完成回调函数void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc);
工程文件下载链接
注入通道序列配置有BUG,仔细观察1/2/3
本次开启3个注入通道,转换序列为:第一个转换(通道0),第二个(通道1),第三个(通道2)
可是STM32CubeMX生产的配置全都是ADC_INJECTED_RANK_1
即第一个转换,执行了三次HAL_ADCEx_InjectedConfigChannel()
都是配置第一个转换的通道,最后变了转换序列为:第一个转换(通道2),第二个(通道0),第三个(通道0)
故需要我们手动调用HAL_ADCEx_InjectedConfigChannel()
进行注入通道序列配置,如方框3
如果使用注入通道的自动注入功能(当规则通道的所有通道转换完成之后开始转换注入通道)
最好的做法就是自己写代码,而不是利用STM32CubeMX进行配置,如下图
手动添加代码实现自动注入功能
/* 设置注入通道的外部触发 软件触发 */
MODIFY_REG(hadc1.Instance->CR2, ADC_CR2_JEXTSEL, ADC_INJECTED_SOFTWARE_START);//设置为软件触发
SET_BIT(hadc1.Instance->CR2, ADC_CR2_JEXTTRIG);//使能注入通道的外部触发
原因:
HAL库的注入通道配置函数HAL_ADCEx_InjectedConfigChannel()
中
在独立ADC模式中,可以通过HAL库进行配置注入通道的自动注入功能,但是多重ADC模式中,注入通道外部触发源默认为000,不是软件触发,故如果通过STM32CubeMX配置,则出错。
转换可以由外部事件触发(例如定时器捕获,EXTI线)。如果设置了EXTTRIG控制位,则外部事件就能够触发转换。EXTSEL[2:0]和JEXTSEL2:0] 控制位允许应用程序选择8个可能的事件中的某一个,可以触发规则和注入组的采样。
注意: 当外部触发信号被选为ADC规则或注入转换时,只有它的上升沿可以启动转换
采用STM32F103C8T6单片机,KeilMDK5.32版本
ADC单次转换,规则通道的外部触发为定时器3的TRGO,定时器3的TRGO事件来源于更新事件,每500ms更新一次,即ADC每500ms转换一次
ADC1开启3个规则通道,转换序列为:通道0(PA0),通道1(PA1),通道2(PA2)
在规则通道每个通道转换完成之后,DMA负责将转换的数据从ADC_DR寄存器传输到用户指定的目的地址
开启3个注入通道,转换序列为:通道0(PA0),通道1(PA1),通道2(PA2)
注入通道触发选择为自动注入(当规则通道的所有通道转换完成之后开始转换注入通道)
开启注入转化完成中断。
注入转换完成之后在注入通道转换完回调函数中串口输出转换的数据
配置要点
STM32CubeMX配置
定时器3配置
ADC初始化函数添加用户代码
这个时候ADC_CR2寄存器的SWSTART位由外部触发来控制
注入通道转换完成中断回调函数
工程文件下载链接
注意在校准之前得开启ADC的时钟与完成使用ADC的GPIO配置(复用模拟模式)
配置过程
ADC开关控制章节
调用HAL库的HAL_ADCEx_Calibration_Start()
来校准ADC。
该demo在ADC独立模式-扫描单次转换-DMA-外部触发-规则和注入通道-自动注入demo的基础上,添加ADC校准功能
STM32CubeMX配置相同
不同之处,在ADC初始化前,开启ADC时钟和配置ADC的GPIO之后,添加ADC校准代码,如下
在HAL_ADC_MspInit()
中添加
注入通道的数据偏移寄存器写入ADC校准值
函数MX_ADC1_Init()
注入通道中断回调函数
工程文件下载链接
使用触发模式时,从ADC需要设置使能外部触发,并且是软件触发。
需要转换完成的中断或者其他中断,尽量使用从ADC的中断
ADC1和ADC2同时开始转换,但是每次转换的通道不能相同,转换完成后的数据存储在每个ADC接口的ADC_JDRx寄存器中,如果需要转换完成中断,则开启相应中断。
与同步注入通道类似,ADC1的数据在ADC1_DR寄存器的低16位中,ADC2的数据在ADC1_DR的高16位中,如果需要转换完成中断,则开启相应中断。
采用STM32F103C8T6单片机,KeilMDK5.32版本
ADC1和ADC2都是单次转换,ADC1的规则通道的外部触发为定时器3的TRGO,定时器3的TRGO事件来源于更新事件,每500ms更新一次,即ADC每500ms转换一次
ADC1开启2个规则通道,转换序列为:通道0(PA0),通道1(PA1)
ADC2开启2个规则通道,转换序列为:通道0(PA1),通道1(PA0)
ADC1和ADC2设置相同通道的转换时间都一样。如,在规则通道上,ADC1和ADC2的通道0转换时间相同。
在规则通道每个通道转换完成之后,DMA负责将转换的数据从ADC_DR寄存器传输到用户指定的目的地址
开启ADC2的规则通道转化完成中断。
转换完成之后在规则通道转换完回调函数中串口输出转换的数据
配置要点
先配置从ADC和双重ADC使用的DMA
主ADC
STM32CubeMX配置
ADC1的初始化函数添加用户代码
ADC2的初始化函数添加用户代码
规则通道转换完成自动回调函数
其实也可以不使用ADC2的规则通道转换完成中断,因为双重ADC使用DMA搬运数据,HAL库会开启DMA的传输完成中断,在DMA传输完成中断会调用ADC的规则转换完成中断回调函数
在同步注入模式下,注入通道有相应的DR寄存器,不需要DMA来搬运,故需要开启注入通道转换完成中断让我们知道转换完成了。
工程文件下载链接
采用STM32F103C8T6单片机,KeilMDK5.32版本
ADC1和ADC2都是单次转换,ADC1的规则通道的外部触发为定时器3的TRGO,定时器3的TRGO事件来源于更新事件,每500ms更新一次,即ADC每500ms转换一次
ADC1开启2个规则通道,转换序列为:通道0(PA0),通道1(PA1)
ADC1开启2个注入通道,转换序列为:通道0(PA0),通道1(PA1)
ADC2开启2个规则通道,转换序列为:通道0(PA1),通道1(PA0)
ADC2开启2个注入通道,转换序列为:通道0(PA1),通道1(PA0)
ADC1和ADC2设置相同通道的转换时间都一样。如,在规则通道上,ADC1和ADC2的通道0转换时间相同。
在规则通道每个通道转换完成之后,DMA负责将转换的数据从ADC_DR寄存器传输到用户指定的目的地址
开启ADC1和ADC2的自动注入功能。
开启ADC2的注入通道转化完成中断。
转换完成之后在注入通道转换完回调函数中串口输出转换的数据
STM32CubeMX配置
ADC2
MX_ADC2_Init()
MX_ADC1_Init()
注入通道转换完成中断回调函数
工程文件下载链接
在该模式下,采样周期必须要小于7个ADC周期
仅用于规则通道,不能使用注入通道的自动注入
在该模式下,采样周期必须要小于14个ADC周期
仅用于规则通道,不能使用注入通道的自动注入
在交叉模式下,不能有注入通道的外部触发产生,包括自动注入模式下
采用STM32F103C8T6单片机,KeilMDK5.32版本
ADC1和ADC2都是单次转换,ADC1的规则通道的外部触发为定时器3的TRGO,定时器3的TRGO事件来源于更新事件,每500ms更新一次,即ADC每500ms转换一次
ADC1开启2个规则通道,转换序列为:通道0(PA0),通道1(PA1)
ADC2开启2个规则通道,转换序列为:通道0(PA0),通道1(PA1)
ADC1和ADC2设置相同通道的转换时间都为1.5个ADC周期。如,在规则通道上,ADC1和ADC2的通道0转换时间相同。
在规则通道每个通道转换完成之后,DMA负责将转换的数据从ADC_DR寄存器传输到用户指定的目的地址
开启ADC1的规则通道转化完成中断。
转换完成之后在规则通道转换完回调函数中串口输出转换的数据
STM32CubeMX配置
ADC初始化函数
ADC1初始化函数
规则转换完中断回调函数
工程文件下载链接
这些模式自行参考用户手册,以后随缘添加demo工程
温度传感器和通道ADC1_IN16相连接,内部参照电压VREFINT和ADC1_IN17相连接。可以按注入或规则通道对这两个内部通道进行转换。
注意: 温度传感器和VREFINT只能出现在主ADC1中。
采用STM32F103C8T6单片机,KeilMDK5.32版本
ADC1采样温度和VREFINT数据。
串口输出相关信息
STM32CubeMX配置
ADC1时钟为12MHz,温度采样建议值为17.1us,则设置采样周期为 17.1 * 12 = 205.2个ADC周期,最接近的为239.5ADC周期