You are on page 1of 68

EE 416

DC/AC Power
Inverter Design
Progress Report
Authors:

Jayson Edmundson

Adam Peretti

Adam Yackley

Mentor:

David DeVries

Team Flavius

Table of Contents
Executive Summary ................................................................................................................................ 3
Introduction............................................................................................................................................ 4
Project Description ................................................................................................................................. 5
Inverter Method ................................................................................................................................. 5
Pulse Width Modulation................................................................................................................. 6
Noise ............................................................................................................................................... 6
Overview......................................................................................................................................... 7
Project Approach ................................................................................................................................ 7
Control Strategy ................................................................................................................................. 8
Modeling, Simulation, and Engineering Analysis ................................................................................... 9
H-Bridge .............................................................................................................................................. 9
Transformer ...................................................................................................................................... 11
Stepped PWM Switches ................................................................................................................... 12
Simulation......................................................................................................................................... 12
Output Filter ..................................................................................................................................... 16
Microcontroller Programming .............................................................................................................. 17
Project Management and Future Work ............................................................................................... 19
Individual and Team Tasks............................................................................................................ 19
Delays and Future Work ............................................................................................................... 19
RISK MANAGEMENT ......................................................................................................................... 21
Impact Analysis ..................................................................................................................................... 23
Conclusion ............................................................................................................................................ 24
References ............................................................................................................................................ 25
Appendices ........................................................................................................................................... 26
Appendix A Data Sheets ( double-click on the grey boxes) ........................................................... 26
Appendix B - Microcontroller Code .................................................................................................. 26
Assembly Code ............................................................................................................................. 26
C Code........................................................................................................................................... 61

Executive Summary
This report discusses the progress made by Team Flavius between January 11th and March 5th 2010. As
described in the original project proposal, Team Flavius is designing a high efficiency, low cost DC/AC
single phase power inverter. This inverter is planned to be a proof of concept prototype that can be
further developed to fit the needs of a possible end user.
The market for high quality DC to AC power converters is expanding, especially with the recent
government emphasis on alternative forms of energy. Current designs of DC to AC power converters,
also called inverters, generally use one of two techniques. Between these two techniques is a classic
tradeoff between price and quality. The proposed design can create a high efficiency, high quality
output, while meeting the price point of lower quality inverters. It accomplishes this by using a different
method than inverters currently available, coupled with a microcontroller (simple computer) to simplify
the rest of the design.
Team Flavius has made progress in modeling/simulation of the inverter components, researched
programming practices of microcontrollers, and created a work-flow diagram as a road map to
converting a DC signal to a sinusoidal AC signal. Described below in the Modeling, Simulation, and
Engineering Analysis section of this document, Team Flavius describes how parts have been modeled
and simulated, and how engineering analysis has been used to validate and refine each component of
the inverter.
Remaining work on the project includes
testing of the final PCB layout for proof
of concept, building an enclosure for the
inverter and prototype station for safety
and exhibition, programming a GUI to
use during exhibition, and testing the
total harmonic distortion of the entire
system plus analog loads. By April 22nd
2010, Team Flavius is confident the
above work will be completed.
1- Team Flavius working on a PSPICE analysis and Microcontroller programming

Introduction
Team Flavius is currently developing algorithms in C++ and refining models of the inverter components
as defined in the Final Design Proposal submitted 11-29-09. Following the completion of the proposal
and oral presentation to David DeVries, Team Flavius lost a team member which has yet to slow the
teams progress. While the loss of Team member Brendon Mesick has increased each team members
work load, the structure of EE 416 has allowed more time for Team Flavius to meet and produce more
relative work per meeting than in the previous EE 415 semester.
Team Flavius worked with David DeVries to finalize the printed circuit board (PCB) design specifications
and have the PCB fabricated through a third party. After the PCB was manufactured, DeVries obtained
the board and proceeded to incorporate the working sections of the inverter into the board. As of this
writing, the board has not been fully assembled for testing.
Since the PCB is not yet in a state to test functionality, Team Flavius has been modeling the H-bridge,
toroidal transformer, switches, and output filter. Ideal sources were used in conjunction with the LT
Spice models to gain intuitive responses with respect to the sinusoidal and square-wave inputs.
The use of a micro controller has introduced some design challenges and uncertainties, although the
team has been able to solve these with the help of Chris Berg from Impel Systems. With a solid
background in Computer Engineering, Edmundson has completed the low-level logic controlling of the
microcontroller and an open-loop algorithm of the MOSFET switching scheme. A closed-loop Algorithm
is being formulated and will be present on the final design.
This report is a milestone in the development process and while much has been accomplished, Team
Flavius recognizes that more work is required to complete the project. Ultimately, the DC/AC inverter
will demonstrate the proposed design concept can triumph in both signal quality and price
competitiveness. While Team Flavius has studied several facets of product integration into lucrative
markets, some practical concerns such as safety implementation and heat dissipation could drive the
cost out of the target value. While these implications directly affect the acceptance of the inverter
proposed, such design criteria are out of the scope of this design project. However, once the
groundwork has been laid by Team Flavius for proof of design, extra work desired in the safety and
cooling sectors could easily be addressed. A detailed report of the project follows, including engineering
analysis and an updated section on project management.

Project Description
Inverter Method
There are two main classifications of inverters; a true sinusoidal and a modified wave inverter. If the
inverter produces equal or better signal fidelity compared to the utility grid, the inverter is classified as a
true sinusoidal inverter. When an inverter does not meet the aforementioned specification, it is
classified as a modified wave inverter.

Since true sinusoidal inverters are required for a variety of sensitive commercial and industrial
equipment, there is a large market for efficient (i.e. cost and power) and accurate inverters. Currently, a
true sinusoidal inverter, with a power rating of 1KW, costs 30-50cents/watt; the price depends on power
efficiency and accuracy.

At its simplest level, a power inverter consists of a single full-bridge inverter also known as an H-bridge
(Figure 1). An H-bridge uses two sets of switches that operate 180 degrees out of phase, which reverse
the polarity of the dc signal and create a square periodic waveform [1].

Figure 1: H-Bridge Diagram [4]


A square periodic signal has a limited number of applications. So to increase the fidelity of a signal, a
technique known as pulse width modulation is often implemented.

Pulse Width Modulation


Pulse width modulation, or PWM, has become an accepted method for generating unique signals, due
to the advancement of microcontrollers and its power efficiency. To create a sinusoidal signal, PWM
uses high frequency square waves with varying duty cycles [1]. Duty cycle is the percentage of time the
signal is on relative to the period. This means as the duty cycle increases, more power is transmitted
(Figure 2).

Figure 2: Pulse Width Modulation of a Sinusoidal


PWM requires rapid on and off signals, which can be achieved using high power MOSFETs [3]. MOSFETs
are ideal switches due to the low power loss when the device is activated. It should be noted, however,
that when a MOSFET is in transition between on and off, the power loss can be significant. For this
reason, the transition times and frequency should be engineered to be as short as possible. This can be
achieved by minimizing the amplitude between the on and off stages and lowering the PWM frequency;
however as the frequency decreases so does the signal quality.

Noise
Due to a non-ideal environment, noise or interference must be taken into consideration. Examples of
interference include: induced current or voltage due to electromagnetic fluxes, thermal noise caused by
unwanted electron movement, and other unpredictable noise within the circuit. To compensate for such
volatile signals and produce a low signal-to-noise ratio, a feedback loop must be implemented. The
design of the feedback is dependent on the quality and safety requirements of the inverter [8]. Most
common feedback loops use a PID controller. A PID controller implements three different parameters:
proportional, integral and derivative. The proportional fraction reacts to the present error of the system,
the integral counters the sum of errors, and the derivative function attempts to anticipate the error.

Overview
As microprocessors have continued to increase in power efficiency and drop in cost, they have
simultaneously become progressively more attractive to the inverter process. Microcontrollers are
specialized processors designed to be self-sufficient and cost-effective. It is possible to program a
microcontroller to control the output of an inverter, and receive feedback to correct any issues of noise
[2]. Solid state devices, such as microcontrollers, continue to become faster and less expensive; which
allows advanced and cost efficient true-sinusoidal inverters.

Project Approach
The team divided the inverter process into four steps (Figure 3). First, the constant DC signal must be
converted into a period signal. Second, the magnitude of the signal must be increased from 24V to 120V
RMS to meet our target specifications. Third, a true sinusoidal wave must be built out of the periodic
signal through the use of PWM. Lastly, the signal will remove noise and harmonic distortion through the
use of an LC passive filter.

Figure 3: Functional Block Diagram

Control Strategy
An early decision to make is simple open-loop control versus a closed-loop system using feedback. While
purely open-loop control is far easier to implement and may work if everything performs according to
theory, it is unlikely to be reliable in reality. It does not account for variability in manufacturing of the
device components and the device itself. Furthermore, it is unable to deal with error imposed from
external sources, such as non-ideal input, electromagnetic interference, or volatile loading scenarios.
Due to these factors, a control scheme lacking feedback is not an option.
With the microcontroller, there also exist several schemes involving machine learning, such as neural
networks. While these are theoretically the most adaptive, they are also somewhat unpredictable, and
ill-suited to an application as sensitive as power delivery. One possible use of machine learning could be
adaptive gains for a PID controller. However, thought must be given to decide if this is far more complex
than necessary, and if it is even possible given resources available to an embedded microcontroller [7].
The last step in the process is filtering, which will eliminate harmonics and transients that are unwanted
in modern power systems. A variety of filters have been tested, and the final design has yet to be
chosen.

Modeling, Simulation, and Engineering Analysis


The design of the AC/DC inverter has several steps that required multiple levels of simulation and
analysis. The majority of the simulation and testing was completed in PSPICE. PSPICE allowed for in
depth and specific analysis. In the near future, MatLab will be used for a complete system modeling;
however, due to the limitations of Simulink, specifically Simscape, the simulation will use ideal
components. The following sections are split into different stages
of the inverting process and will describe the simulations and
analysis performed.

H-Bridge
Starting at the beginning of the inverter process, the H-bridge,
PSPICE was used to emulate the electrical output of the MOSFET
switches and drivers. Due to the limitations of the MOSFET driver
model, only a few simulations were conducted. The inadequacy
of the model and the causes will be discussed later.
The MOSFET driver and MOSFET PSPICE models were available
from International Rectifier. Since PSPICE does not have
programmable logic circuits, the inputs were manually setup

H-Bridge Schematic 1: Ideal H-Brdige Components

using two stepped voltage sources. To make sure, each


component worked correctly, the team took an iterative setup and design approach for the simulation.
The first design used all ideal components to
ensure the logic of the circuit was correct. In

25V

principle, four MOSFETs are used to reverse

20V

the direction of current across a load every


40us. This is achieved by allowing two pairs
of MOSFETs to turn on 180 degrees out of

V(POS,NEG)

15V
10V
5V
0V
-5V

phase with respect to each other. The first

-10V

simulation responded as expected; that is

-15V

the voltage across the 100Ohm load

-25V
0s

-20V
16s

32s

48s

64s

80s

H-Bridge Plot 1: Voltage across the R1 resistor from H-Bridge Schematic 1

reversed at a rate of 50 KHz (H-Bridge Plot and Schematic 1).


Once the ideal design was complete, the schematic components were implemented. First the MOSFET
model, IRFB4410, replaced the ideal MOSFETs. The IRFB4410 data table can be accessed in the Appendix
A. As seen in H-Bridge Plot 2, the resulting plot and data acted remarkably similar to the ideal MOSFETs.
The results show a near zero rise and fall time, which is excellent for the transformer and switching
scheme. Any overshoot or long rise/fall time could cause the PWM switching scheme to be unstable or
produce unreliable results.
Preferably, the feedback control
system will fix any issues, but the
system should not rely strictly on

V(POS,NEG)

25V
20V
15V
10V
5V
0V

the control.

-5V
-10V

The next simulation step includes

-15V
-20V

the MOSFET driver, IR2117. The

-25V
0s

drivers main purpose is to keep the


gate voltage 12V above the source

8s

16s

24s

32s

40s

48s

56s

64s

72s

80s

H-Bridge Plot 2: Voltage across resistor R1 after MOSFET model was implemented

when it the MOSFET is enabled, and


then drive the gate to the source voltage, when the MOSFET is disabled. The expected response of the
driver is approximately 100ns; meaning that after the MOSFET driver is enabled it will take 100ns to
drive the gate voltage to 12V with respect to the source.
At the very beginning of the simulation, problems with program and driver started to arise. While PSPICE
was simulating, it would hang and report that the time step was too small to continue. After researching
the error, it turns out that the problem usually occurs when there is a discontinuity in the circuit
calculations. While examining the error log, it was determined that a diode within the MOSFET driver
was causing the issue. In the IR2117 PSPICE readme, it specifies that MicroSim PSPICE should be used
and that if time step errors do occur, to change specific values in the simulator. Unfortunately, due to a
lack of funds, the team has been using a free version of SPICE known as LTSPICE. While the SPICE
programs are somewhat similar, it is possible that the error could be caused by LTSPICE.
During the troubleshooting process, the team determined the MOSFET will work given certain inputs
and conditions. If the input to the MOSFET drain starts at zero and is immediately increased to 24V,
while the enable input to the MOSFET is a constant DC source, the MOSFETs turn on as desired. The

described conditions provided a static proof of concept that the switches work, however, the result was
slightly disappointing given the simulators capabilities. At any rate, the H-bridge has been tested by
David Devries and perform as expected. When the team receives the board, more iterative testing will
be completed.

Transformer
Moving on to the transformer, the core material was simulated in PSPICE. According to the core
specifications, the effective area is 154.2mm2 and the relative permeability is 2200 units. Unfortunately,
the simulation through PSPICE is not completely accurate, because the transformer is being custom
wound, so the type of wire, number of windings, and the mutual inductance is still unknown. For this
reason, the simulation results are used only to
get a general grasp of the transformer
response, limitations and other peculiarities.
Since the transformers input is a square wave
several problems need to be taken into
consideration. Specifically, after the square
wave reaches its peak it remains relatively
steady; which will cause the magnetic flux to
decrease and as seen in Transformer Plot 1,
the secondary induction will create a quasisquare wave that trails towards zero near peak
period. To resolute the lack of magnetic flux
the mutual induction must increase; which can

Transformer Plot 1: Result of the transformer core and 50 windings


on the primary. The red line represents the input to the transformer.

be accomplished by increasing the number of primary and secondary windings. More windings increase
the magnetic flux, but cause the saturation current to decrease; which means less power can pass
though the transformer.
In addition to mutual induction, there is a slight delay in rise time, which should be taken into
consideration when programming the H-bridge. To enumerate, the H-bridge should preemptively switch
to accommodate for the delay.

Stepped PWM Switches


The stepped switching scheme uses the same MOSFET driver as the H-bridge, so the simulations will
show limited and specific circuit scenarios. At any rate, the simulations still provided the team with a
proof of concept and helped solidify the workings of the circuit.

Simulation
During the first PSPICE simulations, the results were less than ideal. The simulation applied a 170V
sinusoidal wave to the MOSFET, while the driver either enabled or disabled the MOSFETS. When the
driver was enabled, the MOSFET operated perfectly; however, when the driver was disabled, the
MOSFET turned on during two different stages of the sinusoidal input. When the input was higher than
150V the MOSFET broke down. This was expected due to the 150V VDS rating of the MOSFET. However,
when the sinusoidal input reached a negative value the driver was unable to keep the gate voltage low
enough. This failure caused the MOSFET to turn on and pass a current. After several days of analysis and
troubleshooting, the team realized that the setup did not accurately represent the schematic operation.
Specifically, while the output of
the inverter appears to be a
sinusoidal, which ranges from
negative to positive 170V, the
MOSFET input would only range
from 0V to 170V.
Once the issue was resolved, the
Team needed to simulate the
MOSFET driver when it is off and
a square wave was applied to the

Switch Schematic 1: PSPICE schematic of a single switch attached to a 1K resistor

MOSFETs. To setup the experiment, a single switch was attached to a load as shown in Switch Schematic
1. The results in Switch Plot 1 show that as the input increases, the voltage of the load increases to 24V
and then drops after 5us. To test if the current through the MOSFET will cause problems, a second
switch was added in parallel and enabled (Switch Schematic 2). Switch Plot 2 shows that as long as
another switch is enabled it will drive the other switches to zero.
After the design of each switch was functioning properly, two switches were attached in series with a
load in between them (Switch Schematic 3). The proposed setup tested the functionality of reverse

current flow, which has been of some concern. Additionally, the simulation emulated the actual function
of the schematic on a smaller scale. As seen in Switch Figure 3, the simulation worked as designed.
When both of the switches were enabled, the MOSFETs passed the signal across the resistive load.
Since the load attached to the inverter may not always be purely resistive, an inductor was added in
series to the resistor. The simulation confirmed the voltage remained steady, the MOSFET stayed on,
and the current steadied due to the inductor. The results proved, once again, that the circuit meets the
design requirements.

44V

V(output)

V(input)

36V
28V
20V
12V
4V
-4V
0s

20s

40s

60s

80s

100s

120s

Switch Plot 1: When the MOSFET is disabled and the input increases, a small amount of current flows through

Switch Schematic 2: A second switch is enable to drive the first disable MOSFET to zero

180V

V(dis abled_in)

V(output)

20s

60s

V(in1)

160V
140V
120V
100V
80V
60V
40V
20V
0V
0s

40s

80s

100s

120s

Switch Plot 2: Resulting plot when a second MOSFET is present to drive the disabled MOSFET to zero

Switch Schematic 3: Proposed circuit for the existing switching scheme

V(in)

V(output)

160V
120V
80V
40V
0V
0s

30s

60s

90s

120s

Switch Plot 4: Simulation results showing the design functions properly

180V

V(output)

I(R2)

600mA

140V

480mA

100V

360mA

60V

240mA

20V

120mA

-20V
0.0ms 0.1ms 0.2ms

0mA
0.4ms 0.5ms 0.6ms 0.7ms 0.8ms 0.9ms

Switch Plot 3: Simulation of Schematic 3 with a reactive load

1.1ms 1.2ms

Output Filter
The design criteria of the output filter was used to determine the components and their respective
values. Due to the H-bridge frequency of 24 KHz and the 43V switching magnitude, the team needed a
filter to reduce the time harmonic distortion to less than
3%; meaning the calculations expected the cut-off
frequency to be around 8 KHz [5].
To determine the frequency response of various filters,
PSPICE was used to calculate bode plots and the cutoff
frequency. The first simulation started with a simple LC
filter. From Filter Schematic 1, the components include a
6.8uF capacitor and a 100uH inductor. The capacitor is

Filter Schematic 1: Simple LC output filter

set parallel to the inductor to pass high frequency noise. As seen in Filter Plot 1, the simulation provided
the desired cutoff frequency; however, there is a large resonance frequency. The resonance frequency
has a gain of 40dB at 6.5 KHz, and while the
inverter does not create any noise at this
frequency, any electromagnetic or thermal noise
at the resonance frequency could have damaging
effects on equipment.
To resolve the issue, the team used the design
algorithm, acquired from International Rectifiers
application note AN-1095 [6]. The design paper
specifies a dampening resistor in series to the
capacitor. The resistor decreases the gain at the
resonance frequency, but in a hand-off, increases
the cut-off frequency and decreases the roll-off
slope. To create a near critically damped RLC filter,
the resistor in series should range from 4-8 ohms
(Filter Schematic 2). The resulting Filter Plot 2
shows the response as the resistance is increased
and if the inductor is increased.

Filter Plot 1: Bode Plot result of a simple LC filter

Filter Schematic 2: Final output filter with dampening resistor

Filter Plot 2: Bode plots of output filter with vary resistor and inductor values

Microcontroller Programming
The approach used for the microcontroller programming can mostly be divided into two sections. The
first section simply takes the desired magnitude of the transformer output, a number, and determines
the correct pin configurations. This includes changing the configuration at the proper frequency to

produce the PWM output. The majority of this is controlled and timed automatically using the
microcontrollers built in timers and interrupts. The various processes keep track of their status and
communicate with a global gate_state structure. When the target output level needs to be changed,
this is done with the set_output_level() function.
Section two is what determines what the magnitude should be. This is accomplished by implementing a
PID controller. Feedback is measured at the output of the device using an analog to digital converter.
Then error is calculated from this measurement and a reference of the desired waveform. This error is
then fed into the PIDMain() routine, which then outputs a correction, if necessary, to
set_output_level(). In order to properly calculate the derivative and integral terms, the PID system
also has a routine which is called at regular intervals via timer interrupt.
The organization of the source code roughly resembles this division, with the first section in
Switch_Control.c, and the second in PIDInt.asm. There are also several other source files for
neatness and conveniences sake, as well as main.c, which contains the code for the initial startup and
main program loop. More detailed descriptions of all functions, as well as their source code, is available
in Appendix B.
The following flowchart helps to illustrate the general flow of information in the program. It is by no
means the sequential order of actual execution. In fact, most of these processes are happening
simultaneously.

Flow Chart 1: Information flow chart of the microcontroller

Project Management and Future Work


During the transition from EE415 to EE416, team Flavius, unfortunately, lost a valuable team member.
With such news, the team immediate began to delegate new tasks for each of the remaining members.
Essentially, the remaining members picked up the lost work force. Currently, the team members are
working collaboratively on most tasks including simulating, modeling, and programming.

Individual and Team Tasks


Team member, Jayson Edmundson, is the driving force for the microcontroller programming. He has
been assigning specific tasks for the other team members. For example, he requested the team
determine the port addresses and algorithms for each switch involved in the inverting process, while he
programmed microcontroller to perform accordingly. Adam Peretti and Adam Yackley have been
focusing on PSPICE analysis and design. The simulation provides useful data for the setup and
programming of the microcontroller. Additionally, when the board is received from David Devries, the
simulation results will be used for future experimentation comparison and analysis.

Delays and Future Work


There have been some minor setbacks, during the spring semester of EE416. Specifically, the board has
been delayed by approximately two months. This was due to several component delays and
malfunctions. Fortunately, the group had planned for such delays and has been moving forward
regardless. The programming is almost complete; however, without the board to test the code it is hard
to test the actual functionality. Additionally, certain optional tasks such as adaptive gain, and advance
computer communication may be cancelled accordingly.
In the future, the team needs to test the board extensively for harmonics, power losses, and inverter
specifications. The board must be able to output a kilowatt of power for a sustainable amount of time
without failure. Equally important, the range of loads, power factor, and their efficiency must be
determined.

Other future work for Team Flavius includes testing of the final PCB layout for proof of concept, building
an enclosure for the inverter and prototype station for safety and exhibition, programming a GUI to use
during exhibition, and testing the total harmonic distortion of the entire system plus analog loads. By
April 22nd 2010, Team Flavius is confident the above work will be completed. See the Risk management
table below for the teams assessment of possible contingency plans.

RISK MANAGEMENT
RISK

SEVERITY

LIKELIHOOD ACTIONS TO MINIMIZE RISK

Change in customer

HIGH

LOW

preferences

- Work with the customer to refine


specifications.
- Estimate new time and cost penalties of
changes.

Delay in receiving PCB

MEDIUM

LOW

- Schedule other tasks to be done in case


there is a wait.
- Compensate by having some empty space in
schedule.

Developing switch or

MEDIUM

MEDIUM

feedback control system is

- Check the characteristic of the circuit


components and simulation.

taking longer than


- Compensate by having some empty space in

anticipated

schedule.
Poor characteristic of switch

MEDIUM

HIGH

or feedback control

- Check the characteristic of the circuit and


simulate before implementation.
- Have multiple design options available and
tested for experimentation.

Distortions in output
waveform do not meet

LOW

HIGH

- Have multiple design options available and


tested for experimentation.

specifications

The largest risk in project development/completion is the possibility that David DeVries might change his
design preferences. While this does not seem likely this far in the design after implementation of the

PCB, changes to specifications will be reflected in the design and should be anticipated. The team must
coordinate the new time and cost penalties with any design changes that must be made.
Delays in receiving the PCB, delays from switch and feedback control design taking longer than expected
or other possible contingencies, can be accounted for with a reallocation of extra time defaulted as
extra possible added features. Editing and creating simulations for alternate switching and feedback
control systems is an option for a suitable alternate time investment.
The proactive approach to good characteristics for switch and feedback control is to model and simulate
the design before implementation. Having alternative design approaches for testing and
experimentation can be beneficial when there are problems with a particular control system. This is also
true for distortions in the waveform output that do not meet specifications. Beyond modifying the
particular design for better efficiency, other design approaches might be used.
Since the voltage and current levels used in the inverter can be fatal, the enclosure casing should be
constructed to be tamper proof. Additionally, the setup of the product should be straightforward with
color coded leads, clearly labeled inputs and outputs, and a supplemental instruction manual. To ensure
the quality and safety of each product, they should be thoroughly tested before sold.
The uses of the DC-AC inverter are open-ended and completely up to the user, however there are
expected common applications; including a portable inverter, photo voltaic (PV) generation, and
uninterruptable power supply (UPS). The UPS is used in important situations that require power at all
times, even if power goes out. Meaning, the inverter must have a quick start up time and a high
reliability factor. If the inverter is to be portable, as expected, it must be light enough to carry and safe
to handle. When the inverter is used to invert the PV power, it will most likely be attached to the power
grid and supply a high fidelity wave.
All of the above scenarios will add time to the project, and will be evaluated on as if time permits
basis. Since the delay of the board was predicted and planned for earlier, Team Flavius is still on
schedule for completing the design project on time.

Impact Analysis
The low cost/high efficiency design and implementation of this true sine wave inverter is the motivation
behind its development. Its positive impacts are expected to make the proposed inverter desirable to
many stakeholders. It is possible this inverter will open up markets that earlier inverters were too
expensive to sustain. While this inverter design might seem a cure all for a variety of problems, its
feasibility could have many ethical impacts on the global, economic, environmental, and societal levels.
To fully understand the implications of our design, the use of the inverter with a portable fuel cell will be
explored.
Having the ability to power electronics over prolonged periods of time in remote areas is at the heart of
why portable fuel cells are slowly becoming a viable choice for recreation professionals and enthusiasts
alike. Portable fuel cells are found in a variety of products like security and surveillance cameras,
medical equipment, communication equipment, and recreational/emergency power generators. Each of
these devices at one time needed to be tethered to the power grid, limiting their usage and
effectiveness. The introduction of fuel cells has since made these devices better and more versatile by
offering the availability to mobilize such devices.
While these products have already benefitted by becoming mobile, products with motors and other
analog loads suffer in efficiency when coupled with inferior inverters such as modified sine wave-based
inverters. That said consider the following scenario: If a person would like to power an air conditioned
tent in the remote jungle of the Congo, in order to facilitate medical treatment to a group of people,
they would need a true sine wave inverter coupled with a fuel cell to efficiently power the air
conditioner to cool the tent. Without a true sine wave inverter, like the one team Flavius is proposing,
the fuel cell and air conditioner would not be used as efficiently as possible, thus shortening the amount
of time the air conditioner is able to run.
While the above scenario exemplifies global/societal impacts that this inverter can have, the
economic/environmental impacts are a just as important. Portable fuel cells are not cheap to produce or
to maintain, but with the byproduct of the battery being pure water, the alternative is far from
environmental when compared. Consider the following scenario: The US Army Corps of Engineers need
to core drill holes in the side of a rock face in order to detonate it with explosives.

Two methods are compared below to explore the impacts both economically and environmentally when
a portable fuel cell coupled with a true sine wave inverter is used, instead of the alternative.
The current method is to use an excavator like device that has a pneumatic arm used to bore a hole into
the rock. This machine would take 1 day to complete the job. In order to get the machine to the rock
face, 2 acres of trees need to be removed. An additional two weeks are needed for a team of two and
this requires the use of three extra machines (2 chainsaws, 1 tractor). Consider the alternative: Two men
could make their way through the trees with a man-operated drilling device that is easily movable and
requires a portable fuel cell with a true sine wave inverter. The two men could easily make their way
through the trees without any environmental impact, require 1 week to drill the holes, and still not use a
drop of fuel in the process.
By comparing the two methods, it is easy to see the portable drill method is cheaper on labor, quicker
time wise, and more environmentally responsible.

Conclusion
Overall this design project has seen significant progress towards completion and despite the delays and
setbacks, the prototype is still meeting the schedule requirements. In the very near future, Team Flavius
will be receiving the prototype board and the teams programming can be implemented. For this reason,
communication with David Devries will become much more frequent and important as experimentation
and results are achieved.
The teams group dynamic has been successful and the required work been completed in a professional,
timely, and efficient manner. All team members have been satisfied with the individual work load;
however, due to the recent inrush of required analysis the team meetings have been very time
consuming.
The completed project will result in a high efficiency, low cost DC/AC inverter with low time harmonic
distortion. During the poster session, the product should be available for demonstration and each team
member will be required to have expertise in every component of the inverter design.

References
[1] Timothy L. Skvarenina, The Power Electronics Handbook, Florida: CRC Press LLC, 2002.

[2] Akira Nakamori, High Speed Large Capacity Inverter for Power System Apparatus, Hino-city,
Tokyo: Fuji Electric Corporate Research and Development, Ltd, 1996

[3] Dorin O. Neacsu, Power-Switching Converters: Medium and High Power, Florida:
CRC Press LLC, 2006.

[4] "H-bridge." H Bridge. Web. 02 Nov. 2009. <http://en.wikipedia.org/wiki/H-bridge>.

[*5] Salvatore Favuzza, Filippo Spertino , Giorgio Graditi, Gianpaolo Wale, member IEEE Comparison
of Power Quality Impact of Different Photovoltaic Inverters: the viewpoint of the grid, 2004 IEEE
International Conference on Industrial Technology (KIT)
[6] Cesare Bocchiola, Design of the Inverter Output Filter for Motor Drives with IRAMS Power
Modules, International Rectifier
[*7] Li Jian, Kang Yong, and Chen Jian, Fuzzy-Tuning PID Control of an Inverter with Rectifier-Type
Nonlinear Loads, Department of Electrical Engineering, Huazhong University of Science and Technology,
Wuhan, 430074, P. R. Chin
[*8] Li Hozgbo, Yu Jun, Xiong Jian, Shan Hongtao, Single-phase Inverter Voltage Control and Parallel
Circulation Current Suppression, Huazhong University of Science and Technology Institute of Electrical
and Electronic Engineering,Wuhan,430074,China
[*9] A. Tomasi, M. Concina, M. Grossoni, P. Caracino, J.Blanchard, Field Applications: Fuel Cells as
Backup Power for Italian Telecommunication Sites, IEEE 2006

Appendices
Appendix A Data Sheets ( double-click on the grey boxes)

IR2117

IRFB4321

Appendix B - Microcontroller Code


Assembly Code
;*************************************************************************
*****
;* This file contains PID functions with interrupt.
;*************************************************************************
*****
;*File name:
PIDInt.asm
;*Dependencies: p18f452.inc (change to specific application requirements)
;*Processors:

PIC18

;*Assembler:

MPASMWIN 02.70.02 or higher

;*Linker:

MPLINK 2.33.00 or Higher

;*Company:

Microchip Technology, Inc.

;*
;* Software License Agreement
;*
;* The software supplied herewith by Microchip Technology Incorporated
;* (the "Company") for its PICmicro Microcontroller is intended and
;* supplied to you, the Company's customer, for use solely and

;* exclusively on Microchip PICmicro Microcontroller products. The


;* software is owned by the Company and/or its supplier, and is
;* protected under applicable copyright laws. All rights are reserved.
;* Any use in violation of the foregoing restrictions may subject the
;* user to criminal sanctions under applicable laws, as well as to
;* civil liability for the breach of the terms and conditions of this
;* license.
;*
;* THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES,
;* WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
;* TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
;* PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
;* IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
;* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
;*
;*
;*
;* Author

Date

Comment

;*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;* C.Valenti

June 29, 2004

Initial Release (V1.0)

;*
;* Revisions:
;* 7/8/04

-Removed unused variables a_Err1Lim & a_Err2Lim

;*
using
;*

Modified code after the "restore_limit" label to reflect

;*
derivCountVal
;*

-Changed constant: #define derivCount to #define

;*
was added
;*

-In the PidInterrupt routine, the " movlw derivCountVal "

;*

aErr1Lim & aErr2Lim defined constants.

-pidStat1 bit comments were corrected to the correct bit #

for loading the derivCount variable.

;* 10/20/04 -Added bra statment to the Derivative routine


;*

Amended code for checking the a_Error2 limits.

;*
;*********************************************************************

;PID Notes:
;

PROPORTIONAL = (system error * Pgain )

System error = error0:error1

;
;

INTEGRAL = (ACUMULATED ERROR

* Igain)

Accumulated error (a_error) = error0:error1 + a_Error0:a_Error2

;
;

DERIVATIVE = ((CURRENT ERROR

- PREVIOUS ERROR) * Dgain)

delta error(d_error) = errro0:error1 - p_error0:p_error1

;
; Integral & Derivative control will be based off sample periods of "x"
time.
; The above sample period should be based off the PLANT response
;

to control inputs.

SLOW Plant response = LONGER sample periods

FAST Plant response = SHORTER sample periods

;
;

If the error is equal to zero then no PID calculations are completed.

;
; The PID routine is passed the 16- bit errror data by the main
application
; code through the error0:error1 variables.
;
;

The sign of this error is passed through the error sign bit:
pidStat1,err_sign

The PID outputs a 24-bit vaule in pidOut0:pidOut2 and the sign of this

result is the pid_sign bit in the pidStat1 register.

;-----------------------------------------------------------------------

list
#include

p=18F4585
<p18f4585.inc>

;***** SYSTEM CONSTANTS


#define aErr1Lim
#define aErr2Lim
#define
timer1Hi
#define

0x0F
0xA0

;accumulative error limits (4000d)

timer1Hi

0x3E

;Timer1 timeout defined by timer1Lo &

timer1Lo

0x0D

;this timout is based on Fosc/4

#define derivCountVal
term will be executed.

.10

;#define pid_100
scale

;determies how often the derivative

;comment out if not using a 0 - 100%

EXTERN
EXTERN
EXTERN

FXM1616U,FXD2416U,_24_BitAdd,_24_bit_sub
AARGB0,AARGB1,AARGB2,AARGB3
BARGB0,BARGB1,BARGB2,BARGB3

GLOBAL

error0, error1, pidStat1

;***** VARIABLE DEFINITIONS


pid_data UDATA
#ifdef
pid_100
percent_err
RES
100d)
percent_out
RES
#endif

;8-bit error input, 0 - 100% (0 -

;8-bit output, 0 - 100% (0 - 100d)

derivCount
RES 1
Derivative term is

;This value determins how many times the


;calculated based on each Integral

term.
pidOut0
"Plant"
pidOut1
pidOut2
error0
error1
a_Error0 RES
Integral term
a_Error1 RES
a_Error2 RES
p_Error0 RES
Derivative term
p_Error1 RES
d_Error0 RES
error)
d_Error1 RES

RES

RES
RES
RES
RES
1

1
1
1
1

;24-bit Final Result of PID for the

;16-bit error, passed to the PID


;24-bit accumulated error, used for

1
1
1

;16-bit previous error, used for

1
1

;16-bit delta error (error - previous

prop0
prop1
prop2
integ0
integ1
integ2
deriv0
deriv1
deriv2

RES
1
RES
1
RES
1
RES 1
RES
1
RES
1
RES 1
RES
1
RES
1

kp
ki
kd

RES
RES
RES

pidStat1 RES
pidStat2 RES
tempReg

1
1
RES

;24-bit proportional value

;24-bit Integral value

;24-bit Derivative value

1
1
1

;8-bit proportional Gain


;8-bit integral Gain
;8-bit derivative Gain
;PID bit-status register
;PID bit-status register2
;temporary register

;
;

pidStat1 register

_______________________________________________________________________
________________________
; | bit 7
|
bit 6
| bit 5 |
bit 4
|
bit 3
| bit 2
|
bit 1
| bit 0
|
; | pid_sign | d_err_sign |
mag | p_err_sign | a_err_sign | err_sign |
a_err_z
| err_z
|
;
|__________|____________|________|____________|____________|__________|
____________|__________|
err_z
a_err_z
err_sign equ
a_err_sign
= clear
p_err_sign
= clear
mag
= BARGB magnitude
d_err_sign
= clear
pid_sign equ
clear

equ
equ
2
equ

0
1
3

;error zero flag, Zero = set


;a_error zero flag, Zero = set
;error sign flag, Pos = set/ Neg = clear
;a_error sign flag, Pos = set/ Neg

equ

;a_error sign flag, Pos = set/ Neg

equ
equ

;set = AARGB magnitude, clear


;d_error sign flag, Pos = set/ Neg
;PID result sign flag, Pos = set/ Neg =

; ________________________________ pidStat2
register______________________________________
; | bit 7 | bit 6 | bit 5
|
bit 4
|
bit 3
| bit 2 |
bit
1
| bit 0
|
; |
|
|
|
|
|
|
| d_err_z |
;
|_______|_________|__________|____________|____________|_______|_______
_____|__________|
d_err_z

equ

;d_error zero flag, Zero = set

_PIDCODE CODE
;start PID code here
;***********************************************************************;
; Function: PidInit
;
;
;
; PreCondition: Called by the application code for PID initalization ;
;
;
; Overview: PID variables are cleared, PID gains are given values,
;
;
flags are initialized.
;
;
;
; Input:
;
;
;
; Output: none
;
;
; Side Effects: W register is changed

;
;
;
; Stack requirement: 1 levels deep
;
;
;
;***********************************************************************;
PidInitalize:
GLOBAL
PidInitalize
clrf error0
clrf error1
clrf a_Error0
clrf a_Error1
clrf a_Error2
clrf p_Error0
clrf p_Error1
clrf d_Error0
clrf d_Error1
clrf
clrf
clrf
clrf
clrf
clrf
clrf
clrf
clrf

prop0
prop1
prop2
integ0
integ1
integ2
deriv0
deriv1
deriv2

clrf
clrf
clrf

kp
ki
kd

clrf
clrf
clrf

pidOut0
pidOut1
pidOut2

clrf
clrf

AARGB0
AARGB1

clrf
clrf
clrf
clrf
movlw
vlaues that
movwf
by a factor

AARGB2
BARGB0
BARGB1
BARGB2
.160
cannot exceed 255
kp
of 16, max = 255

;10 x 16, Kp, Ki & Kd are 8-bit


;Enter the PID gains scaled

movlw .160
movwf ki

;10 x 16

movlw .160
movwf kd

;10 x 16

movlw .10
movwf derivCount
derivCount
bcf
pidStat1,err_z
zero
bsf
pidStat1,a_err_z
bsf
pidStat2,d_err_z
bsf
pidStat1,p_err_sign
positive
bsf
pidStat1,a_err_sign
positive
bcf
bsf
movlw
from Fosc/4
movwf
movlw
movwf
movlw
movwf

PIR1,TMR1IF
PIE1,TMR1IE
b'00000001'
T1CON
timer1Hi
TMR1H
timer1Lo
TMR1L

return
main application code

;derivative action = TMR1H:TMR1L *


;start w/error not equal to
;start w/a_error equal to zero
;start w/d_error equal to zero
;start w/ previous error =
;start w/ accumulated error =

;clear T1 flag
;enable T1 interrupt
;configure T1 for Timer operation

;load T1 registers with 5ms count

;return back to the

;***********************************************************************;
; Function: PidMain
;
;
;
; PreCondition: error0:erro1 are loaded with the latest system error
;
;
;
; Overview: This is the routine that the application code will call ;
;
to get a PID correction value. First, the error is checked
;
;
to determine if it is zero, if this is true, then the PID
;
;
code is complete.
;

;
;
; Input: error0:error1, sign of the error: pidStat1,err_sign
;
; Output: prop0:prop2
;
; Side Effects: W register is changed

;
;
;
;

;
;
;
; Stack requirement: 5 levels deep
;
;
;
;***********************************************************************;
PidMain:
GLOBAL
PidMain
bcf
PIE1,TMR1IE
;disable T1 interrupt
#ifdef
pid_100
;if using % scale then scale
up PLANT error
movlw .40
; 0 - 100% == 0 - 4000d
mulwf percent_err,1
;40 * percent_err --> PRODH:PRODL
movff PRODH,error0
movff PRODL,error1
;percentage has been scaled and available
in error0:error1
#endif
movlw 0
cpfseq
error0
;Is error0 = 00 ?
bra
call_pid_terms
;NO, done checking
cpfseq
bra
bsf
bsf
return
application code

error1
call_pid_terms
pidStat1,err_z
PIE1,TMR1IE

call_pid_terms
call Proportional
call Integral
call Derivative
call GetPidResult
the system
bsf
PIE1,TMR1IE
return
application code

;YES, Is error1 = 00 ?
;NO, start proportional term
;YES, set error zero flag
;enable T1 interrupt
;return back to the main

;NO, start with proportional term


;get Integral term
;get Derivative term
;get the final PID result that will go to
;enable T1 interrupt
;return back to the main

;***********************************************************************;
; Function: Proportional
;
;
;
; PreCondition: error0:erro1 are loaded with the latest system error
;
;
;
; Overview: This routine will multiply the system's 16-bit error by the ;
;
proportional gain(Kp) --> error0:error1 * Kp
;
;
;
; Input: error0:error1, sign of the error: pidStat1,err_sign
;

;
; Output: prop0:prop2
;
; Side Effects: W register is changed

;
;
;

;
;
;
; Stack requirement: 2 levels deep
;
;
;
;***********************************************************************;
Proportional:
clrf BARGB0
movff kp,BARGB1
movff error0,AARGB0
movff error1,AARGB1
call FXM1616U
;proportional gain * error
movff AARGB1,prop0
movff AARGB2,prop1
movff AARGB3,prop2
return

;AARGB2 --> prop0


;AARGB3 --> prop1
;AARGB4 --> prop2
;return to mainline code

;***********************************************************************;
; Function: Integral
;
;
;
; PreCondition: error0:erro1 are loaded with the latest system error
;
;
;
; Overview: This routine will multiply the system's 16-bit accumulated
;
;
error by the integral gain(Ki)--> a_Error0:a_Error1 * Ki ;
;
;
; Input: a_Error0:a_Error1, sign of a_Error: pidStat1,a_err_sign
;
;
;
; Output: integ0:integ2
;
;
;
; Side Effects: W register is changed
;
;
;
; Stack requirement: 2 levels deep
;
;
;
;***********************************************************************;
Integral:
btfsc pidStat1,a_err_z ;Is a_error = 0
bra
integral_zero
;Yes
clrf
movff
movff
movff
call

BARGB0
ki,BARGB1
a_Error1,AARGB0
a_Error2,AARGB1
FXM1616U

movff AARGB1,integ0
movff AARGB2,integ1
movff AARGB3,integ2
return

;No
;move the integral gain into BARGB1

;Integral gain * accumulated error


;AARGB1 --> integ0
;AARGB2 --> integ1
;AARGB3 --> integ2
;return

integral_zero
clrf integ0
clrf integ1
clrf integ2
return

;a_error = 0, clear Integral term

;***********************************************************************;
; Function: Derivative
;
;
;
; PreCondition: error0:erro1 are loaded with the latest system error
;
;
;
; Overview: This routine will multiply the system's 16-bit delta
;
;
error by the derivative gain(Kd) --> d_Error0:d_Error1 * Kd
;
;
d_Error0:d_Error1 = error0:error1 - p_Error0:p_Error1
;
;
;
; Input: d_Error0:d_Error1, pidStat2,d_err_z
;
;
; Output: deriv0:deriv2
;
; Side Effects: W register is changed

;
;
;

;
;
;
; Stack requirement: 2 levels deep
;
;
;
;***********************************************************************;
Derivative:
btfsc pidStat2,d_err_z ;Is d_error = 0?
bra
derivative_zero
;YES
movff
movff
movff
clrf
call

d_Error1,BARGB1
d_Error0,BARGB0
kd,AARGB1
AARGB0
FXM1616U

movff AARGB1,deriv0
movff AARGB2,deriv1
movff AARGB3,deriv2
return
derivative_zero
clrf deriv0
clrf deriv1
clrf deriv2
return

;result ---> BARGB1


;result ---> BARGB0

;Derivative gain * (error_l - prv_error1)


;AARGB1 --> deriv0
;AARGB2 --> deriv1
;AARGB3 --> deriv2
;return
;d_error = 0, clear Derivative term

;***********************************************************************;
; Function: GetPidResult
;

;
;
; PreCondition: Proportional, Integral & Derivative terms have been
;
;
calculated. The Timer1 interrupt is disabled within
;
;
this routine to avoid corruption of the PID result.
;
;
;
; Overview: This routine will add the PID terms and then scale down ;
;
the result by 16. This will be the final result that is
;
;
calcualted by the PID code.
;
;
;
; Input: prop0:prop2, integ0:integ2, deriv0:deriv2
;
;
; Output: pidOut0:pidOut2
;
; Side Effects: W register is changed

;
;
;

;
;
;
; Stack requirement: 4 levels deep max.
;
;
;
;***********************************************************************;
GetPidResult:
movff prop0,AARGB0
;load Prop term & Integral term
movff prop1,AARGB1
movff prop2,AARGB2
movff integ0,BARGB0
movff integ1,BARGB1
movff integ2,BARGB2
call SpecSign
numbers
btfss pidStat1,mag
bra
integ_mag
magnitude
bra
prop_mag
magnitude

;YES, call routine for add/sub sign


;which is greater in magnitude ?
;BARGB is greater in
;AARGB is greater in

integ_mag
bcf
pidStat1,pid_sign
btfsc pidStat1,a_err_sign
bsf
pidStat1,pid_sign
bra
add_derivative

;integ > prop


;PID result is negative

prop_mag
bcf
pidStat1,pid_sign
btfsc pidStat1,err_sign
bsf
pidStat1,pid_sign

;integ < prop


;PID result is negative

add_derivative
movff deriv0,BARGB0
Prop + Integ

;PID result is positive


;(Prop + Integ) + derivative

;PID result is positive

;YES, AARGB0:AARGB2 has result of

movff deriv1,BARGB1
movff deriv2,BARGB2
movff pidStat1,tempReg
movlw b'11000000'

;load derivative term

;pidStat1 ---> tempReg


;prepare for sign check of bits 7 &

6
andwf tempReg,f
movf

tempReg,w

;check error sign & a_error sign

bits
sublw 0x00
btfsc STATUS,Z
bra
add_neg_d
NEGATIVE, add them
bra
other_combo_d
add_neg_d
call _24_BitAdd
bra
scale_down
other_combo_d
movf tempReg,w
sublw 0xC0
btfsc STATUS,Z
bra
add_pos_d
POSITIVE, add them
bra
find_mag_sub_d
different signs , subtract them
add_pos_d
call _24_BitAdd
bra
scale_down
find_mag_sub_d
call MagAndSub
btfss pidStat1,mag
bra
deriv_mag
magnitude
bra
scale_down
term, leave pid_sign as is
deriv_mag
pid term
bcf
pidStat1,pid_sign
btfsc pidStat1,d_err_sign
bsf
pidStat1,pid_sign
scale_down
clrf BARGB0
= FINAL PID RESULT to plant
movlw 0x10
movwf BARGB1
call FXD2416U
movff AARGB2,pidOut2
movff AARGB1,pidOut1
movff AARGB0,pidOut0
#ifdef
pid_100
be scaled down to 0 - 100%

;bits 7 & 6 (00) are


;bits 7 & 6 not equal to 00
;add negative sign values
;scale result

;bits 7 & 6 (11) are


;bits 7 & 6 (xx) are

;add positive sign values


;scale result
;subtract unlike sign numbers
;which is greater in magnitude ?
;BARGB is greater in
;derivative term < part pid

;derivative term > part


;PID result is negative
;PID result is positive

;(Prop + Integ + Deriv) / 16

;final result ---> pidOut2


;final result ---> pidOut1
;final result ---> pidOut0
;Final result needs to

movlw 0x06
& derivative
movwf BARGB0
movlw 0x40
movwf BARGB1

;% ratio for propotional & integral

call FXD2416U
100% value
movf AARGB2,W
movwf percent_out
now available in a 0 -100% range
#endif

;pidOut0:pidOut2 / % ratio = 0 -

return

;AARGB2 --> percent_out


;error has been scaled down and is

;return to mainline

code

;***********************************************************************;
; Function: GetA_Error
;
;
;
; PreCondition: Proportional term has been calculated
;
;
;
; Overview: This routine will add the current error with all of the
;
;
previous errors. The sign of the accumulated error will
;
;
also be determined.
After the accumulated error is
;
;
calculated then it is checked if it = 00 or as exceeded
;
;
the defined limits.
;
;
;
; Input: a_Error0:a_Error1, error0:error1
;
;
;
; Output: a_Error0:a_Error1 (updated value)
;
;
;
; Side Effects: W register is changed
;
;
;
; Stack requirement: 4 levels deep max.
;
;
;
;***********************************************************************;
GetA_Error:
movff a_Error0,BARGB0
;load error & a_error
movff a_Error1,BARGB1
movff a_Error2,BARGB2
clrf AARGB0
movff error0,AARGB1
movff error1,AARGB2

call SpecSign
numbers
btfss pidStat1,mag
bra
a_err_zero
both are same sign
bcf
pidStat1,a_err_sign
error, a_error is negative
btfsc pidStat1,err_sign
bsf
pidStat1,a_err_sign
a_err_zero
bcf
movlw 0
cpfseq
bra

pidStat1,a_err_z

;call routine for add/sub sign


;which is greater in magnitude ?
;bargb, keep sign as is or

;aargb, make sign same as

;a_error is positive

;clear a_error zero flag

AARGB0
chk_a_err_limit

;is byte 0 = 00
;NO, done checking

cpfseq
bra

AARGB1
chk_a_err_limit

;is byte 1 = 00
;NO, done checking

cpfseq
bra
bsf

AARGB2
chk_a_err_limit
pidStat1,a_err_z

movff AARGB0,a_Error0
movff AARGB1,a_Error1
movff AARGB2,a_Error2
return
chk_a_err_limit
movff AARGB0,a_Error0
movff AARGB1,a_Error1
movff AARGB2,a_Error2

;is byte 2 = 00
;NO, done checking
;YES, set zero flag
;store the a_error

;a_error = 00, return

;store the a_error

movlw 0
cpfseq
a_Error0
limit has been exceeded
bra
restore_limit

;a_error reached limits?


;Is a_Error0 > 0 ??, if yes

cpfseq
a_Error1
limit not exceeded
bra
chk_a_Error1
return
chk_a_Error1
movlw aErr1Lim
cpfsgt
a_Error1
bra
equal_value
aErr1Lim ?
bra
restore_limit
equal_value
cpfseq
a_Error1
return
a_error
chk_a_Error2
movlw aErr2Lim
cpfsgt
a_Error2

;Is a_Error1 = 0 ??, if yes,

;YES, restore limit value

;NO
;YES

;Is a_Error1 > aErr1Lim??


;NO, check for a_Error1 =
;YES, restore limit value
;a_Error1 = aErr1Lim?
;no, done checking

;Yes, a_Error1 = aErr1Lim


;Is a_Error2 > aErr2Lim ??

return

;NO, return to mainline

code
restore_limit
clrf a_Error0
exceeded
movlw aErr1Lim
movwf a_Error1
movlw aErr2Lim
movwf a_Error2
return
code

;YES, a_error limit has been

;return to mainline

;***********************************************************************;
; Function: GetDeltaError
;
;
;
; PreCondition: The derivative routine has been called to calculate the
;
;
derivative term.
;
;
;
; Overview: This routine subtracts the previous error from the current
;
;
error.
;
;
;
; Input: P_Error0:p_Error1, error0:error1
;
;
;
; Output: d_Error0:d_Error1, d_Error sign
;
;
;
; Side Effects: W register is changed
;
;
;
; Stack requirement: 3 levels deep max.
;
;
;
;***********************************************************************;
GetDeltaError:
clrf AARGB0
;load error and p_error
movff error0,AARGB1
movff error1,AARGB2
clrf BARGB0
movff p_Error0,BARGB1
movff p_Error1,BARGB2
movf
movwf
bits 4 & 2
movlw
andwf
movf
bits

pidStat1,w
tempReg

;pidStat1 ---> tempReg


;prepare for sign check of

b'00010100'
tempReg,f
tempReg,w

;check error sign & a_error sign

sublw 0x00
btfsc STATUS,Z
bra
p_err_neg
NEGATIVE,
bra
other_combo2
p_err_neg
call MagAndSub
bcf
pidStat1,d_err_sign
btfsc pidStat1,p_err_sign
sign
bsf
pidStat1,d_err_sign
bra
d_error_zero_chk
other_combo2
movf tempReg,w
sublw 0x14
btfsc STATUS,Z
bra
p_err_pos
bra
p_err_add
signs
p_err_pos
call MagAndSub
bcf
pidStat1,d_err_sign
btfsc pidStat1,p_err_sign
sign
bsf
pidStat1,d_err_sign
bra
d_error_zero_chk
p_err_add
call _24_BitAdd
bcf
pidStat1,d_err_sign
btfsc pidStat1,err_sign
;make
bsf
pidStat1,d_err_sign

;bits 4 & 2 (00) are


;bits 4 & 2 not equal to 00

;d_error is negative
;make d_error sign same as p_error
;d_error is positive
;check if d_error = 0

;bits 4 & 2 (11) are POSITIVE


;bits 4 & 2 (xx) are different

;d_error is negative
;make d_error sign same as p_error
;d_error is positive
;check if d_error = 0
;errors are different sign
;d_error is negative
d_error sign same as error sign
;d_error is positive

d_error_zero_chk
movff AARGB1,d_Error0
movff AARGB2,d_Error1
movff error0,p_Error0
;load current error into previous
for next deriavtive term
movff error1,p_Error1
;load current error into previous
for next deriavtive term
bcf
pidStat1,p_err_sign
;make p_error negative
btfsc pidStat1,err_sign
;make p_error the same sign as error
bsf
pidStat1,p_err_sign
;make p_error positive
bcf
movlw 0
cpfseq
return

pidStat2,d_err_z

cpfseq
return
bsf
return

d_Error1

d_Error0

pidStat2,d_err_z

;clear delta error zero bit


;is d_error0 = 00
;NO, done checking
;YES, is d_error1 = 00
;NO, done checking
;set delta error zero bit
;YES, return to ISR

;***********************************************************************;

; Function: SpecSign
;
;
;
; PreCondition: The sign bits in pidStat1 have been set or cleared
;
;
depending on the variables they represent.
;
;
;
; Overview: This routine takes the numbers loaded into the math
;
;
variables (AARGB, BARGB) and determines whether they
;
;
need to be added or subtracted based on their sign
;
;
which is located in the pidStat1 register.
;
;
;
; Input: pidStat1
;
;
;
; Output: add/sub results in math variables (AARGB, BARGB)
;
;
;
; Side Effects: W register is changed
;
;
;
; Stack requirement: 2 levels deep max.
;
;
;
;***********************************************************************;
SpecSign
movff pidStat1,tempReg
;pidStat1 ---> tempReg
movlw b'00001100'
;prepare for sign check of bits 3 &
2
andwf tempReg,f
movf

tempReg,w

;check error sign & a_error sign

bits
sublw 0x00
btfsc STATUS,Z
bra
add_neg
NEGATIVE (00), add them
bra
other_combo
add_neg
call _24_BitAdd
return
other_combo
movf tempReg,w
sublw 0x0C
btfsc STATUS,Z
bra
add_pos
POSITIVE (11), add them
bra
find_mag_sub
signs (xx), subtract them
add_pos
call _24_BitAdd

;bits 3 & 2 are


;bits 3 & 2 not equal to 00
;add negative sign values

;bits 3 & 2 are


;bits 3 & 2 are different

;add positive sign values

return
find_mag_sub
call MagAndSub
return

;subtract unlike sign numbers

;***********************************************************************;
; Function: MagAndSub
;
;
;
; PreCondition: This routine has been called by SpecSign because the ;
;
numbers being worked on are different in sign.
;
;
;
; Overview: This routine will detemine which math variable
;
;
(AARGB or BARGB) is greater in number manitude and then
;
;
subtract them, the sign of the result will be determined by
;
;
the values in the math variables and their signs.
;
;
;
; Input: pidStat1
;
;
;
; Output: add/sub results in math variables (AARGB, BARGB)
;
;
;
; Side Effects: W register is changed
;
;
;
; Stack requirement: 2 levels deep max.
;
;
;
;***********************************************************************;
MagAndSub:
movf BARGB0,w
subwf AARGB0,w
;AARGB0 - BARGB0 --> W
btfsc STATUS,Z
;= zero ?
bra
check_1
;YES
btfsc STATUS,C
;borrow ?
bra
aargb_big
;AARGB0 > BARGB0, no borrow
bra
bargb_big
;BARGB0 > AARGB0, borrow
check_1
movf BARGB1,w
subwf AARGB1,w
;AARGB1 - BARGB1 --> W
btfsc STATUS,Z
;= zero ?
bra
check_2
;YES
btfsc STATUS,C
;borrow ?
bra
aargb_big
;AARGB1 > BARGB1, no borrow
bra
bargb_big
;BARGB1 > AARGB1, borrow
check_2
movf BARGB2,w
subwf AARGB2,w
btfsc STATUS,C

;AARGB2 - BARGB2 --> W


;borrow ?

bra
bra

aargb_big
bargb_big

aargb_big
call _24_bit_sub
bsf
pidStat1,mag
magnitude
return
bargb_big
movff BARGB0,tempReg
movff AARGB0,BARGB0
movff tempReg,AARGB0

;AARGB2 > BARGB2, no borrow


;BARGB2 > AARGB2, borrow

;AARGB is greater in

;swap AARGB0 with BARGB0

movff BARGB1,tempReg
movff AARGB1,BARGB1
movff tempReg,AARGB1

;swap AARGB1 with BARGB1

movff BARGB2,tempReg
movff AARGB2,BARGB2
movff tempReg,AARGB2

;swap AARGB2 with BARGB2

call _24_bit_sub
bcf
pidStat1,mag
magnitude
return

;BARGB > AARGB


;BARGB is greater in

;***********************************************************************;
; Function: PidInterrupt
;
;
;
; PreCondition: This Routine will be called by the application's main
;
;
code.
;
;
;
; Overview: When Timer 1 overlfows, an updated value for the Integral
;
;
term will be calculated. An updated value for the
derivative;
;
term will be calculated if derivCount = 0. This routine
;
;
will check for error = 0, if this is true,then the routine
;
;
will return back to the main line code.
;
;
;
; Input: pidStat1, a_error
;
;
;
; Output: Integral & Derivative terms, Timer1 registers reloaded
;
;
;
; Side Effects: W register is changed
;
;
;

; Stack requirement: 4 levels deep max.


;
;
;
;***********************************************************************;
PidInterrupt:
GLOBAL
PidInterrupt
btfsc pidStat1,err_z
return
call GetA_Error
00? reached limits?
derivative_ready?
decfsz
derivCount,f
calculate d_error ?
bra
skip_deriv
call GetDeltaError
movlw derivCountVal
movwf derivCount
derivCount
skip_deriv
movlw timer1Hi
constant time count (user defined)
movwf TMR1H
movlw timer1Lo
movwf TMR1L
return
the application's ISR
END
program'

;Is error = 00 ?
;YES, done.
;get a_error, is a_error =

;is it time to
;NO, finish ISR
;error - p_error
;prepare for next delta error
;delta error = TMR1H:TMR1L *

;reload T1 registers with

;return back to

;directive 'end of

;********************************************************
;This file contains the following math routines:
;24-bit addittion
;24-bit subtraction
;16*16

Unsigned Multiply

;24/16

Unsigned Divide

list
#include

p=18F4585
<p18F4585.inc>

#define
#define

_Z
_C

GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL

AARGB0,AARGB1,AARGB2,AARGB3
BARGB0,BARGB1,BARGB2,BARGB3
ZARGB0,ZARGB1,ZARGB2
REMB0,REMB1
TEMP,TEMPB0,TEMPB1,TEMPB2,TEMPB3
LOOPCOUNT,AEXP,CARGB2

LSB
MSB
math_data
AARGB0
AARGB1
AARGB2
AARGB3
BARGB0
BARGB1
BARGB2
BARGB3
REMB0
REMB1
REMB2
REMB3
TEMP
TEMPB0
TEMPB1
TEMPB2
TEMPB3
ZARGB0
ZARGB1
ZARGB2
CARGB2
AEXP
LOOPCOUNT

STATUS,2
STATUS,0

equ
equ

0
7

UDATA
RES 1
RES 1
RES 1
RES 1
RES 1
RES 1
RES 1
RES 1
RES 1
RES 1
RES 1
RES 1
RES 1
RES 1
RES 1
RES 1
RES 1
RES 1
RES 1
RES 1
RES
1
RES 1
RES 1

math_code
CODE
;--------------------------------------------------------------------;
24-BIT ADDITION
_24_BitAdd

GLOBAL
_24_BitAdd
movf BARGB2,w
addwf AARGB2,f
movf BARGB1,w
btfsc _C
incfsz
BARGB1,w
addwf AARGB1,f
movf BARGB0,w
btfsc _C
incfsz
BARGB0,w
addwf AARGB0,f
return
;--------------------------------------------------------------------;
24-BIT SUBTRACTION
_24_bit_sub
GLOBAL
_24_bit_sub
movf BARGB2,w
subwf AARGB2,f
movf BARGB1,w
btfss STATUS,C
incfsz
BARGB1,w
subwf AARGB1,f
movf BARGB0,w
btfss STATUS,C
incfsz
BARGB0,w
subwf AARGB0,f
return
;------------------------------------------------------------------------;
16x16 Bit Unsigned Fixed Point Multiply 16 x 16 -> 32
FXM1616U
GLOBAL

FXM1616U

MOVFF AARGB1,TEMPB1
MOVF
MULWF
MOVFF
MOVFF

AARGB1,W
BARGB1
PRODH,AARGB2
PRODL,AARGB3

MOVF
MULWF
MOVFF
MOVFF

AARGB0,W
BARGB0
PRODH,AARGB0
PRODL,AARGB1

MULWF BARGB1
MOVF PRODL,W
ADDWF AARGB2,F
MOVF PRODH,W
ADDWFC
AARGB1,F
CLRF WREG

ADDWFC

AARGB0,F

MOVF TEMPB1,W
MULWF BARGB0
MOVF PRODL,W
ADDWF AARGB2,F
MOVF PRODH,W
ADDWFC
AARGB1,F
CLRF WREG
ADDWFC
AARGB0,F
RETLW 0x00
;-------------------------------------------------------------------FXD2416U
GLOBAL
FXD2416U
CLRF
REMB0
CLRF
REMB1
CLRF
WREG
TSTFSZ
BARGB0
GOTO
D2416BGT1
MOVFF
BARGB1,BARGB0
CALL
FXD2408U
MOVFF
REMB0,REMB1
CLRF
REMB0
RETLW
0x00
D2416BGT1
CPFSEQ
GOTO
MOVFF
MOVFF
CALL

AARGB0
D2416AGTB
AARGB1,AARGB0
AARGB2,AARGB1
FXD1616U

MOVFF
MOVFF
CLRF
RETLW

AARGB1,AARGB2
AARGB0,AARGB1
AARGB0
0x00

MOVFF
MOVFF
MOVFF
CLRF

AARGB2,AARGB3
AARGB1,AARGB2
AARGB0,AARGB1
AARGB0

MOVFF
MOVFF
MOVFF
MOVFF

AARGB0,TEMPB0
AARGB1,TEMPB1
AARGB2,TEMPB2
AARGB3,TEMPB3

MOVLW
MOVWF

0x02
AEXP

MOVLW
MOVWF

0x01
ZARGB0

BTFSC
GOTO

BARGB0,MSB
D2416UNRMOK

D2416AGTB

; set loop count

CALL
MOVWF

DGETNRMD
ZARGB0

MULWF
MOVF
MOVFF
MOVFF
MULWF
MOVF
ADDWF

BARGB1
BARGB0,W
PRODL,BARGB1
PRODH,BARGB0
ZARGB0
PRODL,W
BARGB0,F

MOVF
MULWF
MOVFF
MOVFF
MULWF
MOVFF
MOVFF
MULWF
MOVF
ADDWF
MOVF
ADDWF

ZARGB0,W
AARGB3
PRODL,TEMPB3
PRODH,TEMPB2
AARGB1
PRODL,TEMPB1
PRODH,TEMPB0
AARGB2
PRODL,W
TEMPB2,F
PRODH,W
TEMPB1,F

; get normalization factor

D2416UNRMOK
BCF
CLRF
RLCF
RLCF
ADDLW
MOVWF
MOVLW
ADDWFC
TBLRD

_C
TBLPTRH
BARGB0,W
TBLPTRH,F
LOW (IBXTBL256+1) ; access reciprocal table
TBLPTRL
HIGH (IBXTBL256)
TBLPTRH,F
*-

D2416ULOOP
MOVFF
MOVFF

TEMPB0,AARGB0
TEMPB1,AARGB1

CALL

FXD1608U2

BTFSS
GOTO

AARGB0,LSB
D2416UQTEST

SETF
MOVFF
MOVF
ADDWF

AARGB1
TEMPB1,REMB0
BARGB0,W
REMB0,F

BTFSC
GOTO

_C
D2416UQOK

D2416UQTEST
MOVF
MULWF

AARGB1,W
BARGB1

; estimate quotient digit

; test

MOVF
SUBWF
MOVF
SUBWFB

PRODL,W
TEMPB2,W
PRODH,W
REMB0,W

BTFSC
GOTO

_C
D2416UQOK

DECF

AARGB1,F

MOVF
ADDWF

BARGB0,W
REMB0,F

BTFSC
GOTO

_C
D2416UQOK

MOVF
MULWF

AARGB1,W
BARGB1

MOVF
SUBWF
MOVF
SUBWFB

PRODL,W
TEMPB2,W
PRODH,W
REMB0,W

BTFSS
DECF

_C
AARGB1,F

MOVFF

AARGB1,ZARGB1

MOVF
MULWF
MOVF
SUBWF
MOVF
SUBWFB

AARGB1,W
BARGB1
PRODL,W
TEMPB2,F
PRODH,W
TEMPB1,F

MOVF
MULWF
MOVF
SUBWF
MOVF
SUBWFB

AARGB1,W
BARGB0
PRODL,W
TEMPB1,F
PRODH,W
TEMPB0,F

BTFSS
GOTO
DECF

TEMPB0,MSB
D2416QOK
ZARGB1,F

MOVF
ADDWF
MOVF
ADDWFC

BARGB1,W
TEMPB2,F
BARGB0,W
TEMPB1,F

DCFSNZ
GOTO

AEXP,F
D2416FIXREM

D2416UQOK

; test

D2416QOK
; is loop done?

MOVFF

ZARGB1,ZARGB2

MOVFF
MOVFF
MOVFF

TEMPB1,TEMPB0
TEMPB2,TEMPB1
TEMPB3,TEMPB2

GOTO

D2416ULOOP

D2416FIXREM
MOVFF
MOVFF

TEMPB1,REMB0
TEMPB2,REMB1

MOVLW
CPFSGT
GOTO
RRNCF
MOVWF
CALL

ZARGB0
D2416REMOK
ZARGB0,W
BARGB0
DGETNRMD

MULWF
MOVFF
MULWF
MOVF
ADDWF
MOVFF

TEMPB2
PRODH,REMB1
TEMPB1
PRODL,W
REMB1,F
PRODH,REMB0

D2416REMOK
CLRF
MOVFF
MOVFF
RETLW

0x01

AARGB0
ZARGB1,AARGB2
ZARGB2,AARGB1
0x00

;---------------------------------------------------FXD2408U
MOVFF
AARGB0,TEMPB0
MOVFF
AARGB1,TEMPB1
MOVFF
AARGB2,TEMPB2
CALL

FXD1608U

MOVFF
MOVFF

AARGB0,TEMPB0
AARGB1,TEMPB1

MOVFF
MOVFF

TEMPB2,AARGB1
REMB0,AARGB0

CALL

FXD1608U

MOVFF
MOVFF
MOVFF

AARGB1,AARGB2
TEMPB1,AARGB1
TEMPB0,AARGB0

RETLW

0x00

;-------------------------------------------------------FXD1608U

GLOBAL
MOVLW
CPFSGT
GOTO

FXD1608U
0x01
BARGB0
DREMZERO8

FXD1608U1
GLOBAL
BCF
CLRF
RLCF
RLCF
ADDLW
MOVWF
MOVLW
ADDWFC
TBLRD

FXD1608U1
_C
TBLPTRH
BARGB0,W
TBLPTRH,F
LOW (IBXTBL256+1) ; access reciprocal table
TBLPTRL
HIGH (IBXTBL256)
TBLPTRH,F
*-

FXD1608U2
GLOBAL

FXD1608U2

MOVFF
MOVFF

AARGB0,REMB1
AARGB1,REMB0

MOVF
MULWF
MOVFF
MOVFF

TABLAT,W
REMB1
PRODH,AARGB0
PRODL,AARGB1

TBLRD
MOVF
MULWF
MOVFF

*+
TABLAT,W
REMB0
PRODH,AARGB2

MULWF
MOVF
ADDWF
MOVF
ADDWFC
CLRF
ADDWFC

REMB1
PRODL,W
AARGB2,F
PRODH,W
AARGB1,F
WREG
AARGB0,F

TBLRD
MOVF
MULWF
MOVF
ADDWF
MOVF
ADDWFC
CLRF
ADDWFC

*TABLAT,W
REMB0
PRODL,W
AARGB2,F
PRODH,W
AARGB1,F
WREG
AARGB0,F

MOVF
MULWF
MOVFF
MOVFF

BARGB0,W
AARGB1
PRODL,AARGB3
PRODH,AARGB2

; estimate quotient

MULWF
MOVF
ADDWF

AARGB0
PRODL,W
AARGB2,F

MOVF
SUBWF
MOVF
SUBWFB

AARGB3,W
REMB0,F
AARGB2,W
REMB1,F

; estimate remainder

BTFSS
RETLW

REMB1,MSB
0x00

; test remainder

DECF
CLRF
SUBWFB

AARGB1,F
WREG
AARGB0,F

MOVF
ADDWF

BARGB0,W
REMB0,F

RETLW

0x00

;---------------------------------------------------------FXD1616U
TSTFSZ
BARGB0
GOTO
D1616B0GT0
MOVFF
BARGB1,BARGB0
CALL
FXD1608U
MOVFF
REMB0,REMB1
CLRF
REMB0
RETLW

0x00

D1616B0GT0
MOVF
SUBWF
BTFSS
GOTO
BTFSS
GOTO

BARGB0,W
AARGB0,W
_C
D1616QZERO
_Z
D1616AGEB

MOVF
SUBWF
BTFSS
GOTO

BARGB1,W
AARGB1,W
_C
D1616QZERO

MOVFF
MOVFF

AARGB0,TEMPB0
AARGB1,TEMPB1

MOVFF
MOVFF
CLRF

AARGB1,CARGB2
AARGB0,AARGB1
AARGB0

MOVFF
MOVFF

BARGB0,BARGB2
BARGB1,BARGB3

D1616AGEB

BTFSC
GOTO

BARGB0,MSB
D1616UNRMOK

MOVF
RLNCF
ADDLW
MOVWF
MOVLW
CLRF
ADDWFC
TBLRD

BARGB0,W
WREG,F
LOW (IBXTBL256+3) ; access reciprocal table
TBLPTRL
HIGH (IBXTBL256)
TBLPTRH
TBLPTRH,F
*

MOVF
MULWF
MOVFF
MOVFF
MULWF
MOVF
ADDWF

TABLAT,W
BARGB3
PRODL,BARGB1
PRODH,BARGB0
BARGB2
PRODL,W
BARGB0,F

MOVF
MULWF
MOVFF
MOVFF
MULWF
MOVF
ADDWF
CLRF
MOVF
ADDWFC

TABLAT,W
TEMPB1
PRODL,CARGB2
PRODH,AARGB1
TEMPB0
PRODL,W
AARGB1,F
AARGB0
PRODH,W
AARGB0,F

D1616UNRMOK
CALL

FXD1608U1

; normalize

; estimate quotient digit

MOVF
MULWF

AARGB1,W
BARGB1

MOVF
SUBWF
MOVF
SUBWFB

PRODL,W
CARGB2,W
PRODH,W
REMB0,W

BTFSS
DECF

_C
AARGB1,F

; test

MOVF
MULWF
MOVF
SUBWF
MOVF
SUBWFB

AARGB1,W
BARGB3
PRODL,W
TEMPB1,F
PRODH,W
TEMPB0,F

; calculate remainder

MOVF
MULWF
MOVF
SUBWF

AARGB1,W
BARGB2
PRODL,W
TEMPB0,F

D1616UQOK

;
;

This test does not appear to be necessary in the 16 bit case, but
is included here in the event that a case appears after testing.

;
;
;

BTFSS
GOTO
DECF

TEMPB0,MSB
D1616QOK
AARGB1

;
;
;
;

MOVF
ADDWF
MOVF
ADDWFC

BARGB3,W
TEMPB1
BARGB2,W
TEMPB0

MOVFF
MOVFF

TEMPB0,REMB0
TEMPB1,REMB1

; test

D1616QOK

RETLW
0x00
;--------------------------------------------------------DGETNRMD
MOVLW
0x10
CPFSLT
BARGB0
GOTO
DGETNRMDH
DGETNRMDL
BTFSC
BARGB0,3
RETLW
0x10
BTFSC
BARGB0,2
RETLW
0x20
BTFSC
BARGB0,1
RETLW
0x40
BTFSC
BARGB0,0
RETLW
0x80
DGETNRMDH
BTFSC
BARGB0,6
RETLW
0x02
BTFSC
BARGB0,5
RETLW
0x04
BTFSC
BARGB0,4
RETLW
0x08
;--------------------------------------------------------------------------------------------; Routines for the trivial cases when the quotient is zero.
; Timing:
9,7,5 clks
;
PM: 9,7,5
DM: 8,6,4
;D3232QZERO
;
MOVFF
;
CLRF

AARGB3,REMB3
AARGB3

;D2424QZERO
;
MOVFF
;
CLRF

AARGB2,REMB2
AARGB2

D1616QZERO
MOVFF
CLRF

AARGB1,REMB1
AARGB1

MOVFF
CLRF
RETLW

AARGB0,REMB0
AARGB0
0x00

CLRF
RETLW

REMB0
0x00

DREMZERO8

;--------------------------------------------------------------------------------------------; The table IBXTBL256 is used by all routines and consists of 16-bit
; upper bound approximations to the reciprocal of BARGB0.
IBXTBL256
GLOBAL
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA

IBXTBL256
0x0000
0x0001
0x8001
0x5556
0x4001
0x3334
0x2AAB
0x2493
0x2001
0x1C72
0x199A
0x1746
0x1556
0x13B2
0x124A
0x1112
0x1001
0x0F10
0x0E39
0x0D7A
0x0CCD
0x0C31
0x0BA3
0x0B22
0x0AAB
0x0A3E
0x09D9
0x097C
0x0925
0x08D4
0x0889
0x0843
0x0801
0x07C2
0x0788
0x0751
0x071D
0x06EC
0x06BD
0x0691
0x0667

DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA

0x063F
0x0619
0x05F5
0x05D2
0x05B1
0x0591
0x0573
0x0556
0x053A
0x051F
0x0506
0x04ED
0x04D5
0x04BE
0x04A8
0x0493
0x047E
0x046A
0x0457
0x0445
0x0433
0x0422
0x0411
0x0401
0x03F1
0x03E1
0x03D3
0x03C4
0x03B6
0x03A9
0x039C
0x038F
0x0382
0x0376
0x036A
0x035F
0x0354
0x0349
0x033E
0x0334
0x032A
0x0320
0x0316
0x030D
0x0304
0x02FB
0x02F2
0x02E9
0x02E1
0x02D9
0x02D1
0x02C9
0x02C1
0x02BA
0x02B2
0x02AB
0x02A4

DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA

0x029D
0x0296
0x0290
0x0289
0x0283
0x027D
0x0277
0x0271
0x026B
0x0265
0x025F
0x025A
0x0254
0x024F
0x024A
0x0244
0x023F
0x023A
0x0235
0x0231
0x022C
0x0227
0x0223
0x021E
0x021A
0x0215
0x0211
0x020D
0x0209
0x0205
0x0201
0x01FD
0x01F9
0x01F5
0x01F1
0x01ED
0x01EA
0x01E6
0x01E2
0x01DF
0x01DB
0x01D8
0x01D5
0x01D1
0x01CE
0x01CB
0x01C8
0x01C4
0x01C1
0x01BE
0x01BB
0x01B8
0x01B5
0x01B3
0x01B0
0x01AD
0x01AA

DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA

0x01A7
0x01A5
0x01A2
0x019F
0x019D
0x019A
0x0198
0x0195
0x0193
0x0190
0x018E
0x018B
0x0189
0x0187
0x0184
0x0182
0x0180
0x017E
0x017B
0x0179
0x0177
0x0175
0x0173
0x0171
0x016F
0x016D
0x016B
0x0169
0x0167
0x0165
0x0163
0x0161
0x015F
0x015D
0x015B
0x0159
0x0158
0x0156
0x0154
0x0152
0x0151
0x014F
0x014D
0x014B
0x014A
0x0148
0x0147
0x0145
0x0143
0x0142
0x0140
0x013F
0x013D
0x013C
0x013A
0x0139
0x0137

DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
DATA
end

0x0136
0x0134
0x0133
0x0131
0x0130
0x012F
0x012D
0x012C
0x012A
0x0129
0x0128
0x0126
0x0125
0x0124
0x0122
0x0121
0x0120
0x011F
0x011D
0x011C
0x011B
0x011A
0x0119
0x0117
0x0116
0x0115
0x0114
0x0113
0x0112
0x0110
0x010F
0x010E
0x010D
0x010C
0x010B
0x010A
0x0109
0x0108
0x0107
0x0106
0x0105
0x0104
0x0103
0x0102
0x0101

C Code
/*************************************************************************
*************************
** main.c
** Created by:
Jayson Edmundson, 4 Feb 2010
** Modified by: Jayson Edmundson, 6 Feb 2010
**
Jayson Edmundson, 16 Feb 2010
**
Jayson Edmundson, 2 Mar 2010
** Description:
**************************************************************************
************************/
#include <p18f4585.h>
#include <timers.h>
#include <compare.h>
#include "Switch_Control.h"

/********** Function Declarations **************/


extern void PidInitalize(void); // from PIDInt.asm
extern void PidInterrupt(void); // from PIDInt.asm
void initialize(void);
void high_isr(void);
void low_isr(void);

/********** Function Definitions ***************/


void main(void)
{
initialize();
while(1);
}
/***********************************************/
void initialize(void)
{
PidInitalize();
/* timers */
OpenTimer2(TIMER_INT_ON &
T2_PS_1_1
&
T2_POST_1_1 );
PR2 = 0x0A;
OpenTimer3(TIMER_INT_ON
&
T3_16BIT_RW
&
T3_SOURCE_INT
&
T3_PS_1_8
&
T3_SOURCE_CCP
);
OpenCompare1(COM_INT_ON & COM_UNCHG_MATCH, 0x0000);
/* ports */
PORTA = 0x00;
TRISA = 0x03; // RA0(AC DETECT) & RA1(V BATT) input, rest output (HBridge or NC)

PORTB = 0x00;
TRISB = 0x1F; // RB0 to RB4 input (jumpers), RB5 to RB7 output (comm
port)
TRISC = 0x00; // All of PORTC/D output (switch control)
TRISD = 0x00;
/* ADC */
ADCON1 = 0x0D; // Vrefs = Vss & Vdd; AN0 & AN1: Analog input, AN2+:
Digital I/O
ADCON0bits.ADON = 1; // enable ADC
/* enable interrupts */
RCONbits.IPEN = 1;
INTCONbits.GIEL = 1;
INTCONbits.GIEH = 1;
}

/********** ISRs *******************************/


#pragma code high_vector=0x08
void high_vector(void) { _asm goto high_isr _endasm }
#pragma code low_vector=0x18
void low_vector(void) { _asm goto low_isr _endasm }
#pragma code
#pragma interrupt high_isr
void high_isr(void)
{
if (PIR1bits.TMR1IF)
{
PIR1bits.TMR1IF = 0;
PidInterrupt();
}
else if (PIR1bits.TMR2IF)
{
PIR1bits.TMR2IF = 0;
flip_h();
}
else if (PIR2bits.TMR3IF)
{
PIR2bits.TMR3IF = 0;
set_pwm_high();
}
else if (PIR1bits.CCP1IF)
{
PIR1bits.CCP1IF = 0;
set_pwm_low();
}
}
#pragma interruptlow low_isr
void low_isr(void)
{
// calculate error and call set_output_level()

/*************************************************************************
*************************
** Types.h
** Created by:
Jayson Edmundson, 2 Mar 2010
** Modified by:
** Description: Just some typedefs to make coding easier/cleaner.
**************************************************************************
************************/
#ifndef TYPES_H
#define TYPES_H
typedef
typedef
typedef
typedef
typedef
typedef
typedef
typedef

unsigned
unsigned
unsigned
unsigned
signed
signed
signed
signed

char
BYTE;
short
u16;
short long u24;
long
u32;
char
s8;
int
s16;
short long s24;
long
s32;

#endif // TYPES_H

/*************************************************************************
*************************
** Switch_Control.h
** Created by:
Jayson Edmundson, 29 Jan 2010
** Modified by:
** Description: Declarations of interface functions for switch control
system.
**************************************************************************
************************/
#ifndef SWITCH_CONTROL_H
#define SWITCH_CONTROL_H
/********** Function Declarations **************/
void set_output_level(void);
void set_pwm_high(void);
void set_pwm_low(void);
void flip_h(void);
#endif // SWITCH_CONTROL_H

/*************************************************************************
*************************

** Switch_Control.c
** Created by:
Jayson Edmundson, 29 Jan 2010
** Modified by: Jayson Edmundson, 4 Feb 2010
**
Jayson Edmundson, 6 Feb 2010
**
Jayson Edmundson, 18 Feb 2010
**
Jayson Edmundson, 2 Mar 2010
** Description: Low level functions to control gate scheme. Main
interface from PID
**
control is the set_output_level() function. Everything
else is
**
automatic, controlled by timers.
**************************************************************************
************************/
#include <p18f4585.h>
#include "Switch_Control.h"
#include "Types.h"

/********** PORTC & PORTD configs **************/


// I figured using these #defines would be a bit clearer than just putting
the hex values in the code.
#define Q4_POS_RC 0x09
#define Q3_POS_RC 0x01
#define Q2_POS_RC 0x01
#define Q1_POS_RC 0x01
#define Q0_POS_RC 0x01
#define Q4_NEG_RC 0x05
#define Q3_NEG_RC 0x01
#define Q2_NEG_RC 0x01
#define Q1_NEG_RC 0x01
#define
#define
#define
#define
#define
#define
#define
#define
#define

Q4_POS_RD
Q3_POS_RD
Q2_POS_RD
Q1_POS_RD
Q0_POS_RD
Q4_NEG_RD
Q3_NEG_RD
Q2_NEG_RD
Q1_NEG_RD

0x02
0x42
0x12
0x05
0x03
0x01
0x81
0x21
0x09

/********** Function Declarations **************/


extern u24 PidMain(void); //from PIDInt.asm

/********** Globals ****************************/


extern BYTE pidStat1; //from PIDInt.asm
volatile struct
{
enum polarity {POS = 0x02, NEG = 0x01} h_polarity, t_polarity;

BYTE level;
enum {LOW=0, HIGH=1} pwm;
} gate_state;

/********** Function Definitions ***************/


void update_pins(void)
{
BYTE level_prime = gate_state.level + (BYTE)gate_state.pwm;
enum polarity final_polarity = gate_state.h_polarity ^
gate_state.t_polarity ^ 0x02;
// H-Bridge
PORTE = (BYTE)gate_state.h_polarity;
// Switches
if (final_polarity == POS)
{
switch (level_prime)
{
case 0:
PORTC = Q0_POS_RC;
PORTD = Q0_POS_RD;
break;
case 1:
PORTC = Q1_POS_RC;
PORTD = Q1_POS_RD;
break;
case 2:
PORTC = Q2_POS_RC;
PORTD = Q2_POS_RD;
break;
case 3:
PORTC = Q3_POS_RC;
PORTD = Q3_POS_RD;
break;
case 4:
PORTC = Q4_POS_RC;
PORTD = Q4_POS_RD;
break;
default:
// error
break;
}
}
else if (final_polarity == NEG)
{
switch (level_prime)
{
case 0:
PORTC = Q0_POS_RC;
PORTD = Q0_POS_RD;
break;
case 1:
PORTC = Q1_NEG_RC;
PORTD = Q1_NEG_RD;
break;

case 2:
PORTC = Q2_NEG_RC;
PORTD = Q2_NEG_RD;
break;
case 3:
PORTC = Q3_NEG_RC;
PORTD = Q3_NEG_RD;
break;
case 4:
PORTC = Q4_NEG_RC;
PORTD = Q4_NEG_RD;
break;
default:
// error
break;
}
}
else
{
// error
}
}
/***********************************************/
void flip_h(void)
{
gate_state.h_polarity ^= 0x03;
update_pins();
}
/***********************************************/
void set_output_level(void)
{
u24 pidOut = PidMain();
if (pidStat1 & 1 << 7) // pid_sign at bit 7
gate_state.t_polarity = POS;
else
gate_state.t_polarity = NEG;
gate_state.level = pidOut / 0x400000;
CCPR1 = (pidOut % 0x400000) / 0x40;
}
/***********************************************/
void set_pwm_high(void)
{
gate_state.pwm = HIGH;
update_pins();
}
/***********************************************/
void set_pwm_low(void)
{

gate_state.pwm = LOW;
update_pins();
}

You might also like