6552|1

693

帖子

7

TA的资源

版主

楼主
 

如何实时动态监测电路中的电池电量? [复制链接]

在日常的电路设计中,电路中电池的电量往往会大大的影响调试的结果。比如:1、风洞的调试


因为我一开始没有管电池电压的事情,就一直在修改PID参数想使乒乓球保持稳定,但是我错了,每次感觉调节好一个参数之后,结果发现乒乓球又漂了,越调越迷茫,最后一分析,原来电池电压在下降(一开始都是使用12V蓝皮电池供电),还有:

2、倒立摆的调试

因为我一开始也没有管电池电压的事情,然后一直在修改PID参数想使摆杆立起来,测量一下电池的电压,还是上面的情况,原来电池电压在下降(一开始都是使用12V蓝皮电池供电)
为了克服电压变化对我PID调节的影响,我最后索性买了个恒定的电源盒

这种装备真的好用,插上220V直接输出基本上恒定的12V电压,完美解决了电压放电对系统PID参数的影响。那么,怎么能够实时动态检测电池电压呢?这个问题是非常重要的,比如可以根据不同的电压值分段程不同的PID参数或者提醒用户停止设备当前的工作更换电池等。

好了,下面开始测试一下我的方案可不可行,首先设计电路,我用Altium Designer 先把电路图画出来

原理图大概就是上面这个样子,利用电阻分压的原理,比如输入电压为U1,则U(ADC)=U1*R2/(R1+R2),然后通过单片机的ADC采集建立输入电压与ADC采集数值之间的关系,这个关系可以用MATLAB软件仿真出来,好了说了这么多的理论,下面开始实践操作,
1、先用洞洞板把电路焊出来,因为我要换电阻来选择合适的分压电阻,所以我把排母焊在洞洞板上,方便更换,实物图如下:

2、选择两个51K电阻,测量后发现阻值有点漂,经过测量后发现实际阻值一个为50.8K欧,一个为50.5K欧。

3、到此处硬件电路基本上就算完成了,下面开始软件部分,我使用的是正点原子的mini开发板,功能和资源还是相当丰富的,强烈推荐作为学习单片机的入门开发板

  1. main函数代码:
  2. #include "led.h"
  3. #include "delay.h"
  4. #include "sys.h"
  5. #include "usart.h"
  6. #include "lcd.h"
  7. #include "adc.h"

  8. //ALIENTEK Mini STM32开发板范例代码15
  9. //ADC实验  
  10. //技术支持:[url]www.openedv.com[/url]
  11. //广州市星翼电子科技有限公司
  12.           
  13. int main(void)
  14. {
  15.         u16 adcx;
  16.         float temp;
  17.         delay_init();                     //延时函数初始化          
  18.         uart_init(9600);                 //串口初始化为9600
  19.         LED_Init();                                  //初始化与LED连接的硬件接口
  20.         LCD_Init();
  21.         Adc_Init();                                  //ADC初始化            
  22.         POINT_COLOR=RED;//设置字体为红色
  23.         LCD_ShowString(60,50,200,16,16,"Mini STM32");       
  24.         LCD_ShowString(60,70,200,16,16,"ADC TEST");       
  25.         LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");
  26.         LCD_ShowString(60,110,200,16,16,"2018/9/20");       
  27.         //显示提示信息
  28.         POINT_COLOR=BLUE;//设置字体为蓝色
  29.         LCD_ShowString(60,130,200,16,16,"ADC_CH1_VAL:");             
  30.         LCD_ShowString(60,150,200,16,16,"ADC_CH1_VOL:0.000V");            
  31.         while(1)
  32.         {
  33.                 adcx = Get_Adc_Average(ADC_Channel_1,10);//去10次平均值后返回adcx
  34.                 LCD_ShowxNum(156,130,adcx,4,16,0);//显示ADC的值
  35.                 temp=(float)adcx*(3.3/4096);//12位分辨率,2的12次方 = 4096
  36.                 adcx=temp;//取整数部分
  37.                 LCD_ShowxNum(156,150,adcx,1,16,0);//显示电压值
  38.                 temp-=adcx;
  39.                 temp*=1000;
  40.                 LCD_ShowxNum(172,150,temp,3,16,0X80);
  41.                 LED0=!LED0;
  42.                 delay_ms(250);       
  43.         }                                                                                            
  44. }       
复制代码


  1. adc.c文件
  2. #include "adc.h"
  3. #include "delay.h"
  4. //////////////////////////////////////////////////////////////////////////////////         
  5. //本程序只供学习使用,未经作者许可,不得用于其它任何用途
  6. //ALIENTEK miniSTM32开发板
  7. //ADC 代码          
  8. //正点原子@ALIENTEK
  9. //技术论坛:[url]www.openedv.com[/url]
  10. //修改日期:2012/9/7
  11. //版本:V1.0
  12. //版权所有,盗版必究。
  13. //Copyright(C) 广州市星翼电子科技有限公司 2009-2019
  14. //All rights reserved                                                                          
  15. //////////////////////////////////////////////////////////////////////////////////
  16.           
  17.                   
  18. //初始化ADC
  19. //这里我们仅以规则通道为例
  20. //我们默认将开启通道0~3                                                                                                                                          
  21. void  Adc_Init(void)
  22. {        
  23.         ADC_InitTypeDef ADC_InitStructure;
  24.         GPIO_InitTypeDef GPIO_InitStructure;

  25.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1        , ENABLE );          //使能ADC1通道时钟


  26.         RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M

  27.         //PA1 作为模拟通道输入引脚                        
  28.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  29.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚
  30.         GPIO_Init(GPIOA, &GPIO_InitStructure);       

  31.         ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值

  32.         ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;        //ADC工作模式:ADC1和ADC2工作在独立模式
  33.         ADC_InitStructure.ADC_ScanConvMode = DISABLE;        //模数转换工作在单通道模式
  34.         ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;        //模数转换工作在单次转换模式
  35.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;        //转换由软件而不是外部触发启动
  36.         ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADC数据右对齐
  37.         ADC_InitStructure.ADC_NbrOfChannel = 1;        //顺序进行规则转换的ADC通道的数目
  38.         ADC_Init(ADC1, &ADC_InitStructure);        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   

  39.   
  40.         ADC_Cmd(ADC1, ENABLE);        //使能指定的ADC1
  41.        
  42.         ADC_ResetCalibration(ADC1);        //使能复位校准  
  43.          
  44.         while(ADC_GetResetCalibrationStatus(ADC1));        //等待复位校准结束
  45.        
  46.         ADC_StartCalibration(ADC1);         //开启AD校准

  47.         while(ADC_GetCalibrationStatus(ADC1));         //等待校准结束

  48. //        ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能

  49. }                                  
  50. //获得ADC值
  51. //ch:通道值 0~3
  52. u16 Get_Adc(u8 ch)   
  53. {
  54.           //设置指定ADC的规则组通道,一个序列,采样时间
  55.         ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );        //ADC1,ADC通道,采样时间为239.5周期                                      
  56.   
  57.         ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能       
  58.          
  59.         while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束

  60.         return ADC_GetConversionValue(ADC1);        //返回最近一次ADC1规则组的转换结果
  61. }

  62. u16 Get_Adc_Average(u8 ch,u8 times)
  63. {
  64.         u32 temp_val=0;
  65.         u8 t;
  66.         for(t=0;t<times;t++)
  67.         {
  68.                 temp_val+=Get_Adc(ch);
  69.                 delay_ms(5);
  70.         }
  71.         return temp_val/times;
  72. }          



























复制代码

  1. adc.h文件
  2. #ifndef __ADC_H
  3. #define __ADC_H       
  4. #include "sys.h"
  5. //本程序只供学习使用,未经作者许可,不得用于其它任何用途
  6. //ALIENTEK战舰STM32开发板
  7. //ADC 代码          
  8. //正点原子@ALIENTEK
  9. //技术论坛:[url]www.openedv.com[/url]
  10. //修改日期:2012/9/7
  11. //版本:V1.0
  12. //版权所有,盗版必究。
  13. //Copyright(C) 广州市星翼电子科技有限公司 2009-2019
  14. //All rights reserved                                                                          
  15. //////////////////////////////////////////////////////////////////////////////////

  16. void Adc_Init(void);
  17. u16  Get_Adc(u8 ch);
  18. u16 Get_Adc_Average(u8 ch,u8 times);

  19. #endif
复制代码



4、将程序下载进开发板



好了,软件和硬件都已经准备完毕,下面就开始我们的测量试验了。
因为单片机ADC采集接口的电压不能超过3.3V,所以还得进行一番理论推导因此来限定一下输入电压的范围,


实验数据如下表所示:
Vin(V) 0.0 0.5 1.0 1.5 2.0 2.5 3.03.5 4.0 4.55.0 5.5 6.0 6.5
ADC 2 305 620 932 1246 1558 1875 2185 2497 2802 3117 3432 3746 4056
上述数据为电阻R1=R2=50.5K欧情况下测得,然后对数据通过MATLAB仿真软件,仿真出输入电压与ADC的关系式得:
ADC = 624.5Vin - 2.829
近似成线性关系
结论:上述方法测量电池电压确实可行,而且还挺方便

最新回复

用电压判断电量,电池一致性好,批次之间起伏不大的话,误差平均30%吧  详情 回复 发表于 2018-9-23 22:34
点赞 关注(1)
 

回复
举报

3986

帖子

0

TA的资源

五彩晶圆(高级)

沙发
 
用电压判断电量,电池一致性好,批次之间起伏不大的话,误差平均30%吧
个人签名

YesWatt艺瓦特电子科技有限公司 傻大粗电源转换器制造商 https://apu5ob0ydv0ysskfm03hs4dtqfr97j68.taobao.com/

 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表