📄 periph.c
字号:
/****************************************************************
*
* Microchip 16-bit Embedded Control Design Contest
*
* Entry # MT2268
*
* Spa Pump Controller
*
*****************************************************************
*
* Miscellaneous peripheral routines:
*
* I/O ports, Analog comparator, Timers
*
*****************************************************************/
#include "PumpCtl.h"
#include "Periph.h"
#include "Inverter.h"
#define INRUSH_THR 215 // Inrush charging threshold (0 - 252V)
// = 240V * sqrt(2) * (1 - exp(-1))
#define INRUSH_MIN 50 // Minimum allowable charge time (msec)
#define INRUSH_MAX 200 // Maximum inrush wait time (msec)
#define VAC_THR_HI 150 // Line voltage comparator rising threshold (0 - 252V)
#define VAC_THR_LO 50 // Line voltage comparator falling threshold (0 - 252V)
#define CMP_INRUSH ((1023UL * (INRUSH_THR) * 1000 / 101) / 2500)
#define CMP_VAC_HI ((1023UL * (VAC_THR_HI) * 1000 / 101) / 2500)
#define CMP_VAC_LO ((1023UL * (VAC_THR_LO) * 1000 / 101) / 2500)
// 10 bits * Threshold (mV) / Res. divider / DAC reference (mV)
static volatile BYTE inrush_timer; // Inrush relay delay timer
static volatile BYTE line_loss_timer; // AC line loss detect timer
static volatile WORD freq_meas_timer; // AC line frequency measurement timer
static volatile BYTE freq_meas_count; // AC line frequency measurement cycle counter
static volatile WORD led_timer; // LED blink timer
static enum {
CMP_LOW = 0,
CMP_RISING = 1,
CMP_HIGH = 2,
CMP_FALLING = 3
} cmp_state;
/*
Initialize I/O pins
*/
void IO_init (void)
{
ADPCFG = 0b10000000; // Set RB7 to digital I/O, RB6:0 to ADC inputs
// RB7 pin doesn't work (per Rev A1 Errata #8)
// LATB = 0b00000000; // Set RB7 low
// TRISB = 0b01111111; // Set RB7 to output
LATE = 0b00000000; // Set RE7 low (turn LED on)
TRISE = 0b01111111; // Set RE7 to output
LATF = 0b01000000; // Set RF6 high (turn relay off)
TRISF = 0b10111111; // Set RF6 to output
}
/*
Initialize comparators
*/
void Cmp_init (void)
{
CMPCON1 = 0x8041; // Enable cmp1 from input 1B (bus voltage) with 2.5V reference
CMPDAC1 = CMP_INRUSH;
CMPCON2 = 0x8001; // Enable cmp2 from input 2A (AC voltage) with 2.5V reference
CMPDAC2 = CMP_VAC_HI;
cmp_state = CMP_LOW;
}
/*
Initialize timers
*/
void Timer_init (void)
{
led_timer = 0;
inrush_timer = 0;
line_loss_timer = 0;
freq_meas_timer = 0;
freq_meas_count = 0;
TMR1 = 0;
PR1 = FRC_CLK_FREQ * 2; // Set period to Fcy (in kHz) for 1 msec timeout
T1CON = 0x8000; // Start the timer
}
/*
The timer 1 interrupt executes every 1 msec
It updates various timer variables, measures the
power line frequency, and checks for power failure.
*/
void _ISR _T1Interrupt (void)
{
_T1IF = 0;
inv_update_timer ++; // Incr inverter periodic update timer
if (inv_update_timer >= INV_UPDATE_RATE) {
inv_update_timer = 0;
inv_update_flag = 1;
}
led_timer ++; // Incr LED blink timer
ping_timer ++; // Incr ping received timer
comm_timer ++; // Incr serial comm timer
if (inrush_timer < 255)
inrush_timer ++; // Incr inrush delay timer
if (line_loss_timer > (1000 + 59) / 60) // If no line signal for 1/60 second
line_loss = 1; // set AC line loss flag
else
line_loss_timer ++; // Incr time between line signal comparator transitions
freq_meas_timer ++; // Incr interrupt counter
/*
The comparator tracks power line zero crossings.
Two identical readings are needed before a transition is assumed.
The threshold is adjusted at each transition to create hysteresis
to help reduce the effect of noise.
The rising transitions are counted, and after 120 of them (equal
to 60 cycles of rectified sine wave), we check to see how many
timer interrupts occurred, and adjust the osc tuning register
if needed to get the correct value.
*/
switch (cmp_state) {
case CMP_LOW:
if (CMPCON2bits.CMPSTAT)
cmp_state = CMP_RISING; // Indicate a rising transition
break;
case CMP_RISING:
if (CMPCON2bits.CMPSTAT) { // High twice in a row,
CMPDAC2 = CMP_VAC_LO; // set threshold for falling detection
cmp_state = CMP_HIGH;
if (sys_mode.b.freq_meas) {
if (line_loss_timer >= 7 && line_loss_timer <= 10) {
freq_meas_count ++; // Incr cycle counter
if (freq_meas_count == 60 * 2) { // Measure time for 60 cycles
if (freq_meas_timer >= 1000 + 5 && freq_meas_timer <= 1000 + 20)
if (OSCTUNbits.TUN != 8) // Timer is 0.5% to 2% too fast,
OSCTUNbits.TUN --; // slow down system clock by 0.4%
if (freq_meas_timer <= 1000 - 5 && freq_meas_timer >= 1000 - 20)
if (OSCTUNbits.TUN != 7) // Timer is 0.5% to 2% too slow,
OSCTUNbits.TUN ++; // speed up system clock by 0.4%
freq_meas_count = 0;
freq_meas_timer = 0;
}
}
else {
freq_meas_count = 0;
freq_meas_timer = 0;
}
}
line_loss_timer = 0; // Reset interval timer
}
else
cmp_state = CMP_LOW;
break;
case CMP_HIGH:
if ( ! CMPCON2bits.CMPSTAT)
cmp_state = CMP_FALLING; // Indicate a falling transition
break;
case CMP_FALLING:
if ( ! CMPCON2bits.CMPSTAT) { // Low twice in a row,
CMPDAC2 = CMP_VAC_HI; // set threshold for rising detection
cmp_state = CMP_LOW;
}
else
cmp_state = CMP_HIGH;
break;
}
}
/*
LED blink task handler, called by the main routine
The LED blink rate is proportional to the motor output frequency,
or once every 2 seconds if stopped, or on solid if any fault.
*/
void LED_run (void)
{
BYTE freq;
if (sys_fault)
LED_ON; // Turn LED on if fault
else {
freq = Inv_get_freq ();
if (led_timer >= (freq != 0) ? (768 - (freq * 2)) : 1000) {
led_timer = 0;
LED_TOGGLE; // Blink LED
}
}
}
/*
Start timing the inrush current capacitor charge time
*/
void Inrush_start (void)
{
RELAY_OFF; // Turn off inrush control relay
inrush_timer = 0;
}
/*
Inrush task handler, called by the main routine
Wait for the bus capacitor to charge up to the inrush threshold,
and check if the charge time is within valid limits.
*/
WORD Inrush_run (void)
{
if (CMPCON1bits.CMPSTAT) {
RELAY_ON; // Turn on inrush control relay
if (inrush_timer >= INRUSH_MIN)
return (0); // Charge time OK
else
sys_fault |= FAULT_inrush_fast; // Charge time too short
}
else if (inrush_timer > INRUSH_MAX)
sys_fault = FAULT_inrush_time; // Charge time too long
return (1);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -