Professional Documents
Culture Documents
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].
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.
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.
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
25V
20V
V(POS,NEG)
15V
10V
5V
0V
-5V
-10V
-15V
-25V
0s
-20V
16s
32s
48s
64s
80s
V(POS,NEG)
25V
20V
15V
10V
5V
0V
the control.
-5V
-10V
-15V
-20V
-25V
0s
8s
16s
24s
32s
40s
48s
56s
64s
72s
80s
H-Bridge Plot 2: Voltage across resistor R1 after MOSFET model was implemented
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
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.
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
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
V(in)
V(output)
160V
120V
80V
40V
0V
0s
30s
60s
90s
120s
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
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
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 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.
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
Change in customer
HIGH
LOW
preferences
MEDIUM
LOW
Developing switch or
MEDIUM
MEDIUM
anticipated
schedule.
Poor characteristic of switch
MEDIUM
HIGH
or feedback control
Distortions in output
waveform do not meet
LOW
HIGH
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.
[*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
PIC18
;*Assembler:
;*Linker:
;*Company:
;*
;* 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
Date
Comment
;*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;* C.Valenti
;*
;* Revisions:
;* 7/8/04
;*
using
;*
;*
derivCountVal
;*
;*
was added
;*
;*
;*
;*********************************************************************
;PID Notes:
;
;
;
* Igain)
;
;
;
; 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.
;
;
;
; 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
;-----------------------------------------------------------------------
list
#include
p=18F4585
<p18f4585.inc>
0x0F
0xA0
timer1Hi
0x3E
timer1Lo
0x0D
#define derivCountVal
term will be executed.
.10
;#define pid_100
scale
EXTERN
EXTERN
EXTERN
FXM1616U,FXD2416U,_24_BitAdd,_24_bit_sub
AARGB0,AARGB1,AARGB2,AARGB3
BARGB0,BARGB1,BARGB2,BARGB3
GLOBAL
derivCount
RES 1
Derivative term is
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
1
1
1
1
1
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
1
1
1
;
;
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
equ
equ
equ
; ________________________________ 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
_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
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
;clear T1 flag
;enable T1 interrupt
;configure T1 for Timer operation
;***********************************************************************;
; 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
;***********************************************************************;
; 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
;***********************************************************************;
; 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_zero
clrf integ0
clrf integ1
clrf integ2
return
;***********************************************************************;
; 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
;***********************************************************************;
; 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
integ_mag
bcf
pidStat1,pid_sign
btfsc pidStat1,a_err_sign
bsf
pidStat1,pid_sign
bra
add_derivative
prop_mag
bcf
pidStat1,pid_sign
btfsc pidStat1,err_sign
bsf
pidStat1,pid_sign
add_derivative
movff deriv0,BARGB0
Prop + Integ
movff deriv1,BARGB1
movff deriv2,BARGB2
movff pidStat1,tempReg
movlw b'11000000'
6
andwf tempReg,f
movf
tempReg,w
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%
movlw 0x06
& derivative
movwf BARGB0
movlw 0x40
movwf BARGB1
call FXD2416U
100% value
movf AARGB2,W
movwf percent_out
now available in a 0 -100% range
#endif
;pidOut0:pidOut2 / % ratio = 0 -
return
;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
;a_error is positive
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
movlw 0
cpfseq
a_Error0
limit has been exceeded
bra
restore_limit
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
;NO
;YES
return
code
restore_limit
clrf a_Error0
exceeded
movlw aErr1Lim
movwf a_Error1
movlw aErr2Lim
movwf a_Error2
return
code
;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
b'00010100'
tempReg,f
tempReg,w
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
;d_error is negative
;make d_error sign same as p_error
;d_error is positive
;check if d_error = 0
;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
;***********************************************************************;
; 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
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
return
find_mag_sub
call MagAndSub
return
;***********************************************************************;
; 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
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
;AARGB is greater in
movff BARGB1,tempReg
movff AARGB1,BARGB1
movff tempReg,AARGB1
movff BARGB2,tempReg
movff AARGB2,BARGB2
movff tempReg,AARGB2
call _24_bit_sub
bcf
pidStat1,mag
magnitude
return
;***********************************************************************;
; 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
;
;
;
;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 *
;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
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
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
; 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
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"
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;
}
/*************************************************************************
*************************
** 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"
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
BYTE level;
enum {LOW=0, HIGH=1} pwm;
} gate_state;
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();
}