找回密码
 立即注册

QQ登录

只需一步,快速开始

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

DIY车用铅酸蓄电池智能充电机

[复制链接]
跳转到指定楼层
楼主
地处北方,冬季车辆易亏电启动困难,需要补充充电。利用手头的老物件AT89C4051,ADC0832制作控制电路,IO口有限使用了PFC8574T驱动1602显示。两个工作模式,三段自动充电模式(充足自动转为浮充)和定时充电模式(恒流充电)。制作完成才发现PCF8574T驱动1602显示刷新太慢了影响响应速度,待充电主回路完成再联调。
#include <reg51.h>
#include <intrins.h>

#define PCF_ADDR 0x4E  //PCF8574T地址
unsigned char Data[3];
unsigned char Table[]="0123456789";
unsigned int delay_time;

long z=0;
unsigned char j;
unsigned char k;
unsigned char h;
unsigned char f;
unsigned char Set_A;
unsigned char Batt_V;
unsigned char Batt_A;
unsigned char JD=0;
unsigned char IS=0;

char hour=1;
char min=0;
char miao=59;
char count=0;
bit  ptt=1;
sbit triac = P3^1;   // 可控硅控制引脚
sbit ON_OFF = P3^7;    //启动停止开关
sbit MODE = P3^3;      //模式
sbit JIA = P3^4;       //加时间
sbit JIAN = P3^5;      //减时间
sbit FMQ = P3^0;       //蜂鸣器
sbit SCL = P1^1;     // I2C时钟线
sbit SDA = P1^0;     // I2C数据线
sbit CS = P1^5;
sbit CLK = P1^6;
sbit DI0 = P1^7;
sbit WCS = P1^2;
sbit WCLK = P1^3;
sbit WDI0 = P1^4;
//----------函数声明----------------------------
void process_3(unsigned int i,unsigned char *p) ;
void display(unsigned char *p);
void delay_us(unsigned int us);
void delay_ms(unsigned int ms);
void I2C_Start();
void I2C_Stop();
void I2C_WriteByte(unsigned char dat);
void PCF8574_Write(unsigned char dat);
void lcd_send_nibble(unsigned char nibble, unsigned char rs);
void lcd_send_byte(unsigned char dat, bit rs);
void lcd_init();
void lcd_set_cursor(unsigned char row, unsigned char col);
void lcd_write_string(char *str);
void init();
void display_SJ(unsigned char hour,unsigned char min);
unsigned char Current();
unsigned char V_SetA(bit CH);   
//---------------------------------------------
unsigned char V_SetA(bit CH)//
{
  unsigned char i,dat,dat2;
  CS=0;
  _nop_();
  DI0=1;
  CLK=1;
  _nop_();
  CLK=0;
  _nop_();
   DI0=1;
  CLK=1;
  _nop_();
  CLK=0;
  _nop_();
if(CH==0)//0通道/设置电流
{
   DI0=0;
}
if(CH==1)//1通道/电压
{
   DI0=1;
}
  CLK=1;
  _nop_();
  CLK=0;
  DI0=1;
  dat=0;
  for(i=0;i<8;i++)
     {
       dat<<=1;
       CLK=1;
       _nop_();
       CLK=0;
       _nop_();
       dat|=DI0;
     }
     dat2=0;
   if(DI0==1)
     dat2=0x80;
   for(i=0;i<7;i++)
      {
        dat2>>=1;
        CLK=1;
        _nop_();
        CLK=0;
        _nop_();
        if(DI0==1)
        dat2|=0x80;
      }
    CS=1;
    CLK=0;
    DI0=1;
    if(dat==dat2)
    return(dat);
    else
    return 0;
}
//--------------------------
unsigned char Current()//0通道/电流
{
  unsigned char i,dat,dat2;
  WCS=0;
  _nop_();
  WDI0=1;
  WCLK=1;
  _nop_();
  WCLK=0;
  _nop_();
  WDI0=1;
  WCLK=1;
  _nop_();
  WCLK=0;
  _nop_();
  WDI0=0;//0通道/电流
  WCLK=1;
  _nop_();
  WCLK=0;
  WDI0=1;
  dat=0;
  for(i=0;i<8;i++)
     {
       dat<<=1;
       WCLK=1;
       _nop_();
       WCLK=0;
       _nop_();
       dat|=WDI0;
     }
     dat2=0;
   if(WDI0==1)
     dat2=0x80;
   for(i=0;i<7;i++)
      {
        dat2>>=1;
        WCLK=1;
        _nop_();
        WCLK=0;
        _nop_();
        if(WDI0==1)
        dat2|=0x80;
      }
    WCS=1;
    WCLK=0;
    WDI0=1;
    if(dat==dat2)
    return(dat);
    else
    return 0;
}
//---------------------------------------------
void process_3(unsigned int i,unsigned char *p)
{
  p[0]=i/100%10;
  p[1]=i/10%10;
  p[2]=i%10;
}
//----------------------------
/*3位数显示函数*/
void display(unsigned char *p)
{
  unsigned char i;
          
  for(i=0;i<3;i++)
  {
    if(i==2)
    {
        lcd_write_string(".");
    }
        lcd_send_byte(Table[p[i]], 1);
  }
}
//------------------------------
void delay_us(unsigned int us) {
    while (us--) {
        _nop_();
        _nop_();
        _nop_();
        _nop_();
    }
}
//------------------------------
void delay_ms(unsigned int ms) {
    unsigned int i, j;
    for (i = 0; i < ms; i++)
        for (j = 0; j < 114; j++);
}
//------------------------------
void I2C_Start() {
    SDA = 1;
    SCL = 1;
    delay_us(5);
    SDA = 0;
    delay_us(5);
    SCL = 0;
}
//-----------------
void I2C_Stop() {
    SDA = 0;
    SCL = 1;
    delay_us(5);
    SDA = 1;
    delay_us(5);
}
//-------------------------------------
void I2C_WriteByte(unsigned char dat) {
    unsigned char i;
    for (i = 0; i < 8; i++) {
        SDA = (dat & 0x80) ? 1 : 0;
        dat <<= 1;
        SCL = 1;
        delay_us(5);
        SCL = 0;
        delay_us(5);
    }
    SDA = 1;  // 释放总线等待ACK
    SCL = 1;
    delay_us(5);
    SCL = 0;
}
//------------------------------------
void PCF8574_Write(unsigned char dat) {
    I2C_Start();
    I2C_WriteByte(PCF_ADDR);
    I2C_WriteByte(dat);
    I2C_Stop();
}
//------------------------------------------------------------
void lcd_send_nibble(unsigned char nibble, unsigned char rs) {
    unsigned char data_pcf;
    // 数据位: P4-P7, RS: P0, E: P2, Backlight: P3 (开启)
    data_pcf = (nibble << 4) | (rs << 0) | (1 << 3);
    // E下降沿
    PCF8574_Write(data_pcf & ~(1 << 2)); // E=0
    delay_us(1);
    PCF8574_Write(data_pcf | (1 << 2));  // E=1
    delay_us(1);
    PCF8574_Write(data_pcf & ~(1 << 2)); // E=0
    delay_us(100);
}
//---------------------------------------------
void lcd_send_byte(unsigned char dat, bit rs) {
    lcd_send_nibble(dat >> 4, rs); // 高四位
    lcd_send_nibble(dat & 0x0F, rs); // 低四位
}
//--------------------------
void lcd_init() {
    delay_ms(50);
    lcd_send_nibble(0x03, 0);
    delay_ms(5);
    lcd_send_nibble(0x03, 0);
    delay_ms(1);
    lcd_send_nibble(0x03, 0);
    delay_us(100);
    lcd_send_nibble(0x02, 0);
    delay_us(100);
    lcd_send_byte(0x28, 0); // 4位, 2行, 5x8
    delay_us(100);
    lcd_send_byte(0x0C, 0); // 显示开, 光标关
    delay_us(100);
    lcd_send_byte(0x06, 0); // 增量不移屏
    delay_us(100);
    lcd_send_byte(0x01, 0); // 清屏
    delay_ms(2);
}
//---------------------------------------------------------
void lcd_set_cursor(unsigned char col, unsigned char row) {
    unsigned char address = (row == 0) ? 0x80 : 0xC0;
    lcd_send_byte(address + col, 0);
}
//-----------------------------------
void lcd_write_string(char *str) {
    while (*str) {
        lcd_send_byte(*str++, 1);
    }
}
//--------------------------
void display_SJ(unsigned char hour,unsigned char min)//时间显示
{
        unsigned int i;
  unsigned char q[2];
  unsigned char w[2];
  q[0]=hour/10;
  q[1]=hour%10;
  w[0]=min/10;
  w[1]=min%10;           
  lcd_send_byte(Table[q[0]],1);
  lcd_send_byte(Table[q[1]],1);
  if(ptt==1||ON_OFF==1)
    {
      lcd_set_cursor( 13, 0 );
      lcd_write_string(":");//秒闪烁
    }
    else
    {
      lcd_write_string(" ");
    }
  lcd_send_byte(Table[w[0]],1);
  lcd_send_byte(Table[w[1]],1);
               
        if(hour==0&&min==0)//定时到
        {
                  TR1=0;
                  TR0=0;
                  ET1=0;
                  ET0=0;
                  EX0=0;
                  EA=0;
                  triac = 1;    // 关闭脉冲
                        for(i=0;i<400;i++)
                        {
                                FMQ=0;
                                delay_ms(120);
                                FMQ=1;
                               
                                lcd_set_cursor( 13, 0 );
                           lcd_write_string(":");
                               
                          j=V_SetA(0);//设置电流
                          Set_A=j*200./255;
                          k=V_SetA(1);//电压
                          Batt_V=k*200./255;
                          h=Current();//电流
                          Batt_A=h*200./255;
                       
                          lcd_set_cursor(4, 0);
                          process_3(Set_A,Data);
                          display(Data);//设置电流
                       
                          lcd_set_cursor(0, 1);
                          process_3(Batt_V,Data);
                          display(Data);//电压
                       
                          lcd_set_cursor(11, 1);
                          process_3(Batt_A,Data);
                          display(Data);//电流
                        }
                 while(1)
                        {
                                j=V_SetA(0);//设置电流
                          Set_A=j*200./255;
                          k=V_SetA(1);//电压
                          Batt_V=k*200./255;
                          h=Current();//电流
                          Batt_A=h*200./255;
                       
                          lcd_set_cursor(4, 0);
                          process_3(Set_A,Data);
                          display(Data);//设置电流
                       
                          lcd_set_cursor(0, 1);
                          process_3(Batt_V,Data);
                          display(Data);//电压
                       
                          lcd_set_cursor(11, 1);
                          process_3(Batt_A,Data);
                          display(Data);//电流
                        }
        }               
}
//-----------------------------------
void init() {
          IT0 = 1;         // INT0(P3.2)下降沿触发模式
          EX0 = 1;         // 允许INT0中断
       
          TMOD=0x11;
         
          ET0 = 1;         // 允许定时器0中断

          TL1 = (65536-50000)%256;                               
          TH1 = (65536-50000)/256;

          ET1 = 1;
          TF1 = 0;
          EA = 0;
          //    EA = 1;          // 开启总中断
}

/* 主函数 */
void main()
{   
          bit a=0;
          bit b=0;
          bit c=0;
          bit x=0;
          
          unsigned char i;
          unsigned char t;
       
          triac = 1;    // 关闭脉冲
          init();       
          lcd_init();
          
          lcd_set_cursor(4, 0);
          lcd_write_string("Hello!!!");
       
          for(i=0;i<5;i++)
                        {
                                FMQ=0;
                                delay_ms(250);
                                FMQ=1;
                                delay_ms(250);
                        }
       
          if(ON_OFF==0)//开关在启动档
                {
                        lcd_send_byte(0x01, 0); // 清屏
                        while(1)
                        {
                           FMQ=0;
                          lcd_set_cursor(3, 0);
                          lcd_write_string("Error!!!");
                        }
                }

                for(i=0;i<5;i++)
                        {
                          delay_ms(20);
                          k=V_SetA(1);
                        }
                Batt_V=k*200./255;
                if(Batt_V==0)//电池没接或反接
                {
                        lcd_send_byte(0x01, 0); // 清屏
                        while(1)
                        {
                          FMQ=0;
                          lcd_set_cursor(3, 0);
                          lcd_write_string("Error!!!");
                        }
                }   
               
          lcd_send_byte(0x01, 0); // 清屏               
          lcd_set_cursor(0, 0);
          lcd_write_string("Set:");
          lcd_set_cursor(8, 0);
          lcd_write_string("A");//设置电流
          lcd_set_cursor(4, 1);
          lcd_write_string("V");//电压
          lcd_set_cursor(15, 1);
          lcd_write_string("A");//电流
               
    while(1)
                {
                         lcd_set_cursor(4, 0);
                         process_3(Set_A,Data);
                         display(Data);//设置电流       
                       
                         lcd_set_cursor(0, 1);
                         process_3(Batt_V,Data);
                         display(Data);//电压
                       
                         lcd_set_cursor(11, 1);
                         process_3(Batt_A,Data);
                         display(Data);//电流
                       
                         f=V_SetA(0);//设置电流
                         j=f;
                         if(JD==0)j=j;//第一阶段恒流
                         if(JD==1)j=j/2;//第二阶段恒流电流减半
                         if(JD==2);//第三阶段恒压
                         Set_A=j*200./255;
                         k=V_SetA(1);//电压
                         Batt_V=k*300./255;
                         h=Current();//电流
                         Batt_A=h*200./255;
                         
                         if(k==0)//电池开路
                         {
                                 lcd_send_byte(0x01, 0); // 清屏
                           while(1)
                           {
                              TR0=0;
                              ET0=0;
                              EX0=0;
                              EA=0;
                              triac = 1;    // 关闭脉冲
                              FMQ=0;
                              lcd_set_cursor(3, 0);
                              lcd_write_string("Error!!!");
                           }
                   }     
                         
                         if(Batt_A>=200)//20.0A过流
                         {
                                FMQ=0;     
                         }
                         else
                         {
                                 FMQ=1;
                         }
                 
         if(ON_OFF==0)//启动
                 {
                         if(x==0)
                         {
                                 FMQ=0;
                                 delay_ms(250);
                                 FMQ=1;
                                 x=1;
                         }
                   EA=1;
                 if(IS==0)//非定时
                 {
                         if((Batt_V<138)&&a==0)//第一阶段恒流
                         {
                                 a=1;
                                 JD=0;
                         }
                         if(((Batt_V>=138)&&(Batt_V<143))&&b==0)//第二阶段恒流
                         {
                                 b=1;
                                 JD=1;
                         }
                         if((Batt_V>=143)&&c==0)//第三阶段恒压14.3V
                         {
                                 c=1;
                                 JD=2;
                         }
                         
                   switch(JD)
                   {
                           case 0:
                                 z=z+(j-h)*2;//第一阶段恒流
                                 if(z<100)z=100;
                                 if(z>8160)z=8160;
                                 delay_time=10000-z;
                           break;
                         
                           case 1:
                                 z=z+(j-h)*2;//第二阶段恒流
                                 if(z<100)z=100;
                                 if(z>8160)z=8160;
                                 delay_time=10000-z;
                           break;
                         
                           case 2:
                                  z=z+(k-183)*2;//第三阶段恒压14.3V
                                 if(z<100)z=100;
                                 if(z>8160)z=8160;
                                 delay_time=10000-z;
                                 
                                 t++;
                                 if(t==10)FMQ=0;
                                 if(t==11)FMQ=1;
                                 if(t==120)t=0;
                                 
                           break;
                         
                           default:
                           break;
                   }
                  }
                  else  //定时
                        {
                                TR1=1;
                                z=z+(f-h)*2;//恒流
                                if(z<100)z=100;
                                if(z>8160)z=8160;//255*32=8160
                                delay_time=10000-z;
                        //        delay_time=10000-(f*32);
                        }
                }        

                 if(ON_OFF==1)//停止
                 {
                         t=0;
                         x=0;
                         EA=0;
                         triac = 1;    // 关闭脉冲
                         
                         if(IS==1)
                         {
                                 TR1=0;
                         }
                         
                         if(JIA==0)//定时加
       {
         FMQ=0;
         delay_ms(100);
         FMQ=1;
         if(JIA==0)
         {
           hour++;
           if(hour>99)
           {
             hour=99;
           }
          }
          while(JIA==0);
        }
        if(JIAN==0)//定时减
        {
          FMQ=0;
          delay_ms(100);
          FMQ=1;
          if(JIAN==0)
          {
            hour--;
            if(hour<1)
            {
              hour=1;
            }
           }
           while(JIAN==0);
          }
                                 
         if(MODE==0)//模式
         {
            FMQ=0;
            delay_ms(100);
            FMQ=1;
            if(MODE==0)
            {
              IS++;
              while(MODE==0);
              if(IS>1)
              {
                IS=0;
              }
             }
          }
         }
                 
                 if(IS==0)
                 {
                         lcd_set_cursor(11, 0);
                         lcd_write_string("--:--");
                 }
                 if(IS==1)
                 {
                         lcd_set_cursor(11, 0);
                         display_SJ(hour,min);//时间
                 }
     }
}

/* INT0中断服务函数 */
void int0_isr() interrupt 0
{
    TR0 = 0;         // 停止定时器0
    // 计算定时器初值(12MHz晶振,1us计数)
    TH0 = (65536 - delay_time) /256;  // 高字节
    TL0 = (65536 - delay_time) %256;// 低字节
    TR0 = 1;         // 启动定时器0      
}

/* 定时器0中断服务函数 */
void timer0_isr() interrupt 1
{
          static unsigned char i;
    TR0 = 0;         // 停止定时器0
    triac = 0;       // 触发可控硅     
    // 短暂延时确保触发(约10us,根据实际需求调整)
    for(i = 0; i < 10; i++); // 粗略延时
    triac = 1;       // 关闭脉冲

}

/* 定时器1中断服务函数 */
void timer1(void) interrupt 3
{
      TL1 = 0xB0;                               
      TH1 = 0x3C;                               
      TF1 = 0;                       
      count++;     
      if(count==20)
        {
          count=0;
          miao--;
          ptt=~ptt;
          if(miao<0)
            {
               miao=59;
               min--;
               if(min<0)
                 {
                   min=59;
                   hour--;
                   if(hour<0)
                     {
                       hour=0;
                     }
                 }
            }
        }
}

2345截图20250627164926.png (74.8 KB, 下载次数: 0)

2345截图20250627164926.png

IMG_20250627_164031.jpg (1.98 MB, 下载次数: 0)

IMG_20250627_164031.jpg

评分

参与人数 2黑币 +60 收起 理由
waerdeng + 10 共享资料的奖励!
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏3 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:106060 发表于 2025-6-30 20:33 | 只看该作者
做的不错。不过是为了充分利用老物件,不然现在的单片机内部都自带了10位的ADC的。硬件就不用这么复杂了。
回复

使用道具 举报

板凳
ID:1136941 发表于 2025-7-1 09:59 | 只看该作者
算法错误更正为:
   case 2:
      //      z=z+(k-183)*2;//第三阶段恒压14.3V
            z=z+(183-k)*2;//第三阶段恒压14.3V
            if(z<100)z=100;
            if(z>8160)z=8160;
            delay_time=10000-z;
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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