ADC 简介
12 位 ADC 是逐次趋近型模数转换器。它具有多达 19 个复用通道,可测量来自 16 个外部
源、两个内部源和 VBAT 通道的信号。这些通道的 A/D 转换可在单次、连续、扫描或不连续
采样模式下进行。ADC 的结果存储在一个左对齐或右对齐的 16 位数据寄存器中。
ADC 具有模拟看门狗特性,允许应用检测输入电压是否超过了用户自定义的阈值上限或下限
ADC 主要特性
● 可配置 12 位、10 位、8 位或 6 位分辨率
● 在转换结束、注入转换结束以及发生模拟看门狗或溢出事件时产生中断
● 单次和连续转换模式
● 用于自动将通道 0 转换为通道“n”的扫描模式
● 数据对齐以保持内置数据一致性
● 可独立设置各通道采样时间
● 外部触发器选项,可为规则转换和注入转换配置极性
● 不连续采样模式
● 双重/三重模式(具有 2 个或更多 ADC 的器件提供)
● 双重/三重 ADC 模式下可配置的 DMA 数据存储
● 双重/三重交替模式下可配置的转换间延迟
● ADC 转换类型(参见数据手册)
● ADC 电源要求:全速运行时为 2.4 V 到 3.6 V,慢速运行时为 1.8 V
● ADC 输入范围:VREF<=VIN <= VREF+
● 规则通道转换期间可产生 DMA 请求
ADC初始化
adc初始化首先我们要做的就是时钟的使能控制,GPIO的配置,如果要用到DMA的话也要使能DMA的时钟,这也是基本所有外设配置都需要的。
ADC通道的选择
有 16 条复用通道。可以将转换分为两组:规则转换和注入转换。每个组包含一个转换序列, 该序列可按任意顺序在任意通道上完成。 一个规则转换组最多由 16 个转换构成。必须在 ADC_SQRx 寄存器中选择转换序列的规 则通道及其顺序。规则转换组中的转换总数必须写入 ADC_SQR1 寄存器中的 L[3:0] 位 一个注入转换组最多由 4 个转换构成。必须在 ADC_JSQR 寄存器中选择转换序列的注入 通道及其顺序。注入转换组中的转换总数必须写入 ADC_JSQR 寄存器中的 L[1:0] 位STM32的ADC可以对一组指定的通道,按照指定的顺序,逐个转换这组通道,转换结束后,再从头循环;这指定的通道组就称为规则组。但是实际应用中,有可能需要临时中断规则组的转换,对某些通道进行转换,这些需要中断规则组而进行转换的通道组,就称为注入组。一个不太恰当的比喻是:规则通道组的转换好比是程序的正常执行,而注入通道组的转换则好比是程序正常执行之外的一个中断处理程序。
触发方式
要触发一次ad转换,可以由内部软件触发,也可以通过外部事件(例如,定时器捕获、EXTI 中断线)触发转换。。要不要使用外部触发由控制寄存器里的EXTTRIG位来指定。
单一和连续
在单次转换模式下,ADC 执行一次转换。CONT 位为 0 时,可通过以下方式启动此模式。在连续转换模式下,ADC 结束一个转换后立即启动一个新的转换。CONT 位为 1 时,可通过外部触发或将 ADC_CR2 寄存器中的 SWSTRT 位置 1 来启动此模式
间断模式
间断模式是将常规和注入组里的序列再切割成更小的组。比如一个常规组含有9个频道,利用间断模式并设置控制寄存器的位,可以将9个频道分成3组。这样一次触发只会采集3个通道,而不是采集9个通道,连续触发3次才能采集完9个通道。
采样频率
Adc模块允许对采样频率进行修改,建议不要使用过高的采样频率,并考虑系统运行时负载的临界值。ADC 会在数个 ADCCLK 周期内对输入电压进行采样,可使用 ADC_SMPR1 和 ADC_SMPR2 寄存器中的 SMP[2:0] 位修改周期数。每个通道均可以使用不同的采样时间进行采样
模拟看门狗
如果 ADC 转换的模拟电压低于阈值下限或高于阈值上限,则 AWD 模拟看门狗状态位会置 1。这些阈值在 ADC_HTR 和 ADC_LTR 16 位寄存器的 12 个最低有效位中进行编程。可以 使用 ADC_CR1 寄存器中的 AWDIE 位使能中断
DMA通道
当在扫描模式和连续模式下,显然每次都将保存采集值的寄存器数据读出来处理是来不及的。设置Adc的DMA使能,可以让每次转换过的数值都经DMA传到指定的内存空间里。
下面附上相关的驱动代码
init初始化
ADC_HandleTypeDef hadcx;
DMA_HandleTypeDef hdma_adcx;
/**
* 函数功能: AD转换初始化
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
void MX_ADCx_Init(void)
{
ADC_ChannelConfTypeDef sConfig;
// ADC功能配置
hadcx.Instance = ADC1;
hadcx.Init.ClockPrescaler=ADC_CLOCKPRESCALER_PCLK_DIV4; //4分频
hadcx.Init.Resolution=ADC_RESOLUTION_12B; //12位模式
hadcx.Init.ScanConvMode = DISABLE; //关闭扫描模式
hadcx.Init.EOCSelection=DISABLE; //关闭EOC中断
hadcx.Init.ContinuousConvMode = ENABLE; //使能连续扫描
hadcx.Init.DiscontinuousConvMode=DISABLE; //禁止不连续采样模式
hadcx.Init.NbrOfDiscConversion=0; //不连续采样通道数为0
hadcx.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
hadcx.Init.DMAContinuousRequests=ENABLE; //打开DMA请求
hadcx.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadcx.Init.NbrOfConversion = 1;
HAL_ADC_Init(&hadcx);
// 配置采样通道
sConfig.Channel = ADC_CHANNEL_4;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
HAL_ADC_ConfigChannel(&hadcx, &sConfig);
/* DMA外设初始化配置 */
hdma_adcx.Instance = DMA1_Stream0;
hdma_adcx.Init.Channel =DMA_CHANNEL_0; //通道0
hdma_adcx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adcx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adcx.Init.MemInc = DMA_MINC_ENABLE;
hdma_adcx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_adcx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_adcx.Init.Mode = DMA_CIRCULAR;//循环模式
hdma_adcx.Init.Priority=DMA_PRIORITY_MEDIUM;//DMA传输方式有关数据格式几次传输
hdma_adcx.Init.FIFOMode=DMA_FIFOMODE_DISABLE;
hdma_adcx.Init.Priority = DMA_PRIORITY_HIGH;
HAL_DMA_Init(&hdma_adcx);
/* 连接DMA */
__HAL_LINKDMA(hadcx,DMA_Handle,hdma_adcx);
}
时钟初始化
/**
* 函数功能: ADC外设初始化配置
* 输入参数: hadc:AD外设句柄类型指针
* 返 回 值: 无
* 说 明: 该函数被HAL库内部调用
*/
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* 外设时钟使能 */
__HAL_RCC_ADC1_CLK_ENABLE();
/* AD转换通道引脚时钟使能 */
__HAL_RCC_GPIOA_CLK_ENABLE();
/* DMA时钟使能 */
__HAL_RCC_DMA2_CLK_ENABLE();
/* AD转换通道引脚初始化 */
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
获取AD值
void Get_Adc_Average(ADC_HandleTypeDef *hadc,char channel,unsigned int SamplingTime)
{
ADC_ChannelConfTypeDef sConfig;
int data = 0;
// 配置采样通道
sConfig.Channel = channel;
sConfig.Rank = 1;
sConfig.SamplingTime = SamplingTime;
HAL_ADC_ConfigChannel(&hadc, &sConfig)//配置采样通道和采样频率
HAL_ADC_Start_DMA(hadc,&data,1);
HAL_DMA_PollForTransfer(&hdma_adcx,HAL_DMA_FULL_TRANSFER,0XFFFFFFFF);
HAL_ADC_Stop_DMA(hadc);
}