放电容量检测(DIY电池容量内阻测试仪程序源码)
Posted
篇首语:只愿我永远在爱里,不断地学习,即使悲伤本文由小常识网(cha138.com)小编为大家整理,主要介绍了放电容量检测(DIY电池容量内阻测试仪程序源码)相关的知识,希望对你有一定的参考价值。
放电容量检测(DIY电池容量内阻测试仪程序源码)
//DIY低成本电池容量测试仪,测试原理:测试有负载与无负载间的电压差,
//通过已知外部电阻计算电池内阻。通过每隔一秒测一下电压,通过已知外部放电电阻计算电流
//累积计算毫安时
//电源为USB5V
//12864接PORTC,* 0: SDI 1: SCK 2: A0 3: RS 4: CS1
//12864 面向正面gnd|VCC|SDI|SCK|A0|RES|CS1,CS1标的1脚
//电池接PORTA 0,通过1K+1K分压接入AD,AD参考源为内部2.56V参考源,PORTA置为AD转换器,可同时测8路电池
//电池通过6.8水泥电阻放电
//继电器接PORTD 7,用于控制电池放电启停
//旋转编码器K关接INT 0,PORTD 2,用于操作放电启停
//旋转编码器A接INT 1,PORTD 3,B接PORT D 4,用于调整放电截止电压,
//注意施转编码器各脚需接104电容到地,通过510电阻到各脚
//开发平台ICCAVR 6.31A,使用了num2str-数字转字符串,mygraphic-抽象图形库,mzl05-针对铭正同创mzl05-12864的硬件层接口
// Target : M16
// Crystal: 8M外部晶振
//发现问题,AD接地仍有电压,可能电AREF没有外接电容,好象不是,PORTA=0x00后解决,但比万用表高0.1
#include <iom16v.h>
#include <macros.h>
#include <eeprom.h>
#include "num2str.h"
#include "mzl05.h"
#include "myGRAPHICS.h"
extern char glcdhalf;//由于M16内存局限每次只刷新半个屏幕
int count;//timer0计数
int adc;//ADC转换结果
float adcfloat;//ADC转换结的浮点表示
int adcnoloadvalue=0,adcloadvalue=0;//无载电压与有载电压,用于计算内阻
unsigned char firststart=0;//第一次进入有载
unsigned char adcbuffer[8];//ADC字符串结果
unsigned char rotate_key=0;//旋转编码器开关状态
unsigned char rotate_code=0;//PIND,用于判断旋转方向
unsigned char rotate_dir=0;//旋转编码器方向
unsigned char hour,minute,second;
unsigned int secondcount;
unsigned int stopvalue=512;//停止放电电压
//unsigned char tempunsignedchar;
float res;//电池内阻
float cap;//电池容量
unsigned int adccap=0;//电池容量整数表示
unsigned char adccurv[128];//放电电压曲线,每分钟一记,可记2小时
unsigned char adccurvcount;
unsigned int i;
void port_init(void)
PORTA = 0x00;
DDRA = 0x00;
PORTB = 0xFF;
DDRB = 0xFF;
PORTC = 0xFF;
DDRC = 0xFF;
PORTD = 0x7F;
DDRD = 0x80;//PORTD PIN7为继电器控制
//外部中断0
#pragma interrupt_handler int0_isr:2
void int0_isr(void)
if(rotate_key==0)//未放电状态
PORTD |=1<<7; //关闭常开触点,开始放电
rotate_key=1; //记录标志
hour=minute=second=0; //初始化计时器
firststart=1; //第一次进入放电状态
else
PORTD &=~(1<<7); //断开继电器
rotate_key=0; //记录标志
//外部中断1
//在旋转编码器A相下降沿查看B相电平,如果是高++
#pragma interrupt_handler int1_isr:3
void int1_isr(void)
rotate_code=PIND;
if((rotate_code & 0x10) == 0x10)
stopvalue++;
else
stopvalue--;
//tempunsignedchar=stopvalue % 256;
//EEPROMwrite(1,tempunsignedchar);
//tempunsignedchar=stopvalue / 256;
//EEPROMwrite(2,tempunsignedchar);
void timer0_init(void) //定时器初始化程序
TCCR0 = 0x00; //停止定时器
//TCNT0 = 0x3A; //设置初始值,75us,合计0.075X256=20ms//3A好用,计算值44
TCNT0=0xCF;//75us/4
TCCR0 = 0x02; //开动定时器,可能是主频/8
void ADInit(void)
ADMUX|=(1<<REFS1)|(1<<REFS0); //选择内部2.56V为ADC的参考电压
ADMUX&=~(1<<ADLAR); //转换结果右对齐
ADMUX&=~(1<<MUX4);
ADMUX&=~(1<<MUX3);
ADMUX&=~(1<<MUX2);
ADMUX&=~(1<<MUX1);
ADMUX&=~(1<<MUX0); //选择通道ADC0
ADCSRA|=(1<<ADPS2)|(1<<ADPS0);
ADCSRA&=~(1<<ADPS1); //时钟分频系数为64
ADCSRA|=(1<<ADEN);//使能AD
ADCSRA&=~(1<<ADATE);//不自动转换
ADCSRA&=~(1<<ADIE);//禁用AD中断
#pragma interrupt_handler timer0_ovf_isr:10
void timer0_ovf_isr(void) //定时器溢出中断程序,大约49*8机器周期中断一次
//TCNT0 = 0x3A; //从新调入初始值
TCNT0=0xCF;
secondcount++;
if(rotate_key==1)//如果开始测量容量,记时,开始计算容量
if(secondcount>10933)//大约一秒,可能还要调一下
secondcount=0;
second++;
if(second>59)
second=0;minute++;
adccurv[adccurvcount]=63-(unsigned char)(adccap/16);
adccurvcount++;
if(minute>59)
minute=0;hour++;
//adccap来自前一次测试时的电压,电压/电阻等于电流,每一秒累加电流*时间等于mAh
cap+=(((float)adccap*2.0*2.56*1000.0)/1024.0)/6.8; //ma,计算mAs
//cap=(((adccap*2.0*2.56/1024.0)/6.8)*1000.0) //ma
// *(hour+minute/60.0+second/3600.0);//hour
count++; //每中断一次加1
if (count>4096) //需要估算时间
//AD转换
ADCSRA|=(1<<ADSC); //启动一次AD转换
while(!(ADCSRA &(1<<ADIF)))
;//ADIF 为1时表示AD转换完成
adc=ADCL;
adc|=(int)(ADCH<<8);
adccap=adc;//随时采集电压用于计算容量
ADCSRA|=(1<<ADIF);
//AD转换结束
if(rotate_key==0)adcnoloadvalue=adc;
if(rotate_key==1 && firststart==1)
firststart=0;
adcloadvalue=adc;
//计算内阻,(无载电压-带载电压)/电流
res=(((adcnoloadvalue-adcloadvalue)*2.0*2.56)/1024.0) //电压差
/((adcloadvalue*2.0*2.56/1024.0)/6.8);//电流,6.8为水泥电阻阻值
cap=0.0;//初始化容量
for(i=0;i<128;i++)adccurv[i]=0;//初始化曲线
adccurvcount=0;
//如果电压低于终止电压,停计容量,断继电器
if(adc<stopvalue && rotate_key==1)
PORTD &=~(1<<7);
rotate_key=0;
adcfloat=2.56*adc/1024.0;
adcfloat=adcfloat*2;//真实电路中电压被分压1/2
Float2Str(adcbuffer,adcfloat,1,3);//格式化成为字符串
glcdhalf=0;
glcd_fillScreen(0);
//当前电压
glcd_text57(2,2,adcbuffer,2,1);
//是否开始,如果已经开始测容量显示stop
if(rotate_key==1)
glcd_text57(96,2,"stop",1,1);
else
glcd_text57(96,2,"start",1,1);
//时钟
Num2Str(adcbuffer,hour,2);
glcd_text57(80,12,adcbuffer,1,1);
glcd_text57(92,12,":",1,1);
Num2Str(adcbuffer,minute,2);
glcd_text57(98,12,adcbuffer,1,1);
glcd_text57(110,12,":",1,1);
Num2Str(adcbuffer,second,2);
glcd_text57(116,12,adcbuffer,1,1);
//时钟end
//终止电压
adcfloat=2.56*stopvalue/1024.0;
adcfloat=adcfloat*2;//真实电路中电压被分压1/2
Float2Str(adcbuffer,adcfloat,1,3);
glcd_text57(96,24,adcbuffer,1,1);
//终止电压end
//内阻
Float2Str(adcbuffer,res,1,3);
glcd_text57(2,18,adcbuffer,2,1);
glcd_text57(60,23,"R",1,1);
//内阻end
//容量
Float2Str(adcbuffer,cap/3600.0,5,1);
glcd_text57(2,40,adcbuffer,2,1);
glcd_text57(80,45,"mAh",1,1);
//容量end
for(i=0;i<adccurvcount;i++)
glcd_pixel(i,adccurv[i],1);
//glcd_line(1,1,64,63,1);
glcd_update();
glcdhalf=1;
glcd_fillScreen(0);
glcd_text57(2,2,adcbuffer,2,1);
if(rotate_key==1)
glcd_text57(96,2,"stop",1,1);
else
glcd_text57(96,2,"start",1,1);
//终止电压
adcfloat=2.56*stopvalue/1024.0;
adcfloat=adcfloat*2;//真实电路中电压被分压1/2
Float2Str(adcbuffer,adcfloat,1,3);
glcd_text57(96,24,adcbuffer,1,1);
//终止电压end
//内阻
Float2Str(adcbuffer,res,1,3);
glcd_text57(2,18,adcbuffer,2,1);
glcd_text57(60,23,"R",1,1);
//内阻end
//容量
Float2Str(adcbuffer,cap/3600.0,5,1);
glcd_text57(2,40,adcbuffer,2,1);
glcd_text57(80,45,"mAh",1,1);
//容量end
for(i=0;i<adccurvcount;i++)
glcd_pixel(i,adccurv[i],1);
//glcd_line(1,1,64,63,1);
glcd_update();
count=0;
//call this routine to initialise all peripherals
void init_devices(void)
//stop errant interrupts until set up
CLI(); //disable all interrupts
port_init();
MCUCR |= 1<<ISC11;
MCUCR &= ~(1<<ISC10); //外部中断1为下降沿触发,用于旋转编码器
MCUCR |= 1<<ISC01;
MCUCR &= ~(1<<ISC00);//外部中断0为下降沿触发,用于旋转编码器开关
GICR = 0b11000000;//外部中断使能1,0
SFIOR&=~BIT(PUD);//使能上拉电阻
TIMSK = 0x01; //timer interrupt sources,enable timer0
timer0_init();
ADInit();
SEI(); //re-enable interrupts
//all peripherals are now initialised
rotate_key=0;
hour=0;
minute=0;
second=0;
secondcount=0;
//tempunsignedchar=EEPROMread(1);
//stopvalue=(unsigned int)tempunsignedchar;
//tempunsignedchar=EEPROMread(2);
//stopvalue=stopvalue+(unsigned int)tempunsignedchar*256;
stopvalue=512;
adcnoloadvalue=adcloadvalue=0;
firststart=0;
cap=0.0;
for(i=0;i<128;i++)adccurv[i]=0;
adccurvcount=0;
void main(void)
init_devices();
glcd_init();
glcd_update();
//glcd_fillScreen(0x01);
//insert your functional code here...
while (1)
;
相关参考
...电池的界面结构和内阻等,进而影响电池整体的容量、充放电电流密度、循环性能以及安全性等。本文通过对国内外电池隔膜测评标准的归纳和整理,较为全面系统地介绍各测试项目,包括其原理、现有标准及测试方法等,并对...
...电池的界面结构和内阻等,进而影响电池整体的容量、充放电电流密度、循环性能以及安全性等。本文通过对国内外电池隔膜测评标准的归纳和整理,较为全面系统地介绍各测试项目,包括其原理、现有标准及测试方法等,并对...
智能蓄电池组负载测试仪(通信动力维护中,蓄电池后备容量与后备时长测算了解一下)
...量放电试验(10小时率、或者3小时率)获得。蓄电池放电测试仪蓄电池组所标注容量均为标准工况下10小时率标称容量(C10),如500AH,指工作温度为25℃,放电电流为50A(I10=0.1C10),可放电1
报废18650处理(拒绝拆机电池 疑似耐时新品18650动力电池曝光)
...3mΩ要小,初步判断该型号电池为准动力电池。在网友的4A放电测试中,发现该电池充满共放出电量2844mAh,也就是该准动力电池的实际容量约为2800mAh,在之后多次测量中数据保持一致。在低温-20℃下,依然能够放出2400mAh的电量,...
...业的电池知识,最简单怎样测容量?干点啥 如果没有放电仪检测容量,可以使用充电估算法。 当电池放电至欠压灯亮,充电(单独一个标准充电器),如果充电时间为8小时转灯的电池容量为12AH,充电时间为6小时为9AH,...
成型弹片(锂电池pack性能测试标准,电池测试模组就选弹片微针模组)
...单个使用的电池叫做电芯,只有连接上保护板,有充电、放电功能的成品电池组才被称为锂电池pack。锂电池pack指的是组合电池,它是通过单体锂电池的串联和并联组成一定的电压和容量,再加装保护板,使成品锂电池可以进行...
开关电源主滤波电容容量下降(开关电源维修,输出滤波电容问题?)
...因为输出滤波电容损坏,滤波电容是有寿命的,长时间充放电会增加内阻ESR,电容内部是有内阻ESR和电感ESL,由于制作工艺,内阻ESR不可能为零,只有在理想状态下是零,当在对电容反复充电过程中,由于内阻ESR的存在,会
锂电池串并联定义由于单体电池的电压和容量有限,在实际使用中都需要进行串并联组合,以获得更高的电压和容量,才能满足设备的实际供电需求。锂电池串联:电压相加,容量不变,内阻增大。锂电池并联:电压不变,容量相...
...器全自动固态恒压型,装备有电子电路,保护电池过充或过放电。充电系统能使电池在全部放电后于24小时内再充电至满容量。灯具的控制电路可用于主电源上,应急照明器和正常传统照明器的操作一样。主电源发生故障时,不管接触...
...器全自动固态恒压型,装备有电子电路,保护电池过充或过放电。充电系统能使电池在全部放电后于24小时内再充电至满容量。灯具的控制电路可用于主电源上,应急照明器和正常传统照明器的操作一样。主电源发生故障时,不管接触...