📄 emeter-background.c
字号:
phase->status |= I_NEUTRAL_POS;
}
#endif
#if !defined(SINGLE_PHASE)
phase++;
}
#endif
#if !defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT) && defined(IRMS_SUPPORT)
/* For multi-phase meters, neutral monitoring is limited to measuring the
RMS current. */
corrected = adc_buffer[++adc_ptr];
if ((corrected >= ADC_MAX || corrected <= ADC_MIN) && neutral.I_endstops)
neutral.I_endstops--;
I_live_sample = corrected - adc_buffer[--adc_ptr];
I_live_sample = dc_filter(&neutral.I_dc_estimate, I_live_sample);
accum48(neutral.I_sq_accum[0], imul16(I_live_sample, I_live_sample));
if (++neutral.sample_count[0] >= samples_per_second)
log_neutral_parameters();
#endif
#if defined(TOTAL_ENERGY_SUPPORT)
/* We now play the last measurement interval's power level, evaluated
in the foreground, through this measurement interval. In this way
we can evenly pace the pulsing of the LED. The only error produced
by this is the ambiguity in the number of samples per measurement.
This should not exceed 1 or 2 in over 4000. */
#if defined(LIMP_MODE_SUPPORT)
if (operating_mode == OPERATING_MODE_NORMAL)
{
#endif
#if defined(INHIBIT_NEGATIVE_TOTAL_POWER_ACCUMULATION)
if (total_power > 0 && (total_power_counter += total_power) >= TOTAL_ENERGY_PULSE_THRESHOLD)
#else
if ((total_power_counter += total_power) >= TOTAL_ENERGY_PULSE_THRESHOLD)
#endif
{
total_power_counter -= TOTAL_ENERGY_PULSE_THRESHOLD;
#if TOTAL_ENERGY_PULSES_PER_KW_HOUR < 1000
if (++extra_total_power_counter >= 16)
{
extra_total_power_counter = 0;
#endif
++total_consumed_energy;
/* Ideally we want to log the energy each kWh unit, but doing
it with a mask here is good enough and faster. */
if ((total_consumed_energy & 0x3FF) == 0)
phase->status |= ENERGY_LOGABLE;
/* Pulse the LED. Long pulses may not be reliable, as at full
power we may be pulsing many times per second. People may
check the meter's calibration with an instrument that counts
the pulsing rate, so it is important the pulses are clear,
distinct, and exactly at the rate of one per
1/ENERGY_PULSES_PER_KW_HOUR kW/h. */
#if defined(set_total_energy_pulse_indicator)
#if defined(FINE_ENERGY_PULSE_TIMING_SUPPORT)
/* TODO: This will not work if extra_total_power_counter is in use */
/* Work out the fraction of an ADC interrupt, in 1/10ths of an ADC interrupt period,
at which the real transition occurs */
/* Break up the loop a bit, for efficiency */
xxx = total_power_counter << 1;
j = 10;
if (xxx >= total_power)
{
xxx -= total_power;
j = 5;
}
xxx += (xxx << 2);
do
j--;
while ((xxx -= total_power) > 0);
/* j is now our fraction of an ADC interrupt. If we use this right now to control timer A
its effect would be indeterminate. We need timer A to be updated at the very start of an
ADC interrupt service, to ensure the fraction of an ADC interrupt is programmed into the
timer while its count is at a well defined value - zero. */
fine_pulse_operation = OUTMOD_5 | SCS;
TACCR2 = j;
#else
set_total_energy_pulse_indicator();
#endif
total_energy_pulse_remaining_time = ENERGY_PULSE_DURATION;
#endif
custom_energy_pulse_start();
#if defined(MULTI_RATE_SUPPORT)
multirate_energy_pulse();
#endif
#if TOTAL_ENERGY_PULSES_PER_KW_HOUR < 1000
}
#endif
}
#if defined(clr_total_energy_pulse_indicator)
if (total_energy_pulse_remaining_time && --total_energy_pulse_remaining_time == 0)
{
#if defined(FINE_ENERGY_PULSE_TIMING_SUPPORT)
/* Turn off the LED at the next CCR2 match. */
fine_pulse_operation = OUTMOD_1 | SCS;
/* Leave TACCR2 alone, and we should get the same offset as last time, resulting in even length pulses */
#else
clr_total_energy_pulse_indicator();
#endif
custom_energy_pulse_end();
}
#endif
#if defined(INHIBIT_NEGATIVE_TOTAL_POWER_ACCUMULATION)
if (total_reactive_power > 0 && (total_reactive_power_counter += total_reactive_power) >= TOTAL_ENERGY_PULSE_THRESHOLD)
#else
if ((total_reactive_power_counter += total_reactive_power) >= TOTAL_ENERGY_PULSE_THRESHOLD)
#endif
{
total_reactive_power_counter -= TOTAL_ENERGY_PULSE_THRESHOLD;
#if TOTAL_ENERGY_PULSES_PER_KW_HOUR < 1000
if (++extra_total_reactive_power_counter >= 16)
{
extra_total_reactive_power_counter = 0;
#endif
++total_consumed_reactive_energy;
/* Ideally we want to log the energy each kWh unit, but doing
it with a mask here is good enough and faster. */
if ((total_consumed_reactive_energy & 0x3FF) == 0)
phase->status |= ENERGY_LOGABLE;
/* Pulse the LED. Long pulses may not be reliable, as at full
power we may be pulsing many times per second. People may
check the meter's calibration with an instrument that counts
the pulsing rate, so it is important the pulses are clear,
distinct, and exactly at the rate of one per
1/ENERGY_PULSES_PER_KW_HOUR kW/h. */
#if defined(set_total_reactive_energy_pulse_indicator)
#if defined(FINE_ENERGY_PULSE_TIMING_SUPPORT)
/* TODO: This will not work if extra_total_power_counter is in use */
/* Work out the fraction of an ADC interrupt, in 1/10ths of an ADC interrupt period,
at which the real transition occurs */
/* Break up the loop a bit, for efficiency */
xxx = total_reactive_power_counter << 1;
j = 10;
if (xxx >= total_reactive_power)
{
xxx -= total_reactive_power;
j = 5;
}
xxx += (xxx << 2);
do
j--;
while ((xxx -= total_reactive_power) > 0);
/* j is now our fraction of an ADC interrupt. If we use this right now to control timer A
its effect would be indeterminate. We need timer A to be updated at the very start of an
ADC interrupt service, to ensure the fraction of an ADC interrupt is programmed into the
timer while its count is at a well defined value - zero. */
fine_pulse_operation = OUTMOD_5 | SCS;
TACCR2 = j;
#else
set_total_reactive_energy_pulse_indicator();
#endif
total_reactive_energy_pulse_remaining_time = ENERGY_PULSE_DURATION;
#endif
#if TOTAL_ENERGY_PULSES_PER_KW_HOUR < 1000
}
#endif
}
#if defined(clr_total_reactive_energy_pulse_indicator)
if (total_reactive_energy_pulse_remaining_time && --total_reactive_energy_pulse_remaining_time == 0)
{
#if defined(FINE_ENERGY_PULSE_TIMING_SUPPORT)
/* Turn off the LED at the next CCR2 match. */
fine_pulse_operation = OUTMOD_1 | SCS;
/* Leave TACCR2 alone, and we should get the same offset as last time, resulting in even length pulses */
#else
clr_total_reactive_energy_pulse_indicator();
#endif
}
#endif
#if defined(LIMP_MODE_SUPPORT)
}
else
{
if ((total_power_counter += LIMP_SAMPLING_RATIO*total_power) >= TOTAL_ENERGY_PULSE_THRESHOLD)
{
total_power_counter -= TOTAL_ENERGY_PULSE_THRESHOLD;
#if TOTAL_ENERGY_PULSES_PER_KW_HOUR < 1000
if (++extra_total_power_counter >= 16)
{
extra_total_power_counter = 0;
#endif
++total_consumed_energy;
if ((total_consumed_energy & 0x3FF) == 0)
phase->status |= ENERGY_LOGABLE;
custom_energy_pulse_start();
#if defined(set_total_energy_pulse_indicator)
set_total_energy_pulse_indicator();
total_energy_pulse_remaining_time = ENERGY_PULSE_DURATION;
#endif
#if defined(set_total_reactive_energy_pulse_indicator)
set_total_reactive_energy_pulse_indicator();
total_reactive_energy_pulse_remaining_time = ENERGY_PULSE_DURATION;
#endif
#if TOTAL_ENERGY_PULSES_PER_KW_HOUR < 1000
}
#endif
}
#if defined(clr_total_energy_pulse_indicator)
if (total_energy_pulse_remaining_time && (total_energy_pulse_remaining_time -= LIMP_SAMPLING_RATIO) == 0)
{
clr_total_energy_pulse_indicator();
custom_energy_pulse_end();
}
#endif
}
#endif
#endif
custom_adc_interrupt();
#if defined(x__MSP430__)
#if defined(POWER_DOWN_SUPPORT) && defined(POWER_UP_BY_SUPPLY_SENSING)
/* Select the lower threshold to watch for the power supply dying. */
CACTL1 = CAREF_1 | CAON;
#endif
#if defined(BASIC_KEYPAD_SUPPORT) || defined(CUSTOM_KEYPAD_SUPPORT)
if (keypad_debounce())
_BIC_SR_IRQ(LPM0_bits);
#endif
#if defined(__MSP430__) && (defined(IEC1107_SUPPORT) || defined(SERIAL_CALIBRATION_SUPPORT))
/* Update the inter-character timeout for receiving IR messages */
if (char_timeout_1107)
char_timeout_1107--;
#endif
#if defined(PWM_DITHERING_SUPPORT)
if (operating_mode == OPERATING_MODE_NORMAL)
{
/* Only try to dither when in full operating mode.
The dithering increases current consumtion a little! */
/* Calculate new PWM duty cycle for the dithering */
if ((meter_status & PWM_RAMPING_DOWN))
{
if (!(TBCCR1 == PWM_MID_POINT && pwm_stutter--))
{
if (--TBCCR1 <= PWM_LOWER_LIMIT)
{
meter_status &= ~PWM_RAMPING_DOWN;
/* Set a small randomised stutter for the cycle
of the triangular dithering waveform to avoid the
possibility of high correlation with the mains
waveform. */
pwm_stutter = ((rndnum >> 8) & 0x7);
}
}
}
else
{
if (++TBCCR1 >= PWM_UPPER_LIMIT)
meter_status |= PWM_RAMPING_DOWN;
}
}
#endif
#if defined(DAC12_DITHERING_SUPPORT)
fred = (rand16() >> 1) & 0x7F;
DAC12_1DAT = fred2 + fred;
fred2 = fred;
#endif
#if defined(POWER_DOWN_SUPPORT) && defined(POWER_UP_BY_SUPPLY_SENSING)
#if defined(__MSP430_HAS_COMPA__)
if ((CACTL2 & CAOUT))
#else
/* Use an I/O pin to sense the power falling */
POWER_GOOD_THRESHOLD_LOW;
if (!POWER_GOOD_SENSE)
#endif
{
/* The comparator output can oscillate a little around the
switching point, so we need to do some debouncing. */
if (power_down_debounce < POWER_FAIL_DEBOUNCE + 1)
{
if (++power_down_debounce == POWER_FAIL_DEBOUNCE)
{
power_down_debounce = 0;
/* The power is falling. We need to get to a low power
consumption state now! The battery will be supplying the
meter soon. */
operating_mode = OPERATING_MODE_POWERFAIL;
#if defined(__MSP430__)
/* Get the foreground to respond quickly. It might be conserving
power (e.g. in limp mode). */
_BIC_SR_IRQ(LPM0_bits);
#endif
}
}
}
else
{
power_down_debounce = 0;
}
#if defined(__MSP430_HAS_COMPA__)
CACTL1 &= ~(CAON);
#endif
#endif
#endif
#if defined(MAGNETIC_INTERFERENCE_SUPPORT)
if (custom_magnetic_sensor_test())
magnetic_sensor_count++;
#endif
#if defined(__MSP430_HAS_SD16_3__)
/* There may be some current samples available, which we need to pick up */
#if defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT)
if ((SD16CCTL_NEUTRAL & SD16IFG))
{
adc_buffer[2] = SD16MEM_NEUTRAL;
SD16CCTL_NEUTRAL &= ~SD16IFG;
}
#endif
if ((SD16CCTL_LIVE & SD16IFG))
{
adc_buffer[1] = SD16MEM_LIVE;
SD16CCTL_LIVE &= ~SD16IFG;
}
#endif
/**/ P3OUT |= 0x04;
}
#if defined(__MSP430__) && defined(__MSP430_HAS_ADC12__)
/* Interrupt to dynamically enable the ADC in limp mode */
ISR(TIMERA1, adcx_interrupt)
{
/* Re-enable the ADC in time to take the next set of samples */
if ((TACCTL2 & CCIFG))
{
//P2SEL &= ~BIT4;
//P2OUT &= ~BIT4;
TACCTL2 &= ~CCIFG;
ADC12CTL0 |= (ENC | ADC12ON);
}
}
#endif
#if defined(__MSP430__) && defined(__MSP430_HAS_SD16_3__)
/* Interrupt to trigger the SD16 ADC in limp mode */
ISR(TIMERA0, limp_trigger_interrupt)
{
#if defined(RF_LINK_SUPPORT)
if (rf_timeout < 0)
{
/* Enable the USART */
U0ME |= (UTXE0 | URXE0);
#if defined(__MSP430_HAS_FLLPLUS__) || defined(__MSP430_HAS_FLLPLUS_SMALL__)
/* Speed up the clock to 8.388608MHz */
SCFI0 = FN_3 | FLLD_4;
SCFQCTL = 64 - 1;
#endif
custom_rf_exchange();
/* Disable the USART */
U0ME &= ~(UTXE0 | URXE0);
/* Disable the TIMER_A0 interrupt */
TACTL = 0;
TACCTL0 = 0;
#if defined(__MSP430_HAS_FLLPLUS__) || defined(__MSP430_HAS_FLLPLUS_SMALL__)
/* Slow the clock to 1MHz as quickly as possible. The FLL will not be active
in LPM3, so switch it off now, and force the FLL's RC oscillator to
about 1MHz. The exact frequency is not critical. */
_BIS_SR(SCG0); /* switch off FLL locking */
SCFI0 = FLLD_1;
SCFQCTL = (32 - 1) | SCFQ_M;
SCFI0 = 0x0;
SCFI1 = 0x37;
#endif
rf_timeout = 0;
}
else
#endif
{
/* Trigger the ADC to perform a single conversion from all inputs. */
#if defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT)
SD16PRE_NEUTRAL = 0;
#endif
SD16PRE_LIVE = 0;
SD16PRE_VOLTAGE = 0;
SD16CCTL_VOLTAGE |= SD16SC;
}
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -