UPS (Uninterruptible Power Supply) Reference Design


UPS (Uninterruptible Power Supply) Reference Design provides a ready-made uninterruptible power supply solution with the flexibility of a microcontroller - PIC17C43 that offers a low cost solution and high performance not found in other microcontrollers.

1. Introduction

The PIC17C43 PWM controls an inverter whose output, when filtered, results in a sinusoidal AC output waveform. Fault signaling can be initiated internal or external to the PIC17C43 depending on the type of fault. A fault will disable the entire inverter. The output voltage and current will be monitored by the PIC17C43 to make adjustments “real-time” to correct for DC offset and load changes. The PIC17C43 uses zero crossing for synchronization of input voltage/phase to output voltage/phase. All internal module synchronization is handled by the PIC17C43.

PIC17C43 Microcontroller Benefits:

      • Digital Filtering
      • Peripheral Integration
      • Ease of Interfacing
      • High Quality Sine Wave - High throughput allows for high quality output
      • Time to Market
      • Flexibility - core control features and operations can be changed with software modifications only
      • Transportability of Design
      • Variable Loop Response
              • Testability

2. System Overview

The Uninterruptible Power Supply (UPS) is supplying power based on the input power, if the unit is plugged in, or based on the batteries. The input power is filtered (when available) for common mode noise and is protected from surges/spikes by input power protection circuitry. Then the power goes into the power factor correction (PFC) module which forces the input current to be sinusoidal so that power utilization is more efficient. The PFC module also rectifies the input AC power to produce voltage-regulated DC power which is used by the rest of the functional modules (Figure 1).

ups bloc diagram

Figure 1: Block diagram

The PIC16/17 family of microcontrollers offers a wide variety of options for a UPS design from the PIC16C72 to the PIC17C756.

3. Hardware and software Overview

The PIC17C43 is the heart of this reference design. The high performance of the Harvard architecture gives the user the throughput needed for high quality sine wave generation. The single-cycle multiply means faster program execution and response to waveform changes. Only 8 bits of the 10-bit PWM is needed to resolve a high quality output waveform. The PIC17C43 embedded software controls the operation of the AC sine wave generation. It is imperative that the loop response be fast enough to minimize distortion on the output wave. Therefore, the throughput of the microcontroller is a critical parameter.
System Specifications:

      AC Input: 120/240 VAC ± 10%, 50/60 Hz ± 3Hz
      UPS Output: 120/240 VAC ± 10%, 50/60 Hz ± 3Hz (User-Selectable), Sinusoidal
      Rating: 1400 VA
      Input Filtering: EMI/RFI Filtering
              Metal Oxide Varistor (MOV) for Spike/Surge Protection

The UPS may be split into 4 main circuits:

      Input Power
      Factor Correction
      Battery Boost
      Free-Running Chopper

The UPS is an on-line device which normally will have the Power Factor Correction circuit feeding the Chopper, which then feeds the Inverter. If the input power should be lost, the Power Factor Correction circuit falls out of the power flow and the Battery Boost circuit automatically provides power to the Chopper.In the Battery Boost circuit, the transistor pairs are connected in parallel for the purpose of handling high currents. The current transformer T2 is connected as shown to sense each pair’s current with just one transformer, i.e., to prevent it from saturating. The control for the 120V/240V relay (power switch) was not implemented. Wherever input power monitoring would take place, monitoring for 120 or 240V would also occur and switch the relay. These functions would be placed before the PFC circuit.

Source Code:

* Filename: MAIN.C

* Include Files:
* Description: The main routine calls all the functions for generating
* an OPEN_LOOP or FEEDBACK sine wave of either 50 or 60 Hz.
* main()
* Description: The main routine initializes the registers and loops
* forever. All control is handled in the TMR0 INT
* routine.
* Input Variables: NONE
* Output Variables: NONE
//#define OPEN_LOOP
#define FEEDBACK
//#define 50Hz
#define 60Hz
#pragma option v
#include <17c43.h>
#ifdef OPEN_LOOP
// This table yields Full VRMS input
unsigned char const pwmtab[32]={0,25,50,74,98,120,142,162,180,197,212,
// This table yields slightly less than Full VRMS input
unsigned char const pwmtab[32]={0,20,40,60,79,97,114,131,145,159,171,
long read_ad(unsigned char); // Prototype for A/D converter function
unsigned char index; // Index into the sinewave reference table
unsigned char sign; // Flag used to unfold sinewave reference table
long reference; // Value of the sinewave refrence after unfolding
unsigned char reference_lo @ reference;
// V1.21 of Compiler does not type cast unsigned
// char to long so we will write to low byte separately
long out_volt; // Magnitude of the output voltage;
long y; // Variables used in compensation routine
long yold;
long x;
long xold;
long ad_value; // A/D Converter Value
void main(void)
PORTC = 0; // Zero out portc latches
DDRC = 0x22; // Set up Data direction register for C
DDRB = 0; // Set up Data direction register for B
PR1 = 0xFF; // Setup PR1 register (24.4Khz @ 25Mhz clk)
PW1DCL = 0; // Set low bits of PWM to 0
PW1DCH = 0; // Init PWM duty cycle to 0
T0STA = 0x20; // Configure Timer0 prescaler
INTSTA.T0IE = 1; // Enable Timer 0 interrupt
TCON1.T16 = 0;
TCON2.TMR1ON = 1; // Start timer 1 (PWM timer)
TCON2.PWM1ON = 1; // Turn on the PWM
CPUSTA.GLINTD = 0; // Unmask the interrupts
index = 0; // Initialize variables
sign = 0;
y = 0;
yold = 0;
x = 0;
xold = 0;
PORTC.0 = 1; // Enable the Inverter
while(1); // Loop forever, execute in INT Routine
__TMR0() // Timer interrupt
T0STA.T0CS = 0; // Stop timer
#ifdef 60Hz
TMR0H=0xF9; // Make Timer0 interrupt at 3.84KHz for 60Hz output
#ifdef 50Hz
TMR0L=0x5F; // Make Timer0 interrupt at 3.20KHz for 50Hz output
T0STA.T0CS = 1; // Start timer
reference = 0; // Clear Reference Value
reference_lo = pwmtab[index]; // Lookup the value of the sinewave reference
if (!index) // Toggle Sign Every Cycle Through table
sign = ~sign;
++index; // Increment index
if (index == 32) // If end of table, reset counter
index = 0;
if (sign) // If negative going wave
reference = ~reference; // V1.21 of Compiler negate (-ref) doesn’t work for
reference = reference + 1; // ref<=0
ad_value = read_ad(0);
out_volt = ad_value - 512; // Read output voltage (512 counts=0 volts out)
// Form the expression y = yold + (0.09261 * (x + xold))
// Where yold, xold is the value of y, x from the previous sample
// x is the , formed by the difference between the output
// of the inverter and the reference signal.
x = out_volt - reference;
y = ((x + xold) * 24);
y = y / 256;
y = y + yold;
if (y >= 0)
PORTC.2 = 0; // Set positive going cycle
} else
PORTC.2 = 1; // Set negative going cycle
y = ~y;
y = y + 1;
if (y > 255)
y = 255; // Limit y
PW1DCH = y; // Update duty cycle
xold = x; // Store previous sample’s state
yold = y;
#ifdef OPEN_LOOP
// The inverter runs in an open loop mode with OPEN_LOOP defined.
__TMR0() // Timer interrupt
T0STA.T0CS = 0; // Stop timer
#ifdef 60Hz
TMR0H=0xF9; //Make Timer0 interrupt at 3.84KHz for 60Hz output
#ifdef 50Hz
TMR0L=0x5F; //Make Timer0 interrupt at 3.20KHz for 50Hz output
T0STA.T0CS=1; //Start timer
PW1DCH = pwmtab[index];
if (!index)
PORTC.0 = 0; // Gate Drive off
PORTC.2 = ~PORTC.2; // Flip Pos/Neg bit
PORTC.0 = 1; // Gate Drive on
if (index == 32)
index = 0;
PORTC.3 = ~PORTC.3; // Toggle bit to test freq.
long read_ad(unsigned char channel)
long result;
PORTC.6 = 1; // Write bit high
PORTC.7 = 1; // Read bit high
PORTC.4 = 1; // Chip select high
DDRD = 0; // Make PORTD an output
PORTD = 0x04; // Single ended mode signed 10 bit chan 0 Right justified
PORTC.4 = 0; // Select chip
PORTC.6 = 0; // latch command word int A/D
PORTC.6 = 1; // Start conversion
PORTC.4 = 1; // Deselect chip
while (PORTC.5); // Wait for conversion to complete
DDRD = 0xFF; // Make PORTD an input
PORTC.4 = 0; // Select chip
PORTC.7 = 0; // Read high byte
*( ((unsigned char*)&result) + 1) = PORTD;
PORTC.7 = 1;
PORTC.4 = 1;
PORTC.4 = 0;
PORTC.7 = 0; // Read low byte
*( ((unsigned char*)&result) ) = PORTD;
PORTC.7 = 1;
PORTC.4 = 1; // Reset chip select lines
return (result); // Return data


4. UPS Demo Unit

The Demo Unit is a subset of the UPS. This unit was designed to showcase the inverter, featuring the PIC17C43 microcontroller. Therefore, there is no battery back-up circuitry. The circuit boards used on the demo unit are the inverter drive PCB, the inverter control PCB and a bias supply board used to supply 15Vdc to the unit’s discrete components (Figure 2).


Figure 2: Demo Partial Assembly - Top View

Follow these steps to demo the UPS Demo Unit:

      1. Plug the receptacle end of a power cord into the UPS Demo Unit “AC Input”. Plug the pronged end of the power cord into an AC wall socket.
      2. Plug the load into the UPS Demo Unit “Load” socket (Optional). Make sure load can be driven by the UPS Demo.
      3. Connect an oscilloscope probe to the UPS Demo Unit “Load Monitor” BNC connector.
              4. Display (Stepped Down) AC Output waveform on oscilloscope.


Leave a Reply