基于STC12C5A60S2可编程智能充电器找寻HEX
本帖最后由 SengChuary 于 2013-1-8 18:03 编辑以下是网上找的资料,想DIY一个,一直没有找到HEX文件,有谁知道帮忙提供一下吗,本来想自己写,自己单片机能力有限,望大家知道的帮忙提供一下,再此感谢了
制作一个智能充电器,实时显示充电电压和电流,“充电”指示,可设定充电参数,最高充电电压和最大充电电流, 电压范围1V到13V,电流范围0.5A到2.5A,充电过程按“涓流”“恒流”“恒压”模式。
一个比较完善的充电器应该能完成以下三个步骤:
(1) 涓流充电
(2) 恒流充电
(3) 恒压充电
首先要检测电池的电压是否低于2.7V,当电池的电压低于2.7V的时候就要进行涓流充电,不能灌以大电流。有一个很形象的比喻就是不能给一个饿的快不行的人大鱼大肉的吃,那样会吃出问题的。电池也一样,当电快耗尽了,就不能猛的进行充电,要进行涓流补充,一般都是以100mA的电流充10分钟左右。这个阶段过了以后就可以放心大胆的给电池进行灌电流了,但前提条件是电池两端的电压不能高于4.2V。恒流充电的电流一般在你电池容量的0.2—1.5倍。我测试过我的诺基亚手机充电器,充电电流大约是300个mA,充电时间比较长,但是充电很稳定,这或许就是别人做的比较好的原因吧。市面上买的那种万能充一般都是用灌大电流的方式来缩短充电的时间,殊不知这样做严重损害了电池,所以很多同学抱怨那种万能充把电池给充鼓了。那就是劣质产品带来的后果啊,为了使你的手机电池寿命更长一点,我建议还是用手机原装的充电器充电吧。恒流充电到一定的过程时,电压就会接近4.2V的极限位置,此时就换恒压充电,一般还是用4.2V来充,但是电流会慢慢的下降,当电流下降到100mA以下就可以认为电池已经充满了,充电过程可以结束了。
上述分析已经把充电过程解释的很详细了。还需要补充的一点是,我们所用电池的里面其实还有一块保护电路,当充电电压超过里面的保护电压时,内部电路自动断开,外面就无法继续进行充电。当检测外部电压低于保护电压时,内部电路又会自动接通,外部电路又可以对其充电了。
原理图:
PCB:
先提供一个从其它地方收集的基于STC万能充电器源码供大家参考
//---------------------------------------------------------------------
//#include <REG52.H>
#include <intrins.H>
#include "NEW_8051.H"
//WDT_CONTR//狗
//---------------------------------------------------------------------
typedef unsigned char INT8U;
typedef unsigned int INT16U;
//定义常量
//pulse_width_MAX = pulse_width_MIN时, 输出脉冲宽度不变。
#define pulse_width_MAX0x65 //PWM 脉宽最大值, 占空比 =75%
#define pulse_width_MIN0x45 //PWM 脉宽最小值, 占空比 =25%
//#define step 0x38 //PWM 脉宽变化步长
#define pulse_width0x30H
#define ADC_Power_On_Speed_Channel_0 0xE0 //P1.0 作为 A/D 输入
#define ADC_Power_On_Speed_Channel_1 0xE1 //P1.1 作为 A/D 输入
#define ADC_Power_On_Speed_Channel_2 0xE2 //P1.2 作为 A/D 输入
#define ADC_Power_On_Speed_Channel_3 0xE3 //P1.3 作为 A/D 输入
#define ADC_Power_On_Speed_Channel_4 0xE4 //P1.4 作为 A/D 输入
#define ADC_Power_On_Speed_Channel_5 0xE5 //P1.5 作为 A/D 输入
#define ADC_Power_On_Speed_Channel_6 0xE6 //P1.6 作为 A/D 输入
#define ADC_Power_On_Speed_Channel_7 0xE7 //P1.7 作为 A/D 输入
sbit B_LED = P3^4;//
sbit B_LED2 = P1^4;
sbit B_ON = P3^5;
sbit B_PW = P3^7;
INT8U con_state,ADC_Channel_2_Result_date,T_N;
INT16UAD_date,S_N;
//#define ADC_YUCHONGDIAN 0x39 //1.12V,6V
//#define ADC_YUCHONGDIAN_0 0x3E //1.21,6.4V
//#define ADC_JIESHU 0x51 //1.58,8.4V
//#define ADC_YUCHONGDIAN 0x4D //1.51V,8V
//#define ADC_YUCHONGDIAN_0 0x55 //1.65,8.8V
//#define ADC_JIESHU 0x74 //2.26,12V
//#define ADC_KONG 0x8D //2.82,15V
//#define ADC_DUANLU 0x30
//#define ADC_YUCHONGDIAN 0x40 //1.12V,6V
//#define ADC_YUCHONGDIAN_0 0x44 //1.21,6.4V
//#define ADC_JIESHU 0x58 //1.58,8.4V
#define ADC_21 0x89 //21V
#define ADC_24 0x9c //24V
#define ADC_27 0xB0 //27V
#define ADC_28 0xB7 //28V
#define ADC_KONG 0xC8 //2.82,15V
#define ADC_DUANLU 0x30
#define ADC_135 0x58 //21V
#define ADC_13 0x54 //0.153,21V
/***********************
init port
***********************/
void INITAL_port(void)
{
P0=0xff;
P1=0xff;
P2=0xff;
P3=0xff;
}
/***********************
init PCA
************************/
void initiate_pca (void);
void delay(INT8U delay_time) // 延时函数
{
INT16U n;
while(delay_time--)
{
n = 6000;
while(--n);
}
}
/***********************
init AD
************************/
//--------------------------------------------------------------
void ADC_Power_On(void)
{
ADC_CONTR|=0x80; //开 A/D 转换电源
delay(20); //开 A/D 转换电源后要加延时,1mS 以内就足够了
}
void Set_P12_Open_Drain(void) //设置 P1.2,设置 A/D 通道所在的 I/O 为开漏模式
{
P1M0|=0x4;
P1M1|=0x4;
}
void Set_ADC_Channel_2(void)
{
ADC_CONTR=ADC_Power_On_Speed_Channel_2;
//选择 P1.2 作为 A/D 转换通道
//更换 A/D 转换通道后要适当延时, 使输入电压稳定
//以后如果不更换 A/D 转换通道的话, 不需要加延时
delay(5); //切换 A/D 转换通道,加延时 20uS~200uS 就可以了,与输入电压源的内阻有关
//如果输入电压信号源的内阻在 10K 以下,可不加延时
}
void initiate_AD (void)
{
ADC_Power_On (); //开 ADC 电源, 第一次使用时要打开内部模拟电源 ;开 ADC 电源, 可适当加延时,1mS 以内就足够了
Set_P12_Open_Drain (); //设置 P1.2 为开漏
Set_ADC_Channel_2(); //设置 P1.2 作为 A/D 转换通道
}
//----------------------------------------------------------
INT8U Get_AD_Result(void)
{
ADC_DATA=0;
//ADC_CONTR = AD_SPEED;
//ADC_CONTR = 0xE0; //1110,0000 清 ADC_FLAG, ADC_START 位和低 3 位
//ADC_CONTR |= channel; //选择 A/D 当前通道
Set_ADC_Channel_2();
delay(1);
ADC_CONTR|= 0x08; //启动 AD 转换
//判断 AD 转换是否完成
while (1) //等待A/D转换结束
{
if (ADC_CONTR & 0x10) //0001,0000 测试A/D转换结束否
{ break; }
}
ADC_CONTR&=0xE7; //清 0 ADC_FLAG, ADC_START 位, 停止 A/D 转换
return ADC_DATA;
}
//---------------------------------------------------------------------
void Send_Byte(INT8U one_byte) //发送一个字节
{
TI = 0; //清零串口发送中断标志
SBUF = one_byte;
while (TI == 0);
TI = 0; //清零串口发送中断标志
}
//------------------------------------------------------------
void timer_start(void)
{
ET0 =1;
TR0 =1;
}
void timer_stop(void)
{
ET0 =0;
TR0 =0;
}
//------------------------------------------------------------
void PWM (INT8U width)
{
CCAP0H=width; // 示例程序核心语句
PCA_PWM0=0x00; //示例程序核心语句P3.7
PCA_PWM1=0x03;
delay(5);
}
void pwm_stop(void)
{
PCA_PWM0=0x03;//释放本行注释,PWM输出就一直是0,无脉冲;-------------------------
PCA_PWM1=0x03;
delay(250);
}
//------------------------------------------------------------
void initiate_RS232 (void) //串口初始化
{
SCON = 0x50; //可变波特率. 8位无奇偶校验
TMOD = 0x21;
TH1= 0xe7;//5.8mhz 600/s
TL1 = 0xe7;
AUXR &= 0xBF;
TR1=1;
ES = 0; //禁止串口中断
}
//---------------------------------------------------------------------
void initiate_pca (void)
{
CMOD=0x82;
//PCA 在空闲模式下停止 PCA 计数器工作 ;PCA 时钟模式为fosc/12
//禁止 PCA 计数器溢出中断
CCON=0x00; //禁止 PCA 计数器工作, 清除中断标志、计数器溢出标志
CL=0x00; //清 0 计数器
CH=0x00;
//设置模块 0 为 8 位 PWM 输出模式, PWM 无需中断支持。脉冲在 P3.7(第 11 脚)输出
CCAPM0 =0x42; //示例程序核心语句 0100,0010
//PCA_PWM0=0x00H;//示例程序核心语句P3.7;
PCA_PWM0=0x03; //释放本行注释,PWM输出就一直是0,无脉冲;-------------------------
//设置模块 1 为 8 位 PWM 输出模式, PWM 无需中断支持。脉冲在 P3.5(第 9 脚)输出
//CCAPM1=0x42; //示例程序核心语句 0100,0010
//PCA_PWM1=0x00;//示例程序核心语句 P3.5
//PCA_PWM1=0x03; //释放本行注释, PWM 输出就一直是 0, 无脉冲。
//B_MO_1=0;
EPCA_LVD=1; //开pca中断
EA=1;
CR=1; //将 PCA 计数器打开
}
//---------------------------------------------------------------------
//**********************************************
void Initial_T0(void)
{
TH0=0x4C ;//设置定时器0 自动重装数 11M
TL0=0x00 ;//500uS
//AUXR&=0xBF; //定时器1 工作在12T 模式,与普通的8051 相同
ET0=0;
TR0=0; //启动定时器1
}
void timer_init(void)
{
TH0=0x4C ;//设置定时器0 自动重装数 11M
TL0=0x00 ;//50MS
ET0=1;
TR0=1;
}
//---------------------------------------
void con (void)
{
AD_date=AD_date+Get_AD_Result();
AD_date=AD_date>>1;
if (AD_date<ADC_DUANLU)
{
con_state=4;
}
switch(con_state)
{
case 0:
if (AD_date < ADC_21)
{
S_N=60000;
PWM(pulse_width_MAX) ;//为输出脉冲宽度设置初值。
timer_init();
con_state=1;
}
else
{
if (AD_date<ADC_28)
con_state=2;
}
break;
case 1:
if (AD_date>ADC_21)
{
con_state=2;
}
if (S_N==0)
{
con_state=2;
}
break;
case 2:
S_N=60000;
PWM(pulse_width_MAX) ;//为输出脉冲宽度设置初值。
timer_init();
con_state=3;
break;
case 3:
if(AD_date>ADC_28)
{
con_state=4;
}
if (S_N==0)
{
con_state=4;
}
break;
case 4://如果没有电池或者在很长一段时间后重新启动初始化
pwm_stop();
TR0=0;
ET0=0;
con_state=5;
B_LED=0;
B_LED2=0;
break;
case 5://如果没有电池或者在很长一段时间后重新启动初始化
if (AD_date>ADC_KONG)
{
con_state=0;
B_LED=1;
B_LED2=1;
}
break;
default:
break;
}
}
//---------------------------------------
void timer0(void) interrupt 1
{
INT8U ACC_temp;
ACC_temp= ACC;
TR0=0;
if(S_N!=0)
{
S_N--;
}
if(T_N==0&con_state!=5)
{
B_LED=~B_LED;
B_LED2=~B_LED2;
T_N=10;
}
T_N--;
timer_init();
ACC= ACC_temp;
}
//------------------------------------------------------------
void serial()interrupt 4
{ INT8U ACC_temp;
if(RI==0)
TI=0;
else
{
RI=0;
ES=0;
ACC_temp=ACC ;
//RS_do(SBUF);
ACC=ACC_temp ;
ES=1;
}
}
//---------------------------------------------------------------------
void main()
{ INT8U n;
INITAL_port();
T_N=0;
B_PW= 0 ;
n=0;
initiate_pca();
initiate_RS232(); //波特率 = 600
initial_T0();
//Send_Byte(0xAA); //为便于观察, 发送 2 个 0xAA
B_LED=0;
B_LED2=0;
delay(0x250);
B_LED=1;
B_LED2=1;
initiate_AD();
ES=1;
con_state=0;
AD_date=Get_AD_Result();
//Send_Byte(AD_date);
while(1)
{
con();
WDT_CONTR=0x3f; //看门狗
if(n>10)
{
Send_Byte(AD_date);
n=0;
}
n++;
}
}
硬件电路图看的我眼都花了,如果可以改下颜色,帮顶下 bbssilverkey 发表于 2013-1-8 14:46 static/image/common/back.gif
硬件电路图看的我眼都花了,如果可以改下颜色,帮顶下
不好意思可能图片原因没处理好,已经更新。 本人初学者,楼主解析一下原理图。 能上一份PCB吗?要Protel的,帮顶。
页:
[1]