您的位置:首页 > 其它

智能型磷酸铁锂电池快速充电控制器设计

2013-08-19 17:44 260 查看
 

先给整体设计框图:

 



 

废话不多说了,

程序框图:



 

源码:

/************************************
*********STC89C51**********
**********12MHz晶振********/

#include "reg51.h"

#define uint8 unsigned char
#define uint16 unsigned int
#define uchar unsigned char
#define uint unsigned int

/********************寄存器内部地址定义********************/
sfr P2M0 = 0x96;
sfr P2M1 = 0x95;
sfr P1M0 = 0x92;
sfr P1M1 = 0x91;

sfr ADC_CONTR = 0xBC;
sfr ADC_RES   = 0xBD;
sfr ADC_RESL  = 0xBE;
sfr P1ASF     = 0x9D;

sfr CCON     = 0xD8; //PCA控制寄存器
sfr CMOD     = 0xD9; //PCA模式寄存器
sfr CCAPM0   = 0xDA; //PCA模块0模式寄存器 //模块0对应P1.3/CEX0/PCA0/PWM0(STC12C5A60S2系列)
sfr CCAPM1   = 0xDB; //PCA模块1模式寄存器 //模块1对应P1.4/CEX1/PCA1/PWM1(STC12C5A60S2系列)
sfr CL       = 0xE9;    //PCA 定时寄存器 低位
sfr CH       = 0xF9; //PCA 定时寄存器 高位
sfr CCAP0L   = 0xEA; //PCA模块0的 捕获寄存器 低位
sfr CCAP0H   = 0xFA;    //PCA模块0的 捕获寄存器 高位
sfr CCAP1L   = 0xEB; //PCA模块1的 捕获寄存器 低位
sfr CCAP1H   = 0xFB; //PCA模块1的 捕获寄存器 高位
sfr PCA_PWM0 = 0xF2; //PCA PWM 模式辅助寄存器0
sfr PCA_PWM1 = 0xF3; //PCA PWM 模式辅助寄存器1
sbit CF   = CCON^7;     //PCA计数溢出标志位
sbit CR   = 0xDE;     //PCA计数器 运行控制位
sbit CCF1 = CCON^1;     //PCA模块1中断标志
sbit CCF0 = CCON^0;     //PCA模块0中断标志
/************************************************************/

#define TIMER0_HIGHT 0xE5	//设置定时器0工作方式1自动装载初值,定时5ms,Fosc=12MHZ
#define TIMER0_LOW   0xF3

#define LCD_Data P0           //LCD的数据口
sbit    LCD_BF=LCD_Data^7;    //LCD忙信号位
sbit    LCD_RS=P2^6;
sbit    LCD_RW=P2^5;
sbit    LCD_EN=P2^4;
sbit    BEEP=P2^3;//控制喇叭
sbit    RED=P2^1;//控制红灯
sbit    YELLOW=P2^0;//控制黄灯
sbit    OPEN=P2^2;//控制继电器

unsigned int  I_DATA=0;
unsigned int  V_DATA=0;
unsigned char Time5ms=0;

unsigned char tp=0;
unsigned int  ad_average_result,R,Vin;
unsigned char Start=0;
unsigned char D2=0;
unsigned char D1=0;
unsigned int  U_SET=370;

unsigned int  I_D[3];

unsigned char Ms_flag=0;

/*-------------------延时子函数-------------------------*/
#define XTAL 16                       //晶振频率,单位MHz
void delay_1us(void)                 //1us延时函数
{
// a_nop_();
}

void delay_nus(unsigned int n)       //N us延时函数
{
unsigned int i=0;
for (i=0;i<n;i++)
delay_1us();
}

void delay_1ms(void)                 //1ms延时函数
{
unsigned int i;
for (i=0;i<(unsigned int)(XTAL*143-2);i++);
}

void delay_nms(unsigned int n)       //N ms延时函数
{
unsigned int i=0;
for (i=0;i<n;i++)
{
delay_1ms();
}
}

//---------------------------------------------------

#define LCD_GO_HOME               0x02         //AC=0,光标、画面回HOME位

//输入方式设置
#define LCD_AC_AUTO_INCREMENT     0x06         //数据读、写操作后,AC自动增一
#define LCD_AC_AUTO_DECREASE      0x04         //数据读、写操作后,AC自动减一
#define LCD_MOVE_ENABLE           0x05         //数据读、写操作,画面平移
#define LCD_MOVE_DISENABLE        0x04         //数据读、写操作,画面不动

//设置显示、光标及闪烁开、关
#define LCD_DISPLAY_ON            0x0C         //显示开
#define LCD_DISPLAY_OFF           0x08         //显示关
#define LCD_CURSOR_ON             0x0A         //光标显示
#define LCD_CURSOR_OFF            0x08         //光标不显示
#define LCD_CURSOR_BLINK_ON       0x09         //光标闪烁
#define LCD_CURSOR_BLINK_OFF      0x08         //光标不闪烁

//光标、画面移动,不影响DDRAM
#define LCD_LEFT_MOVE             0x18         //LCD显示左移一位
#define LCD_RIGHT_MOVE            0x1C         //LCD显示右移一位
#define LCD_CURSOR_LEFT_MOVE      0x10         //光标左移一位
#define LCD_CURSOR_RIGHT_MOVE     0x14         //光标右移一位

//工作方式设置
#define LCD_DISPLAY_DOUBLE_LINE   0x38         //两行显示
#define LCD_DISPLAY_SINGLE_LINE   0x30         //单行显示
/*定义子程序*/
void LCD_ClrAll(void);              //清屏
void Judge_LCD_busy(void);           //检测是否忙碌
void LCD_Write(uchar WriteData);     //写控制字
void LCD_write_data(uchar LCD_data); //写数据显示
void LCD_cursor(uchar x);    //光标起始地址
void LCD_printc(unsigned char lcd_data) ;  //输出一个字符
void LCD_prints(unsigned char *lcd_string);//输出字符串

/*LCD1602忙碌判断子程序*/
void Judge_LCD_busy(void)   //判断LCD1602是否忙状态
{
while(1)
{
LCD_EN=0;
LCD_RS=0;
LCD_RW=1;
LCD_Data=0xff;
LCD_EN=1;   //EN 是 1—0 使能
if(!LCD_BF)break; //LCD_BF=1表示忙碌,需要等待。
}
LCD_EN=0;
}
/******LCD清屏***************/
void LCD_ClrAll(void)
{

Judge_LCD_busy();   //判断是否忙碌
LCD_RS=0;
LCD_RW=0;
LCD_Data=0x01;
LCD_EN=1;
LCD_EN=0;

}
/*******LCD写数据定义各种模式*********/
void LCD_Write(uchar WriteData)   //写指令到LCD
{
Judge_LCD_busy();
LCD_RS=0;
LCD_RW=0;

LCD_Data=WriteData; //把WriteData的数据送到数据口
LCD_EN=1;
LCD_EN=0;
}
/********LCD显示数据***********/
void LCD_write_data(uchar LCD_data)      //输出一个字节数据到LCD
{
Judge_LCD_busy();
LCD_RS=1;
LCD_RW=0;

LCD_Data=LCD_data;
LCD_EN=1;
LCD_EN=0;
}
/****光标位置的确定***/
void LCD_cursor(uchar x)            //LCD光标定位到x处
{
LCD_Write(0x80+x);                       //第一行地址是0x80

}
/*输出一个字符*/
void LCD_printc(unsigned char lcd_data)
{
LCD_write_data(lcd_data);
}

/*输出字符串*/
void LCD_prints(unsigned char *lcd_string)
{
unsigned char i=0;
while(lcd_string[i]!=0x00)
{
LCD_write_data(lcd_string[i]);
i++;
}
}

/*初始化程序*/
void LCD_initial(void)                        //初始化LCD
{
LCD_Write(LCD_AC_AUTO_INCREMENT|LCD_MOVE_DISENABLE);
LCD_Write(LCD_DISPLAY_ON|LCD_CURSOR_OFF);
LCD_Write(LCD_DISPLAY_DOUBLE_LINE);
LCD_ClrAll();
}
//---------------------------AD模块程序----------------------

void ADC_Power_On()      //AD转换电
{
ADC_CONTR|=0x80;
delay_nms(5);     //必要的延时
}

void get_ad_result_P1_7() //取AD结果函数,它是十位AD转换,每十次平均,最后取低八位作为AD采样数据
{

tp=0;
ADC_RES=0;     //高八位数据清零,STC12C5A60S2 AD数据寄存名与STC12C54××系列不同
ADC_RESL=0;    //低两位清零
ADC_CONTR|=0x08; //启动AD转换
while(!tp)     //判断AD转换是否完成
{
tp=0x10;
tp&=ADC_CONTR;
}
ADC_CONTR&=0xe7;
ad_average_result=ADC_RES*4+ADC_RESL;

ad_average_result=(float)(ad_average_result/2.074);
V_DATA=ad_average_result;
}

void get_ad_result_P1_6() //取AD结果函数,它是十位AD转换,每十次平均,最后取低八位作为AD采样数据
{

tp=0;
ADC_RES=0;     //高八位数据清零,STC12C5A60S2 AD数据寄存名与STC12C54××系列不同
ADC_RESL=0;    //低两位清零
ADC_CONTR|=0x08; //启动AD转换
while(!tp)     //判断AD转换是否完成
{
tp=0x10;
tp&=ADC_CONTR;
}
ADC_CONTR&=0xe6;
ad_average_result=ADC_RES*4+ADC_RESL;

ad_average_result=ad_average_result*1.011;
I_DATA=ad_average_result;
}
//---------------------电压采样程序---------------------------
void caiyangP1_7()     //测电压
{
ADC_CONTR=0xE7;   //设置P1.7为输入AD转换口/电压
delay_nms(5);
get_ad_result_P1_7();        //取转换数据
Vin=ad_average_result;

}

//---------------------电流采样程序---------------------------
void caiyangP1_6()     //测电压
{
ADC_CONTR=0xE6;   //设置P1.7为输入AD转换口/电压
delay_nms(5);
get_ad_result_P1_6();        //取转换数据
Vin=ad_average_result;

}

void  Value_to_ASCII_U(unsigned int value,uchar add)
{
unsigned char temp[] = "U=0.00V";

temp[2] = value/100 +0x30;
value = value%100;
temp[4] = value/10 + 0x30;
value = value%10;
temp[5] = value + 0x30;

LCD_cursor(add);   //光标起始地址 ,第一行地址是0x00~0x0F,第二行地址是0x40~0x4f
LCD_prints(temp);
}

void  Value_to_ASCII_I(unsigned int value,uchar add)
{
unsigned char temp[] = "I=0000ma";
temp[2] = value/1000 + 0x30;//数字转换成字符型
value = value%1000;
temp[3] = value/100 +0x30;
value = value%100;
temp[4] = value/10 + 0x30;
value = value%10;
temp[5] = value + 0x30;
LCD_cursor(add);   //光标起始地址 ,第一行地址是0x00~0x0F,第二行地址是0x40~0x4f
LCD_prints(temp);
}

//分显示
void  Value_to_ASCII_min(unsigned int value)
{
unsigned char temp[] = "000";
temp[0] = value/100 +0x30;
value = value%100;
temp[1] = value/10 + 0x30;
value = value%10;
temp[2] = value + 0x30;
LCD_cursor(0x07);//写地址
LCD_prints(temp);
}
//秒显示
void  Value_to_ASCII_SEC(unsigned int value)
{
unsigned char temp[] = "00";
temp[0] = value/10 + 0x30;
value = value%10;
temp[1] = value + 0x30;
LCD_cursor(0x0B);//写地址
LCD_prints(temp);
}
//------------------充电检测------------------------

void  Change(void){

if(Start==1)  {

if(V_DATA<300){//电压低于3V,涓流充电
CCAP0H=230;}
else{
CCAP0H=62;
}

if(I_DATA>11){RED=1;YELLOW=0;}//开始充电
if(I_DATA<10&&V_DATA>365){//表示充满

RED=0;YELLOW=1;OPEN=1;//报警,开启继电器
BEEP=0;

}

if(V_DATA<20&&I_DATA==0){BEEP=1;Start=0;OPEN=1;RED=0;YELLOW=1;}//电流=0,电压小于0.2V表示电池已经拔掉
}

}

//--------------------主程序--------------------------------
void main()
{

//------------------P1口配置---------------
P1M0=0X18;
P1M1=0XE7;
//------------------PWM配置---------------
CMOD=0X0E;      //f=7.8Khz
CL=0;
CH=0;

CCAPM1=0X42;
CCAPM0=0X42;

CCAP1H=124-(float)((U_SET-420)/3.2);//设置电压PWM

CCAP0H=62;//设置电流PWM

CR=1;

//------------------AD配置---------------
ADC_Power_On();      //AD转换电

//---------------中断配置----------------
TMOD &= 0xF0;
TMOD |= 0x01;		//设置定时器0,方式1:16位定时器
TH0 = TIMER0_HIGHT;	//设置定时器0高字节初值
TL0 = TIMER0_LOW;	//设置定时器0低字节初值
TR0 = 1;			//启动定时器0
ET0 = 1;			//开定时器0中断
EA = 1;         	//开总中断
//---------------------------------------

RED=0;
YELLOW=1;
BEEP=1;
Start=0;//关闭充电
LCD_initial();

LCD_cursor(0x00);//写地址

LCD_prints("Battery Charger ");

LCD_cursor(0x40);//写地址

LCD_prints("I=     ");

LCD_cursor(0x49);//写地址

LCD_prints("U=     ");

EA = 1;  //使能全局中断

while(1)
{

//按键检测------------------
if((P1&0x01)==0x00){
delay_nms(10);
if((P1&0x01)==0x00){

Start=!Start;
if(Start==1){
caiyangP1_7();

OPEN=0;//开启继电器
CCAP0H=230;
delay_nms(200);//延时
caiyangP1_6();
caiyangP1_7();
delay_nms(200);
caiyangP1_6();
caiyangP1_7();
delay_nms(200);
caiyangP1_6();
caiyangP1_7();
delay_nms(200);
caiyangP1_6();
caiyangP1_7();
delay_nms(200);
caiyangP1_6();
caiyangP1_7();

}else{OPEN=1;RED=0;YELLOW=1;BEEP=1;}

while((P1&0x01)==0x00);//等待按键释放

}
}

if(Ms_flag){//查询中断标志
Ms_flag=0;

D1++;

caiyangP1_6();//AD
caiyangP1_7();//AD

I_D[1]= I_D[1]+I_DATA;//求和
I_D[2]= I_D[2]+V_DATA;
if(D1==20){

I_DATA=I_D[1]/20;//求平均
V_DATA=I_D[2]/20;
I_D[1]=0;I_D[2]=0;
D1=0;

Value_to_ASCII_I(I_DATA,0x40);//更新液晶显示电流值
Value_to_ASCII_U(V_DATA,0x49);//更新液晶显示电压值

}
D2++;
if(D2==5){
D2=0;
Change();//充电检测
}

}

}

}

/********************************************************************
函数功能:定时器/计数器0中断处理
入口参数:null
返    回:null
备    注:null
********************************************************************/
void Timer0IntProc() interrupt 1
{
TH0 = TIMER0_HIGHT;	//设置定时器0高字节初值
TL0 = TIMER0_LOW;	//设置定时器0低字节初值

Time5ms++;
if(Time5ms==10){Ms_flag=1;Time5ms=0;}

}


 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: