最近发帖比较频繁,前一段时间开源了一个智能小车,小车需要锂电池供电,家里一大堆电池,当使用的时候才发现好久没有容量大减,正好最近在研究labview,所以就做了1个来测试一下电池容量,其实原理非常简单,用单片机就能轻松搞定,为了高大上而且能为了能看到电池充电和放电的曲线所以就需要上位软件了,第一次用labview编程程序写的非常烂高手见谅了功能:上位机 labview 负责采集数据计时显示设置充放电截止电压和电池曲线图下位机 stc125a60s2 负责ad检测电压电流串口通信
由于手底下没有mos管所以暂时使用317进行横流放电充电采用锂电池专用模块通信 串口发送字符串检测电压电流 Work_v_ad充电 Work_v_cd放电 Work_v_fd关闭 Work_voff 电脑和单片机通信采用一个usb ttl下载器进行ad采集为了准确,采用Tl431做标准基准源,还算比较准确的
由于临时电路做的比较粗糙
暂时还没想到其他功能,留了一些地方准备扩展用
洞洞板后面有点乱
在电路板上面加一个手动按钮,方便在没电脑的情况下充放电
由于没找到0.1欧姆电阻,只能使用10个1欧姆电阻并联
上位机界面充电曲线 蓝色为电压,红色为电流
开始放电
放电根据自己设定的截止电压检测,我设置的是3v为了以防万一电池上面我加了保护板,由于手头没有热敏电阻所以暂时没加电池容量随时计算10s检测一次电压和电流1分钟上传图表一次
第一次写labview写的很差,我用手机发的帖子,不能上传附件有需要的可以找我要
图表可以到处还是比较方便的
程序贴底下了 供大家参考
#include<stc12c5a60s2.h>#include"stdio.h"#include"intrins.h"
#define uint unsigned int#define uchar unsigned char
sbit v_cd=P2^0;sbit v_fd=P2^1;sbit key=P2^2;
int volt,curr;uchar key_flag=0;uchar num;uchar shi,ge,xiao1,xiao2;uchar s,g,x1,x2;uchar data table[12]; //暂存数组,可以将10改为你需要的数值uint i=0;uchar code table1[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39};bit com_flag;
void AD_init();unsigned int AD_get(unsigned char channel);float AD_work(unsigned char channel);void delayms(uint z);void delay(unsigned int a); //延时约1msvoid UART_init(void); //初始化函数void senddata(uchar dat);void uart_sendstring(uchar *upStr);
void delayms(uint z){ uint x,y; for(x=z;x>0;x--) for(y=110;y>0;y--);}
/**********************************************************/
void UART_init(void) //初始化函数{ SCON = 0x50; TMOD = 0x20; TH1 = 0xFD; //波特率9600 TL1 = 0xFD; TR1 = 1; ES = 1; EA = 1;// TI =0;// REN = 1;
}/**********************************************************/
void senddata(uchar dat){
ES = 0; //关串口中断 TI = 0; //将串口发送完成中断请求标志清零 SBUF = dat; //写数据到发送缓冲区 while(!TI); //等待发送完成 TI = 0; //将串口发送完成中断请求标志清零 ES = 1; //将串口发送完成中断请求标志清零}/* ***************************************************** */
// 函数名称:UART_SendString()// 函数功能:发送字符串// 入口参数:待发送的字符串(*upStr)// 出口参数:无/* ***************************************************** */void uart_sendstring(uchar *upStr){ while(*upStr) // 检测是否发送完毕 { senddata(*upStr++); // 调用UART_SendOneByte函数一个字节一个字节发送数据 }}/* ***************************************************** */
void delay(unsigned int a) //延时约1ms{ unsigned int i; while (--a!=0) for(i=600;i>0;i--); //1T单片机i=600,若是12T单片机i=125}
void AD_init(){ P1ASF=0xff; //P1口全部作为模拟功能AD使用 ADC_RES=0; //清零转换结果寄存器高8位 ADC_RESL=0; //清零转换结果寄存器低2位 ADC_CONTR=0x80;//开启AD电源 delay(2); //等待1ms,让AD电源稳定}
unsigned int AD_get(unsigned char channel){ ADC_CONTR=0x88|channel; //开启AD转换1000 1000 即POWER SPEED1 SPEED0 ADC_FLAG ADC_START CHS2 CHS1 CHS0 _nop_(); _nop_(); _nop_(); _nop_();//要经过4个CPU时钟的延时,其值才能够保证被设置进ADC_CONTR 寄存器 while(!(ADC_CONTR&0x10)); //等待转换完成 ADC_CONTR&=0xe7; //关闭AD转换,ADC_FLAG位由软件清0 return(ADC_RES*4+ADC_RESL); //返回AD转换完成的10位数据(16进制)}
void keysean(){ if(key==0) { delay(10); if(key==0) { key_flag++; if(key_flag>2) key_flag=0; } while(!key); } if(key_flag==0) { v_fd=1; v_cd=1; } if(key_flag==1) { v_fd=1; v_cd=0; } if(key_flag==2) { v_cd=1; v_fd=0; } } // float AD_work(unsigned char channel)// {// float AD_val; //定义处理后的数值AD_val为浮点数// unsigned char i;// for(i=0;i<100;i++) // AD_val+=AD_get(channel); //转换100次求平均值(提高精度)// AD_val/=100;// // AD_val=(AD_val*2.5)/1024; //AD的参考电压是单片机上的5v,所以乘5即为实际电压值// return AD_val;// }
void main(){ AD_init(); UART_init(); v_cd=1; v_fd=1; while(1) { if(com_flag==0) keysean(); }}
/**********************************************************/
void interrupt_uart() interrupt 4{
ES=0; //关串口中断 table=SBUF;//命令存到命令数组 if(table[0]=='W') i++; else RI=0; //软件清除接收中断 ES=1;//开串口中断 if(i>8) //如果接受字节大于8个开始检测接受字节后六位数据 Work_v_ad { if(table[5]=='v'&&table[6]=='_'&&table[7]=='a'&&table[8]=='d') { shi=volt/1000; ge=volt%1000/100; xiao1=volt%100/10; xiao2=volt%10; senddata(table1[shi]); senddata('.'); senddata(table1[ge]); senddata(table1[xiao1]); senddata(table1[xiao2]); volt=(AD_get(2)*0.002)*1000; shi=volt/1000; ge=volt%1000/100; xiao1=volt%100/10; xiao2=volt%10; senddata('_'); if(shi>0) senddata(table1[shi]); senddata(table1[ge]); senddata(table1[xiao1]); senddata(table1[xiao2]); } if(table[5]=='v'&&table[6]=='_'&&table[7]=='a'&&table[8]=='a') { volt=(AD_get(2)*0.002)*1000; shi=volt/1000; ge=volt%1000/100; xiao1=volt%100/10; xiao2=volt%10; senddata(table1[shi]); //senddata('.'); senddata(table1[ge]); senddata(table1[xiao1]); senddata(table1[xiao2]); senddata(0x0d); senddata(0x0a); com_flag=1; } if(table[5]=='v'&&table[6]=='_'&&table[7]=='c'&&table[8]=='d') { com_flag=1; v_fd=1; v_cd=0; } if(table[5]=='v'&&table[6]=='_'&&table[7]=='f'&&table[8]=='d') { com_flag=1; v_cd=1; v_fd=0; } if(table[5]=='v'&&table[6]=='o'&&table[7]=='f'&&table[8]=='f') { com_flag=1; v_cd=1; v_fd=1; } i=0; } }
根据大家要求我今天补了1张临时现画的
[ 此帖被gs0208在2017-05-12 09:23重新编辑 ]