STM32F103 ADC详解

简介

ADC(Analog-to-digital converters,模数转换器)的作用是将外部的模拟信号转变为数字信号。
STM32F103的ADC使用的是12位逐次逼近型的模数转换器,共有18个通道,可测量16个外部和2个内部信号。ADC框图如下:
ADC
这个框图展示了ADC的18个输入源、注入组与规则组的结构、可触发的中断请求和DMA请求等。要注意的是ADC的输入范围是0~3.3V,如果超过3.3V可能会导致芯片烧毁。

代码实践

我们通过句柄ADC_HandleTypeDef来学习如何使用ADC,下面给出一个初始化实例

ADC_HandleTypeDef g_adc_handler = {0};
GPIO_InitTypeDef gpio_init_struct = {0};

g_adc_handler.Instance = ADC1;
g_adc_handler.Init.DataAlign = ADC_DATAALIGN_RIGHT;
g_adc_handler.Init.ScanConvMode = ADC_SCAN_DISABLE;
g_adc_handler.Init.ContinuousConvMode = DISABLE;
g_adc_handler.Init.NbrOfConversion = 1;
g_adc_handler.Init.DiscontinuousConvMode = DISABLE;
g_adc_handler.Init.NbrOfDiscConversion = 0;
g_adc_handler.Init.ExternalTrigConv = ADC_SOFTWARE_START;
	
HAL_ADC_Init(&g_adc_handler);						/* 初始化ADC */
HAL_ADCEx_Calibration_Start(&g_adc_handler);		/* 校准ADC */

/* 设置AD采集通道对应IO引脚工作模式 */
gpio_init_struct.Pin = ADC_ADCX_CHY_GPIO_PIN;                           /* ADC通道对应的IO引脚 */
gpio_init_struct.Mode = GPIO_MODE_ANALOG;                               /* 模拟 */
HAL_GPIO_Init(ADC_ADCX_CHY_GPIO_PORT, &gpio_init_struct);

Instance 配置使用的ADCx,这里使用的是ADC1。
Init是ADC_InitTypeDef,用来保存初始化ADC的参数。
DataAlign 数据对齐方式,由于ADC的DR数据寄存器是16位的,而分辨率是12位,即只用到16位中的12位,所以要选择数据是左对齐还是右对齐,一般是选择右对齐ADC_DATAALIGN_RIGHT。
ScanConvMode 扫描转换模式,当使能启用扫描模式时,ADC会采集每一个激活的ADC通道;当失能时,仅采集一个ADC通道。
ContinuousConvMode 连续模式,当连续模式被使能时,ADC就会自动进行一轮又一轮的采集。也就是持续采集,不需要等待触发信号。
NbrOfConversion 指定转换通道数,每使用一个ADC转换通道,就加一。
DiscontinuousConvMode 间断转换模式,一种特殊的转换模式,用于在特定条件下按组(分组)进行多通道采样。每次触发仅转换一个组内的通道。
NbrOfDiscConversion 指定间断转换通道数,每使用一个ADC转换通道,就加一。
ExternalTrigConv外部触发配置,可以设置不同定时器来作为ADC的触发信号,这里使用的软件触发ADC_SOFTWARE_START。
配置完句柄后调用HAL_ADC_Init()即可完成对ADC的初始化,函数HAL_ADCEx_Calibration_Start()是为了校准ADC,在官方的注释中,该函数的执行是可选的。

下面看看ADC的时钟配置,通过官方注释我们了解到,除了使能ADC的时钟外,还需要配置ADC的时钟。代码如下:

/* 使能ADC1时钟 */
__HAL_RCC_ADC1_CLK_ENABLE();
/* 设置ADC时钟 */
RCC_PeriphCLKInitTypeDef adc_clk_init = {0};
adc_clk_init.PeriphClockSelection = RCC_PERIPHCLK_ADC;                  /* ADC外设时钟 */
adc_clk_init.AdcClockSelection = RCC_ADCPCLK2_DIV6;                     /* 分频因子6时钟为72M/6=12MHz */
HAL_RCCEx_PeriphCLKConfig(&adc_clk_init);                               /* 设置ADC时钟 */

这里主要配置的是ADC的分频因子,可以调整ADC的频率。

之后还需要配置ADC通道。

    /* 配置ADC通道 */
ADC_ChannelConfTypeDef adc_ch_conf = {0};
adc_ch_conf.Channel = ADC_ADCX_CHY;                                     /* 通道 */
adc_ch_conf.Rank = ADC_REGULAR_RANK_1;                                  /* 序列 */
adc_ch_conf.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;                  /* 采样时间,设置最大采样周期:239.5个ADC周期 */
HAL_ADC_ConfigChannel(&g_adc_dma_handle, &adc_ch_conf);                 /* 通道配置 *

ADC支持轮询和DMA方式获取数据。
轮询方式代码如下:

HAL_ADC_Start(&g_adc_handler); /* 开始转换 */
HAL_ADC_PollForConversion(&g_adc_handler, 10); /* 等待常规组转换完成 */
uint16_t adc_value = HAL_ADC_GetValue(&g_adc_handler);

DMA方式如下:

DMA_HandleTypeDef g_dma_adc_handle = {0};                                   /* 定义要搬运ADC数据的DMA句柄 */
uint32_t buffer[10];

__HAL_RCC_DMA1_CLK_ENABLE();                                        	/* DMA1时钟使能 */
/* 初始化DMA */
g_dma_adc_handle.Instance = ADC_ADCX_DMACx;                             /* 设置DMA通道 */
g_dma_adc_handle.Init.Direction = DMA_PERIPH_TO_MEMORY;                 /* 从外设到存储器模式 */
g_dma_adc_handle.Init.PeriphInc = DMA_PINC_DISABLE;                     /* 外设非增量模式 */
g_dma_adc_handle.Init.MemInc = DMA_MINC_ENABLE;                         /* 存储器增量模式 */
g_dma_adc_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;    /* 外设数据长度:16位 */
g_dma_adc_handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;       /* 存储器数据长度:16位 */
g_dma_adc_handle.Init.Mode = DMA_NORMAL;                                /* 外设流控模式 */
g_dma_adc_handle.Init.Priority = DMA_PRIORITY_MEDIUM;                   /* 中等优先级 */
HAL_DMA_Init(&g_dma_adc_handle);

__HAL_LINKDMA(&g_adc_dma_handle, DMA_Handle, g_dma_adc_handle);         /* 将DMA与adc联系起来 */

/* 配置DMA数据流请求中断优先级 */
HAL_NVIC_EnableIRQ(ADC_ADCX_DMACx_IRQn);

HAL_DMA_Start_IT(&g_dma_adc_handle, (uint32_t)&ADC1->DR, buffer, 10);       /* 启动DMA,并开启中断 */
HAL_ADC_Start_DMA(&g_adc_dma_handle, &buffer, 10);                          /* 开启ADC,通过DMA传输结果 */

ADC采集的数据会被DMA输入到buffer中,可以设置一个DMA传输结束标志,当执行DMA中断处理函数时,对标志置一表示传输完成。

最后,还可以对ADC读取到的数据进行处理。由于分辨率是12位的,所以ADC采集到的数据范围在0 - 4095之间,我们可以将其转为0 - 3.3V电压,方便查看。

uint32_t result = buffer[i] * (3.3 / 4096)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值