找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 15569|回复: 6
打印 上一主题 下一主题
收起左侧

自制18650电池容量检测器

  [复制链接]
跳转到指定楼层
楼主
本文原作者为wosiyabo 版权归作者所有
根据电池容量的mAh,可以计算电池的持续放电时间的电流数去确定电池的容量。以下用了一个STC12C5608AD去做检测电池放电400mA的时间,再以公式400mA*时间=mAh

(注意,有保护板的测不到因为低于2.86V会断电)


     
谁也没想到德力普的2500mAh的电池竟然实测只有1860mAh........ 原理图忘记加12MHz晶振了。。。请各位后期制作加上去吧。。单片机定时器1内用PWM输出控制在~400mA以内,电压降低时PWM提升幅度。已经调得很准了,不过温漂会有少少误差。
(刚开始时用电阻做负载,后来发现电压降到3.3V左右时电流变成300几毫安,后来才改成PWM模式保持电流在2.83V都可以400mA)

单片机源程序:
  1. #include "reg51.h"
  2. //#include
  3. #include "intrins.h"
  4. #define uchar unsigned char
  5. #define uint unsigned int
  6. #define ulong unsigned long
  7. #define ADC_POWER   0x80            //ADC电源控制位
  8. #define ADC_FLAG    0x10            //ADC完成标志
  9. #define ADC_START   0x08            //ADC起始控制位
  10. #define ADC_SPEEDLL 0x00            //540个时钟
  11. #define ADC_SPEEDL  0x20            //360个时钟
  12. #define ADC_SPEEDH  0x40            //180个时钟
  13. #define ADC_SPEEDHH 0x60            //90个时钟

  14. sfr CCON        =   0xD8;           //PCA control register
  15. sbit CCF0       =   CCON^0;         //PCA module-0 interrupt flag
  16. sbit CCF1       =   CCON^1;         //PCA module-1 interrupt flag
  17. sbit CR         =   CCON^6;         //PCA timer run control bit
  18. sbit CF         =   CCON^7;         //PCA timer overflow flag
  19. sfr CMOD        =   0xD9;           //PCA mode register
  20. sfr CL          =   0xE9;           //PCA base timer LOW
  21. sfr CH          =   0xF9;           //PCA base timer HIGH
  22. sfr CCAPM0      =   0xDA;           //PCA module-0 mode register
  23. sfr CCAP0L      =   0xEA;           //PCA module-0 capture register LOW
  24. sfr CCAP0H      =   0xFA;           //PCA module-0 capture register HIGH
  25. sfr PCAPWM0     =   0xF2;



  26. sfr AUXR        =   0x8e;               //辅助寄存器
  27. sfr P1ASF       =   0x9D;           //P1口第2功能控制寄存器
  28. sfr ADC_RES     =   0xBD;           //ADC高8位结果
  29. sfr ADC_CONTR  = 0xc5;
  30. sfr ADC_DATA   = 0xc6;
  31. sfr ADC_LOW2   = 0xbe;

  32. sfr P0M0  = 0x93;
  33. sfr P0M1  = 0x94;
  34. sfr P1M0  = 0x91;
  35. sfr P1M1  = 0x92;
  36. sfr P2M0  = 0x95;
  37. sfr P2M1  = 0x96;
  38. sfr P3M0  = 0xb1;
  39. sfr P3M1  = 0xb2;  

  40. typedef unsigned char BYTE;

  41. uchar code table[]="0123456789BatTime:V.mAh_";
  42. uchar time1,time2,time3,pwm1;
  43. uint fen=0,ad1=138,ad0;

  44. sbit P12 = P1^2;
  45. sbit P13 = P1^3;
  46. sbit LED = P3^2;  //背光脚H亮
  47. sbit  rs = P3^3;  //
  48. sbit POW = P3^7;  //PWM
  49. sbit  en = P3^5;  //
  50. sbit SPK = P3^4;  //蜂鸣器

  51. void InitADC();
  52. uint GetADCResult(BYTE ch);
  53. void Delayus(uint us);
  54. void Delayms(unsigned int ms);
  55. void write_com(uchar com);
  56. void write_dat(uchar dat);
  57. void init();
  58. void Timer0Init(void);

  59. /*----------------------------
  60. 读取ADC结果
  61. ----------------------------*/
  62. uint GetADCResult(BYTE ch)
  63. {
  64.     ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ch | ADC_START;
  65.     _nop_();                        //等待4个NOP
  66.     _nop_();
  67.     _nop_();
  68.     _nop_();
  69.     while (!(ADC_CONTR & ADC_FLAG));//等待ADC转换完成
  70.     ADC_CONTR &= ~ADC_FLAG;         //Close ADC
  71.         return (ADC_DATA*4+ADC_LOW2);        //adc_data*4的意思是左移两位,4 = 2的2次方。
  72.                                     //然后左移后加上adc_low的值,这个值应该是adc转换的低两位。  

  73. //        ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ch | ADC_START;
  74.    // _nop_();                        //Must wait before inquiry
  75.    // _nop_();
  76.   // _nop_();
  77.    // _nop_();
  78.    // while (!(ADC_CONTR & ADC_FLAG));//Wait complete flag
  79.    // ADC_CONTR &= ~ADC_FLAG;         //Close ADC
  80.     //return ADC_DATA;                //Return ADC result         */

  81. }

  82. /*----------------------------
  83. 初始化ADC
  84. ----------------------------*/
  85. void InitADC()
  86. {
  87.     P1 = P1M0 = P1M1 = 0x03;        //Set all P1 as Open-Drain mode
  88.         ADC_RES = 0;
  89.     ADC_DATA = 0;                   //Clear previous result
  90.         ADC_LOW2 = 0;
  91.     ADC_CONTR = ADC_POWER | ADC_SPEEDLL;
  92.     Delayms(2);                       //ADC上电并延时
  93. }

  94. void Delayus(uint us)                //@12.000MHz
  95. {
  96.    while(--us)
  97.    {
  98.                 _nop_();
  99.                 _nop_();
  100.                 _nop_();
  101.                 _nop_();
  102.    }
  103. }
  104. void Delayms(unsigned int ms)                //@12.000MHz
  105. {
  106.         unsigned char i, j;
  107.         while(--ms)
  108.         {
  109.                 i = 12;
  110.                 j = 169;
  111.                 do
  112.                 {
  113.                         while (--j);
  114.                 } while (--i);
  115.         }
  116. }
  117. void write_com(uchar com)
  118. {
  119.         rs=0;
  120.         en=0;
  121.         P2=com;
  122.         Delayms(2);
  123.         en=1;
  124.         Delayms(2);
  125.         en=0;
  126. }
  127. void write_dat(uchar dat)
  128. {
  129.         rs=1;
  130.         en=0;
  131.         P2=dat;
  132.         Delayms(2);
  133.         en=1;
  134.         Delayms(2);
  135.         en=0;
  136. }
  137. void init()
  138. {
  139.         Delayms(15);
  140.         write_com(0x38); //写指令38H(不检测忙信号)
  141.         Delayms(5);
  142.         write_com(0x38); //写指令38H(不检测忙信号)
  143.         Delayms(5);
  144.         write_com(0x38); //写指令38H(不检测忙信号)
  145.         write_com(0x08); //写指令08H:显示关闭
  146.         write_com(0x01); //写指令01H:显示清屏
  147.       
  148.         write_com(0x06); //写指令06H:显示光标移动设置
  149.         write_com(0x0C); //写指令0CH:显示开及光标设置
  150. }

  151. void Timer0Init(void)                //2毫秒@12.000MHz
  152. {
  153.         AUXR &= 0x7F;                //定时器时钟12T模式
  154.         TMOD &= 0xF0;                //设置定时器模式
  155.         TMOD |= 0x01;                //设置定时器模式
  156.         TL0 = 0x30;                //设置定时初值
  157.         TH0 = 0xF8;                //设置定时初值
  158.         TF0 = 0;                //清除TF0标志
  159.         TR0 = 0;                //定时器0开始计时
  160. }


  161. void Timer1Init(void)                //5毫秒@12.000MHz
  162. {
  163.         AUXR &= 0xBF;                //定时器时钟12T模式
  164.         TMOD &= 0x0F;                //设置定时器模式
  165.         TMOD |= 0x10;                //设置定时器模式
  166.         TL1 = 0x78;                //设置定时初值
  167.         TH1 = 0xEC;                //设置定时初值
  168.         TF1 = 0;                //清除TF1标志
  169.         TR1 = 1;                //定时器1开始计时
  170. }


  171. void main()
  172. {      
  173.    bit q1=0,q2=0,q3=0;
  174.         uchar k1;
  175.         ulong ww=1667;
  176.         P0M0 = P0M1 = 0x00;
  177.         //P1M0 = 0x00;
  178.         //P1M1 = 0x00;
  179.         P2M0 = P2M1 = 0x00;
  180.         P3M1 = 0x94;
  181.         P3M0 = 0x00;
  182.         POW=0;
  183.         LED=1;
  184.         SPK=0;
  185.         init();
  186.         InitADC();
  187.         Timer0Init();
  188.         Timer1Init();
  189.         TR0 = 1;                        //timer0 start running
  190.     ET0 = 1;                        //enable timer0 interrupt
  191.     //TR1 = 1;                        //timer1 start running
  192.     //ET1 = 1;                        //enable timer1 interrupt
  193.     EA = 1;                         //open global interrupt switch
  194.                   
  195.         for(k1=255;k1>0;k1--)
  196.            {
  197.                    SPK=~SPK;
  198.                 Delayus(k1);
  199.            }   
  200.            SPK=0;

  201.           write_com(0x80); //80为上排第一个
  202.           write_dat(table[10]);
  203.           write_dat(table[11]);
  204.           write_dat(table[12]);
  205.           write_dat(table[12]);
  206.           write_dat(table[17]);
  207.           write_com(0xC0); //C0为下排第一个
  208.           write_dat(table[13]);
  209.           write_dat(table[14]);
  210.           write_dat(table[15]);
  211.           write_dat(table[16]);
  212.           write_dat(table[17]);
  213.           write_com(0xC0+6);
  214.           write_dat(table[0]);
  215.           write_dat(table[0]);
  216.           write_dat(table[17]);
  217.           write_dat(table[0]);
  218.           write_dat(table[0]);
  219.           write_dat(table[17]);
  220.           write_dat(table[0]);
  221.           write_dat(table[0]);
  222.         while(1)
  223.         {


  224.           while(1)
  225.           {

  226.            if(EA==1)
  227.               {
  228.                         write_com(0xC0+13);
  229.                         write_dat(table[time1%10/1]);
  230.                         write_com(0xC0+12);
  231.                         write_dat(table[time1%100/10]);
  232.                         write_com(0xC0+10);
  233.                         write_dat(table[time2%10/1]);
  234.                         write_com(0xC0+9);
  235.                         write_dat(table[time2%100/10]);
  236.                         write_com(0xC0+7);
  237.                         write_dat(table[time3%10/1]);
  238.                         write_com(0xC0+6);
  239.                         write_dat(table[time3%100/10]);
  240.               }


  241.          
  242.          
  243.           if(q1==0&time1==2)
  244.              {
  245.                         write_com(0x85);
  246.                         write_dat(table[ad0%1000/100]);
  247.                         write_com(0x86);
  248.                         write_dat(table[19]);
  249.                         write_com(0x87);
  250.                         write_dat(table[ad0%100/10]);
  251.                         write_com(0x88);
  252.                         write_dat(table[ad0%10/1]);
  253.                         write_com(0x89);
  254.                         write_dat(table[18]);
  255.                         q1=1;                              

  256.                                    for(k1=0;k1<255;k1++)
  257.                            {
  258.                                    SPK=~SPK;
  259.                                 Delayus(150);
  260.                            }
  261.                                 Delayms(100);
  262.                                    for(k1=0;k1<255;k1++)
  263.                            {
  264.                                    SPK=~SPK;
  265.                                 Delayus(150);
  266.                            }
  267.                             SPK=0;
  268.                                 CCON = 0;                       //Initial PCA control register
  269.                                                                 //PCA timer stop running
  270.                                                                 //Clear CF flag
  271.                                                                 //Clear all module interrupt flag
  272.                                 CL = 0;                         //Reset PCA base timer
  273.                                 CH = 0;
  274.                                 CMOD = 0x02;                    //Set PCA timer clock source as Fosc/2
  275.                                                                 //Disable PCA timer overflow interrupt
  276.                                 CCAP0H = CCAP0L = 0xFF;         //PWM0 port output 50% duty cycle square wave
  277.                                 CCAPM0 = 0x42;                  //PCA module-0 work in 8-bit PWM mode and no PCA interrupt
  278.                               
  279.                                 CR = 1;                         //PCA timer start run
  280.                             TR0 = 1;
  281.                                 ET1 = 1;
  282.                }      

  283.                         write_com(0x8B);
  284.                         write_dat(table[ad0%1000/100]);
  285.                         write_com(0x8C);
  286.                         write_dat(table[19]);
  287.                         write_com(0x8D);
  288.                         write_dat(table[ad0%100/10]);
  289.                         write_com(0x8E);
  290.                         write_dat(table[ad0%10/1]);
  291.                         write_com(0x8F);
  292.                         write_dat(table[18]);

  293.           if(fen>=1)LED=0;
  294.           if(ad0<=286)q3=1;
  295.            while(q3==1)
  296.            {
  297.                         for(k1=0;k1<100;k1++)
  298.                            {
  299.                                    SPK=~SPK;
  300.                                 Delayus(110);
  301.                            }
  302.                                 SPK=0;                        
  303.                                 LED=~LED;
  304.                                 CCAP0H = CCAP0L = 0xFF;
  305.                                 POW=0;
  306.                                 EA=0;
  307.                                 Delayms(500);
  308.                         ad0=GetADCResult(0);
  309.                         write_com(0x8B);
  310.                         write_dat(table[ad0%1000/100]);
  311.                         write_com(0x8C);
  312.                         write_dat(table[19]);
  313.                         write_com(0x8D);
  314.                         write_dat(table[ad0%100/10]);
  315.                         write_com(0x8E);
  316.                         write_dat(table[ad0%10/1]);
  317.                         write_com(0x8F);
  318.                         write_dat(table[18]);
  319.                  if(!q2)
  320.                  {      
  321.                    ww*=fen;
  322.                    ww*=4;
  323.                     write_com(0xC0+0);
  324.                         write_dat(table[23]);
  325.                         write_com(0xC0+1);
  326.                         write_dat(table[23]);
  327.                     write_com(0xC0+2);
  328.                         write_dat(table[23]);
  329.                     write_com(0xC0+3);
  330.                         write_dat(table[23]);
  331.                     write_com(0xC0+4);
  332.                         write_dat(table[23]);
  333.                     write_com(0xC0+5);
  334.                         write_dat(table[23]);
  335.                         write_com(0xC0+6);
  336.                         write_dat(table[23]);
  337.                         write_com(0xC0+7);
  338.                         write_dat(table[ww%100000000/10000000]);
  339.                         write_com(0xC0+8);
  340.                         write_dat(table[ww%10000000/1000000]);
  341.                         write_com(0xC0+9);
  342.                         write_dat(table[ww%1000000/100000]);
  343.                         write_com(0xC0+10);
  344.                         write_dat(table[ww%100000/10000]);
  345.                         write_com(0xC0+11);
  346.                         write_dat(table[ww%10000/1000]);
  347.                         write_com(0xC0+12);
  348.                         write_dat(table[20]);
  349.                         write_com(0xC0+13);
  350.                         write_dat(table[21]);
  351.                         write_com(0xC0+14);
  352.                         write_dat(table[22]);
  353.                         Delayms(1000);
  354.                 q2=1;
  355.                  }
  356.            }

  357.                  
  358.           }

  359.         }  
  360. }
  361. void tm0_isr() interrupt 1 using 1
  362. {
  363.   static uchar i1,i2;
  364.         TL0 = 0x30;                //设置定时初值
  365.         TH0 = 0xF8;                //设置定时初值
  366.         i1++;
  367.         if(i1>=50)
  368.         {
  369.           i1=0;
  370.           i2++;
  371.           if(i2>=10)
  372.                   {
  373.                    i2=0;
  374.                    time1++;
  375.                   if(time1>=60)
  376.                          {
  377.                            time1=0;
  378.                            time2++;
  379.                            fen++;
  380.                           if(time2>=60)
  381.                                   {
  382.                                     time2=0;
  383.                                         time3++;
  384.                                         if(time3>=24)time3=0;
  385.                                   }
  386.                           }
  387.                           }
  388.         }
  389.    ad0=GetADCResult(0);      
  390. }

  391. void tm1_isr() interrupt 3 using 1
  392. {
  393.         TL1 = 0x78;                //设置定时初值
  394.         TH1 = 0xEC;                //设置定时初值
  395.         if(ad0>=428)CCAP0H = CCAP0L = 142;
  396.         if(ad0<=427&&ad0>424)CCAP0H = CCAP0L = 142;
  397.         if(ad0<=424&&ad0>420)CCAP0H = CCAP0L = 141;
  398.         if(ad0<=420&&ad0>416)CCAP0H = CCAP0L = 140;
  399.         if(ad0<=416&&ad0>412)CCAP0H = CCAP0L = 139;
  400.         if(ad0<=412&&ad0>408)CCAP0H = CCAP0L = 138;
  401.         if(ad0<=408&&ad0>404)CCAP0H = CCAP0L = 137;
  402.         if(ad0<=404&&ad0>400)CCAP0H = CCAP0L = 136;
  403.         if(ad0<=400&&ad0>396)CCAP0H = CCAP0L = 135;
  404.         if(ad0<=396&&ad0>392)CCAP0H = CCAP0L = 134;
  405.         if(ad0<=392&&ad0>388)CCAP0H = CCAP0L = 132;//
  406.         if(ad0<=388&&ad0>384)CCAP0H = CCAP0L = 131;
  407.         if(ad0<=384&&ad0>380)CCAP0H = CCAP0L = 129;
  408.         if(ad0<=380&&ad0>376)CCAP0H = CCAP0L = 128;
  409.         if(ad0<=376&&ad0>372)CCAP0H = CCAP0L = 127;
  410.         if(ad0<=372&&ad0>368)CCAP0H = CCAP0L = 126;//
  411.         if(ad0<=368&&ad0>364)CCAP0H = CCAP0L = 125;
  412.         if(ad0<=364&&ad0>360)CCAP0H = CCAP0L = 123;
  413.         if(ad0<=360&&ad0>356)CCAP0H = CCAP0L = 122;
  414.         if(ad0<=356&&ad0>352)CCAP0H = CCAP0L = 120;
  415.         if(ad0<=352&&ad0>348)CCAP0H = CCAP0L = 119;
  416.         if(ad0<=348&&ad0>344)CCAP0H = CCAP0L = 117;
  417.         if(ad0<=344&&ad0>340)CCAP0H = CCAP0L = 116;
  418.         if(ad0<=340&&ad0>336)CCAP0H = CCAP0L = 114;
  419.         if(ad0<=336&&ad0>332)CCAP0H = CCAP0L = 113;
  420.         if(ad0<=332&&ad0>328)CCAP0H = CCAP0L = 111;
  421.         if(ad0<=328&&ad0>324)CCAP0H = CCAP0L = 109;
  422.         if(ad0<=324&&ad0>320)CCAP0H = CCAP0L = 108;
  423.         if(ad0<=320&&ad0>316)CCAP0H = CCAP0L = 106;
  424.         if(ad0<=316&&ad0>312)CCAP0H = CCAP0L = 105;
  425.         if(ad0<=312&&ad0>308)CCAP0H = CCAP0L = 103;
  426.         if(ad0<=304&&ad0>300)CCAP0H = CCAP0L = 100;
  427.         if(ad0<=300&&ad0>296)CCAP0H = CCAP0L = 98;
  428.         if(ad0<=296&&ad0>292)CCAP0H = CCAP0L = 97;
  429.         if(ad0<=292&&ad0>288)CCAP0H = CCAP0L = 94;
  430.         if(ad0<=288&&ad0>284)CCAP0H = CCAP0L = 91;
  431.         if(ad0<=284)CCAP0H = CCAP0L = 0xFF;
  432.       
  433.         //CCAPM0 = 0x42;
  434. }
复制代码
本文原作者为:wosiyabo 版权归作者所有
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏10 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:204108 发表于 2017-5-24 06:36 | 只看该作者
楼主大神,我想自己动手焊接一个,能将所需的电子原件和加完晶振的电路图告诉我吗,不胜感激!!!
回复

使用道具 举报

板凳
ID:191195 发表于 2017-5-24 07:00 来自手机 | 只看该作者
好资料呀,支持一下。
回复

使用道具 举报

地板
ID:140980 发表于 2017-5-27 08:18 | 只看该作者
没有电流检测电路,怎么保证电流的准确.
回复

使用道具 举报

5#
ID:67537 发表于 2018-12-30 22:31 | 只看该作者
如果是一次性的锂电池,有什么办法测量容量
回复

使用道具 举报

6#
ID:358930 发表于 2018-12-31 09:45 来自手机 | 只看该作者
yyhhgg 发表于 2018-12-30 22:31
如果是一次性的锂电池,有什么办法测量容量

好像是算内阻值的,电动车不是有那种短路一样的容量表吗?你去修车那看看就知道了
回复

使用道具 举报

7#
ID:412684 发表于 2019-3-20 17:55 | 只看该作者
czvsgd 发表于 2017-5-24 06:36
**** 作者被禁止或删除 内容自动屏蔽 ****

很给力
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表