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

📄 avr

📁 使用MEGA88制作电表的程序
💻
📖 第 1 页 / 共 3 页
字号:
  // the analogue front end may typically contribute up to six degrees
  // of additional phase lag. Phase distortions are calibrated using
  // linear interpolation, as follows:
  //
  //	Calibrated = x[n-1] + CalibCoefficient * ( x[n] - x[n-1] )
  //
  // Note that linear interpolation is the same as a fixed time delay.
  // This means that higher frequency componentes will not be adjusted
  // correctly. Typically, though, not enough energy is present in the
  // higher frequency components to cause this to degrade accuracy below
  // acceptable levels.
  //
  // Also note that the higher the sampling rate, the lower is the
  // calibration range in degrees. If the sampling rate is too high,
  // then the linear interpolation as such can not compensate for the
  // phase lag of some DC immuned current transformers. Such
  // transformers can have a phase lag in excess of six degrees.
  TempL=Sample[Index].Filtered-Sample[Index].PreviousFiltered;
  TempL=TempL*CalCoeff.PCC[Index];
  TempL=TempL>>16;
  Sample[Index].Calibrated=Sample[Index].Filtered-TempL;
  
  // Save measurement data for voltage, current and active power on all
  // channels. For active power measurements; accumulate instantaneous
  // power product. For current and voltage measurements: accumulate
  // square of samples
  //
  // Range check:
  //
  // 	Filtered data:		Filtered  Range=[FFFE0280...0001FD80]
  // 	Prescaled data (>>5):	TempX	  Range=[FFFFF014...00000FEC]
  // 	Multiplication result:	(n/a)	  Range=[FF027E70...00FD8190]
  // 
  // 	Prescaled data (>>6):	TempX	  Range=[FFFFF80A...000007F6]
  // 	Multiplication result:	(n/a)	  Range=[FFC09F9C...003F6064]
  // 
  // Assuming that sampled data is stuck at full-scale (which it can't
  // be, since the high-pass filter would bias such a signal to zero),
  // then for accumulation purposes the maximum number of samples that
  // can be integrated is:
  //
  // 	MaxSamples(presc=32) = 7FFFFFFFh / 00FD8190h = 0081h = 129d
  // 	MaxSamples(presc=64) = 7FFFFFFFh / 003F6064h = 0205h = 517d
  //
  // Note: Index=0 -> ADC2, Index=1 -> ADC0, Index=2 -> ADC1
  Temp[Index]=Sample[Index].Calibrated>>6;
  switch (Index)
  {
    case 0: // Index=0 => ADC2 (Voltage)
            Accumulator.U2=Accumulator.U2+(Temp[0]*Temp[0]);
            break;
    case 1: // Index=1 => ADC0 (Current L)
            Accumulator.IL2=Accumulator.IL2+(Temp[1]*Temp[1]);
            Temp[3]=Temp[0]*Temp[1];
            Accumulator.PL=Accumulator.PL+Temp[3];
            break;
    case 2: // Index=2 => ADC1 (Current N)
            Accumulator.IN2=Accumulator.IN2+(Temp[2]*Temp[2]);
            Temp[4]=Temp[0]*Temp[2];
            Accumulator.PN=Accumulator.PN+Temp[4];
            SampleCounter++;
            break;
  }
  if (SampleCounter==NMAX)
  {
    SampleCounter=0;
    if (Flags&GROGGY)
    {
      // Clear unsettled, accumulated data
      Accumulator.PL=0;
      Accumulator.PN=0;
      Accumulator.U2=0;
      Accumulator.IL2=0;
      Accumulator.IN2=0;
      Flags=Flags&(0xFF-GROGGY);          // Clear flag; we are OK now
    }
    else
      Flags=Flags|CYCLE_FULL;
  }
  
  // Maintain multiplexing of input channels
  if (++Index > 2)
    Index=0;
  ADMUX=ADC_VREF_TYPE+Index;		// Select next ADC input

  // Maintain display counter pulse, if activated. Toggle pulse as follows:
  //          ________
  // DPP:  __/        \___________________________________
  //                            ________
  // DPN:  ____________________/        \_________________
  //
  // TIME: --+--------+--------+--------+------------------>
  //         0      DPon    2*DP_ON  3*DP_ON      1T = 1/fs
  //
  // Use DP_ON constant to set pulse lentgh according to display counter specs
  if (DPCActive>0)
  {
    DPCActive++;
    switch (DPCActive)
    {
      case  DP_ON:    PORTD=(PIND&DIRD)&(0xFF-DPP);
                      break;
      case  2*DP_ON:  PORTD=(PIND&DIRD)|DPN;
                      break;
      case  3*DP_ON:  PORTD=(PIND&DIRD)&(0xFF-DPN);
                      DPCActive=0;
                      break;
    }
  }
  PORTB=(PINB&DIRB)&(0xFF-DUTY);
  asm("wdr");				// Watchdog reset
}                                       // End of ADC_ISR


/////////////////////////////////////////////////////////////////////////////
//  S U B F U N C T I O N S
/////////////////////////////////////////////////////////////////////////////

// Fundamental function for character-based input
int getchar(void)
{
  Flags=Flags&(0xFF-KEY_PRESSED);
  return RxBuffer;
}

// Fundamental function for character-based output (printf, etc)
int putchar(int Data)
{
  while ((UCSR0A & (1<<UDRE0))==0);
  UDR0=Data;
  return(Data);
}

// Calculate CRC16 Checksum based on initial checksum. Return new checksum.
unsigned int CRC(unsigned int chksum, unsigned char buffer)
{
  unsigned char j=8;
  
  chksum ^= (unsigned int)(buffer);
  do
  {
    if(chksum&0x8000)
      chksum=(chksum<<1) ^ CRC_POLYNOME;
    else 
      chksum=chksum<<1;
  }
  while(--j);
  return(chksum);
}

// Called after a device reset; initialises only registers which are required
// to have a non-default value
void Initialise(void)
{
  ACSR=0x80;      // Disable analogue comparator; save power

  DDRB=DIRB;
  DDRC=DIRC;
  DDRD=DIRD;

  TCCR1A=0x80;    // CLEAR output on next match (no EP output yet)
  TCCR1B=0x0D;	  // CTC Mode, Top=OCR1A, CLK/1024
  OCR1A=0xFFFF;   // Assume zero power; set max pulse interval
  OCR1B=0x00C3;   // Length of EP; T = (1024*195)/4000000 = 49.92ms
  TIMSK1=0x07;    // T/C1: Output compare match A & B + overflow

  UCSR0A=0x02;     // USART 2x speed enabled, Multi-processor mode disabled
  UCSR0B=0xD8;     // Rx and Tx enabled, Rx and tx interrupts enabled
  UCSR0C=0x06;     // Asynchronous, no parity, 8 data bits, 1 stop bit
  UBRR0=0x000C;    // f=4.000MHz, U2X=1: 38400 baud +/- 0.2%

  // ADC initialization:
  // Enable ADC interrupt and use internal voltage reference with stabilising
  // capacitor on AREF. Set multiplexer input to first channel and do not set
  // ADC to High Speed Mode. Set Auto Trigger Source to Free Running Mode.
  //
  //  fCLK | ADPS | Prescaler | ADCCLK | Sampl.Rate
  // ------+------+-----------+--------+-----------
  // 4.000 |  111 |       128 | 31250  |       2403

  ADMUX=ADC_VREF_TYPE;
  ADCSRA=0xEF;    // Enable ADC, start, auto trigger, int enable, presc = 128

  Flags=Flags|DISPLAY;            // Set flag
  Flags=Flags|GROGGY;             // Just woke up, hold on for a while...
  TC1extTOP=0xFFFF;               // Assume zero power; set max count
  DPCIncrement=0;                 // No increment; no displ counter pulses yet

  SampleCounter=-1200+NMAX;       // Allow HPF to settle to within 1%
  PORTC=(PINC&DIRC)|EARTH|REVDIR; // Set signals high to start with
}

void InitGainControl(void)
{
  // The LessGain flags will be set when any sample reaches high limit
  Flags=Flags&(0xFF-LESSGAIN0);
  Flags=Flags&(0xFF-LESSGAIN1);
  
  // The MoreGain flags will be cleared when any sample reaches threshold
  Flags=Flags|MOREGAIN0;
  Flags=Flags|MOREGAIN1;
}

void ReadCalibration(void)
{
  // Remember that interrupts must be disabled when accessing EEPROM!
  //
  // ADDR | +0x00 | +0x01 | +0x02 | +0x03 | +0x04 | +0x05 | +0x06 | +0x07
  // -----+-------+-------+-------+-------+-------+-------+-------+-------
  // 0x00 | PCC0H | PCC0L | PCC1H | PCC1L | PCC2H | PCC2L | ILG0H | ILG0L
  // 0x08 | ILG1H | ILG1L | ILG2H | ILG2L | ING0H | ING0L | ING1H | ING1L
  // 0x10 | ING2H | ING2L |   UGH |   UGL |   MCH |   MCL |  DPCH |  DPCL
  // 0x18 |       |       |       |       | CRCWH | CRCWL | CRC16 | CRC16
  //
  // FEATURE: DO NOT FILL EEPROM WITH ZEROS, SINCE IT WILL GIVE A VALID
  // CHECKSUM BUT INVALID CALIBRATION COEFFICIENTS!
  
  unsigned char n=0,Hi,Lo;
  unsigned int crc=0;
  
  // Calculate checksum for first 24 bytes of EEPROM  
  for (n=0;n<0x18;n++)
  {
    __EEGET(Hi,n);
    crc = CRC(crc,Hi);
  }
  
  // Write checksum to EEPROM if CRCW = 0x4357
  __EEGET(Hi,0x1C);
  if (0x43==Hi)
  {
    __EEGET(Lo,0x1D);
    if (0x57==Lo)
    {
      __EEPUT(0x1C,0x00);
      __EEPUT(0x1D,0x00);
      __EEPUT(0x1E,(crc>>8));
      __EEPUT(0x1F,(crc&0xFF));
    }
  }
  
  // Read calibration coefficients from EEPROM, if checksum holds
  __EEGET(Hi,0x1E);
  __EEGET(Lo,0x1F);
  if (crc-(Hi<<8)-Lo)
  {
    // put error handler here
  }
  else
  {
    for (n=0;n<3;n++)
    {
      __EEGET(Hi,0x00 + n*2);
      __EEGET(Lo,0x01 + n*2);
      CalCoeff.PCC[n]=(Hi<<8) + Lo;
  
      __EEGET(Hi,0x06 + n*2);
      __EEGET(Lo,0x07 + n*2);
      CalCoeff.ILG[n]=1.0 / ((Hi<<8) + Lo);
  
      __EEGET(Hi,0x0C + n*2);
      __EEGET(Lo,0x0D + n*2);
      CalCoeff.ING[n]=1.0 / ((Hi<<8) + Lo);
    }
  
    __EEGET(Hi,0x12);
    __EEGET(Lo,0x13);
    CalCoeff.UG=(unsigned int)((Hi<<8) + Lo) / 65536.0;
    
    __EEGET(Hi,0x14);
    __EEGET(Lo,0x15);
    CalCoeff.MC=(Hi<<8) + Lo;
    
    __EEGET(Hi,0x16);
    __EEGET(Lo,0x17);
    CalCoeff.DPC=(Hi<<8) + Lo;
  }

  // Save clock cycles; calculate numerator now, rest when adjusting EP T/C:
  //
  //   Tnum = (3600 x fCLK)/(Prescaler x P[kW])
  //        = (3600 x 4000000 x 1000)/(1024 x MC)
  //        = 14 062 500 000 / MC
  Tnum=14062500000.0/CalCoeff.MC;
}

void SetGain(unsigned char Channel, unsigned char Level)
{
  //  ADC |        |      |    PD    |   PORTD  |   DDRD  
  //  Ch. |  Range | Gain | 76543210 | 76543210 | 76543210
  // -----+--------+------+----------+----------+----------
  //   0  |    Low |    1 | xxxxLLxx | xxxx00xx | xxxx11xx
  //   0  | Medium |    8 | xxxxHLxx | xxxx10xx | xxxx11xx
  //   0  |   High |   64 | xxxxLHxx | xxxx01xx | xxxx11xx
  //   1  |    Low |    1 | xxLLxxxx | xx00xxxx | xx11xxxx
  //   1  | Medium |    8 | xxHLxxxx | xx10xxxx | xx11xxxx
  //   1  |   High |   64 | xxLHxxxx | xx01xxxx | xx11xxxx
  
  #define   GC0   0x0C
  #define   GC1   0x30
  
  switch (Level)
  {
    case LOW:	switch (Channel)
                {
                  case ADC0:  // set gain control pins LOW, only
                              PORTD=(PIND&DIRD)&(0xFF-GC0);
                              ADC0_Gain=LOW;
                              break;
                  case ADC1:  // set both gain control pins LOW
                              PORTD=(PIND&DIRD)&(0xFF-GC1);
                              ADC1_Gain=LOW;
                              break;
                }
                break;
    case MEDIUM:  switch (Channel)
                  {
                    case ADC0:  // set PD2 LOW and PD3 HIGH
                                PORTD=((PIND&DIRD)&(0xFF-GC0))|(1<<PD3);
                                ADC0_Gain=MEDIUM;
                                break;
                    case ADC1:  // set PD4 LOW and PD5 HIGH
                                PORTD=((PIND&DIRD)&(0xFF-GC1))|(1<<PD5);
                                ADC1_Gain=MEDIUM;
                                break;
                  }
                  break;
    case HIGH:	  switch (Channel)
                  {
                    case ADC0:  // set PD2 HIGH and PD3 LOW
                                PORTD=((PIND&DIRD)&(0xFF-GC0))|(1<<PD2);
                                ADC0_Gain=HIGH;
                                break;
                    case ADC1:  // set PD4 HIGH and PD5 LOW
                                PORTD=((PIND&DIRD)&(0xFF-GC1))|(1<<PD4);
                                ADC1_Gain=HIGH;
                                break;
                  }
                  break;
  }
  GainHysteresis=GAIN_HOLD;

⌨️ 快捷键说明

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