コード例 #1
0
ファイル: ReadInductance.c プロジェクト: lyovav/mkstuff
//=================================================================
void ReadInductance(void) {
#if FLASHEND > 0x1fff
  // check if inductor and measure the inductance value
  unsigned int tmpint;
  unsigned int umax;
  unsigned int total_r;		// total resistance of current loop
  unsigned int mess_r;		// value of resistor used for current measurement
  unsigned long inductance[4];	// four inductance values for different measurements
  union t_combi{
  unsigned long dw;     // time_constant
  uint16_t w[2];
  } timeconstant;
  uint16_t per_ref1,per_ref2;	// percentage
  uint8_t LoPinR_L;	// Mask for switching R_L resistor of low pin
  uint8_t HiADC;	// Mask for switching the high pin direct to VCC
  uint8_t ii;
  uint8_t count;	// counter for the different measurements
  uint8_t cnt_diff;     // resistance dependent offset
  uint8_t LowPin;	// number of pin with low voltage
  uint8_t HighPin;	// number of pin with high voltage 
  int8_t ukorr;		// correction of comparator voltage
  uint8_t nr_pol1;	// number of successfull inductance measurement with polarity 1
  uint8_t nr_pol2;	// number of successfull inductance measurement with polarity 2


  inductor_lpre = 0;	// H units, mark inductor as 0
  if(PartFound != PART_RESISTOR) {
     return;	//We have found no resistor  
  }
  if (ResistorsFound != 1) {
     return;	// do not search for inductance, more than 1 resistor
  }
     if (resis[0].rx > 21000) return;

     // we can check for Inductance, if resistance is below 2100 Ohm
     for (count=0;count<4;count++) {
        // Try four times (different direction and with delayed counter start)
        if (count < 2) {
           // first and second pass, direction 1
           LowPin = resis[0].ra;
           HighPin = resis[0].rb;
        } else {
           // third and fourth pass, direction 2
           LowPin = resis[0].rb;
           HighPin = resis[0].ra;
        }
        HiADC = pgm_read_byte(&PinADCtab[HighPin]);	// Table of ADC Pins including | TXD_VAL
        LoPinR_L = pgm_read_byte(&PinRLtab[LowPin]);	//R_L mask for HighPin R_L load
        //==================================================================================
        // Measurement of Inductance values
        R_PORT = 0;		// switch R port to GND
        ADC_PORT =   TXD_VAL;		// switch ADC-Port to GND
        if ((resis[0].rx < 240) && ((count & 0x01) == 0)) {
           // we can use PinR_L for measurement
           mess_r = RR680MI - R_L_VAL;			// use only pin output resistance
           ADC_DDR = HiADC | (1<<LowPin) | TXD_MSK;	// switch HiADC and Low Pin to GND, 
        } else {
           R_DDR = LoPinR_L;   		// switch R_L resistor port for LowPin to output (GND)
           ADC_DDR = HiADC | TXD_MSK;	// switch HiADC Pin to GND 
           mess_r = RR680MI;			// use 680 Ohm and PinR_L for current measurement
        }
        // Look, if we can detect any current
        for (ii=0;ii<20;ii++) {
            // wait for current is near zero
            umax = W10msReadADC(LowPin);
            total_r =  ReadADC(HighPin);
            if ((umax < 2) && (total_r < 2)) break;	// low current detected
        }
        // setup Analog Comparator
        ADC_COMP_CONTROL = (1<<ACME);			//enable Analog Comparator Multiplexer
        ACSR =  (1<<ACBG) | (1<<ACI)  | (1<<ACIC);	// enable, 1.3V, no Interrupt, Connect to Timer1 
        ADMUX = (1<<REFS0) | LowPin;			// switch Mux to Low-Pin
        ADCSRA = (1<<ADIF) | AUTO_CLOCK_DIV; //disable ADC
   
      // setup Counter1
        timeconstant.w[1] = 0;		// set ov counter to 0
        TCCR1A = 0;			// set Counter1 to normal Mode
        TCNT1 = 0;			//set Counter to 0
        TI1_INT_FLAGS = (1<<ICF1) | (1<<OCF1B) | (1<<OCF1A) | (1<<TOV1);	// reset TIFR or TIFR1
//        HiADC |= TXD_VAL;
        wait200us();			// wait for bandgap to start up
        if ((count & 0x01) == 0 ) {
           //first start counter, then start current
           TCCR1B =  (1<<ICNC1) | (0<<ICES1) | (1<<CS10);	//start counter 1MHz or 8MHz
           ADC_PORT = HiADC;		// switch ADC-Port to VCC
        } else {
           //first start current, then start counter with delay
           //parasitic capacity of coil can cause high current at the beginning
           ADC_PORT = HiADC;		// switch ADC-Port to VCC
      #if F_CPU >= 8000000UL
           wait3us();		// ignore current peak from capacity
      #else
           wdt_reset();			// delay
           wdt_reset();			// delay
      #endif
           TI1_INT_FLAGS = (1<<ICF1);	// Reset Input Capture
           TCCR1B =  (1<<ICNC1) | (0<<ICES1) | (1<<CS10);	//start counter 1MHz or 8MHz
        }
      
      //******************************
        while(1) {
           // Wait, until  Input Capture is set
           ii = TI1_INT_FLAGS;		//read Timer flags
           if (ii & (1<<ICF1))  {
              break;
           }
           if((ii & (1<<TOV1))) {		// counter overflow, 65.536 ms @ 1MHz, 8.192ms @ 8MHz
              TI1_INT_FLAGS = (1<<TOV1);	// Reset OV Flag
              wdt_reset();
              timeconstant.w[1]++;		// count one OV
              if(timeconstant.w[1] == (F_CPU/100000UL)) {
                 break; 	//Timeout for Charging, above 0.13 s
              }
           }
        }
        TCCR1B = (0<<ICNC1) | (0<<ICES1) | (0<<CS10);  // stop counter
        TI1_INT_FLAGS = (1<<ICF1);			// Reset Input Capture
        timeconstant.w[0] = ICR1;		// get previous Input Capture Counter flag
      // check actual counter, if an additional overflow must be added
        if((TCNT1 > timeconstant.w[0]) && (ii & (1<<TOV1))) {
           // this OV was not counted, but was before the Input Capture
           TI1_INT_FLAGS = (1<<TOV1);		// Reset OV Flag
           timeconstant.w[1]++;			// count one additional OV
        }

        ADC_PORT = TXD_VAL;		// switch ADC-Port to GND
        ADCSRA = (1<<ADEN) | (1<<ADIF) | AUTO_CLOCK_DIV; //enable ADC
        for (ii=0;ii<20;ii++) {
            // wait for current is near zero
            umax = W10msReadADC(LowPin);
            total_r =  ReadADC(HighPin);
            if ((umax < 2) && (total_r < 2)) break;	// low current detected
        }
  #define CNT_ZERO_42 6
  #define CNT_ZERO_720 7
//#if F_CPU == 16000000UL
//  #undef CNT_ZERO_42
//  #undef CNT_ZERO_720
//  #define CNT_ZERO_42 7
//  #define CNT_ZERO_720 10
//#endif
        total_r = (mess_r + resis[0].rx + RRpinMI);
//        cnt_diff = 0;
//        if (total_r > 7000) cnt_diff = 1;
//        if (total_r > 14000) cnt_diff = 2;
        cnt_diff = total_r / ((14000UL * 8) / (F_CPU/1000000UL));
        tmpint = ref_mv_offs;		// corrected reference voltage (for C)
        if (mess_r < R_L_VAL) {
           // measurement without 680 Ohm
           cnt_diff = CNT_ZERO_42;
           if (timeconstant.dw < 225) {
              ukorr = (timeconstant.w[0] / 5) - 20;
           } else {
              ukorr = 25;
           }
           tmpint -= (((REF_L_KORR * 10) / 10) + ukorr);
        } else {
           // measurement with 680 Ohm resistor
           // if 680 Ohm resistor is used, use REF_L_KORR for correction
           cnt_diff += CNT_ZERO_720;
           tmpint += REF_L_KORR;
        }
        if (timeconstant.dw > cnt_diff) timeconstant.dw -= cnt_diff;
        else          timeconstant.dw = 0;
       
        if ((count&0x01) == 1) {
           // second pass with delayed counter start
           timeconstant.dw += (3 * (F_CPU/1000000UL))+10;
        }
        if (timeconstant.w[1] >= (F_CPU/100000UL)) timeconstant.dw = 0; // no transition found
        if (timeconstant.dw > 10) {
           timeconstant.dw -= 1;
        }
        // compute the maximum Voltage umax with the Resistor of the coil
        umax = ((unsigned long)mess_r * (unsigned long)ADCconfig.U_AVCC) / total_r;
        per_ref1 = ((unsigned long)tmpint * 1000) / umax;
//        per_ref2 = (uint8_t)MEM2_read_byte(&LogTab[per_ref1]);	// -log(1 - per_ref1/100)
        per_ref2 = get_log(per_ref1);		// -log(1 - per_ref1/1000)
/* ********************************************************* */
#if 0
          if (count == 0) {
             lcd_line3();
             DisplayValue(count,0,' ',4);
             DisplayValue(timeconstant.dw,0,'+',4);
             DisplayValue(cnt_diff,0,' ',4);
             DisplayValue(total_r,-1,'r',4);
             lcd_space();
             DisplayValue(per_ref1,-1,'%',4);
             lcd_line4();
             DisplayValue(tmpint,-3,'V',4);
             lcd_space();
             DisplayValue(umax,-3,'V',4);
             lcd_space();
             DisplayValue(per_ref2,-1,'%',4);
             wait_about4s();
             wait_about2s();
          }
#endif
/* ********************************************************* */
        // inductor_lx in 0.01mH units,  L = Tau * R
        per_ref1 = ((per_ref2 * (F_CPU/1000000UL)) + 5) / 10;
        inductance[count] = (timeconstant.dw * total_r ) / per_ref1;
        if (((count&0x01) == 0) && (timeconstant.dw > ((F_CPU/1000000UL)+3))) {
           // transition is found, measurement with delayed counter start is not necessary
           inductance[count+1] = inductance[count];	// set delayed measurement to same value
           count++;		// skip the delayed measurement
        }
        wdt_reset();
     }  //end for count
     ADC_PORT = TXD_VAL;		// switch ADC Port to GND
     wait_about20ms();
     nr_pol1 = 0;
     if (inductance[1] > inductance[0]) { nr_pol1 = 1; } 
     nr_pol2 = 2;
     if (inductance[3] > inductance[2]) { nr_pol2 = 3; } 
     if (inductance[nr_pol2] < inductance[nr_pol1]) nr_pol1 = nr_pol2;
     inductor_lx = inductance[nr_pol1];
     inductor_lpre = -5;	// 10 uH units
     if (((nr_pol1 & 1) == 1) || (resis[0].rx >= 240)) {
        // with 680 Ohm resistor total_r is more than 7460
        inductor_lpre = -4;	// 100 uH units
        inductor_lx = (inductor_lx + 5) / 10;
     } 
     if (inductor_lx == 0) inductor_lpre = 0;	//mark as zero

  // switch all ports to input
  ADC_DDR =  TXD_MSK;		// switch all ADC ports to input
  R_DDR = 0;			// switch all resistor ports to input
#endif
  return;
 } // end ReadInductance()
コード例 #2
0
ファイル: cap.c プロジェクト: gojimmypi/ComponentTester
uint8_t SmallCap(Capacitor_Type *Cap)
{
  uint8_t           Flag = 3;      /* return value */
  uint8_t           TempByte;      /* temp. value */
  int8_t            Scale;         /* capacitance scale */
  uint16_t          Ticks;         /* timer counter */
  uint16_t          Ticks2;        /* timer overflow counter */
  uint16_t          U_c;           /* voltage of capacitor */
  uint32_t          Raw;           /* raw capacitance value */
  uint32_t          Value;         /* corrected capacitance value */


  /*
   *  Measurement method used for small caps < 50uF:
   *  We need a much better resolution for the time measurement. Therefore we
   *  use the MCUs internal 16-bit counter and analog comparator. The counter
   *  inceases until the comparator detects that the voltage of the DUT is as
   *  high as the internal bandgap reference. To support the higher time
   *  resolution we use the Rh probe resistor for charging.
   *
   *  Remark:
   *  The analog comparator has an Input Leakage Current of -50nA up to 50nA 
   *  at Vcc/2. The Input Offset is <10mV at Vcc/2.
   */

  Ticks2 = 0;                           /* reset timer overflow counter */

  /*
   *  init hardware
   */

  /* prepare probes */
  DischargeProbes();                    /* try to discharge probes */
  if (Check.Found == COMP_ERROR) return 0;     /* skip on error */

  /* set probes: Gnd -- all probes / Gnd -- Rh -- probe-1 */
  R_PORT = 0;                           /* set resistor port to low */
  /* set ADC probe pins to output mode */
  ADC_DDR = (1 << TP1) | (1 << TP2) | (1 << TP3);
  ADC_PORT = 0;                         /* set ADC port to low */
  R_DDR = Probes.Rh_1;                  /* pull-down probe-1 via Rh */

  /* setup analog comparator */
  ADCSRB = (1 << ACME);                 /* use ADC multiplexer as negative input */
  ACSR =  (1 << ACBG) | (1 << ACIC);    /* use bandgap as positive input, trigger timer1 */
  ADMUX = (1 << REFS0) | Probes.Pin_1;  /* switch ADC multiplexer to probe 1 */
                                        /* and set AREF to Vcc */
  ADCSRA = ADC_CLOCK_DIV;               /* disable ADC, but keep clock dividers */
  wait200us();

  /* setup timer */
  TCCR1A = 0;                           /* set default mode */
  TCCR1B = 0;                           /* set more timer modes */
  /* timer stopped, falling edge detection, noise canceler disabled */
  TCNT1 = 0;                            /* set Counter1 to 0 */
  /* clear all flags (input capture, compare A & B, overflow */
  TIFR1 = (1 << ICF1) | (1 << OCF1B) | (1 << OCF1A) | (1 << TOV1);
  R_PORT = Probes.Rh_1;                 /* pull-up probe-1 via Rh */  
                                        
  /* enable timer */
  if (Check.Found == COMP_FET)
  {
    /* keep all probe pins pulled down but probe-1 */
    TempByte = (((1 << TP1) | (1 << TP2) | (1 << TP3)) & ~(1 << Probes.Pin_1));    
  }
  else
  {
    TempByte = Probes.ADC_2;            /* keep just probe-1 pulled down */
  }

  /* start timer by setting clock prescaler (1/1 clock divider) */
  TCCR1B = (1 << CS10);
  ADC_DDR = TempByte;                   /* start charging DUT */


  /*
   *  timer loop
   *  - run until voltage is reached
   *  - detect timer overflows
   */

   while (1)
   {
     TempByte = TIFR1;                  /* get timer1 flags */

     /* end loop if input capture flag is set (= same voltage) */
     if (TempByte & (1 << ICF1)) break;

     /* detect timer overflow by checking the overflow flag */
     if (TempByte & (1 << TOV1))
     {
       /* happens at 65.536ms for 1MHz or 8.192ms for 8MHz */
       TIFR1 = (1 << TOV1);             /* reset flag */
       wdt_reset();                     /* reset watchdog */
       Ticks2++;                        /* increase overflow counter */

       /* end loop if charging takes too long (13.1s) */
       if (Ticks2 == (CPU_FREQ / 5000)) break;
     }
   }

  /* stop counter */
  TCCR1B = 0;                           /* stop timer */
  TIFR1 = (1 << ICF1);                  /* reset Input Capture flag */

  Ticks = ICR1;                         /* get counter value */

  /* disable charging */
  R_DDR = 0;                  /* set resistor port to HiZ mode */

  /* catch missed timer overflow */
  if ((TCNT1 > Ticks) && (TempByte & (1 << TOV1)))
  {
    TIFR1 = (1 << TOV1);                /* reset overflow flag */
    Ticks2++;                           /* increase overflow counter */
  }

  /* enable ADC again */
  ADCSRA = (1 << ADEN) | (1 << ADIF) | ADC_CLOCK_DIV;

  /* get voltage of DUT */
  U_c = ReadU(Probes.Pin_1);       /* get voltage of cap */

  /* start discharging DUT */
  R_PORT = 0;                      /* pull down probe-2 via Rh */
  R_DDR = Probes.Rh_1;             /* enable Rh for probe-1 again */

  /* skip measurement if charging took too long */
  if (Ticks2 >= (CPU_FREQ / 5000)) Flag = 1;


  /*
   *  calculate capacitance (<50uF)
   *  - use factor from pre-calculated SmallCap_table
   */

  if (Flag == 3)
  {
    /*  combine both counter values */
    Raw = (uint32_t)Ticks;                /* set lower 16 bits */
    Raw |= (uint32_t)Ticks2 << 16;        /* set upper 16 bits */
    if (Raw > 2) Raw -= 2;                /* subtract processing time overhead */

    Scale = -12;                          /* default factor is for pF scale */
    if (Raw > (UINT32_MAX / 1000))        /* prevent overflow (4.3*10^6) */
    {
      Raw /= 1000;                        /* scale down by 10^3 */
      Scale += 3;                         /* add 3 to the exponent (nF) */
    }

    /* multiply with factor from table */
    Raw *= GetFactor(Config.Bandgap + NV.CompOffset, TABLE_SMALL_CAP);

    /* divide by CPU frequency to get the time and multiply with table scale */
    Raw /= (CPU_FREQ / 10000);
    Value = Raw;                          /* take raw value */

    /* take care about zero offset if feasable */
    if (Scale == -12)                     /* pF scale */
    {
      if (Value >= NV.CapZero)            /* if value is larger than offset */
      {
        Value -= NV.CapZero;              /* substract offset */
      }
      else                                /* if value is smaller than offset */
      {
        /* we have to prevent a negative value */
        Value = 0;                        /* set value to 0 */
      }
    }

    /* copy data */
    Cap->A = Probes.Pin_2;    /* pull-down probe pin */
    Cap->B = Probes.Pin_1;    /* pull-up probe pin */
    Cap->Scale = Scale;       /* -12 or -9 */
    Cap->Raw = Raw;
    Cap->Value = Value;       /* max. 5.1*10^6pF or 125*10^3nF */


    /*
     *  Self-adjust the voltage offset of the analog comparator and internal
     *  bandgap reference if C is 100nF up to 20µF. The minimum of 100nF
     *  should keep the voltage stable long enough for the measurements. 
     *  Changed offsets will be used in next test run.
     */

    if (((Scale == -12) && (Value >= 100000)) ||
        ((Scale == -9) && (Value <= 20000)))
    {
      int16_t         Offset;
      int32_t         TempLong;

      /*
       *  We can self-adjust the offset of the internal bandgap reference
       *  by measuring a voltage lower than the bandgap reference, one time
       *  with the bandgap as reference and a second time with Vcc as
       *  reference. The common voltage source is the cap we just measured.
       */

       while (ReadU(Probes.Pin_1) > 980)
       {
         /* keep discharging */
       }

       R_DDR = 0;                       /* stop discharging */

       Config.AutoScale = 0;            /* disable auto scaling */
       Ticks = ReadU(Probes.Pin_1);     /* U_c with Vcc reference */
       Config.AutoScale = 1;            /* enable auto scaling again */
       Ticks2 = ReadU(Probes.Pin_1);    /* U_c with bandgap reference */

       R_DDR = Probes.Rh_1;             /* resume discharging */

       Offset = Ticks - Ticks2;
       /* allow some offset caused by the different voltage resolutions
          (4.88 vs. 1.07) */
       if ((Offset < -4) || (Offset > 4))    /* offset too large */
       {
         /*
          *  Calculate total offset:
          *  - first get offset per mV: Offset / U_c
          *  - total offset for U_ref: (Offset / U_c) * U_ref
          */

         TempLong = Offset;
         TempLong *= Config.Bandgap;         /* * U_ref */
         TempLong /= Ticks2;                 /* / U_c */

         NV.RefOffset = (int8_t)TempLong;
       }


      /*
       *  In the cap measurement above the analog comparator compared
       *  the voltages of the cap and the bandgap reference. Since the MCU
       *  has an internal voltage drop for the bandgap reference the
       *  MCU used actually U_bandgap - U_offset. We get that offset by
       *  comparing the bandgap reference with the voltage of the cap:
       *  U_c = U_bandgap - U_offset -> U_offset = U_c - U_bandgap
       */

      Offset = U_c - Config.Bandgap;

      /* limit offset to a valid range of -50mV - 50mV */
      if ((Offset > -50) && (Offset < 50)) NV.CompOffset = Offset;
    }
  }

  return Flag;
}