智能型磷酸铁锂电池快速充电控制器设计
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;} }
相关文章推荐
- 东芝光耦TLP521-1智能型双电源开关控制器设计的实现
- USB Type-C设计,快速充电使用电源---凯利讯半导体
- 请教电源切换电路,直流输入和锂电池之间切换如何设计最好。另请推荐2节锂电池的充电
- Linux 2.6 驱动设计快速入门
- 快速JavaEE轻量级框架&公用业务模块 设计&实现 7 - WEB MVC设计
- 基于AMBA-AHB总线的SDRAM控制器设计方案
- 基于ARM控制器的渗炭炉温度控制系统的设计
- 学会三个范式快速成为数据库设计
- 架构设计:系统间通信(36)——Apache Camel快速入门(上)
- Silverlight企业应用快速开发平台框架设计(二)分析-平台实现重点是什么,要怎么做?
- TWIG 模板设计 快速入门手册 中文
- Linux 2.6 驱动设计快速入门
- 大数据量快速处理的架构设计
- JavaBean——四舍五入(保留一定的小数),MVC设计模式,EL表达式和JSTL标签快速入门,软件三层架构设计
- Material Design 设计师分享如何快速入门 UX 设计 | Google Play 开发者 FAQ 特别篇
- Unity3D快速实现UI架构设计一
- Axure RP 快速原型设计工具
- LINQ快速开发设计最佳实践(二) 构建Model模型
- ASP.NET MVC快速开发框架清新简洁界面设计,有兴趣可以模仿参考
- QT -- 快速设计对话框1