📄 analog.c
字号:
/* This file has been prepared for Doxygen automatic documentation generation.*/
/*! \file *********************************************************************
*
* \brief
* Sampling and calculations.
*
* \par Application note:
* AVR453: Smart Battery Reference Design
*
* \par Documentation:
* For comprehensive code documentation, supported compilers, compiler
* settings and supported devices see readme.html
*
* \author
* Atmel Corporation: http://www.atmel.com \n
* Support email: avr@atmel.com \n
* Original author: Rob G. Fries - Apt Inc.\n
*
* $Revision: 2687 $
* $URL: http://revisor.norway.atmel.com/AppsAVR8/avr453_Smart_battery_reference_design/tags/20071112_release/code/analog.c $
* $Date: 2007-11-12 10:39:44 +0100 (ma, 12 nov 2007) $ \n
******************************************************************************/
/* Validation Test for Current Measurement:
Using the I-SIM circuit, apply 20.0mV to the ATmega406 CCADC input.
Read back the variable LatestCCI. Multiply this value by 53.7uV/count.
You should get approximately 20,000uV, or 20mV. The variable LatestCCI
is intended to be used for cell impedance measurements and is not filtered
or scaled in any way, but is a copy of the raw result of the instantaneous
CC reading.
The variable CCarray contains averaged 1-second Current readings based on the
results of the Instantaneous reading of the CCADC. These calculations
assume a 5mOhm sense resistor. To verify these readings, pick one
sample out of the CCarray and convert to decimal. The value should be read
directly in mA. If using 20mV as noted above, this would correspond to
a value of 20mV/5mOhm = 4000mA, therefore all non-zero elements in the array
should read approx. 4000 (decimal).
The Accumulator should also be tested, since its reading must also be
scaled in order to be read as mA. Assuming 20mV applied to the input,
and each bit corresponding to 1.678uV, then each 1-second reading of the
CCADC accumulated result should be approx. 20mV/1.678uV = 0x2EF8.
This number must be multiplied by 3600 to convert from seconds to hours.
Dividing this result by 10727 will yield the current in mAHr, in this
case approximately 4000mAHr.
*/
//#include "iom406_320.h"
#include <iom406.h> // IAR headerfile for Mega406 (EW 410)
#include <inavr.h>
#include "main.h"
#include "pack.h"
#define MODULE_ANALOG
#include "analog.h"
#define MODULE_CALIBRATION
#include "calibration.h"
#include "smbus.h"
#include "timer.h" // (for access to the Timer32KHz variable)
#include "pwrmgmt.h"
#include "ee.h"
//Local prototypes (not exposed in analog.h)
void CCarray_Init(void);
//Local variables (not exposed in analog.h)
//signed long RunningAcc = 0; //this must be externally visible for Hibernate mode estimated power loss
signed long MaxTopAcc = 0;
signed long MaxBottomAcc = 0;
unsigned char CC_delay_acc = 0;
unsigned char CC_delay_inst = 0;
//Calculated, calibrated results
unsigned int CellV[4] = {0};
unsigned int OnChipTemp = 0;
//Intermediate results
unsigned int Thermistor[4] = {0}; // this hold an Ohmic value, scaled per "FixedThermistorPullup"
unsigned int VPA4 = 0; // this is V(ADC4) * 5
// The following variables are used for the 1-minute (approx) average of current flow.
// We treat CCarray as a circular buffer, containing the 64 most recent samples available.
// Each sample is properly scaled (mA) but does not include temperature or offset effects.
// These functions are kept local to this file and are not made public.
signed int CCarray[64]; //positive (charging) or negative (discharging).
char CCindex = 0;
char CCvalidsamples = 0;
//Support variables
unsigned int ADCbuffer[10]; //raw converted results
unsigned int ADCgain[4]; //gain values for Cell1-4
unsigned int VTgain; //gain for on-chip temperature sensor
unsigned char ADCchannel; //visible so we can force the start channel
#define FixedThermistorPullup 1000 /* ohmic value */
/* =====================================================================================
=====================================================================================
===================================================================================== */
//Public functions (exposed in analog.h)
void SetMaxTopAcc(long value)
{
MaxTopAcc = value;
}
void FullChargeReached(void)
{
signed long temp;
temp = RunningAcc - MaxBottomAcc;
RunningAcc = MaxTopAcc = temp;
MaxBottomAcc = 0;
SMBvariables[SMBV_BattStatus][lobyte] &= ~FULLY_DISCHARGED;
SMBvariables[SMBV_BattStatus][lobyte] |= FULLY_CHARGED;
}
void FullDischargeReached(void)
{
MaxTopAcc -= RunningAcc;
RunningAcc = MaxBottomAcc = 0;
SMBvariables[SMBV_BattStatus][lobyte] |= FULLY_DISCHARGED;
SMBvariables[SMBV_BattStatus][lobyte] &= ~FULLY_CHARGED;
}
/* =====================================================================================
=====================================================================================
===================================================================================== */
//Assorted local-support math functions
unsigned int GetVoltage(void) //also serves as "cmd = 9"
{
unsigned int volt;
volt = ReadCell(1);
volt += ReadCell(2);
if(PACKSTACK > 2)
volt += ReadCell(3);
if(PACKSTACK > 3)
volt += ReadCell(4);
return volt;
}
long GetCharge(void) //in mAHrs
{
unsigned long calc = (RunningAcc / 10727); // 10,727 LSB/mAh, see app-note for more details
return calc;
}
long GetCharge_mAmins(void) //in mAmins
{
unsigned long calc = (RunningAcc / 179); // 10727 / 60 ~= 179
return calc;
}
long GetChgUntilFull_mAmins(void) //in mAmins
{
unsigned long calc = (MaxTopAcc - RunningAcc);
return (calc / 179);
}
unsigned int GetMaxChg(void) //calculate the maximum charge that the pack is presently
//capable of holding (not same as DESIGN capacity)
{
unsigned long calc = MaxTopAcc / 10727;
return (unsigned int) calc;
}
/*
unsigned int GetCapacity(void) //designed capacity @1C, in mAHr
{
return PACK_DESIGNCAPTYP;
}
unsigned long GetCapacity_mAmins(void) //designed capacity @1C, in mAmins
{
return (PACK_DESIGNCAPTYP*60);
}
*/
/* =====================================================================================
=====================================================================================
===================================================================================== */
//Functions to support specific SMBus Slave READ commands
unsigned int AtRateTTF(void) // cmd = 5
{
signed long calc;
unsigned int temp = (unsigned int)SMBvar_int[SMBV_AtRate];
if((signed int) temp > 0) //For TTF, AtRate must be POSITIVE & NON-ZERO.
{
if(SMBvariables[SMBV_BattMode][hibyte] & CAPACITY_MODE) //use mW
{
temp = 65535; //optional mode, not implemented.
}
else //use mA in calculations
{
calc = PACK_DESIGNCAPTYP;
calc = calc * 60;
calc -= GetCharge_mAmins();
temp = calc / temp; // (mAmins / mA) = mins
}
}
else //error
temp = 65535;
return temp;
}
unsigned int AtRateTTE(void) // cmd = 6
{
signed long calc;
unsigned int temp = (unsigned int)SMBvar_int[SMBV_AtRate];
if((signed int) temp < 0) //For TTE, AtRate must be NEGATIVE & NON-ZERO.
{
temp = -((signed int) temp);
if(SMBvariables[SMBV_BattMode][hibyte] & CAPACITY_MODE) //use mW
{
calc = GetCharge_mAmins() * PACK_MINV; //this is now in uWmins
calc = calc / 10000; //this is now in 10mWmins
temp = calc / temp; // (10mWmins / 10mW) = mins
}
else //use mA in calculations
{
calc = GetCharge_mAmins();
temp = calc / temp; // (mAmins / mA) = mins
}
}
else //error
temp = 65535;
return temp;
}
unsigned int AtRateOK(void) // cmd = 7
{
unsigned long calc; //used as available capacity
unsigned int temp = (unsigned int)SMBvar_int[SMBV_AtRate]; //used as total rate of consumption
if((signed int) temp < 0) //For AtRateOK, AtRate must be NEGATIVE & NON-ZERO.
{
temp = -((signed int) temp);
if(SMBvariables[SMBV_BattMode][hibyte] & CAPACITY_MODE) //use mW in calculations
{
calc = Current1Sec() * GetVoltage(); //in uW (alternate: can use PACK_MINV)
calc = calc / 10000; //in 10mW
temp += calc; //combine AtRate and present load; shouldn't overflow!
calc = GetCharge_mAmins();
calc = calc * PACK_MINV;
calc = calc * 6; //this is now in mW-10Secs
calc = calc / 10; //this is now in 10mW-10Secs
}
else //use mA in calculations
{
temp += Current1Sec(); //add in the present discharge rate too!
calc = GetCharge_mAmins() * 6; //convert to 10-second rate
}
if(calc > temp)
temp = 65535; //return TRUE, as there is enough energy.
else
temp = 0; //return FALSE. We're almost dead!
}
else //error
temp = 65535;
return temp;
}
unsigned int GetTemperature(void) // cmd = 8
{ // Returns temperature of MEGA406, in 0.1 degrees Kelvin.
return ReadTemperature(0); //channel 0 is the on-chip sensor.
}
unsigned char RelativeSOC(void) // cmd = 13
{
unsigned long charge = (RunningAcc * 100) / MaxTopAcc;
// return (unsigned int) charge;
return (unsigned char) charge;
}
unsigned int AbsoluteSOC(void) // cmd = 14
{
unsigned long charge = (GetCharge() * 100);
charge = charge / PACK_DESIGNCAPTYP;
return (unsigned int) charge;
}
unsigned int RemainingCap(void) // cmd = 15
{ //! \todo This implementation does not take into account C/5 vs 1C capacity delta.
unsigned long calc;
unsigned int charge = GetCharge(); //in mAH
if(SMBvariables[SMBV_BattMode][hibyte] & CAPACITY_MODE) //use mW in calculations
{
calc = charge * GetVoltage(); //in uWH
charge = calc / 10000; //in 10mWH
}
return charge;
}
unsigned int FullChgCap(void) //cmd = 16
{ //! \todo This implementation does not take into account C/5 vs 1C capacity delta.
unsigned long calc = GetMaxChg();
if(SMBvariables[SMBV_BattMode][hibyte] & CAPACITY_MODE) //use mW in calculations
{
calc = calc * PACK_NOMINALV;
calc = calc / 10000;
}
return (unsigned int) calc;
}
// Pass in 0 for 1-sec basis, 1 for 1-minute avg'd basis.
unsigned int TimeToEmpty(unsigned char avgd) //cmd = 17,18; how many mins until battery is discharged at present rate
{
signed int rate;
unsigned long presentrate;
unsigned long cap;
if(0 == avgd)
rate = Current1Sec();
else
rate = CCarray_Average();
if(rate >= 0)
return 65535;
rate = -rate;
if(SMBvariables[SMBV_BattMode][hibyte] & CAPACITY_MODE) //use mW in calculations
{
//First, determine actual rate of Wattage being used.
presentrate = rate * GetVoltage(); //this is in uW scale
//Next, determine capacity at pack's minimum V (full discharge)
cap = GetCharge_mAmins() * PACK_MINV; //this is in uWmins scale
//Divide uWmins by uW and you get minutes.
cap = cap / presentrate;
}
else
{
cap = GetCharge_mAmins() / rate; // (mAmins / mA) = minutes
}
return (unsigned int) cap;
}
unsigned int AvgTimeToFull(void) //cmd = 19
{
signed int rate;
unsigned long presentrate;
unsigned long cap;
rate = Current1Sec();
if(rate <= 0)
return 65535;
if(SMBvariables[SMBV_BattMode][hibyte] & CAPACITY_MODE) //use mW in calculations
{
//First, determine actual rate of Wattage being used.
presentrate = rate * GetVoltage(); //this is in uW scale
//Next, determine capacity at pack's minimum V (full discharge)
cap = GetChgUntilFull_mAmins() * PACK_MINV; //this is in uWmins scale
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -