————————————————————————————————————
⏩ 大家好哇!我是小光,嵌入式爱好者,一个想要成为系统架构师的大三学生。
⏩最近在开发一个STM32H723ZGT6的板子,使用STM32CUBEMX做了很多驱动,包括ADC、UART、RS485、EEPROM(IIC)、FLASH(SPI)等等。
⏩本篇文章对STM32CUBEMX配置多通道ADC做一个详细的使用教程。
⏩感谢你的阅读,不对的地方欢迎指正。
————————————————————————————————————
一.ADC工作原理
工作原理
ADC芯片即模数转换器,是将模拟量转化为数字量的芯片,在如今的这个时代,这是很重要的芯片。在许多高精度测量领域,都在大规模的使用ADC芯片,我们在做项目的时候也会大量使用,熟悉它的参数才能更好的使用它。
模拟信号转化为数字信号,一般分为4个步骤进行,即采样、保持、量化和编码。前两个步骤在采样-保持电路中完成,后两个步骤则在ADC中完成。ADC是把经过与标准量比较处理后的模拟量转化为二进制数值表示的离散信号的转化器。所以任何一个模数转化器都需要一个参考模拟量作为转换的标准,比较常见的参考标准为ADC芯片最大的可转换信号大小。
参数详解
1.分辨率
分辨率n是用于表示模拟信号的位数,如果ADC是3位的,那么就共有8种输出码。分辨率越高,ADC就可识别更小的输入电压变化。VREF/2n-1(2的n次方减1)即为分辨率,n位的ADC,即有2n(2的n次方)个输出,共有2n-1(2的n次方减1)个间隔,这个间隔即是ADC芯片能识别的最小输入信号变化量。
2.转换率/采样率/转化时间
转换时间Tconv表示完成一次模数转换消耗的时间,或相邻两次转换的时间间隔;
转化率/采样率Ws:表示ADC数据转换的频率,单位为:采样/秒(SPS),两者互为倒数关系。
3.最低有效位(LSB)/最高有效位(MSB)
即ADC芯片的最高位和最低位。那么1LSB的电压值,就是ADC的分辨精度,是由ADC的参考电压VREF和分辨率n共同决定的。
4.量化误差
输入信号在量化门限之间随机变化,则量化误差e在两次采样间基本不相关,且在±LSB/2范围内均匀分布,我们可以将其视为一种白噪声。因为ADC采样出来的信号是离散的,而实际模拟信号是连续信号,所以ADC采样出来的两个相邻离散信号不能精准表示模拟信号而带来的误差。
5.SNR
SNR即为信噪比,是信号功率与ADC噪声功率的比。理想ADC的SNR是信号功率和量化误差e带来的噪声功率(DC-Fs/2的频率范围)的比值。那也就是说在只考虑量化噪声的情况下,知道了ADC的位数N就可以确定信噪比的大小,SNR=1.76+6.02N dB。但实际上ADC,有量化噪声、本征噪声、系统噪声、时间抖动等噪声。
后面还有等等参数就不介绍了
MX配置
1.时钟和调试配置
2.ADC配置
我配置的是16位的分辨率,也就是说我们在将采集的ADC值转换成电压的公式是:V = adc_value*3.3/65536。
当我们配置完以上,就可以看到对应的引脚变成绿色,并且变成了我们想要的名字。
3.工程配置
驱动代码编写
adc.h
#include "stm32H7xx_hal.h" //HAL库文件声明
#define NUM_ADC_CHANNEL 4 //采集板通道数
void ADC_Get_Value(uint32_t adc_value[]);//获取信号采集板J1和J2中ADC通道的值
#endif
adc.c
#include "adc.h"
/**
* 函数名:ADC_Get_Value
* 描述:获取信号版J1或J2的ADC通道的值
* 参数:adc_value[]:存放信号版J1或J2的ADC通道的值的数组
* 返回值:无
*/
void ADC_Get_Value(uint32_t adc_value[])
{
int i = 0;
for(i = 0;i < NUM_ADC_CHANNEL;i++)
{
HAL_ADC_Start(&hadc1);//开启ADC1
HAL_ADC_PollForConversion(&hadc1,10);//等待转换完成
adc_value[i] = HAL_ADC_GetValue(&hadc1);//获取ADC的值
}
HAL_ADC_Stop(&hadc1);
return;
}
main.c
uint32_t adc_value[NUM_ADC_CHANNEL] = {0};
while(1)
{
ADC_Get_Value(adc_value);
printf("ADC_CH1 adc_value:%d f_adc_value:%.2f\r\n",adc_value[0],adc_value[0]*3.3/65536);
printf("ADC_CH2 adc_value:%d f_adc_value:%.2f\r\n",adc_value[1],adc_value[1]*3.3/65536);
printf("ADC_CH3 adc_value:%d f_adc_value:%.2f\r\n",adc_value[2],adc_value[2]*3.3/65536);
printf("ADC_CH4 adc_value:%d f_adc_value:%.2f\r\n",adc_value[3],adc_value[3]*3.3/65536);
HAL_Delay(500);
}
调试结果
可以看到四个通道都有数据,当然正确的测试应该是把ADC引脚接到一个可变电源进行调试,我这里有数据就可以,后面再调。