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

📄 calibration.c

📁 基于MSPF449的三相电压表功率的开发程序
💻 C
字号:
//**************************************************************************
//    This program extracts the pulse from a reference meter and use this to calculate
//     the calibration the meter.
//    This program also stores the calibrated values in flash
//    A 32 bit threshold called E_accum_threshold and A 32 bit energy register call E_accum
//      is used
//    A 32 bit counter call E_accum_count shows the amount of counts of the E_accum 
//      exceeding E_accum_threshold
//    Add a new flag called energy tick.
// 
//    Vincent Chan 
//    Texas Instruments Hong Kong Ltd
//    Date        Comments
//    =====================
//    01/10/15    Code Starts, need to add more variables to the channel parameters long array
//    01/10/5     module more or less working.
//    01/10/23    phase compensation and pulse compensation now working. Pulse compensation
//                has been tested with a reference meter.
//    01/11/27    Now the reference pulse comes into P1.1/TA0 so use CCR0 for reference pulse
//**************************************************************************

#include "emeter_3phase.h"
#include "math.h"
//--------------------------------------------------------------------------
unsigned int local_pulse_count,ref_pulse_count;
unsigned int local_last_capture,ref_last_capture;
unsigned long local_total_time,ref_total_time;
extern long FLASH_INFO_E_accum_threshold;
extern long logged_shifted_p_accum,shift_p_accum;
extern int logged_shifted_p_count,shifted_p_count;
extern int sinne_1,sinne_2;
extern int samples_read_index,samples_write_index,shifted_samples_read_index;
extern double chan1_ratio;
extern int chan1_int_params[17];
extern int FLASH_INFO_average_temperature,FLASH_INFO_average_VeREF_range;
extern int average_temperature,average_VeREF_range;
extern int instant_temperature,instant_VeREF_PLUS,instant_VeREF_MINUS;

void calibrate_starts(int* int_params, long* long_params)
{
int* chan_int_params;
long* chan_long_params;
long  l_word;
float* f_ptr;
int i;
float ratio,param1,param2;

chan_long_params=long_params;
chan_int_params=int_params;

//setup and enable TIMER_A for channel 1 calibrating
//setup TAR_A to use 32768 as master clock
//CCR2 as capture mode
//TACCTL1=CAP+CCIS0+CM1;           //

//TACCTL1=CAP+CM_1;
//TACCTL0=CAP+CCIS0+CM_1;                                 
//TACTL=TACLR+MC_2+TASSEL_1+ID1+ID0;               
                                  // start TIMER_A continous mode, ACLK as input clock 
                                  // DIV by 16 to give 8 seconds maximum duration

//wait for the first 6 pulses to let self settle, then start real calibration

local_last_capture=0;
ref_last_capture=0;
ref_total_time=0;
local_total_time=0;
local_pulse_count=16;
ref_pulse_count=16;
do
  {
  if((TACCTL0&CCIFG)&&(ref_pulse_count))                    
                                      //reference meter pulse received
                                      //only deal with it when pulse_count>0
    {
    TACCTL0&=~CCIFG;                  //reset flag
    i=TACCR0-ref_last_capture;   //work out delta
    ref_last_capture=TACCR0;              //store last value
    if(ref_pulse_count<=10)
          ref_total_time+=i;              //only accum. after 6 pulses
    DISPLAY(i,0);
    DISPLAY_1DIGIT(ref_pulse_count,5);    //display number of pulses captured
    DISPLAY_1DIGIT(10,6);                     //display A for ref pulse
    --ref_pulse_count;
    } 
//  if((TACCTL0&CCIFG)&&(local_pulse_count))           //local pulse received
//    {
//    TACCTL0&=~CCIFG;         //reset flag
//    i=TACCR0-local_last_capture;
//    local_last_capture=TACCR0;
  if((int_params[channel_status]&E_TICK)&&(local_pulse_count))
    {
    int_params[channel_status]&=~E_TICK;  
    i=int_params[ENERGY_PERIOD];
    if(local_pulse_count<=10)
          local_total_time+=i;
    DISPLAY(i,0);
    DISPLAY_1DIGIT(local_pulse_count,5);    //display number of pulses captured
    DISPLAY_1DIGIT(11,6);                   //display B for localpulse
    --local_pulse_count;        
    }
  average_temperature=(average_temperature+instant_temperature)/2;
  average_VeREF_range=(average_VeREF_range+(instant_VeREF_PLUS-instant_VeREF_MINUS))/2;     
  }while((local_pulse_count!=0)||(ref_pulse_count!=0));


 //calculate the ratio between the reference pulse and generated pulse length
 //Threshold = old Threshold * ref_time/local_time
 //If reference meter pulse is quicker, then ref_total_time<local_total_time, we then
 //  want to decrease the threshold to make the local pulse faster. Hence
 //  Threshold * ref_time/local_time
 
ratio = (float) long_params[E_accum_threshold];
param1 = (float) local_total_time;
param2 = (float) ref_total_time;
ratio = ratio * param2/param1;
long_params[E_accum_threshold] = (long) ratio;

//*****************************************************
// Use the pulse period to calculate displayed power
//  then the scale factor
//*****************************************************
  #if 1
l_word=0;

for(i=0;i<8;i++)
  {
  while(!(int_params[channel_status]&NEW_P_LOG));
  l_word+=long_params[logged_P_accum]/int_params[logged_P_count];
  int_params[channel_status]&=~NEW_P_LOG;
  DISPLAY(i,0);
  }
l_word=l_word/8;                    //this is the average power by averageing
f_ptr= (float*) &long_params[POWER_SCALE_FACTOR];
DISPLAY(power_conversion(l_word,*f_ptr),0);

param1=(float)l_word;
                                    //since float and long has the same number of words
                                    //use a long array element to store a float
                                    
                                    //reading/(32768/8) = time, 
                                    //power = 3600/(reading/4096) =3600*4096/reading;
                                    //power to 0.1 Watt = 36000*4096/reading;
        
param2=(float) 36000*4096;
                                    //work out the channel power
param2=param2/(float) int_params[ENERGY_PERIOD];
                                    //channel_power=averaged_power*power_scale_factor
                                    //power_scale_factor=channel_power/averaged_power
param2=param2/param1;                                    
                                    //store results                                    
f_ptr = (float*) & long_params[POWER_SCALE_FACTOR];                                   
*f_ptr = param2;

  #endif

TACCTL0&=~CCIFG;
while(!(TACCTL0&CCIFG));
TACCTL0&=~CCIFG;
while(!(TACCTL0&CCIFG));
  
long_params[E_accum] = 0;


DISPLAY_1DIGIT(0x10,5);                           //0x10 equivalent to 0
DISPLAY_1DIGIT(0x10,6);
//Disable TIMER_A and comparator
//TACTL=0;
//store results in parameters in flash
}


void sync_with_reference(void)
{
_DINT();
//setup and enable TIMER_A for channel 1 calibrating
//setup TAR_A to use 32768 as master clock
//CCR2 as capture mode
//TACCTL1=CAP+CCIS0+CM1;           //enables interrupt at CCR2 capture
                                  //use comparator output as input
                                  //use negative edge as input
//TACCTL1=CAP+CM_1;
//TACCTL0=CAP+CCIS0+CM_1;                                 
//TACTL=TACLR+MC_2+TASSEL_1+ID1+ID0;  
 
//wait for pulses from reference meter

TACCTL0&=~CCIFG;
while(!(TACCTL0&CCIFG));
TACCTL0&=~CCIFG;
while(!(TACCTL0&CCIFG));
//TACTL=0;

_EINT();
}

int calibrate_CT(int* int_params, long* long_params)
{
long total_power,shifted_total_power;
int i,j,k;
double phase_shift,ratio;
float* f_ptr;
      
_EINT();

k=0,j=0;
do                     //make this stable
  {
  if(int_params[channel_status]&(NEW_P_LOG+NEW_I_LOG+NEW_V_LOG))
    {
                      //this flags indicates an X number of cycles of voltage signals as been
                      // added, the sum is divided by the number of samples to extract the 
                      // DC bias level
    if(int_params[channel_status]&NEW_V_LOG)
      {
      i=long_params[logged_V_accum]/int_params[logged_V_count];
      int_params[V_bias]=(i+int_params[V_bias])/2;
      int_params[channel_status]&=~NEW_V_LOG;
      //DISPLAY(int_params[V_bias],0);
      }
                      //this flags indicates an X number of cycles of current signals as been
                      // added, the sum is divided by the number of samples to extract the 
                      // DC bias level      
    if(int_params[channel_status]&NEW_I_LOG)
      {
      i=long_params[logged_I_accum]/int_params[logged_I_count]; 
      int_params[I_bias]=(int_params[I_bias]+i)/2;  
      int_params[channel_status]&=~NEW_I_LOG;
      //DISPLAY(int_params[I_bias],0);
      }
    if(int_params[channel_status]&NEW_P_LOG)
      {
      total_power+=long_params[logged_P_accum]/int_params[logged_P_count];
      shifted_total_power+=long_params[logged_PS_P_accum]/int_params[logged_PS_P_count];
      int_params[channel_status]&=~NEW_P_LOG;
      if(++j>=8)
        {
        total_power/=8;
        shifted_total_power/=8; 
        ratio= (double) shifted_total_power/total_power;
        f_ptr= (float*) &long_params[POWER_SCALE_FACTOR];
//        DISPLAY(power_conversion(shifted_total_power,*f_ptr),0);
        DISPLAY(power_conversion(total_power,*f_ptr),0);
        DISPLAY_1DIGIT(k,5);
        total_power=0;
        shifted_total_power=0;
        j=0;
        k++;
        }
      average_temperature=(average_temperature+instant_temperature)/2;
      average_VeREF_range=(average_VeREF_range+(instant_VeREF_PLUS-instant_VeREF_MINUS))/2;       
      }
    }      
//  }while(k<10);  
  }while(k<5);
//each sample = (50/3276.8)*360 =  5.4931640625 degree or  0.09587379924285 rad
//each CT compensation step =    0.08583068847656 degree 0.00149802811317 rad
//This calculate the phase_shift based on the ratio between non shifted power and
phase_shift =calc_phase_shift(ratio);
phase_shift = phase_shift/(0.00149802811317);    // divide by CT compensation step to get index
phase_shift += 0.5;                              // will convert result to integer only so need to
                                                //  do fractional adjustment
return((int) phase_shift);
} 




//  This rouine returns a phase shift in radians
//  It uses the ratio between the power with an artificial current phase shift of 60.4 degree,
//                            and the power without this shift
//  If p is the phase shift of the CT. Then the ratio can be expressed as:
//  cos(60.4+p)/cos(p)=ratio
//  cos(60.4)-sin(60.4)sin(p)/cos(p)=ratio
//  sin(p)/cos(p)=[cos(60.4)-ratio]/sin(60.4)]
//  Let's say [cos(60.4)-ratio]/sin(60.4)] = Q
//  p = arc_cos[ square_root(1/(Q^2+1))]
//  p is in radians.
//  This equation does not detect sign of the shift which needs to be additionally worked out

double calc_phase_shift(double ratio)
{
double result;
int sign;

if(ratio>0.4935653955488) sign=1;
else sign=0;                                            //delay by 11*5.49 degree
result=(0.4935653955488-ratio)/0.8697086870423;         //= (cos(60.4)-ratio)/sin(60.4)
result= result*result+1;
result=1/result;
result=sqrt(result);
result =acos(result);
if(sign) return (-result);
else return(result);                                    // each step = [(50/3276.8)2*PI]/64
}    

⌨️ 快捷键说明

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