ADC模数转换器电路设计

2023-07-27 16:26:11 来源:编程外星人

在我们的控制系统中需要使用一个"模数转换"的功能。所谓“模数转换”,就是将模拟量转换为数字量,也就是我们经常说的ADC采集,其中ADC的全称为:“Analogto Digital Converter”。我们的电路设计中,采用的电源是3S锂电池,其电压最大值为12.6v,最小值为11.1v。所以我们通过了一路ADC采集到电压的模拟量将其转为数字量。我们先来看一下电路设计:


(相关资料图)

我们可以看到,电源输出VIN通过R6和R5两个分压电阻,将其线性的降压到ADC1_CH0电路中,并接到PA0引脚上。我们可以通过计算得到以下内容:

也就是说,我们通过了这个两个电阻分压的线性降压电路将11.1v到12.6v的电压降低到2.868v到3.256v。为什么这个做呢?原因是STM32的AD转换引脚能够接受的模拟电压范围为的最大值是3v。当我们通过STM32的ADC采集将降压后的电源转为数字信号,再通过程序还原成原始的电压数值(线性降压之前的电压),我们就可以得到电源电压了。假设ADC采集到的电压为v,于是我们可以得到电源电压V的值的计算方法为:

接下来,我们来编写STM32程序,通过ADC采集到我们的电源电压:

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //配置GPIOA时钟总线RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1, DISABLE); //停用ADC1,以便下面进行ADC1的配置GPIO_InitTypeDef GPIO_InitStructure;              //配置PA0作为ADC1的CH0的引脚GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_Init(GPIOA, &GPIO_InitStructure);ADC_Cmd(ADC1, DISABLE);    //禁用ADC1ADC_DeInit();        //ADC1重定义ADC_CommonInitTypeDef ADC_CommonInitStructure;ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; //独立模式ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_10Cycles; //两个采样阶段之间的延迟ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; //DMA使能ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div8; //预分频8分频ADC_CommonInit(&ADC_CommonInitStructure);ADC_InitTypeDef ADC_InitStructure;ADC_InitStructure.ADC_ScanConvMode = DISABLE; //模数转换工作在单通道模式ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //模数转换工作在单次转换模式ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConvEdge_None; //转换由软件而不是外部触发启动ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;ADC_InitStructure.ADC_NbrOfConversion = 16; //顺序进行转换通道的数目ADC_Init(ADC1, &ADC_InitStructure); //初始化外设ADC寄存器ADC_Cmd(ADC1, ENABLE); //使能指定的ADC

这样我们就完成了ADC1的CH0的配置工作。之后我们还需要编写一个函数用于读取ADC1中CH0的数字信号值:

uint16_t adc_get(uint8_t ch){  //设置指定ADC的规则组通道,一个序列,采样时间  ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_144Cycles);  ADC_SoftwareStartConv(ADC1);  while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC))  {  }  //返回最近一次ADC1规则组的转换结果  return ADC_GetConversionValue(ADC1); }

最后,我们通过在main函数中对ADC1中的CH0进行配置,并在主循环中读取电源电压信息:

init_adc();uart_init();while (1){  uint16_t v = adc_get(0);  uart_write(v & 0xff);  uart_write((v > > 8) & 0xff);  uart_write(0x0);  uart_write(0x0);  // ...}

当我们通过调用adc_get(0)函数得到采集电压v之后,再通过uart_write(v)函数将电压值发送到串口当中方便我们观察。注意,其中串口功能的配置与使用我们将下一讲中来学习,这里不再赘述。读者只需要了解得到电压v之后如何计算出电源电压即可。例如我们从串口中得到的数据如下:

实际上,我们得到了很多组数据,它们之间会存在一些小的差别,但并不很大,我们以上图中的D0 FD这一组数据为例,16进制数据为0xFDD0,转为10进制为64976,除以16位ADC分辨率65535(16进制为0xFFFF)得到结果为0.991470207,再乘以3.256,得到3.228226993v,最后转换为电源电压3.228226993v * 387 / 100 = 12.493238463v,保留3位小数得到12.493v。于是我们就得到了当前电源电压为12.493v。

我们,可以在电源电压接近11v时再进行一次采集和计算,我们采集到的数据为50 DF:

通过上述方法计算得到电源电压为:

16进制转10进制: 0xDF50 = 57168除以16通道分辨率: 57168 / 65535 = 0.872327764乘以电路中分压值3.256v: 0.872327764 × 3.256 = 2.840299199转为实际电源电压: 2.840299199 × 387 ÷ 100 = 10.992

最后,我们就得到了电源电压为10.992v约等于11v

于是,我们通过程序来计算上面的内容:

这样我们就完成了通过STM32采集电源的电压,方便我们以后实时查看小车的电源情况。

标签:

上一篇:STM32 USART串口的应用 STM32中断系统专题讲解
下一篇:最后一页