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

📄 emeter-foreground.c

📁 msp430F437三相电表DEMO(编译器 IAR 3.42A)
💻 C
📖 第 1 页 / 共 4 页
字号:
    {
        P1OUT &= ~BIT4;
        if ((j & 0x80))
            P1OUT |= BIT7;
        else
            P1OUT &= ~BIT7;
        P1OUT |= BIT4;
        j <<= 1;
    }
    /* Clock the data into the output register */
    P1OUT &= ~BIT6;
    P1OUT |= BIT6;
}
#endif

#if defined(SINGLE_PHASE)  &&  defined(NEUTRAL_MONITOR_SUPPORT)  &&  defined(POWER_BALANCE_DETECTION_SUPPORT)
static long int test_phase_balance(long int live_signal, long int neutral_signal, int threshold)
{
    int permitted_imbalance_fraction;

    /* This may be testing between two currents, or between two powers. I normal mode it
       is testing between two power readings. In limp mode it is testing between two
       current readings. */
    /* See which one is bigger, with some tolerance built in. If the signal measured
       from the neutral is more than 6.25% or 12.5% (options) different from the signal
       measured from the live there is something wrong (maybe fraudulent tampering, or
       just something faulty). In this case we use the current measured from the
       channel with the higher signal. When the channel is reasonably balanced, we use
       the signal from the live lead. If neither signal is above the threshold we use
       a more relaxed measure of imbalance (say 25% or even 50%), to allow for the lower
       accuracy of these small signals (remember, we need the test to work well under
       transient conditions, so the threshold needs to be far more relaxed than the
       basic measurement accuracy would indicate). Assessments are persistence checked
       to avoid transient conditions causing a false change of imbalance status. */
    if (live_signal <= threshold  &&  neutral_signal <= threshold)
        permitted_imbalance_fraction = RELAXED_IMBALANCE_FRACTION;
    else
        permitted_imbalance_fraction = PERMITTED_IMBALANCE_FRACTION;
    /* We have a signal strong enough for proper assessment. */
    if ((phase->status & PHASE_UNBALANCED))
    {
        /* We are looking for the restoration of balance between the
           live and neutral. */
        if ((live_signal - (live_signal >> permitted_imbalance_fraction)) < neutral_signal
            &&
            neutral_signal < (live_signal + (live_signal >> permitted_imbalance_fraction)))
        {
            /* Things might be balanced, but persistence check to be sure. */
            if (--current_unbalanced <= -PHASE_UNBALANCED_PERSISTENCE_CHECK)
            {
                /* Things look genuinely balanced. */
                phase->status &= ~(PHASE_UNBALANCED | CURRENT_FROM_NEUTRAL);
                current_unbalanced = 0;
            }
        }
        else
        {
            current_unbalanced = 0;
            /* The imbalanced might have swapped around - check. */
            /* Here we just choose the greater signal each block, as we have
                already confirmed (i.e. debounced) the imbalance condition. */
            if (neutral_signal > live_signal)
                phase->status |= CURRENT_FROM_NEUTRAL;
            else
                phase->status &= ~CURRENT_FROM_NEUTRAL;
        }
    }
    else
    {
        /* We are looking for the live and neutral becoming unbalanced. */
        if ((live_signal - (live_signal >> permitted_imbalance_fraction)) > neutral_signal
            ||
            neutral_signal > (live_signal + (live_signal >> permitted_imbalance_fraction)))
        {
            /* Things might be unbalanced, but persistence check to be sure. */
            if (++current_unbalanced >= PHASE_UNBALANCED_PERSISTENCE_CHECK)
            {
                /* Things look genuinely unbalanced. */
                current_unbalanced = 0;
                phase->status |= PHASE_UNBALANCED;
                if (neutral_signal > live_signal)
                    phase->status |= CURRENT_FROM_NEUTRAL;
                else
                    phase->status &= ~CURRENT_FROM_NEUTRAL;
            }
        }
        else
        {
            current_unbalanced = 0;
        }
    }
    /* Clear the unbalanced detection, so we don't display unbalanced. This should eliminate
       flashing of the LED if the are transient conditions causing false indications of
       imbalance. */
    if (live_signal <= threshold  &&  neutral_signal <= threshold)
        phase->status &= ~PHASE_UNBALANCED;
    if ((phase->status & CURRENT_FROM_NEUTRAL))
        return  neutral_signal;
    return  live_signal;
}
#endif

#if defined(MAINS_FREQUENCY_SUPPORT)
#if defined(SINGLE_PHASE)
int frequency(void)
#else
int frequency(struct phase_parms_s *phase)
#endif
{
    long int x;
    int step;
    int offset;

    /* Calculate the mains frequency in 1/100Hz increments, based on the mains
       period assessment from the background activity. */
#if defined(LIMP_MODE_SUPPORT)
    if (operating_mode == OPERATING_MODE_LIMP)
    {
        /* In limp mode there is no voltage waveform, so we get the frequency from
           the current in the active lead. This may fail to measure frequency
           correctly for very low currents, and very distorted current waveforms. */
    #if defined(SINGLE_PHASE)  &&  defined(NEUTRAL_MONITOR_SUPPORT)
        if ((phase->status & CURRENT_FROM_NEUTRAL))
            x = phase->neutral.mains_period;
        else
    #endif
            x = phase->current.mains_period;
    }
    else
    {
#endif
        /* Normally we get the mains frequency from the voltage. Voltage is always
           present, and is not subject to the same level of distortion as the current
           waveform with difficult loads. */
        /* Offset by half a sample period, as the FIR table gives delays between - and + 1/2 sample */
        x = (phase->mains_period >> 18) - 128;
        /* We have a whole cycle period, but we want the delay for 90 degrees, so we shift 2 for that.
           We have estimated the period in 1/256 sample steps, but the FIR table is in 1/128th sample
           steps. We shift 1 more for that. */
        step = (x >> 8) + 1;
        offset = 127 - ((x >> 1) & 0x7F);
    #if REACTIVE_POWER_BY_QUADRATURE_SUPPORT
        phase->current.quadrature_fir_beta = fir_coeffs[offset][0];
        phase->current.quadrature_fir_gain = fir_coeffs[offset][1];
        phase->current.quadrature_phase_correction_step = step + phase->current.in_phase_phase_correction_step[0];
        #if defined(SINGLE_PHASE)  &&  defined(NEUTRAL_MONITOR_SUPPORT)
        phase->neutral.quadrature_fir_beta = fir_coeffs[offset][0];
        phase->neutral.quadrature_fir_gain = fir_coeffs[offset][1];
        phase->neutral.quadrature_phase_correction_step = step + phase->neutral.in_phase_phase_correction_step[0];
        #endif
    #endif
        x = phase->mains_period;
#if defined(LIMP_MODE_SUPPORT)
    }
#endif
    x = (int32_t) SAMPLES_PER_10_SECONDS*256L*10L/(x >> 16);
    return  x;
}
#endif

#if defined(VRMS_SUPPORT)
    #if defined(SINGLE_PHASE)
long int voltage(void)
    #else
long int voltage(struct phase_parms_s *phase, struct phase_nv_parms_s const *phase_nv)
    #endif
{
    int i;
    long int x;

    /* Calculate the RMS voltage in 10mV increments. Return -1 for overrange
       (i.e. ADC clip). */
    if ((phase->status & V_OVERRANGE))
        return -1;
    x = div_sh48(phase->V_sq_accum_logged, 26 - 2*ADC_BITS, phase->sample_count_logged);
    #if defined(LIMP_MODE_SUPPORT)
    if (operating_mode == OPERATING_MODE_LIMP)
        i = phase_nv->V_rms_limp_scale_factor;
    else
    #endif
        i = phase_nv->V_rms_scale_factor;
    x = isqrt32(x);
    x = (x >> 12)*i;
    x >>= 14;
    return x;
}
#endif

#if defined(IRMS_SUPPORT)
    #if defined(SINGLE_PHASE)
long int current(void)
    #else
long int current(struct phase_parms_s *phase, struct phase_nv_parms_s const *phase_nv, int ph)
    #endif
{
    #if defined(DYNAMIC_PHASE_CORRECTION_SUPPORT)
    int i;
    int j;
    long int z;
    int gain;
    #endif
    long int x;
    #if defined(SINGLE_PHASE)  &&  defined(NEUTRAL_MONITOR_SUPPORT)
    long int y;
    #endif

    /* Calculate the RMS current in 1mA increments. Return -1 for overrange
       (i.e. ADC clip). A side effect of this routine is it updates the dynamic
       phase correction settings, based on the newly calculated current. */
    /* We always have to work out the properly scaled current from both leads, in
       order to work out the FIR coeffs for the next block. */
    #if defined(SINGLE_PHASE)  &&  defined(NEUTRAL_MONITOR_SUPPORT)
    if ((phase->status & I_NEUTRAL_OVERRANGE))
    {
        y = -1;
        #if defined(PRECALCULATED_PARAMETER_SUPPORT)
        phase->neutral.I_rms = y;
        #endif
        #if defined(DYNAMIC_PHASE_CORRECTION_SUPPORT)
        /* Use the last step in the phase shift table (i.e. the 55A and up step) */
        i = 6 + 50 + 20;
        j = 0;
        #endif
    }
    else
    {
        #if ADC_BITS == 16
        y = div48(phase->neutral.I_sq_accum_logged[0], phase->sample_count_logged);
        #else
        y = div_sh48(phase->neutral.I_sq_accum_logged[0], 32 - 2*ADC_BITS, phase->sample_count_logged);
        #endif
        y = isqrt32(y) - nv_parms.seg_a.s.neutral.ac_offset;
        #if defined(LIMP_MODE_SUPPORT)
        if (operating_mode == OPERATING_MODE_LIMP)
            y = (y >> 12)*nv_parms.seg_a.s.neutral.I_rms_limp_scale_factor;
        else
        #endif
            y = (y >> 12)*nv_parms.seg_a.s.neutral.I_rms_scale_factor;
        y >>= 14;
        #if defined(PRECALCULATED_PARAMETER_SUPPORT)
        phase->neutral.I_rms = y;
        #endif
        #if defined(DYNAMIC_PHASE_CORRECTION_SUPPORT)
        if (y < 0)
        {
            /* This should not happen, but just in case... */
            i = 0;
            j = 0;
        }
        else if (y < 5000)
        {
            /* 0.1A steps up to 5A */
            i = y/100;
            j = y%100;
        }
        else if (y < 25000)
        {
            /* 1A steps up to 25A */
            i = (y - 5000)/1000 + 50;
            j = (y%1000)/10;
        }
        else if (y < 55000)
        {
            /* 5A steps up to 60A */
            i = (y - 25000)/5000 + 50 + 20;
            j = (y%5000)/50;
        }
        else
        {
            /* Stick at the 55A position */
            i = 6 + 50 + 20;
            j = 0;
        }
        #endif
    }
        #if defined(DYNAMIC_PHASE_CORRECTION_SUPPORT)
    gain = (uint8_t) phase_corrections[i][NEUTRAL_CURRENT_CHANNEL][1];
    j = ((phase_corrections[i + 1][NEUTRAL_CURRENT_CHANNEL][0] - phase_corrections[i][NEUTRAL_CURRENT_CHANNEL][0])*j)/100;
    i = nv_parms.seg_a.s.neutral.phase_correction + phase_corrections[i][NEUTRAL_CURRENT_CHANNEL][0] + j;
    /* Adjust the phase shift to allow for the current mains frequency. This is just a linear
       approximation, but should be good enough over the frequency ranges we must cover. */
    if (frequency_phase_factor[NEUTRAL_CURRENT_CHANNEL])
    {
        /* The frequency correction is phase-shift dependant, and is proportional to the square of
           the phase-shift. */
        z = i*i;
        z *= ((int) phase->frequency - MAINS_NOMINAL_FREQUENCY*100);
        //z = z*frequency_phase_factor[NEUTRAL_CURRENT_CHANNEL];
        z >>= 16;
        /* Half bit round */
        z++;
        i -= z;
    }
            #if defined(__MSP430_HAS_ADC12__)  ||  defined(__MSP430_HAS_ADC10__)
    /* We use a +/- 0.5 sample FIR interpolator to perform the phase correction. We use a set
       of coefficients from a table of 128 spread evenly across the +/- 0.5 sample range.
       We need to get the phase shift into range, and end up with an FIR table entry in the 
       range 0 (-0.5 samples) to 127 (+0.5 samples), and the number of whole sample steps
       to use inconjunction with it. */
    i += 128;
            #endif
    gain = 32767 - (gain << 2);
    /* Update the whole group quickly, so the interrupt routine uses a consistent pair of
       step and beta values. */
    phase->neutral.in_phase_phase_correction_step[0] = 2 + (i >> 8);
    i &= 0xFF;
            #if defined(__MSP430_HAS_ADC12__)  ||  defined(__MSP430_HAS_ADC10__)
    i >>= 1;
    phase->neutral.in_phase_fir_beta[0] = fir_coeffs[i][0];
    phase->neutral.in_phase_fir_gain[0] = Q1_15_mul(gain, fir_coeffs[i][1]);
            #elif defined(__MSP430_HAS_SD16_3__)
    if (operating_mode == OPERATING_MODE_NORMAL  &&  phase->neutral.sd16_preloaded_offset != i)
    {
        SD16PRE_NEUTRAL = phase->neutral.sd16_preloaded_offset - i;
        phase->neutral.sd16_preloaded_offset = i;
    }
            #endif
        #endif
    #endif
    if ((phase->status & I_OVERRANGE))
    {
        x = -1;
    #if defined(PRECALCULATED_PARAMETER_SUPPORT)
        phase->current.I_rms = x;
    #endif
    #if defined(DYNAMIC_PHASE_CORRECTION_SUPPORT)
        /* Use the last step in the table (i.e. the 55A and up step) */
        i = 6 + 50 + 20;
        j = 0;
    #endif
    }
    else
    {
    #if ADC_BITS == 16
        x = div48(phase->current.I_sq_accum_logged[0], phase->sample_count_logged);
    #else
        x = div_sh48(phase->current.I_sq_accum_logged[0], 32 - 2*ADC_BITS, phase->sample_count_logged);
    #endif
        x = isqrt32(x) - phase_nv->current.ac_offset;
        
    #if defined(LIMP_MODE_SUPPORT)
        if (operating_mode == OPERATING_MODE_LIMP)
            x = (x >> 12)*phase_nv->current.I_rms_limp_scale_factor[0];
        else
    #endif
            x = (x >> 12)*phase_nv->current.I_rms_scale_factor[0];
        x >>= 14;
    #if defined(PRECALCULATED_PARAMETER_SUPPORT)
        phase->current.I_rms = x;
    #endif
    #if defined(DYNAMIC_PHASE_CORRECTION_SUPPORT)
        if (x < 0)
        {
            /* This should not happen, but just in case... */
            i = 0;
            j = 0;
        }
        else if (x < 5000)
        {
            /* 0.1A steps up to 5A */
            i = x/100;
            j = x%100;
        }
        else if (x < 25000)
        {
            /* 1A steps up to 25A */
            i = (x - 5000)/1000 + 50;
            j = (x%1000)/10;
        }
        else if (x < 55000)
        {
            /* 5A steps up to 60A */
            i = (x - 25000)/5000 + 50 + 20;
            j = (x%5000)/50;
        }
        else
        {
            /* Stick at the 55A position */
            i = 6 + 50 + 20;
            j = 0;
        }
    #endif
    }
    #if defined(DYNAMIC_PHASE_CORRECTION_SUPPORT)
        #if !defined(SINGLE_PHASE)
    gain = (uint8_t) phase_corrections[i][ph][1];
    j = ((phase_corrections[i + 1][ph][0] - phase_corrections[i][ph][0])*j)/100;
    i = phase_nv->current.phase_correction + phase_corrections[i][ph][0] + j;
        #else
    gain = (uint8_t) phase_corrections[i][0][1];
    j = ((phase_corrections[i + 1][0][0] - phase_corrections[i][0][0])*j)/100;
    i = phase_nv->current.phase_correction + phase_corrections[i][0][0] + j;
        #endif
    /* Adjust the phase shift to allow for the current mains frequency. This is just a linear
       approximation, but should be good enough over the frequency ranges we must cover. */
        #if defined(SINGLE_PHASE)
    if (frequency_phase_factor[0])
        #else
    if (frequency_phase_factor[ph])
        #endif
    {
        /* The frequency correction is phase-shift dependant, and is proportional to the square of
           the phase-shift. */
        z = i*i;
        z *= ((int) phase->frequency - MAINS_NOMINAL_FREQUENCY*100);
        //z = z*frequency_phase_factor[ph];
        z >>= 16;

⌨️ 快捷键说明

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