一乐电子

一乐电子百科

 找回密码
 请使用微信账号登录和注册会员

QQ登录

只需一步,快速开始

快捷登录

手机号码,快捷登录

搜索
查看: 13870|回复: 76
收起左侧

[51单片机] 采用AT89C2051的智能锂电池充电器

  [复制链接]
发表于 2013-4-9 12:27 | 显示全部楼层 |阅读模式
本帖最后由 sunny20 于 2013-4-9 12:53 编辑

cdq.JPG 充电器.rar (22.4 KB, 下载次数: 342) 本人经过两天的奋斗,终于制作成功了一款采用AT89C2051的智能充电器,工作电压5V。而且无需A/D芯片,具备LED显示电量,充满自停等功能。市面上的充电器充电电压都不准确,很容易充坏电池,本充电器能把电池准确充到4.2V并且立即停止充电!具体操作及原理:
接通电源,CPU通过P3.3脚输出2Hz方波检测信号,用来检测电池,这个时候双色LED显示绿色,表示没有放入电池,当接入电池时,在方波期间,R4将产生压降。此压降加到IC1B,IC1是一块运算比较器,ICB对R4的压降时刻进行比较,平时输出为低电平,如果放入电池,R4两端的电压将大于反相,这个时候比较器翻转为高电平,通过调节VR2来控制翻转电压。当放入电池后,CPU的P3.5脚将变为高电平,这个时候CPU认为检测到电池,于是置P3.3为持续的低电平,Q1导通,开始充电,并且双色LED变为红色表示正在充电。这个时候由IC1A组成的简单的压控振荡器开始震荡,震荡频率由电池的电压决定,电池电压高,频率就高。振荡器时刻监视着电池电压,把频率反应给CPU,CPU里面的计数器不断对频率进行采样,与内部程序设置的门限进行比较,通过P1口的4个LED显示相应的电量,相应的LED会闪烁,比如充到50%,那么50%的LED会闪烁,其余50%以下的会变常亮!调节VR1可以控制检测的准确性。注意:此部分电路任意一个元件的数值改变,将直接影响电量的检测的准确性。当电池充满后,4个LED全亮,双色LED变为绿色并且闪烁表示充满,CPU的P3.3脚变为高电平,Q1截止停止充电。
程序及其电路如下,全部免费,体现本人的无私,呵呵....
充电器.JPG

评分

参与人数 8一乐金币 +175 收起 理由
倪大德 + 40 支持原创
fat + 40 支持开源,感谢分享。
ayumi7 + 20 很给力!
conjim + 10 很给力!享用后勿忘加分!
dxq100 + 5 赞一个!
af5498 + 20 赞一个!
红塔山 + 20 很给力!
gw168sh + 20

查看全部评分

发表于 2013-4-9 12:49 | 显示全部楼层
沙发,这东西要顶
发表于 2013-4-9 12:56 | 显示全部楼层
如果能加上后期涓流充电就更好了
发表于 2013-4-9 13:15 | 显示全部楼层
好东西           
发表于 2013-4-9 13:27 | 显示全部楼层
mark!!!好东西   
发表于 2013-4-9 13:44 | 显示全部楼层
看看,学习者
发表于 2013-4-9 14:14 | 显示全部楼层
很不错,顶一下。
发表于 2013-4-9 16:12 | 显示全部楼层
最好电池没有电的时候进行涓流充电会好些,就如楼上3楼所说,
可以参考一下下面的帖子看一下:
http://bbs.elecfans.com/forum.php?mod=viewthread&tid=270784

下面是采用STC AD PWM做的充电源码

  1. //---------------------------------------------------------------------
  2. //#include <REG52.H>
  3. #include <intrins.H>
  4. #include "NEW_8051.H"
  5. //WDT_CONTR  //狗
  6. //---------------------------------------------------------------------
  7. typedef    unsigned char   INT8U;
  8. typedef    unsigned int    INT16U;
  9. //定义常量
  10. //pulse_width_MAX = pulse_width_MIN  时, 输出脉冲宽度不变。
  11. #define     pulse_width_MAX  0x65         //PWM 脉宽最大值, 占空比 =75%
  12. #define     pulse_width_MIN  0x45          //PWM 脉宽最小值, 占空比 =25%
  13. //#define   step             0x38          //PWM 脉宽变化步长
  14. #define    pulse_width  0x30H

  15. #define ADC_Power_On_Speed_Channel_0   0xE0    //P1.0 作为 A/D 输入
  16. #define ADC_Power_On_Speed_Channel_1   0xE1    //P1.1 作为 A/D 输入
  17. #define ADC_Power_On_Speed_Channel_2   0xE2    //P1.2 作为 A/D 输入
  18. #define ADC_Power_On_Speed_Channel_3   0xE3    //P1.3 作为 A/D 输入
  19. #define ADC_Power_On_Speed_Channel_4   0xE4    //P1.4 作为 A/D 输入
  20. #define ADC_Power_On_Speed_Channel_5   0xE5    //P1.5 作为 A/D 输入
  21. #define ADC_Power_On_Speed_Channel_6   0xE6    //P1.6 作为 A/D 输入
  22. #define ADC_Power_On_Speed_Channel_7   0xE7    //P1.7 作为 A/D 输入




  23. sbit B_LED         =    P3^4;//
  24. sbit B_LED2        =    P1^4;
  25. sbit B_ON          =    P3^5;
  26. sbit B_PW          =    P3^7;

  27. INT8U con_state,ADC_Channel_2_Result_date,T_N;
  28. INT16U  AD_date,S_N;


  29.   
  30. //#define ADC_YUCHONGDIAN             0x39    //1.12V,6V
  31. //#define ADC_YUCHONGDIAN_0           0x3E    //1.21,6.4V
  32. //#define ADC_JIESHU                  0x51    //1.58,8.4V
  33. //#define     ADC_YUCHONGDIAN           0x4D   //1.51V,8V
  34. //#define     ADC_YUCHONGDIAN_0         0x55    //1.65,8.8V
  35. //#define     ADC_JIESHU                0x74    //2.26,12V
  36. //#define     ADC_KONG                  0x8D      //2.82,15V
  37. //#define     ADC_DUANLU                 0x30
  38. //#define ADC_YUCHONGDIAN          0x40    //1.12V,6V      
  39. //#define ADC_YUCHONGDIAN_0        0x44    //1.21,6.4V     
  40. //#define ADC_JIESHU               0x58    //1.58,8.4V     
  41. #define     ADC_21           0x89   //21V
  42. #define     ADC_24           0x9c   //24V

  43. #define     ADC_27         0xB0    //27V
  44. #define     ADC_28                0xB7    //28V
  45. #define     ADC_KONG                  0xC8      //2.82,15V
  46. #define     ADC_DUANLU                 0x30                 
  47. #define     ADC_135           0x58   //21V
  48. #define     ADC_13           0x54   //0.153,21V     
  49. /***********************
  50.                 init port
  51. ***********************/
  52. void INITAL_port(void)
  53. {
  54. P0=0xff;
  55. P1=0xff;
  56. P2=0xff;
  57. P3=0xff;
  58. }
  59. /***********************
  60.                  init PCA
  61. ************************/
  62. void initiate_pca (void);


  63. void delay(INT8U delay_time)        // 延时函数
  64. {
  65.     INT16U n;
  66.     while(delay_time--)
  67.     {
  68.         n = 6000;
  69.         while(--n);
  70.     }
  71. }

  72. /***********************
  73.                  init AD
  74. ************************/
  75. //--------------------------------------------------------------
  76. void ADC_Power_On(void)
  77. {
  78.    
  79.      ADC_CONTR|=0x80;          //开 A/D 转换电源
  80.    
  81.      delay(20);                   //开 A/D 转换电源后要加延时,1mS 以内就足够了
  82. }  


  83. void Set_P12_Open_Drain(void) //设置 P1.2,设置 A/D 通道所在的 I/O 为开漏模式
  84.     {
  85.    
  86.     P1M0|=  0x4;
  87.     P1M1|=  0x4;     
  88.     }


  89. void Set_ADC_Channel_2(void)
  90. {
  91.     ADC_CONTR=ADC_Power_On_Speed_Channel_2;
  92.                     //选择 P1.2 作为 A/D 转换通道
  93.                     //更换 A/D 转换通道后要适当延时, 使输入电压稳定
  94.                     //以后如果不更换 A/D 转换通道的话, 不需要加延时
  95.    delay(5);        //切换 A/D 转换通道,加延时 20uS~200uS 就可以了,与输入电压源的内阻有关
  96.                     //如果输入电压信号源的内阻在 10K 以下,可不加延时
  97.      
  98. }
  99. void initiate_AD (void)
  100. {
  101.      ADC_Power_On ();             //开 ADC 电源, 第一次使用时要打开内部模拟电源                                    ;开 ADC 电源, 可适当加延时,1mS 以内就足够了
  102.     Set_P12_Open_Drain ();       //设置 P1.2 为开漏
  103.     Set_ADC_Channel_2();         //设置 P1.2 作为 A/D 转换通道
  104. }   
  105. //----------------------------------------------------------
  106. INT8U Get_AD_Result(void)
  107. {
  108.                   
  109.     ADC_DATA=0;
  110.     //ADC_CONTR = AD_SPEED;
  111.     //ADC_CONTR = 0xE0;               //1110,0000 清 ADC_FLAG, ADC_START 位和低 3 位
  112.     //ADC_CONTR |= channel;           //选择 A/D 当前通道
  113.     Set_ADC_Channel_2();
  114.     delay(1);   
  115.    
  116.     ADC_CONTR|= 0x08;     //启动 AD 转换
  117.             //判断 AD 转换是否完成
  118.      while (1)                       //等待A/D转换结束
  119.     {
  120.         if (ADC_CONTR & 0x10)       //0001,0000 测试A/D转换结束否
  121.         { break; }
  122.     }
  123.      
  124.     ADC_CONTR&=0xE7;     //清 0 ADC_FLAG, ADC_START 位, 停止 A/D 转换
  125.     return ADC_DATA;   
  126.    
  127. }





  128.    

  129. //---------------------------------------------------------------------
  130. void Send_Byte(INT8U one_byte)      //发送一个字节
  131. {
  132.     TI = 0;                         //清零串口发送中断标志
  133.     SBUF = one_byte;
  134.     while (TI == 0);
  135.     TI = 0;                         //清零串口发送中断标志
  136. }

  137. //------------------------------------------------------------
  138. void timer_start(void)
  139. {
  140.         ET0 =1;
  141.         TR0 =1;
  142. }
  143. void timer_stop(void)
  144. {
  145.         ET0 =0;
  146.         TR0 =0;
  147. }
  148. //------------------------------------------------------------
  149. void PWM (INT8U width)
  150. {

  151.           
  152.           CCAP0H=width;    // 示例程序核心语句
  153.           PCA_PWM0=0x00  ; //示例程序核心语句P3.7
  154.           PCA_PWM1=0x03;
  155.           delay(5);             
  156. }

  157. void pwm_stop(void)
  158. {
  159.   PCA_PWM0=0x03  ;//释放本行注释,PWM输出就一直是0,无脉冲;-------------------------
  160.   PCA_PWM1=0x03  ;
  161.   delay(250);
  162. }
  163. //------------------------------------------------------------



  164. void initiate_RS232 (void)          //串口初始化
  165. {
  166.                               
  167.     SCON = 0x50;                    //可变波特率. 8位无奇偶校验
  168.     TMOD = 0x21;
  169.     TH1  = 0xe7;//5.8mhz 600/s
  170.     TL1 = 0xe7;                  
  171.     AUXR &= 0xBF;
  172.     TR1  =1;
  173.     ES = 0;                         //禁止串口中断
  174. }

  175. //---------------------------------------------------------------------
  176. void initiate_pca (void)
  177. {
  178.    CMOD=0x82;
  179.                      //PCA 在空闲模式下停止 PCA 计数器工作         ;PCA 时钟模式为fosc/12         
  180.                      //禁止 PCA 计数器溢出中断
  181.    CCON=0x00;        //禁止 PCA 计数器工作, 清除中断标志、计数器溢出标志
  182.    CL  =0x00;        //清 0 计数器
  183.    CH  =0x00;
  184.            
  185.                      //设置模块 0 为 8 位 PWM 输出模式, PWM 无需中断支持。脉冲在 P3.7(第 11 脚)输出
  186.    CCAPM0 =0x42;     //示例程序核心语句 0100,0010
  187.                      //PCA_PWM0=0x00H;  //示例程序核心语句P3.7;
  188.    PCA_PWM0=0x03;    //释放本行注释,PWM输出就一直是0,无脉冲;-------------------------
  189.    
  190.                      //设置模块 1 为 8 位 PWM 输出模式, PWM 无需中断支持。脉冲在 P3.5(第 9 脚)输出
  191.    //CCAPM1=0x42;      //示例程序核心语句 0100,0010
  192.    //PCA_PWM1=0x00;  //示例程序核心语句 P3.5
  193.    //PCA_PWM1=0x03;    //释放本行注释, PWM 输出就一直是 0, 无脉冲。
  194.    //B_MO_1=0;
  195.    EPCA_LVD=1;      //开pca中断
  196.    EA=1;
  197.    CR=1;            //将 PCA 计数器打开
  198. }
  199. //---------------------------------------------------------------------

  200. //**********************************************
  201. void Initial_T0(void)
  202. {
  203.   TH0=0x4C        ;//设置定时器0 自动重装数 11M
  204.   TL0=0x00       ;//500uS
  205.    
  206.   //AUXR&=0xBF;         //定时器1 工作在12T 模式,与普通的8051 相同

  207.   ET0=0;
  208.   TR0=0;                       //启动定时器1     
  209. }

  210. void timer_init(void)
  211. {
  212.   TH0=0x4C        ;//设置定时器0 自动重装数 11M
  213.   TL0=0x00       ;//50MS
  214.   ET0=1;
  215.   TR0=1;      
  216. }   
  217. //---------------------------------------
  218. void con (void)
  219. {
  220. AD_date=AD_date+Get_AD_Result();
  221. AD_date=AD_date>>1;
  222. if (AD_date<ADC_DUANLU)
  223.                                    {
  224.                                             
  225.              con_state=4;                  
  226.                                    }   
  227.         switch(con_state)
  228.    {
  229.            case 0:
  230.                      
  231.                if (AD_date < ADC_21)
  232.                            {
  233.                                                     S_N=60000;
  234.                  
  235.                      PWM(pulse_width_MAX) ;//为输出脉冲宽度设置初值。
  236.                      timer_init();
  237.                      con_state=1;                  
  238.                                    }
  239.                            else
  240.                                    {
  241.                                            if (AD_date<ADC_28)
  242.                                            con_state=2;
  243.                                    }
  244.                                             
  245.            break;
  246.     case 1:
  247.                      
  248.                            if (AD_date>ADC_21)
  249.                                    {
  250.                                             
  251.              con_state=2;                  
  252.                                    }
  253.                            if (S_N==0)
  254.                                    {
  255.                                             
  256.              con_state=2;                  
  257.                                    }
  258.                                             
  259.            break;       
  260.           
  261.     case 2:
  262.                    S_N=60000;         
  263.             
  264.                  
  265.              PWM(pulse_width_MAX) ;//为输出脉冲宽度设置初值。
  266.              timer_init();
  267.              con_state=3;                                                       
  268.            break;       
  269.     case 3:
  270.                    if(AD_date>ADC_28)
  271.                            {
  272.                    
  273.               
  274.               con_state=4;
  275.               }
  276.              if (S_N==0)
  277.                                       {
  278.                                             
  279.              con_state=4;                  
  280.                                       }                                                      
  281.            break;       
  282.     case 4:  //如果没有电池或者在很长一段时间后重新启动初始化
  283.                  
  284.                            pwm_stop();               
  285.               TR0=0;
  286.               ET0=0;
  287.               
  288.               con_state=5;
  289.               B_LED=0;
  290.                           B_LED2=0;
  291.             
  292.     break;
  293.     case 5:  //如果没有电池或者在很长一段时间后重新启动初始化
  294.                  
  295.           if (AD_date>ADC_KONG  )
  296.                                    {     
  297.               con_state=0;
  298.               B_LED=1;
  299.                           B_LED2=1;                  
  300.                                    }   
  301.     break;


  302.    

  303.          
  304. default:
  305.                   
  306.                    break;  
  307.        }
  308.      
  309. }

  310. //---------------------------------------
  311. void timer0(void) interrupt 1
  312. {
  313. INT8U ACC_temp;

  314.    ACC_temp= ACC;  
  315.    TR0=0;
  316.    if(S_N!=0)
  317.            {
  318.            S_N--;       
  319.            }
  320.    if(T_N==0&con_state!=5)
  321.            {
  322.            B_LED=~B_LED;
  323.         B_LED2=~B_LED2;
  324.            T_N=10;
  325.            }
  326.    T_N--;
  327.    timer_init();
  328.    ACC= ACC_temp;   
  329. }
  330. //------------------------------------------------------------
  331. void serial()interrupt 4
  332. {        INT8U ACC_temp;
  333.         if(RI==0)
  334.                 TI=0;
  335.         else
  336.                 {
  337.                         RI=0;
  338.                         ES=0;
  339.                         ACC_temp=ACC ;
  340.                        
  341.                         //RS_do(SBUF);
  342.                         ACC=ACC_temp ;
  343.                         ES=1;   
  344.                 }
  345. }
  346.    

  347. //---------------------------------------------------------------------
  348. void main()

  349. {     INT8U n;
  350.       INITAL_port();
  351.       T_N=0;
  352.           B_PW= 0 ;
  353.           n=0;
  354.          
  355.    
  356.     initiate_pca();
  357.     initiate_RS232();               //波特率 = 600
  358.      
  359.     initial_T0();
  360.     //Send_Byte(0xAA);          //为便于观察, 发送 2 个 0xAA
  361.    
  362.     B_LED=0;
  363.         B_LED2=0;
  364.              
  365.     delay(0x250);
  366.     B_LED=1;
  367.         B_LED2=1;
  368.     initiate_AD();
  369.     ES=1;
  370.     con_state=0;
  371.     AD_date=Get_AD_Result();
  372.    
  373.     //Send_Byte(AD_date);
  374.     while(1)
  375.     {     
  376.      con();
  377.      WDT_CONTR=0x3f;          //看门狗       
  378.          if(n>10)
  379.          {
  380.         Send_Byte(AD_date);
  381.         n=0;
  382.          }
  383.     n++;
  384.      
  385.     }
  386. }

复制代码
发表于 2013-4-9 16:13 | 显示全部楼层
还有本坛另一个帖子作一下参考:
https://www.yleee.com.cn/thread-22891-1-1.html
发表于 2013-4-9 16:25 | 显示全部楼层
看起来很好

本版积分规则

QQ|一淘宝店|手机版|商店|电子DIY套件|一乐电子 ( 粤ICP备09076165号 ) 公安备案粤公网安备 44522102000183号

GMT+8, 2024-3-28 23:50 , Processed in 0.052827 second(s), 38 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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