模拟技术
在我们的控制系统中需要使用一个"模数转换"的功能。所谓“模数转换”,就是将模拟量转换为数字量,也就是我们经常说的ADC采集,其中ADC的全称为:“Analog to 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); //禁用ADC1
ADC_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:
通过上述方法计算得到电源电压为:
最后,我们就得到了电源电压为10.992v约等于11v
于是,我们通过程序来计算上面的内容:
这样我们就完成了通过STM32采集电源的电压,方便我们以后实时查看小车的电源情况。
全部0条评论
快来发表一下你的评论吧 !