项目背景
在水墨屏天气时钟的项目中,需要显示电池的剩余电量,本次使用STM32自带的12位ADC功能检测电池电压并且计算锂电池的剩余电池电量。
设计思路
1.锂电池电压先经过两个电阻分压。
2.ADC采集分压电阻的电压。
3.根据关系计算电池剩余电量。
4.在水墨屏上显示。
硬件方案
电路设计其实很简单,就是用两个大电阻去分压电池的电压,注意电阻的电阻值要大一点,并且最好是1%精度以下的电阻。分压后的BAT_ADC直接输入到单片机的ADC脚位。
电池电压和电池剩余电量的关系
根据锂电池放电特性(电池容量与电池电压的关系,具体还要看电池厂家给的资料,这里的数据只作为参考):
电池电量 | 电池电压 |
---|---|
100 % | 4.2V |
90% | 4.08V |
80% | 4.0V |
70% | 3.93V |
60% | 3.87V |
50% | 3.83V |
40% | 3.79V |
30% | 3.77V |
20% | 3.73V |
10% | 3.68V |
5% | 3.5V |
0% | 2.5V |
代码设计
软件设计就没什么好讲的了,就是开启STM32的ADC功能,然后得出BAT_ADC的电压,最后算出电池电压,根据关系得出电池电量。
c
//电池电压ADC采集初始化,ADC12_IN9,PB1
void BAT_ADC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_ADC1,ENABLE);
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
ADC_DeInit(ADC1);
ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;//连续转化模式设置
ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//数据左对齐
ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//软件触发
ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;//独立模式
ADC_InitStructure.ADC_NbrOfChannel=1;//通道数
ADC_InitStructure.ADC_ScanConvMode=DISABLE;//扫描模式设置
ADC_Init(ADC1,&ADC_InitStructure);
ADC_Cmd(ADC1,ENABLE);//使能指定ADC外设
ADC_ResetCalibration(ADC1);//使能复位校准
while(ADC_GetResetCalibrationStatus(ADC1));//等待复位校准结束
ADC_StartCalibration(ADC1);//开启AD校准
ADC_GetCalibrationStatus(ADC1);//等待AD校准结束
}
//获得ADC值
//通道9采样值
uint16_t Get_Adc(void)
{
ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 1, ADC_SampleTime_239Cycles5 ); //ADC1,ADC通道,采样时间为239.5周期
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//使能指定的ADC1的软件转换启动功能
while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));//等待转换结束
return ADC_GetConversionValue(ADC1);//返回最近一次ADC1规则组的转换结果
}
//计算电池的电压
float Get_BAT_Voltage()
{
u16 BAT_ADC=0;
float BAT_Voltage=0;//电池的电压
int i=0;
for(i=0;i<5;i++)
{
BAT_ADC=BAT_ADC+Get_Adc();
delay_ms(10);
}
BAT_ADC=BAT_ADC/5;
BAT_Voltage=(float)BAT_ADC*(3.3/4096);
//这里乘以2是因为两个电阻分压了
BAT_Voltage=BAT_Voltage*2;
return BAT_Voltage;
}