第八章 STM32F103C8T6的HAL库ADC单通道使用
文章目录
前言
本章开始学习STM32hal库的ADC单通道使用,了解ADC工作原理,ADC主要特性,掌握ADC单通道的配置使用,能够借助串口调试助手与电脑进行通信,并将检测出的数据显示在电脑上。末尾附带源代码供参考学习。
一、ADC工作原理
ADC,全称:Analog-to-Digital Converter,指模拟/数字转换器,主要功能是将连续变化的模拟信号转换为离散的数字信号。比如将光敏传感器接收到的信号转换成电压信号。
二、ADC主要特性
ADC的主要特性为分辨率,STM32 的 ADC 通常具有 12 位分辨率,这意味着它可以将模拟输入电压范围划分为 2^12(即 4096)个离散值。高分辨率能够更精确地表示模拟信号的大小。
ADC的输入时钟频率不得超过14MHz,它是由PCLK2经分频产生。一般设置对72MHz进行6分频得到12MHz。
采样时间可以在软件中进行设置,对于STM32的供电电压、参考电压、输入电压最高为3.3V,最低为0V。
三、ADC框图简介
3.1.参考电压
在 STM32F103C8T6 中,虽然没有明确标识为 “VREF+” 和 “VREF-” 的引脚,通常情况下,该芯片的 ADC 正向参考电压在实际应用中连接到芯片的模拟电源电压(VDDA)。当使用板载的电源系统时,这个电压为 3.3V。这意味着 ADC 将以 3.3V 作为参考电压的高电平,将输入的模拟信号与此参考电压进行比较和转换。而负向参考电压(VSSA)通常接地(GND),即 0V。
3.2.输入通道
STM32F103C8T6 有 10 个 ADC 通道(ADC1 的通道 0 - 9)对应的引脚,分别为:
(1)PA0 - ADC1_IN0,这个引脚可以作为规则组通道 0 的输入,用于连接需要转换的模拟信号,比如可以连接一个温度传感器的输出引脚,将温度对应的模拟电压信号引入 ADC 进行转换。
(2)PA1 - ADC1_IN1,适用于连接如光敏电阻等模拟信号源,用于采集光照强度对应的电压信号等。
(3)PA2 - ADC1_IN2、PA3 - ADC1_IN3、PA4 - ADC1_IN4、PA5 - ADC1_IN5、PA6 - ADC1_IN6、PA7 - ADC1_IN7、PB0 - ADC1_IN8、PB1 - ADC1_IN9。这些引脚都可以作为规则组的 ADC 输入通道,根据具体的应用需求,连接各种模拟信号源,如压力传感器、液位传感器等的输出信号。
3.3.转换序列
A/D转换分为规则组和注入组。
3.3.1.规则组
规则组的转换是按照预先编程设置的顺序(称为规则序列)进行的。它可以通过软件触发或者硬件触发来启动转换。例如,在软件触发方式下,当程序执行相应的指令(如设置 ADC 控制寄存器中软件触发位)时,ADC 就会按照规则序列中定义的通道顺序依次进行转换。规则组适用于对多个通道进行有规律的、顺序性的转换。
可以把规则组想象成一个按照固定流程工作的生产线。比如,在一个环境监测系统中,需要依次采集温度、湿度、光照强度等多个传感器的模拟信号,这些信号对应的 ADC 通道就可以按照顺序放入规则组序列中,通过一次触发完成多个通道的转换。
规则组的引脚如上述的输入通道,ADC的九个通道均可作为规则组的ADC输入通道。
3.3.2.注入组
注入组转换可以打断规则组转换,具有更高的优先级。它主要用于需要紧急处理的模拟信号转换。注入组转换通常是由外部事件触发,例如一个紧急的故障检测信号(如过流检测信号)。当这个信号出现时,注入组转换会立即启动,优先处理这个紧急信号对应的模拟通道转换。
就像医院的急诊通道一样,当有紧急情况(如注入组触发事件)出现时,会优先处理紧急患者(注入组对应的模拟通道转换),而暂时中断正常的挂号看病流程(规则组转换)。
注入组和规则组共享模拟输入引脚。例如,在一个应用场景中,如果规则组正在按照顺序转换多个通道的模拟信号,当注入组触发条件满足时,注入组可以中断规则组的转换,使用相同的引脚(如 PA0 - ADC1_IN0 等)来获取需要紧急转换的模拟信号。也就是说,注入组的通道同样可以使用上述规则组所提到的引脚作为输入,不过要注意的是,注入组最多支持 4 个通道。
3.4.触发源
触发源分为软件触发和外部触发。
软件触发通过程序设置 ADC 控制寄存器(ADC_CR2)中的相关位来启动转换。这种触发方式的优点是简单直接,易于控制。它适用于对转换时机要求不高、按照程序流程进行数据采集的场景。
外部触发又可分为定时器触发和外部中断触发。
STM32F103C8T6 的定时器(如 TIM1 - TIM8)输出的信号能够触发 ADC 转换。通过配置 ADC 外部触发寄存器(ADC_ETR)和定时器的相关输出比较寄存器,可以实现定时器触发 ADC 转换。例如在一个电机控制系统中,为了实时监测电机的运行参数(如电流、电压等),可以使用定时器每隔一定的时间间隔触发 ADC 转换,这样能够精确地获取在固定时间点的电机参数,方便后续的分析和控制,比如实现电机的闭环控制。
外部中断触发当外部引脚(如 PA0 - PA15 等)上的电平发生变化或者出现特定的外部事件(如外部传感器产生的脉冲信号)时,可以触发 ADC 转换。例如在一个事件计数系统中,当外部传感器检测到一个物体通过时会产生一个脉冲信号,这个脉冲信号可以作为外部中断触发 ADC 转换,从而获取与该事件相关的模拟信号(如传感器的供电电压等),用于对事件的进一步分析,如统计物体通过的频率、判断物体的大小等。
3.5.转换时间
ADC使用若干个ADC_CLK周期对输入电压采样,采样周期数目可以通过ADC_SMPR1和
ADC_SMPR2寄存器中的SMP[2:0]位更改。每个通道可以分别用不同的时间采样。
如下面的程序选择的为ADC_SAMPLETIME_239CYCLES_5,即为239.5个ADC时钟周期。
adc_channel_set(&g_adc_handle , ch, ADC_REGULAR_RANK_1, ADC_SAMPLETIME_239CYCLES_5);
其他的时钟周期可以进行选择
总转换时间如下计算:
举个例子:ADC时钟频率为12MHz时,选择ADC_SAMPLETIME_1CYCLE_5 ,ADC最短的转换时间是多少?
⑥和⑦ 主要是进行数据存储传递至数据总线上并在转换结束时触发ADC中断。
四、ADC单通道配置
4.1.ADC初始化函数
对STM32F103C8T6只能选择ADC1,数据对齐方式中右对齐方式是ADC 转换后的数字数据的最低有效位(LSB)存放在数据寄存器的最低位。右对齐方式比较符合常规的数字数据处理习惯,因为数据的最低位在最低地址,就像普通的二进制数一样,更容易理解和操作。
左对齐方式下,ADC 转换后的数字数据的最高有效位(MSB)存放在数据寄存器的最低位。对于 12 位的 ADC 转换结果,最高位存放在数据寄存器的第 0 位,最低有效位存放在数据寄存器的第 11 位,当需要优先处理数据的高位部分时,左对齐方式比较有用。
对于单通道的连续转换模式可以根据使用场景进行设定,如在一个温度监测系统中,要持续获取环境温度的变化。通过开启连续转换模式,可以让 ADC 不断地将热敏电阻两端的模拟电压转换为数字量,从而及时捕捉温度的动态变化。
如果只是需要对一个模拟信号进行单次测量,例如在一个简单的电池电量检测系统中,只需要在特定时刻(如开机时或用户手动触发时)测量一次电池电压,此时就不需要开启连续转换模式。
void adc_init(void)
{
g_adc_handle.Instance = ADC1; /* 选择哪个ADC */
g_adc_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; /* 数据对齐方式:右对齐 */
g_adc_handle.Init.ScanConvMode = ADC_SCAN_DISABLE; /* 非扫描模式,仅用到一个通道 */
g_adc_handle.Init.ContinuousConvMode = DISABLE; /* 关闭连续转换模式 */
g_adc_handle.Init.NbrOfConversion = 1; /* 赋值范围是1~16,本实验用到1个规则通道序列 */
g_adc_handle.Init.DiscontinuousConvMode = DISABLE; /* 禁止规则通道组间断模式 */
g_adc_handle.Init.NbrOfDiscConversion = 0; /* 配置间断模式的规则通道个数,禁止规则通道组间断模式后,此参数忽略 */
g_adc_handle.Init.ExternalTrigConv = ADC_SOFTWARE_START; /* 触发转换方式:软件触发 */
HAL_ADC_Init(&g_adc_handle); /* 初始化 */
HAL_ADCEx_Calibration_Start(&g_adc_handle); /* 校准ADC */
}
4.2.ADC底层驱动函数
此函数中需要开启GPIOA的引脚时钟和ADC1的时钟,对ADC的时钟进行分频,因为ADC时钟最大为14MHz,此次挂载总线时钟为72MH在,进行6分频得到12MHz,此次选用ADC1的通道1,查看引脚定义可以看到该引脚为PA1。
void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
{
if(hadc->Instance == ADC1)
{
GPIO_InitTypeDef gpio_init_struct;
RCC_PeriphCLKInitTypeDef adc_clk_init = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_ADC1_CLK_ENABLE();
/* 设置ADC时钟 */
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时钟 */
/* 设置AD采集通道对应IO引脚工作模式 */
gpio_init_struct.Pin = GPIO_PIN_1 ; /* ADC通道IO引脚 */
gpio_init_struct.Mode = GPIO_MODE_ANALOG; /* 模拟 */
HAL_GPIO_Init(GPIOA, &gpio_init_struct);
}
}
4.3.ADC通道配置
此函数配置ADC的序列和采样时间,但具体的设定在结果转换函数中。
void adc_channel_set(ADC_HandleTypeDef *adc_handle, uint32_t ch, uint32_t rank, uint32_t stime)
{
ADC_ChannelConfTypeDef adc_ch_conf;
adc_ch_conf.Channel = ch; /* 通道 */
adc_ch_conf.Rank = rank; /* 序列 */
adc_ch_conf.SamplingTime = stime; /* 采样时间 */
HAL_ADC_ConfigChannel(adc_handle, &adc_ch_conf); /* 通道配置 */
}
4.4.ADC结果转换函数
在此函数中设定通道,序列和采样时间,得到结果。
其中 HAL_ADC_PollForConversion(&g_adc_handle, 10);的10代表的是超时时间(单位通常是毫秒,具体取决于库的实现)。如果经过了10毫秒,ADC 转换还没有完成,函数会返回一个超时错误码(具体的错误码定义也与库相关),这可以用来提示用户或者进行错误处理,比如重新启动转换或者采取其他措施来保证系统的正常运行。
uint32_t adc_get_result(uint32_t ch)
{
adc_channel_set(&g_adc_handle , ch, ADC_REGULAR_RANK_1, ADC_SAMPLETIME_239CYCLES_5); /* 设置通道,序列和采样时间 */
HAL_ADC_Start(&g_adc_handle); /* 开启ADC */
HAL_ADC_PollForConversion(&g_adc_handle, 10); /* 轮询转换 */
return (uint16_t)HAL_ADC_GetValue(&g_adc_handle); /* 返回最近一次ADC1规则组的转换结果 */
}
}
4.5.main主函数
主函数中获得ADC检测结果并进行换算得到电压值,通过USART传到串口调试助手上进行显示。
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
delay_init(72); /* 延时初始化 */
led_init();
key_init();
usart_init();
adc_init();
float temp = 0;
float adcx;
printf("电压值为:");
while(1)
{
adcx = adc_get_result(ADC_CHANNEL_1); /* 获取通道1的转换值 */
temp = adcx * (3.3 / 4096); /* 获取计算后的带小数的实际电压值,比如3.1111 */
adcx = temp;
printf("%f\r\n",adcx);
delay_ms(1000);
}
}
}
}
此外需要对adc.h和main.h文件中也需要添加相关头文件声明,具体的看查看文章最下面链接中的源码。
总结
以上就是今天要讲的内容,本文仅仅简单介绍了一些STM32的ADC工作原理,ADC主要特性,ADC单通道的配置使用,能够借助串口调试助手与电脑进行通信,并将检测出的数据显示在电脑上。能够帮助读者更好地掌握STM32的应用,如果有疑问的地方或者需要源代码可以私信我,若有讲错的地方还请批评指正,让我们一起学习,一起进步。
源代码链接:https://pan.baidu.com/s/1hzCq_nN06fB_h3cj6ShVmQ
提取码:zstu