|
前一段时间开源了一个智能小车,小车需要锂电池供电,家里一大堆电池,当使用的时候才发现好久没有容量大减,正好最近在研究labview,所以就做了1个来测试一下电池容量,其实原理非常简单,用单片机就能轻松搞定,为了高大上而且能为了能看到电池充电和放电的曲线所以就需要上位软件了,第一次用labview编程程序写的非常烂高手见谅了
功能:
上位机 labview 负责采集数据计时显示设置充放电截止电压和电池曲线图
下位机 stc125a60s2 负责ad检测电压电流串口通信
由于手底下没有mos管所以暂时使用317进行横流放电
充电采用锂电池专用模块
通信 串口发送字符串
检测电压电流 Work_v_ad
充电 Work_v_cd
放电 Work_v_fd
关闭 Work_voff
电脑和单片机通信采用一个usb ttl下载器进行
ad采集为了准确,采用Tl431做标准基准源,还算比较准确的
这个是第二版带LCD,可以脱机使用
labview显示电池放电曲线
蓝色是放电 红色是充电
放电根据自己设定的截止电压检测,我设置的是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); //延时约1ms
void 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;
}
}
|
|