⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 analog.c

📁 用AVR453开发的电池保护板的C语言程序,希望对大家有用!
💻 C
📖 第 1 页 / 共 3 页
字号:

    //Divide uWmins by uW and you get minutes.
    cap = cap / presentrate;
  }
  else
  {
    cap = GetChgUntilFull_mAmins() / rate;	// (mAmins / mA) = minutes
  }

  return (unsigned int) cap;
}







/* =====================================================================================
   =====================================================================================
   ===================================================================================== */


//Local 'helper' functions (not exposed in analog.h)


//! \todo  NOTE: the signature/fab.calibration bytes definitions assume Rev *E* silicon ONLY.
//! Earlier revisions will require changes.
#define FAST_RC_CAL    (sig_array[0x01])
#define SLOW_RC_LO_CAL (sig_array[0x06])
#define SLOW_RC_HI_CAL (sig_array[0x07])
#define BG_C_CAL       (sig_array[0x09])
#define CELL1_LO_CAL   (sig_array[0x10])
#define CELL1_HI_CAL   (sig_array[0x11])
#define CELL2_LO_CAL   (sig_array[0x12])
#define CELL2_HI_CAL   (sig_array[0x13])
#define CELL3_LO_CAL   (sig_array[0x14])
#define CELL3_HI_CAL   (sig_array[0x15])
#define CELL4_LO_CAL   (sig_array[0x16])
#define CELL4_HI_CAL   (sig_array[0x17])
#define ADC0_LO_CAL    (sig_array[0x18]) // currently not used
#define ADC0_HI_CAL    (sig_array[0x19]) // currently not used
#define VPTAT_LO_CAL   (sig_array[0x1A])
#define VPTAT_HI_CAL   (sig_array[0x1B])

// Old defines (for rev.D), not fully compatible with new routines
/*
#define FAST_RC_CAL  (sig_array[0x01])
#define SLOW_RC_CAL  (sig_array[0x03])
#define BG_C_CAL     (sig_array[0x09])
#define BG_R_CAL     (sig_array[0x0B])
#define VPTAT_HI_CAL (sig_array[0x0D])
#define VPTAT_LO_CAL (sig_array[0x0F])
#define CELL1_CAL    (sig_array[0x11])
#define CELL2_CAL    (sig_array[0x13])
#define CELL3_CAL    (sig_array[0x15])
#define CELL4_CAL    (sig_array[0x17])
*/


void ReadFactoryCalibration(void)
{
  unsigned char __flash * ptr = 0;
  char i;
  char flags = SREG;
  char temp;
  unsigned char sig_array[0x1C];   //Array with signature/fab.calibration bytes


  __disable_interrupt();
  for(i=0; i< 0x1C; i++)
  {
    SPMCSR = (1<<SIGRD) | (1<<SPMEN);
    temp = *ptr++;
    sig_array[i] = temp;
  }

  if(flags & 0x80)
    __enable_interrupt();

  //Now apply the Cal values we just read out.

//  SlowRCCal = SLOW_RC_CAL;
  SlowRCCal = (SLOW_RC_HI_CAL << 8)|(SLOW_RC_LO_CAL);
  FastRCCal = FAST_RC_CAL;

  //Calibrate bandgap (fab. or battery factory)
  BGCCRCal = BG_C_CAL| 0x80;
  if (ReadVrefCalibration()) {
	calibration_state &= ~CAL_VREF_MASK;
	calibration_state |=  CAL_VREF_OK;
  } else {
    calibration_state &= ~CAL_VREF_MASK;
  }

  //Save the Cell1-Cell4 gain values
  ADCgain[0] = (CELL1_HI_CAL << 8)|(CELL1_LO_CAL);
  ADCgain[1] = (CELL2_HI_CAL << 8)|(CELL2_LO_CAL);
  ADCgain[2] = (CELL3_HI_CAL << 8)|(CELL3_LO_CAL);
  ADCgain[3] = (CELL4_HI_CAL << 8)|(CELL4_LO_CAL);

  //On-chip temperature sensor calibration value
  VTgain = (VPTAT_HI_CAL<<8) | VPTAT_LO_CAL;	//on-chip temp sensor

  // Calibration values for CCoffset and CCIoffset?
  if (ReadCCOffsetCalibration()) {
	calibration_state &= ~CAL_CC_MASK;
	calibration_state |=  CAL_CC_OK;
  } else {
    calibration_state &= ~CAL_CC_MASK;
  }
}



unsigned char ReadVrefCalibration(void)
{
  unsigned char temp;

  while(EECR & (1<<EEPE));
  EEAR = EESTORAGE_BGCCR;
  EECR = (1<<EERE);	//read
  temp = EEDR;
  if (temp != 0xFF) {
    BGCCR = temp;
    while(EECR & (1<<EEPE));
    EEAR = EESTORAGE_BGCRR;
    EECR = (1<<EERE);	//read
    BGCRR = EEDR;
    return(1);
  } else {
    BGCRR = 0x0F;
    BGCCR = BGCCRCal;		// signature value (with Band gap enabled)
    return(0);
  }
}


unsigned char ReadCCOffsetCalibration(void)
{
  signed char temp;

  while(EECR & (1<<EEPE));
  EEAR = EESTORAGE_CC_valid;
  EECR = (1<<EERE);	//read
  temp = EEDR;
  if (temp != -1) {
    do {} while(EECR & (1<<EEPE));
    EEAR = EESTORAGE_CCoffset;
    EECR = (1<<EERE);	//read
    temp = EEDR;
    CCoffset = (signed int)temp;
    do {} while(EECR & (1<<EEPE));
    EEAR = EESTORAGE_CCIoffset;
    EECR = (1<<EERE);	//read
    temp=EEDR;
    CCIoffset = (signed long)temp;
    return(1);
  } else {
    CCIoffset = 0;
    CCoffset  = 0;
    return(0);
  }
}

/* =====================================================================================
   =====================================================================================
   ===================================================================================== */


/* Calibration routines for VREF and CC/CCIoffset
*/



unsigned char CalibrateVREF(void)         // calibration of VREF
{
  long int V_error;                       // Variable to keep error after conversion
  long int old_V_error;                   // Value used to keep old error value during linear scan
  unsigned char ratio_counter;            // Value used to count up the BGCCR value
  unsigned char loopcount;                // Value used during temperature calibration
  volatile unsigned int vui_temp;         // Dummy variable used to ensure correct reading of VADC

  BGCRR = 0x0f;							  // Load Factory calibration
  BGCCR = BGCCRCal;  			          // Load Factory calibration (with Band gap enabled)
  VADMUX = CAL_CHANNEL;                   // Select terminal input defined in calibration.h
  VADCSR = (1 << VADEN);                  // Enable the VADC
  vui_temp = VADC;                        // Dummy read(s) to ensure proper operation
  loopcount = CAL_WAIT;				      // Wait for error from CellBalancing to cancel
  while (loopcount--) {
    VADCSR |= (1 << VADSC) | (1 << VADCCIF);// Start a VADC conversion and clear any pending interrupts
    do {} while(!(VADCSR & (1 << VADCCIF)));// Wait while conversion in progress
    vui_temp = VADC;                      // Dummy read(s) to ensure proper operation
  }
  VADCSR |= (1 << VADSC) | (1 << VADCCIF);// Start a VADC conversion and clear any pending interrupts
  do {} while(!(VADCSR & (1 << VADCCIF)));// Wait while conversion in progress
  V_error = VADC;                   	  // Calculate the error of the measured value
  V_error = V_error * CAL_GAIN;
  V_error = V_error - Vcalibration_value;
  loopcount = 8;						  // Check for all different test limits
  while (V_error < vcalibration_level[loopcount]) {
    loopcount--;
    if (!loopcount) {
      break;
    }
  }
  BGCRR = tempcal[loopcount];             // Set BGCRR to correct setting

  V_error = vcalibration_level[7];        // Init old_V_errror
  ratio_counter = (1 << BGEN) - 1;        // Reset ratio counter (keep Band gap enabled), -1 because of increment
  do                                      // Repeat until VADC value becomes larger than reference
  {
    ratio_counter++;                      // Select next BGCCR value;
    BGCCR = ratio_counter;                // Set new BGCCR value
    old_V_error = V_error;                // Calulate the error of the measured value
    if(ratio_counter & 0x40)              // Ratio_counter bit 6 set means calibration failed
    {
      BGCRR = 0x0f;						  // Load Factory calibration
      BGCCR = BGCCRCal; 			      // Load Factory calibration (with Band gap enabled)
      return 0;                           // Return with fail flag
    }
    vui_temp = VADC;                      // Dummy read to ensure proper operation
    VADCSR |= (1 << VADSC) | (1 << VADCCIF);// Start a VADC conversion and clear any pending interrupts
    do {} while(!(VADCSR & (1 << VADCCIF)));// Wait while conversion in progress
    V_error = VADC;                   	  // Calulate the error of the measured value
    V_error = V_error * CAL_GAIN;
    V_error = V_error - Vcalibration_value;
  } while(V_error > 0);                   // Loop until VADC output is larger than the reference setting
  if(old_V_error < (-V_error)) {          // Select the best value out of the last two BGCCR values
    ratio_counter--;                      // Value below the reference setting is closest to the reference
  }
  BGCCR = ratio_counter;                  // Set the correct BGCCR value

  do {} while(EECR & (1<<EEPE));
  do {} while(SPMCSR & (1<<SPMEN));
  EEAR = EESTORAGE_BGCRR;
  EEDR = tempcal[loopcount];
  EECR = (0<<EEPM1) | (0<<EEPM0) | (0<<EERIE) | (1<<EEMPE) | (0<<EEPE) | (0<<EERE);	//arm
  EECR = (0<<EEPM1) | (0<<EEPM0) | (0<<EERIE) | (1<<EEMPE) | (1<<EEPE) | (0<<EERE);	//go

  do {} while(EECR & (1<<EEPE));
  EEAR = EESTORAGE_BGCCR;
  EEDR = ratio_counter;
  EECR = (0<<EEPM1) | (0<<EEPM0) | (0<<EERIE) | (1<<EEMPE) | (0<<EEPE) | (0<<EERE);	//arm
  EECR = (0<<EEPM1) | (0<<EEPM0) | (0<<EERIE) | (1<<EEMPE) | (1<<EEPE) | (0<<EERE);	//go

  return 1;
}



unsigned char CalibrateCCoffset(void)         // calibration of CC offset
{                                       // assumes 0 current through shunt for minimum 1 second before calibration
  unsigned char index = CCindex;
  volatile signed long cc_temp;         // for dummy reads

  index--;
  index &= 63;
  CCIoffset = CCarray[index];

  ChangePowerMode(POWERMODE_ACTIVE,0);
  while (CC_delay_acc--) {  // check if we need to discard samples
    do {} while (!(CADCSRB & (1<<CADACIF)));
    cc_temp = CADAC;
    CADCSRB = (1<<CADACIE) | (1<<CADICIE) | (1<<CADACIF) | (1<<CADRCIF) | (1<<CADICIF);
  }
  CCoffset = CADAC;

  if ((CCoffset > CCoffset_limit) || (CCIoffset > CCIoffset_limit) ||
      (CCoffset < -CCoffset_limit) || (CCIoffset < -CCIoffset_limit)) {  // Max offset limits to avoid wrong calibration
    CCoffset = 0;
    CCIoffset = 0;
    return(0);

  } else {
    do {} while(EECR & (1<<EEPE));
    do {} while(SPMCSR & (1<<SPMEN));
    EEAR = EESTORAGE_CC_valid;
    EEDR = 0x00;
    EECR = (0<<EEPM1) | (0<<EEPM0) | (0<<EERIE) | (1<<EEMPE) | (0<<EEPE) | (0<<EERE);	//arm
    EECR = (0<<EEPM1) | (0<<EEPM0) | (0<<EERIE) | (1<<EEMPE) | (1<<EEPE) | (0<<EERE);	//go

    do {} while(EECR & (1<<EEPE));
    EEAR = EESTORAGE_CCIoffset;
    EEDR = (unsigned char)CCIoffset;
    EECR = (0<<EEPM1) | (0<<EEPM0) | (0<<EERIE) | (1<<EEMPE) | (0<<EEPE) | (0<<EERE);	//arm
    EECR = (0<<EEPM1) | (0<<EEPM0) | (0<<EERIE) | (1<<EEMPE) | (1<<EEPE) | (0<<EERE);	//go

    do {} while(EECR & (1<<EEPE));
    EEAR = EESTORAGE_CCoffset;
    EEDR = (unsigned char)CCoffset;
    EECR = (0<<EEPM1) | (0<<EEPM0) | (0<<EERIE) | (1<<EEMPE) | (0<<EEPE) | (0<<EERE);	//arm
    EECR = (0<<EEPM1) | (0<<EEPM0) | (0<<EERIE) | (1<<EEMPE) | (1<<EEPE) | (0<<EERE);	//go
    return(1);
  }
}



/* =====================================================================================
   =====================================================================================
   ===================================================================================== */



/* General description of Coulomb Counter usage:
 *
 * The Coulomb Counter must be running whenever the chip is not
 * in deep sleep mode.  The interrupt is used to perform software
 * accumulation & must also handle analog offset voltage correction
 * for the input stage.
 *
*/

void CCmode(unsigned char mode)
{
  switch (mode)
  {
    default:
    case CC_DISABLED:
      CCSR = 0;					//switch to the Slow RC Oscillator to save power
      CCarray_Init();
      CADCSRA = 0;
      break;

    case CC_ACCUMULATE:				//enable both Accumulate and Instantaneous
      if(CCSR != ((1<<XOE)|(1<<ACS)))		//if the 32KHz xtal isn't already in use, start it up.
      {
        Timer32KHz = 9;
        CCSR = (1<<XOE);
      }
      BGCCR |= (1<<BGEN);			//ensure that the bandgap is enabled
      CADCSRB = (1<<CADACIE) | (1<<CADICIE) | (1<<CADACIF) | (1<<CADRCIF) | (1<<CADICIF);
      while ( CADCSRA & (1<<CADUB) );		//wait for clock domain sync
      CADCSRA = (1<<CADEN) | ACCUM_CONV_TIME;	//! \todo  See ANALOG.H to choose your interval for CC_ACCUMULATE
      CC_delay_acc  = 4;			//must ignore the first 4 readings!
      CC_delay_inst = 4;			//must ignore the first 4 readings!
      CCarray_Init();
      break;

    case CC_REGULAR:				//enable ONLY Regular mode is enabled
      if(CCSR != ((1<<XOE)|(1<<ACS)))		//if the 32KHz xtal isn't already in use, start it up.
      {
        Timer32KHz = 9;
        CCSR = (1<<XOE);
      }
      CCarray_Init();
      BGCCR |= (1<<BGEN);			//ensure that the bandgap is enabled
      CADRDC = -(ACTIVE_CURRENT_THRESHOLD + (CCIoffset>>4));
      CADCSRB = (1<<CADRCIE) | (1<<CADACIF) | (1<<CADRCIF) | (1<<CADICIF);
      while ( CADCSRA & (1<<CADUB) );		//wait for clock domain sync
      CADCSRA = (1<<CADSE) | REG_CONV_TIME;	//! \todo  See ANALOG.H to choose your interval for CC_REGULAR
      break;
  }
}


void CCinit(void)
{
  CCmode(CC_DISABLED);
}



/* =====================================================================================
   =====================================================================================
   ===================================================================================== */





//Call this at startup to ensure the buffer is cleared.
void CCarray_Init(void)
{
  CCvalidsamples = 0;			//reset the # of valid samples
  CCindex = 0;				//reset the insertion index
}


//This inserts a new sample into the circular buffer.
void CCarray_AddSample(signed int newsample)
{
  if(CC_delay_inst)
  {
    CC_delay_inst--;
    return;
  }

  CCarray[CCindex++] = newsample;
  CCindex &= 63;

  if(CCvalidsamples < 64)
    CCvalidsamples++;
}


//This retrieves the most recent sample out of the circular buffer.
signed int Current1Sec(void)	//! \todo  NOTE: This could produce a bad result within the first 1Sec of operation.
{
  unsigned char temp = CCindex;

  temp--;
  temp &= 63;
  return CCarray[temp];
}





//Note: the data source here is INSTANTANEOUS CURRENT readings, not the Accumulator.
//  Although it is not as precise as the Accum, it is accurate within 0.5% of full-scale.
signed int CCarray_Average(void)	//this will accurately reflect up to 64 seconds of data.
{					
  signed long avg = 0;
  unsigned char ctr = CCvalidsamples;	//grab a local copy since CCvalidsamples is modified by an INTERRUPT
  unsigned char temp;
  signed int * ptr = CCarray;		//the same as saying  &CCarray[0]

  if(0 == ctr)
    return 0;

  temp = ctr;
  while(temp--)				//add up ONLY the valid samples!
    avg += *ptr++;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -