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

📄 analog.c

📁 用AVR453开发的电池保护板的C语言程序,希望对大家有用!
💻 C
📖 第 1 页 / 共 3 页
字号:
  if(64 == ctr)
    return (signed int) (avg >> 6);	//use this optimized version after the first 64 seconds
  else
  if(1 == ctr)
    return (signed int) (avg);
  else
    return (signed int) (avg / ctr );	//this takes longer due to division.
}



/* ******************************************************************** *
 * Coulomb Counter, Instantaneous conversion complete ISR
 *
 * This interrupt fires after every conversion, at 3.9ms intervals.
 * Every 256 interrupts is therefore 1 second.
 *
 * Each count of the result is 53.7uV, which, into a 5mOhm sense R,
 * indicates 10.74mA flowing.  This is quick-responding and can therefore
 * be used in conjunction with cell voltage measurements to calculate
 * cell impedance by watching the delta-V on the cells when compared to
 * any available delta-I.  There obviously must be sufficient delta-I
 * to permit a reasonably accurate division result, otherwise the
 * calculation could be way off.  Note that the CC ADC is separate
 * hardware from the 12-bit general-purpose ADC and can therefore do a
 * current measurement in parallel with one cell voltage measurement.
 * There is a global variable, LatestCCI, that always contains the most
 * recent value.  The intent is that this value would be captured along
 * with the individual cell voltage at a given instant.
 *
 * ( NOTE: if you use LatestCCI, remember that it is NOT SCALED TO mA! )
 *
 * We also use this as the basis of the required 1-minute averaged current.
 * We play some tricks to get this value without doing ugly math.
 * Since the values need to be available in milliamps, we must accumulate
 * lots of samples to make up for the fact there's over a 10X scale delta.
 * Specifically, we get 1 count for every 10.74mA.  If we accumulate
 * 10.74 x 16 = 172 samples, then we can simply divide by 16 to get a
 * 1mA/step average result. We will thus take 172 samples per second.
 * (Note: this value could be modified SLIGHTLY to effect a 'calibration'
 *  without adding additional math processing burden.)
 *
 * The next problem is to spread these samples out evenly over the sampling
 * period (1 second).  To do this, we use a simple first-order sigma-delta
 * software modulator; if its 1-bit output is a '1', then we accumulate the
 * sample that's available at this moment.
 *
 * ******************************************************************** */



#define CCI_CAL 172	/* # of samples we need to accumulate in a second */

#pragma vector = CCADC_vect
__interrupt void CC_Instantaneous_ISR(void)
{
  static unsigned char timer = 0;	//256 interrupts = 1 second
  static signed long sl = 0;		//averaging accumulator
  static unsigned char mod_remainder;	//used by sigma-delta modulator
  signed int temp,temp2;



  if(PowerMode == POWERMODE_IDLE)	//do Regular Current mode instead.
  {
    temp = CADIC;
    temp <<= 3;				//note: CADIC is actually 13 bits incl. sign
    RunningAcc += (signed long) temp;	//update the charge state
    RunningAcc += (signed long) temp;	//update the charge state
    RunningAcc += (signed long) temp;	//update the charge state
    RunningAcc += (signed long) temp;	//must do it 4 times (Instantaneous * 32 = Accumulate)

    //Note: it is POSSIBLE to overflow here, but not likely unless pushing lots of current.
    temp2 = CADIC;
    temp = temp2;
    temp += temp2;
    temp += temp2/2;			//10.5x, a good approximation of 10.7x
    temp -= CCIoffset;			//subtract the offset calibration value
    CCarray_AddSample(temp);		//update the 64-second average
    return;
  }

  //If get here, we're running in Active mode, so we use this only for 1-second avg current reading.
  if(0 == ++timer)			//one per second, pull out the accumulated
  {					// result and update the 64-second list.
    sl /= 16;				//divide result by 16, per our math.
    sl -= CCIoffset;        //subtract the offset calibration value
    CCarray_AddSample((signed int) sl);	//extract the properly scaled current value.
    sl = 0;				//clear the accumulator
  }

  // Now, accumulate SOME of the available samples, specifically, (10.74 x 16) of them,
  //  to ultimately yield a 1mA-per-bit current measurement in the accumulator variable "sl".

  temp = mod_remainder;			//(this auto-clears the upper byte, by promotion.)
  temp += CCI_CAL;			//if this addition causes a CARRY, then USE this sample.
  mod_remainder = (unsigned char) temp;	//Re-save.

  if(temp>>8)	//was a CARRY generated?
  {
    temp = CADIC;			//grab the result
//    temp -= CCIoffset;     // remove offset from each sample, different value than the one currently used/calibrated
    LatestCCI = temp;			//update the globally-available value
    sl += temp;
  }
  else
    LatestCCI = CADIC;			//update the globally-available value
}




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






/* ******************************************************************** *
 * Coulomb Counter, Regular Current ISR
 *
 * This interrupt is tripped when the discharge current exceeds the amount
 * specified in the CADRDC register (set up by the CCmode() function).
 * When this fires, it indicates that the system needs to switch back to
 * Active Mode.
 *
 * ******************************************************************** */

#pragma vector = CCADC_REG_CUR_vect
__interrupt void CC_RegularCurrent_ISR(void)
{
  ChangePowerMode(POWERMODE_ACTIVE,0);
}








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


/* ********************************************************************
 * Coulomb Counter, Accumulator ISR
 *
 *! \todo
 * This interrupt is the main mechanism for collecting charge estimates
 * for the 'fuel gauge' function.  Note that CCADC offset error must also
 * be corrected here, and temperature should be taken into account in
 * subsequent calculations as well.
 *
 * ******************************************************************** */

//unsigned char ccindex = 0;
//long ccarray[256];

#pragma vector = CCADC_ACC_vect
__interrupt void CC_Accumulator_ISR(void)
{
  union {signed long acc; unsigned char byte[4];} lastCCreading;

//! \todo If using IAR3.20, the following lines need to be enabled and the one below disabled.
/*
  lastCCreading.byte[0] = CADAC0;	//grab the ACC value
  lastCCreading.byte[1] = CADAC1;	//grab the ACC value
  lastCCreading.byte[2] = CADAC2;	//grab the ACC value
  lastCCreading.byte[3] = CADAC3;	//grab the ACC value
*/
  lastCCreading.acc = CADAC;  // Only works with IAR 4.10 and later

  lastCCreading.acc -= (signed long) CCoffset;	//although the CC's offset is temperature-dependent
  				// we have NOT implemented thermal compensation.

  if(CC_delay_acc)
  {
    CC_delay_acc--;
    return;
  }

  RunningAcc += lastCCreading.acc;	//merge this sample with the main accumulator.

}





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






/* General description of ADC usage:
 *
 * The ADC handles 10 different inputs.  We trigger a periodic
 * scan through all the channels back-to-back by a timer.
 * Then, when desired, the user can request a particular measurement,
 * according to its function group, and will get back a properly
 * scaled and calibrated value.  For instance, reading a temperature
 * will scale the ADC result including gain and offset; when reading
 * a particular cell's voltage, it will be corrected according to the
 * offset and gain for that particular channel.
 *
 * When reading cell voltages, we must ensure that cell balancing FETs
 * are disabled.
 *
 * The time required for fully charging a cell's input bypass cap to
 * within 1/4000th of full-scale (about 1mV error, max.) is approx.
 * 8 time-constants (not 9, since the cap starts at cellV/2 rather
 * than at 0.00V).  In the configuration we use, we have a 0.1uF with
 * a 500ohm resistor, giving a TC of 50uS.  400uS is therefore required
 * before commencing a reading of any cell's ADC channel.  We accomplish
 * this delay without cost by reading the other channels first, THEN
 * reading the cell inputs.
 *
*/






void ADCinit(void)
{
//  char i;

  ReadFactoryCalibration();

  // Note: SLOW_RC_CAL is used in calculations on the Wakeup timer to
  // calculate the elapsed time, rather than to adjust its oscillator.
}




//This routine starts a scan of all 10 ADC channels back-to-back.
// The parameter specifies which Thermistor input to read (0-3).
void StartAdc(unsigned char select)
{
  unsigned char temp = (1<<select);


  //! \todo  NOTE: If not using ADC0-3 exclusively as analog inputs, you MUST modify the following code.
  DIDR0 = 0x0F;						//disable ADC0-3 digital input buffer

  PORTA &= 0xE0;
  PORTA |= (1<<4);		//drive PA4 high!
  DDRA  &= 0xE0;
  DDRA  |= (1<<4) | temp;	//make PA4 and the selected signal be Outputs

  VADMUX = 5;						//set up for channel 5 first.
  VADCSR = (1<<VADEN) | (1<<VADCCIF);			//clear any pending int
  VADCSR = (1<<VADEN) | (1<<VADSC) | (1<<VADCCIE);	//Start the first conversion & ena int's
}



// Automatically scan through all ADC channels.
// When all 10 are done, this interrupt disables itself.
#pragma vector = VADC_vect
__interrupt void ADC_INT(void)
{
  unsigned char temp;
  static char counter;	//added to handle Rev E silicon errata.

  temp = VADMUX;

  ADCbuffer[temp-1] = VADC;	//save the result

  if((temp <= 4) && (temp >= 1))	//just read a Cell?
    cell_current[temp-1] = LatestCCI;	//save its associated CCI reading for impedance.

  if(temp == 5) {			// init counters before getting there during scan.
    counter = VPTAT_READINGS; // per errata for Rev E silicon
    temp++;
  }

  if((temp == 6)||(temp == 7)) {  //
    if(--counter == 0) {		  // wait for VPTAT to stabilize, per errata for rev.E
      temp++;
      counter = ADC0_READINGS;    // wait for VREF to stabilize after VPTAT readings
    }
  } else {
    temp++;
    if(10 == temp) {         // earliest possible 8, latest 10, if earlier use 6/7 ifs above
      DisableCellBalancing();	//if more than 519uS is needed, we can do this earlier than 10!
    } else {
      if(10 < temp) {			// continue with cell1-4?
        temp = 1;
      } else {
        if(5 == temp) {	  //have we scanned ALL channels now?
          SetADCScanDone;		//flag Mainline that we have new samples!
          EnableCellBalancing();
          VADCSR = 0;		//disable this ADC and its Interrupt.
          return;
        }
      }
    }
  }

  VADMUX = temp;
  VADCSR |= (1<<VADSC);		//start next conversion now.
}




//This should be called from main().
//After an ADC scan, this will calculate new results.
//This needs to know the state from the thermistor state machine.
void CalculateADCresults(void)
{
  unsigned long calc;
  unsigned char index;
//  unsigned int fixedV;
  unsigned int thermV;

  //Calculate new cell voltages
  for(index = 0; index < PACKSTACK; index++)
  {
    calc = ADCbuffer[index]<<2;
    calc = calc * ADCgain[index];
    calc >>= 16;
    CellV[index] = (unsigned int)(calc);
    if((unsigned int)calc < CELL_TOOLITTLEV)
      DoShutdown(SHUTDOWN_REASON_UNDERVOLTAGE);		//go to Shutdown Mode if cell is drained!
    if((unsigned int)calc > CELL_TOOMUCHV)
      DoShutdown(SHUTDOWN_REASON_OVERVOLTAGE);		//go to Shutdown Mode if cell is too full!
  }

  //! \todo  Code could be added HERE to do something with the cell_current[] array,
  //!        for the purpose of determining cell impedances.

  //Calculate new ADC4 (PA4) reading due to its scale factor of ~0.2X
  calc = ADCbuffer[4];
  calc = calc * 344;
  VPA4 = (unsigned int) (calc >> 8);


  //Calculate on-chip temperature. There may be ways to optimize this,
  // such as pre-scaling VTgain up by 2.5X, then scaling ADCbuffer[6] by 4X,
  // so that when multiplied you get 10X. Can then shift the result UP by 2,
  // then grab the upper two bytes as the result. Not sure if VTgain can be
  // scaled by 2.5X and still fit in an INT.  Doing this optimization would save a long div.
  calc = ADCbuffer[5];
  calc = calc * VTgain;			//this gives 'K * 2^14
  OnChipTemp = (unsigned int) (calc / 1638);	//divide by (2^14 / 10) to get 0.1'K


  //Update the result for the thermistor that was just checked.
  index = ThermistorSelect;	//ThermistorSelect says which output was low.
  index++;			//Go to next channel & use that reading as midpoint.
  index &= 0x03;
  thermV = ADCbuffer[index+7];
  Thermistor[ThermistorSelect] = thermV;
}




// Returns on-chip temperature in 0.1 degrees Kelvin.
// Returns Thermistor resistance reading directly in Ohms (change this as needed).
// channel: 0=on-chip; 1-4 = PA0-3 thermistors
unsigned int ReadTemperature(unsigned char channel)
{

  if(0 == channel)
    return OnChipTemp;

//  temperature = ADCbuffer[6] * VTgain;
//  temperature = temperature / 1638;		// =16384/10
//    temperature -= 2731;			//convert from 'K to 'C (0'C = 273.15K)
//    return (unsigned int) temperature;


  if(channel > 5)
    return 0;				//choose what error value you want.

  //! \todo   Insert calculations here to convert voltage reading(s) to temperature(s).
  return Thermistor[channel-1];		//for now, just return the VADC result

}



//Read the cell voltage in millivolts (always positive). (cell = 1-4)
unsigned int ReadCell(char cell)
{
  if((cell == 0) || (cell > 4))
    return 0;

  return CellV[cell-1];
}


void DisableCellBalancing(void)
{
  CBCR = 0;
}


void EnableCellBalancing(void)	//if CellToBalance = 0, no balancing req'd.
{
  if(CellToBalance)
  {
    CBCR = (1<<(CellToBalance-1));
  }
  else
    CBCR = 0;
}




⌨️ 快捷键说明

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