DQE/N ASA/0310-1

NASA

DEVELOPMENT OF A MICROPROCESSOR CONTROLLER

FOR STAND-ALONE PHOTOVOLTAIC POWER SYSTEMS

Alan R. Millner and David L. Kaufman

TriSolarCorp.

Bedford, Massachusetts 01730

N86-2T979 {N4SA-CB-17U723) DEVELOPMENT-O F A

HICBOPBOCESSOE CGKTROLLER FOB'STAND-ALONE

PHOTOVOLTAIC POSEE SYSTEMS final Beport

(TriSolar Corp.) 192 p HC A09/HF A01, Onclas

CSCL-10B G3/4U - 05822_

June 1984

Prepared for

National Aeronautics and Space Administration

Lewis Research Center .

Cleveland, OH 44135

For

U.S. DEPARTMENT OF ENERGY

Conservation and Renewable Energy

Division of Photovoltaic Energy

Washington. D.C. 20545

Under Interagency Agreement DE-A101-79ET20.4S5
DEVELOPMENT OF A MICROPROCESSOR CONTROLLER 

FOR STAND-ALONE PHOTOVOLTAIC POWER SYSTEMS 

Alan R. Millner and David L. Kaufman 

TriSolarCorp. 

Bedford, Massachusetts 01 730 

June 1984 

Prepared for 

National Aeronautics and Space Administration 

Lewis Research Center 

Cleveland, OH 44135 

For 

U.S. DEPARTMENT OF ENERGY 

Conservation and Renewable Energy 

Division of Photovoltaic Energy Technology 

Washington, D.C. 20545 

Under l nteragency Agreement DE-A101-79ET20485 
FORWARD 

The authors wish to acknowledge the ' 

excellent software development effort 

of Dr. Thomas Maier and others of the 

staff of the Mellon Institute. 

PRECEDING 'PAGE BLANK NOT FILNIE:D 

iii 
FINAL REPORT 

NASA FINAL 'REPORT 

DEVELOPMENT OF A MICROPROCZSSOR CONTROLLER FOR STAND-ALONE 

PHOTOVOLTAIC POWER SYSTEMS 

TABLE OF CONTENTS 

1.0 EXECUTIVE SUMMARY 1 

1 .I The Problem 1 

1.2 Hardware Description 1 

1.3 Software Description 3 

1.3.1 Battery Control 

1.3.2 Array Control 

1.3.3 Load Control 

1.3.4 Control Panel 

1.3.5 Self Testing 

1.3.6 Serial Port Functions 

1.4 Test Results and Conclusion 7 

2.0 DESIGN CONSIDERATIONS 9 

2.1 Industry Needs 9 

2.2 Major Cost Impact Items 17 

2.2.1 System Level Items 11 

2.2.2 Battery Control Considerations 11 

' 2.2.3 Array Control Considerations 15 

2.2.4 Load Control Considerations 19 

2.2.5 User Service Considerations 20 

2.2.6 Self Test Considerations 2 1 

2.2.7 Other Considerations 2 1 

2.3 Options Deferred 2 1 

2.3.1 Zero Option 22 

2.3.2 Layer Power Stages for Maximum Power Control 22 

2.3.3 Multiple MPC Control 22 

2.3.4 Variable AC Motor Control 2 4 

2.3.5 Multiple Battery Strings 2 4 

2.3.6 System Topologies 2 4 

2.3.7 Other Processors 2 9 

2.4 Controller Specifications 3 2 
3.0 DESCRIPTION 

3.1 Hardware 

FINAL RZPORT 

3.1.1 Power Supply 

3.7.2 Display and Control 

3.1.3 Resistor Divider Board 

3.1.4 Power Modules , 

3.7.5 Processor 

3.2 Software 

3.2.7 Battery Control 

3.2.2 Array Control 

3.2.3 Load or Auxiliary Charger Control 

3.2.4 Control Panel Functions 

3.2.5 Self-Testing 

3.2.6 Serial Port Functions 

3.3' System Configuration 

4.0 PRODUCTION COST ANALYSIS 

4.1 Material and Labor 

4.2 Modelling of Industrial Producer 

5.0 TESTING 

6.0 CONCLUSIONS 

APPZNDIX I: Schematic Diagram 

APPENDIX 11: Pseudocode Listing 

NOTICE: Certain material contained in this report is proprietary to 

TriSolarCorp. In particular, the improved solar array control 

method is the subject of a patent application, and the software is 

copyrighted by TriSolarCorp, 1984. 

PREC=WG PAhih BMK NOT FILMED 

vii 
FIGURE NUMBER 

FINAL REPORT 

LIST OF FIGURES 

PAGE NUMBER 

Preliminary PV Industry parameters 10 

Design Considerations 12 

Major Functions of the Controller 13 

Specifications for "Zero Optionw Controller 23 

15 kW System Alternatives 26 

FMEA System Level .27 

FMEA Impact Chart 28 

Commercially Available CMOS Microprocessors 30 11 11 11 It 3 7 

Block Diagram - Microprocessor Controller 

Microprocessor Controller 

Control Parameter List 

Battery State of Charge Control Algorithm 

Maximum Power Control Algorithm 

Corrected State of Charge Thresholds 

Product Storage Algorithm 

Product Storage Algorithm Thresholds 

Public Functions 

Password Accessible Functions 

Debug Monitor Functions 

Maintenance and Logging Functions 

Data Format 

Typical Pumping System Wiring 

Typical Battery System Wiring 

Microprocessor Control Functions 

Balance Sheet and Income Statement Summary It I1 11 11 11 11 

It 11 11 I1 I1 11 

PRECDWG PAGE BMK NQT RQMEQ 

PAGE L/([/ =INMnONALLY BUINK 
1.0 EXECUTIVE SUMMARY 

FINAL REPORT 

1.1 - THE PROBLEM 

Photovoltaic systems need controls of varying scope depending on the 

system size and application. While low cost voltage regulators are 

adequate and available for small battery chargers, many larger or 

more complex systems require control algorithms which until now could 

only be achieved by costly custom engineered products. The problem 

is made more difficult because the modular nature of photovoltaic 

systems results in a great variety of controller requirements. 

As the cost of photovoltaic modules decreases, system control and 

related engineering costs become very important. To meet this need 

for flexibility with a minimum of customizing cost, and yet consume 

only a few watts of power is within the capabilities of today's 

microprocessor. 

The first unit was produced under D.O.E. contract DEN3-310 and tested 

for NASA at TriSolarCorp. This unit is photographed in Figure 1.1-1. 

It is a 5kW maximum power controlling battery charger which can also 

be configured as a 5kW batteryless motor drive. 

The entire controller interfaces with existing 500 watt MPC power 

modules, operates in a NEMA-4 enclosure over an ambient temperature 

range of -25 degree C to +45 degrees C, operates from either a 12V 

battery or a 40V to 300V DC unregulated solar array or battery bus. 

1.2 HARDWARE DESCRIPTION 

The prototype microprocessor PV system controller consists of a NEMA4 enclosure containing the following major electronic assemblies: 

A. Power Supply 

B. Display and Control Interface 

C. Resistor Divider Board 

D. Power Modules (70) 

E. Processor 

The power supply consists of a wide input range DC to DC down 

converter and a multi-output flyback DC to DC converter. The 

downconverter accepts 40V to 300V DC. 

The display board consists of a 4 1/2 digit LCD display, a 16 key 

membrane switch pad (calculator style), an audible alarm, and three 

LED'S: RED, YELLOW, and GREEN. The keypad allows manual control 

(under password security) of the system and calls up any one of over 

50 different quantities to be displayed. The display normally shows 

battery state of charge but can display the voltage, current, or 

power of any array string, load bus, battery, motor, or other 

monitored point, monitored temperatures, or time of day. The LED'S 

summarize system status: The GREEN LED shows that the processor is 

running and servicing timer interrupts. The RED LED indicates that 
FINAL REPORT 

the battery is dangerously lot and loads have been shed, and the 

YELLOW LED indicates that stored energy is in short supply and should 

be conserved. 

The resistor divider board serves as an interface between the high 

voltages in the power system and the low voltage signals measured by 

the processor. 

The power modules are 500 watt DC to DC converters used, for the 

prototype, to couple the 180 volt nominal solar array inputs to the 

120 volt nominal battery and load bus. These are 20kHz switching 

type bucking converters, with typical efficiency of 98%. They 

include internal fast current limiting. Ten power modules are 

provided in the prototype. 

The processor is a large board containing the following parts: 

1. Central Processor: CPU, timer, ROM, RAM 

2. Analog input section: differential current, 

multiplexer, single-ended voltage multiplexer, 

and 10 bit plus sign A/D converter 

3. Display and control interface: UART for RS232 

interface support; PIA for keypad, LED, LCD, 

and interrupt support; 6 optoisolators for 

load control 

4. Array control buffers: 10 digital outputs 

which can be used as pulse width modulated 

20kHz signals for the power modules for 

maximum power point tracking, or can be used as DC level 

digital switch drive signals for discrete array control. 

The central processor is built around a 65C02 CPU, which operates at 

1MHz with an 8 bit data bus and a 16 bit address bus. This addresses 

, 16k bytes of CMOS EPROM and up to 6k bytes of CMOS RAM. (This 

program requires only 2k of RAM.) The heart of the analog input 

section is the AD7571 analog to digital converter. This new device 

is a CMOS low cost unit, with 10 bits plus sign accuracy, and 

internal interface to an 8 bit microprocessor bus. 

The RS232 port is provided by an IM6402 CMOS UART, which with a few 

discrete driver elements, makes a complete bi-directional 

asynchronoeus communications interface. This port allows data 

logging to an external printer, automated testing during manufacture, 

or computer interfacing in special applications. 

The array control functions consist of a set of latches, gates, and 

buffers allowing 12 digital outputs to be driven as independent relay 

drive signals for discrete array control, or as separately buffered 

pulse width modulated 20kHz signals for maximum power point tracking. 

A watchdog timer turns off the array control and load outputs if the 

processor fails to reset it within 240msec. An additional analog 

output, 0 to 10V, is available for continuous analog control of 

variable loads such as variable speed motor drives. This is realized 

by low pass filtering of a second PWM signal. 
FINAL REPORT 

SOFTWARE DESCRIPTION 

The software design was based on two decisions. First, the software 

is modular. This allows an orderly linking of software modules using 

the principles of structured programming and allows modules to be 

modified without interfering with the rest of the program. Second, 

the modules were defined using wpseudocodev, an explicit definition 

of each algorithm in plain English with a program format. This 

allowed clear communication between system designer, hardware 

designer, and software designer in advance of actual programming and 

eased the task of writing assembly language code. 

The MAC unit is designed to operate without needing any human 

intervention. It performs the following functions automatically: 

7. Battery Control 

2. Array Control 

3. Load or auxiliary display on the 

control panel 

4. Status display on the control panel 

5. Self-test 

6. Data logging via RS232C port 

In addition, the MAC unit provides the following facilities for 

manual control: 

1. Manual battery charge initialization 

2. Manual array control 

3. Manual load or auxiliary charger control 

4. Control panel display of system 

operating parameters 

5. Manual test calibration mode and time of 

day 

6. Remote control and parameter measurement 

or automated testing via the RS232C port 

Each function is described below, with the automatic and manual 

functions described together for ease of understanding. 

1.3.1 Battery Control 

The state of charge describes the battery's condition at an instant 

in time. The initial battery state of charge can be entered manually 

from either the keyboard or the RS232C terminal. This can be based 

on a hydrometer reading of battery acid density, or simply an 

estimate. If it is wrong, the system will eventually correct it 

without damage to the battery. Default value at power-up is 50%. 

The state of charge is increased by the number of ampere-hours 

flowing into the battery, and decreased by the number of ampere-hours 

flowing out of the battery. Rate of increase is modified by a 

tabulated coulombic charging efficiency which depends on state of 

charge. If the battery voltage exceeds expected limits, the state of 

charge is automatically adjusted to account for the variation. 
FINAL REPORT 

For every ampere-hour of discharge by the battery, one equalization 

fraction ampere-hour of extra or equalization charging is 

automatically programmed when energy becomes available and 100% state 

of charge has been reached. This is needed to bring all cells up to 

full charge and to stir the acid by generating small amounts of gas. 

This prolongs battery life. 

If the battery goes through many partial charge and discharge cycles 

before equalizing, the total equalization charge is limited to the 

equalization total percentage to avoid excessive water useage. 

During charging and equalization, the battery is allowed to rise to 

the equalization voltage. After equalization is completed, the 

battery voltage is limited to the float voltage, which is below the 

point of significant gassing and so uses up less water. This float 

level charge makes up for internal battery self-discharging. 

1.3.2 Array Control 

If the battery is not fully charged and equalized, the voltage limit 

is the equalization voltage. If fully equalized, the voltage limit 

is the float voltage. Until reaching voltage limit, the solar array 

charges the battery as much as the available energy allows. 

There are two automatic modes of array control resident in the 

program. The first is discrete array control. This.turnsS strings 

on, one per second as long as the battery voltage is less the 94% of 

its maximum limit. It makes no change until the battery voltage 

reaches 97% of its maximum limit. Between 97% and 100% of its 

maximum limit, strings are turned off one per second. Above 100% of 

maximum limit, all strings are turned off. The battery voltage used 

for this algorithm is averaged over 4 samples to minimize noise 

problems. 

The second mode is maximum power tracking. The controller drives up 

to 10 power modules with a 20kHz pulse width modulated drive signal, 

13 volts = high = OFF, 0 volts = ON. The pulse width is set in 1/4 

microseconds increments. It is initialized to 0 and changed in small 

(1/4 microseconds) or large (2 microseconds) steps every 100 

milliseconds. At each step, the total delivered power is calcualted 

and compared with the power delivered at the previous duty cycle. If 

the power changed by less than 1.5%. and if no limiting conditions 

were encountered, small steps are used, otherwise big steps are used 

to speed up the process. 

If the power level was found to be constant or increasing, the next 

step is taken in the same direction as the last. If the power was 

found to be decreasing, the directign of step in duty cycle is 

reversed. Therefore, the duty cycle is adjusted to the maximum power 

operating point, and hunts there +/- one or two small steps, 

representing an operating point within +/- 1% of maximum power. 

This improved array control method is the subject of a patent 

application. 
FINAL REPORT 

1.3.3 - Load Control 

The battery is assumed to be loaded by up to 5 separate load busses, 

with separate voltage sensing, current shunts in the negative load, 

and relay control responsive to the optoisolator output 1-5 of the 

controller. These may in fact be auxiliary chargers as well as 

loads. 

Each load bus is also automatically monitored for excessive current, 

providing a built in circuit breaker function. Each load or charger 

bus can also be manually controlled from the keypad or the serial 

port . It is often desirable to use more energy if it's going to be a sunny 

day. This may be to avoid short cycles of load useage or simply to 

increase energy useage efficiency. Therefore, between 8AM and 

12Noon, if the sunlight level is high enough to provide at least 10% 

of the maximum charger current limit to the battery, all the battery 

corrected SOC levels for load shed and restoration are decreased by a 

constant preset SOC, called DELTA SOC. This allows loads to turn ON 

earlier on a sunny morning than would otherwise be the case. 

The MAC can perform a control strategy to allocate available energy 

into two different forms of storage. One of these is electrical 

energy stored in a battery. The other is a form of "product 

storage." This might be water stored in a tank, or thermal, storage of 

cold in a refrigerator, freezer or ice stored in an icemaker. To use 

this capability, it is necessary to be able to measure the amount of 

product stored. This combination of trip points creates a.set of 

four states of the controller, defined by the amount of product 

stored and the battery state of charge. By setting various values 

for the boundary parameters, various priorities can be placed in the 

use of energy. 
FINAL REPORT 

7.3.4 CONTROL PANEL 

The control panel has a keypad for manual inputs, a 4-1/2 digit LCD 

display for selected quantities, a set of red, yellow, and green 

LED1s for quick status summary, and an audio alarm. There is also an 

emergency switch located at the bottom of the unit which, when turned 

OFF, will turn OFF all array strings and loads. When turned ON, it 

will restart the program. 

The LCD display can be thought of as a multimeter which will display 

one of a menu of system parameters. The default condition is state 

of charge, and after a data dump each half hour, it returns to this 

parameter setting. It can also display any array string voltage, any 

charger output string current, (not the array current, but the 

converted output from that string at the battery voltage level), the 

delivered string power to the battery, the battery voltage current or 

power, any of five load bus voltages or currents or powers, the 

battery temperature, one other temperature (used here for freezer 

product measurement), the pulse width, the equalization charge 

needed, the system zero voltage and 4.00 volt reference level, the 

temperature corrected state of charge, the time of day, and the 

software version number. These are selected using the keypad. 

The keypad can also be used to change control functions. To do this, 

the correct password must be entered. Password accessible functions 

include setting a new load and restore thresholds for each'load bus, 

setting initial state of charge and setting the manual control for 

each load bus ON or Off. 

1.3.5 Self-testing 

The autdmatic tesing of battery SOC and load currects is described 

elsowhere. Also, the unit can be placed in a test/cal mode where 

data is refreshed but the states of charge, max power tracking and 

load controls do not automatically change. This allows them to be 

manually set and measurements taken. For example, a fixed pulse 

width can be set from the serial port, or a lamp test can be 

performed. 

The display performs one more automatic test. If one of the charger 

power module output currents is less than a constant (lamp) below the 

average of all such currents, the "ContinuityN segments of the LCD is 

turned ON. This means that one string of the array or one power 

module of the charger is either shadowed or broken. Examination of 

array voltages and currents will show the cause. 

Besides these external tests, the unit performs an automatic test of 

its RAM and ROM access whenever it is started up. When running, any 

error causing the program not to execute properly will result in a 

watchdog timer fault turning off all loads and the solar array and 

causing the green LED to go out. 
FINAL REPORT 

1.3.6 Serial Port - Functions 

The manual test/cal mode was partially described in the previous 

section. However, with an RS232C terminal, much more extensive 

manual testing is possible. A standard debug monitor is implemented 

which can examine memory locations, insert bytes into memory, begin 

execution at a given memory location, insert or remove breakpoints, 

and download and program into memory. 

A data dump of all system voltages, currents, temperatures, switch 

positions and states of charge is sent to the serial port every half 

hour or whenever requested. A printer there will provide data 

logging. 

This powerful access allows many possible uses. The processor can be 

automatically tested during manufacture this way. A printer attached 

at the site can serve as a data logger. A telephone modem or other 

communication interface would allow automatic remote data logging or 

even, remote system control. 

The use of a small RS232C terminal by a repair technician allows 

fault isolation and diagnosis beyond the capabilities of the keypad 

and display, since small special test routines can be run. Software 

modification is greatly eased as well. 

1.4 - TEST RESULTS - AND CONCLUSIONS 

The battery charge control algorithm works as described. Its 

estimate of the fraction of capacity available is limited mainly by 

the accuracy of the battery's rated capacity at a given discharge 

rate which is supplied by the battery manufacturer. Long term low 

current operation is dominated by internal battery self-discharge, 

typicalIy 1% to 2% per week, and current offset errors of 0.1% of 

maximum, which is often a similar percentage per week. This is 

corrected whenever the battery is fully charged, so that batteries 

cycled daily or weekly are not affected. 

The array control modes, both max power tracking and discrete 

switching, work very well and provide a nice tapered current 

finishing charge for a battery with very low water loss. The max 

power tracking with two step sizes is a real advance in the state of 

the art, as it provides a combination of more accurate tracking of a 

static max power point plus a faster acquisition time for a varying 

load or insolation. A chart comparing these performance figures is 

given here. 
Acquisition 

time +/-2% 

FINAL REPORT 

COMPARISON OF MPC FUNCTIONS 

Previous State of the MAC 

Art Equipment 

MaxDither,stable 3% 

load 

Product 9 1 

This means that, for example, a volumetric pump or other slowly 

cycling loads can be dynamically matched to the solar array with 

reduced need for expensive or lossly load-levelling mechanisms as 

large flywheels, batteries, etc. This opens up additional 

applications for the controller. 

Load management in response to battery state of charge is very good. 

It is free of the chattering and instability characteristices of many 

voltage-related load management schemes. The algorithm for product 

storage and apportioning energy to several types of loads works as 

expected. However, its sophistication makes it difficult for a user 

to verify that it is operating properly, and this may make it less 

popular than other approaches based solely on battery status. 

Instrumentation of the system using the keypad and LCD display is 

very effective. A permanently posted list of command codes on the 

unit near the keypad was found to be useful. 

Data logging via the RS232C terminal to an inexpensive printer is 

very helpful in village systems. Of less use in smaller 

applications, it is quite helpful for maintenance or fault diagnosis 

using a small hand held battery-powered RS232 terminal. The 

possibilities inherent in a phone coupler or other communicaions port 

for remote system control have not been explored, but they are 

potentially very interesting. The self-test functions of the 

controller are an effective means of allowing unskilled personnel to 

monitor a complex PV system. 

In conclusion, the microprocessor automatic controller works as well 

as, or better than, any existing PV system control equipment, and can 

be adapted to a wide variety of systems simply by plugging in an 

EPROM. This makes it a very attractive con,troller for PV systems 

where large size (over IkW), remote location or special control 

requirements justify this type of unit. 
FINAL REPORT 

2.0 DESIGN CONSIDERATION 

INDUSTRY NEEDS 

The photovoltaic industry is growing today at an annual rate of 

nearly 65%. This growth includes a varied mix of small simple 

battery chargers, pump drives, large sophisticated battery chargers, 

and utility interactive systems. As the cost of the PV module 

decreased, the fraction of the system cost represented by controls 

and engineering becomes more important. In order to allow the 

continued growth of volume and reduction of system prices, a 

controller is needed which is flexible enough for all applications 

while easy to apply without high recurring engineering costs. The 

microprocessor represents an opportunity to supply that need. 

In order to determine the range of system parameters required for a 

controller, a preliminary analysis of the near term PV market is 

useful. The following figure 2.1-1 indicates the breakdown of the 

1983-84 PV market, using a variety of various documented and informal 

sources, to ascertain the relative market share of various types of 

systems. The first rows of figures give the breakdown by system 

size, first a typical size, then a range of sizes, by half-decade 

logarithmic steps. The percent of power sold represents the fraction 

of PV kilowatts used in that size system. The percent of systems 

sold gives the fraction of the total number of systems regardless of 

size. A typical installed system price in $/watt is indicated for 

reference. 

The next section characterizes the controls, including power 

conditioning, for a PV system in terms of the dollar cost of controls 

at the OEM level divided the peak watts of PV in the system. These 

are divided into systems with Maximum Power Controllers (MPC) and 

those without. The difference represents the incremental cost of the 

MPC. The approximate fraction of systems without MPC1s is indicated, 

and multiplied by the number of systems in each category, to give the 

number of controllers with and without MPC~S in each system size 

category. This shows that the market for MPC type controller falls 

primarily in the 300 watt to 30 kW size range. The large number of 

systems at smaller sizes indicates the attractiveness of marketing a 

small, inexpensive controller which might be able to capture the 100 

W to 300 W market even without maximum power control. The high cost 

of controls below 100 watts size indicates that any controller will 

be hard to sell for such small systems. 

The last row of figures estimate the incremental value of an MPC 

for 1983 and 1986 PV systems. These estimates are based on the 

following rows of figures for typical system voltage, typical 

controllers and PV utilization, efficiency, and typical incremental 

PV array installed prices. Comparing these figures with the 

controller costs determines the utility of an MPC in such a system. 

Note that MPC1s are probably worthwhile for systems over 300 watts at 

present and over 1 kW in 1986. 

Based on these results, it appears that a controller intended for the 
PRELIMINARY- PV INDUSTRY 83-84 PARAMETERS 

ESTIMATED 5 MEGAWATTS/YEAR, 10K SYSTEMS 

Range lOOW 100-300 300-1K 1 K-3K 3K-1 OK 1 OK-30K 30~-100K 

SYSTEMS 

Z of power 

sold 5 10 15 15 20 15 10 

% of systems 

sold 55 25 15 3 1-5 -38 .1 

Inst. $/watt 

cost 3 0 27 25 22 20 17 15 

CONTROLS, $/W COST (INCLUDING POWER CONDITIONING) 

MPC 3.00 2.00 1-00 0.80 0.70 0.60 0.50 

% With MPC 0 1 5 15 20 40 , 50 

f W/O MPC 5.5K 2.5K 1.5K 255 120 22 5 

I W/ MPC 0 25 75 45 30 16 5 

Incr . value 

of MPC 

1983 $/w -030 -20 -70 1.0 .1.20 1-20 -80 

TYPO SYS. 

Voltage 12 12-24 24-48 48-90 120 120 240 

MPC effic. .82 

No MPC 

ef fic . .85 .85 .85 .85 -85 -85 90 

Assume incremental PV array prices. 

200K 

1 OOK 

$/W installed 

1983 1984 1985 1986 

10 8 6 5 

FIGURE 2-1-1 
FINAL REPORT 

100 watt to 300 kW size range will'market well if it: 

1) includes MPC capability at an incremental cost of under 

$ .4Q/watt 

2) is also useful for battery management without an MPC 

3) costs less than $300 in a minimal configuration without the 

power electronics of an MPC. (The cost of a no-MPC 

controller for a 500W system) 

The needs of the industry can then be segregated into at least two 

different types of controllers. The very.smal1, very inexpensive 

controller (typically one quad comparator today) for systems of a few 

hundred watts or less is not the same as the flexible, sophisticated 

unit for larger systems. The small controller is discussed later as 

the "zero optionv. The larger controller can then be examined in 

terms of those characteristics which have a major affect on the unit 

cost. 

2.2 -- MAJOR COST IMPACT ITEMS 

System level items -- 

The items affecting controller cost fall into two categories: those 

which describe the system, and those which describe the controller 

itself. These are listed in Figure 2.2-1. System characteristics 

affect the controller by the number of analog currents or voltages to 

be measured, by the number of counter/timer functions, and by the 

power or energy level of those parameters. This last group impacts 

the sizing of relays, power converters, shunts, and terminals in an 

obvious way which is separate from the control function itself; and 

is easy'to design as required. In particular, any inputs or outputs 

of the control system which are continuously variable rather than 

switched are most expensive because they require either A/D or D/A 

converters, analog multiplexers, or counter/timer functions. Zxtra 

array measurements, maximum power controllers for the array, and 

variable loads (such as motor drives) are in these categories. Also, 

since battery control is the most complex function of the controller, 

dominating its accuracy and speed requirements, the number of 

batteries to be controlled independently is a major factor. 

The effect of controller characteristics on cost requires further 

description of these tasks. Figure 2.2-2 lists major control 

functions. 

2.2.2 Battery Control Considerations 

The basic algorithm to be used for battery state of charge (SOC) 

estimation will be ampere-hour integration. Total ampere-hours into 

and out of the battery will be used to estimate change in SOC. 

Beyond this, a variety of checks, adjustments and corrections might 

have been used. 
DESIGN CONSIDERATIONS HAVING STRONG EFFECTS 

ON THE DESIGN OBJECTIVES AND COSTS 

I. PHOTOVOLTAIC SYSTEM CHARACTERISTICS 

1. Photovoltaic array size 

2. Type, number and total energy of storage elements 

3. Type, number and total power of variable controlled loads 

11. CONTROL SUBSYSTEM CHARACTERISTICS 

Array control 

Battery SOC algorithm 

Load management 

Product storage load management 

Requirement for independent manual control override 

Manufacturability 

Adaptability 

Maintainability skill, test equipment and MTTR 

Reliability - MTBF 

Figure 2.2-1 
Major Functions of the Controller 

1. Battery State of Charge estimation 

- amp hour accumulation 

- temperature compensated voltage limits 

and float voltage 

- MPC inhibit 

- automatic charge equalization 

2. Maximum Power Controller 

- input filtering 

- comparison and duty cycle stepping 

- limits 

- direct digital PWM control 

- output buffering 

3. Load Control 

- variable load setting 

- multiple fixed loads 

- response to SOC 

- backup generator control 

- product storage status response 

4. User Service 

- keypad input scan 

- parameter settings 

- multimeter readout 

- SOC readout 

- diagnostic readout 

5. Self Test Capability 

- Array and battery and load monitoring programs 

- Self monitoring programs 

6. RS232C Interface 

Figure 2.2-2 
FINAL REPORT 

The coulombic efficiency of the battery is not 100%. As the battery 

becomes more fully charged, this value drops from near 100% until the 

battery is fully charged and equalized and the coulombic efficiency 

reaches zero. One correction then is to discount some fraction of 

charging current based on SOC. This was implemented. 

The battery's self-discharge rate represents internal reduction of 

SOC without external current flow. This depends on battery 

chemistry, temperature, and age. Therefore, some estimate of 

internal self-discharge rate based on temperature might be used as an 

approximation. However, this was not included in the present unit 

because it is so dependent on manufacturing parameters of the 

battery. 

Battery terminal voltage depends on age, temperature, SOC, rate and 

past history. However, at full charge and at full discharge, the I-V 

characteristic of the battery can be well established, with a 

suitable temperature correction. This means that at a temperaturecorrected float voltage, the SOC is corrected to 100%, or at a 

minimum voltage the SOC is corrected to 0. Another alternative is to 

measure the current drawn at the float voltage at a given temperature 

and extend the charge cycle (lower the calculated SOC) if it is too 

high. This last was not implemented because it again is very battery 

dependent. The first alternatives were implemented, however. 

Equalization of cells is done as a voltage-limited (temperature 

compensated) charge based on a number of ampere-hours required equal 

to a fraction F of ampere-hours discharged from the battery. After 

the completion of equalization, the charge may have been terminated 

to save water, or a lower voltage trickle charge may might be 

maintained. Based on our experience with systems, the latter was 

chosen. 

An estimate of the time to next required battery watering of amount 

of water required could be made by the processor. This would be 

somewhat inaccurate, but might be of some use in warning of required 

maintenance before actual failure. This was not implemented. 

The battery state of charge is defined to be the fraction of 

nameplate ampere-hour capacity which can be delivered at a nominal 

discharge rate before dropping below a voltage threshhold (typically 

1.75 volts per cell). This changes with the battery temperature. (If 

the value is corrected for temperature, the result may exceed 100% on 

a warm day.) This value was chosen for load control functions, and 

for front panel display of system status. 

Estimates of state of charge by combining voltage, current, and 

temperature using a ROM look-up table at intermediate SOC level has 

been found previously to be inaccurate during charging periods, and 

was not used. Another approach, modelling the battery internally by 

a series of coefficients representing internal circuit elements, has 

been proposed by researchers at Tel Aviv University. See for example 

"Measurement of the State of Battery Charge using Improved Loaded 

Voltmeter Test," E. Ofrey and S. Singer, IEEE Trans, in 
FINAL REPORT 

Instrumentation and Measurement, Vsl . IM-37 No. 3, pp. 754-158, Sept . 1982. This approach was found to give good long term results, but 

only after a particular make and model of battery was characterized 

extensively. Since this implies a practical limit in the flexibility 

of the controller, this approach was not utilized either. Instead, a 

current integration (amp-hour meter) approach corrected for coulombic 

efficiency based on state of charge was used. This is in turn 

corrected if it exceeds the extreme temperature-compensated voltage 

limits expected for that battery; a much easier parameter to specify. 

To measure battery current within half the rate of the internal selfdischarge current, it was necessary to resolve to the nearest 550 

hour rate. This compares with typical maximum charge/discharge rates 

of 4 hours typically, or 1 hour in an extreme case. Therefore 

resolution within 9 bits was required. Since the full scale range of 

the shunt may not correspond to the maximum rates (by a factor of 2 

or 3), resolution to 10 bits minimum was required. 12 bit resolution 

would be nice but not absolutely necessary. If 100 millivolt shunts 

are used, this implies offsets near 25 microvolts will be visible. 

Therefore, the design should strive for 12 bit or 25 microvolt 

resolution of battery currents, with only 10 bits or 100 microvolts 

actually required. The use of a 10 bit plus sign A/D converter and 

4X signal averaging was selected. 

One major expansion of the controller's task would be to separately 

calculate SOC of multiple parallel battery strings. This takes up 

some extra RAM, processing time, and implies a higher level of system 

costs to implement for equalizong strings separately. However, 

reliability and cost savings warrant the added complexity in some 

cases. This was not implemented in order to keep controller cost 

down. 

2.2.3 Array Control Considerations 

The PV array must be controlled under the following circumstances: 

1. If a battery is used and is fully charged, to avoid excessive 

water useage. 

2. To avoid excess voltage on the load. 

3. To allow the load(s) to be turned off if the array dconnects 

directly to it, as discussed under load control. 

4. To allow a portion of the array to be safely repaired while 

the remainder of the system is running. 

5. To avoid discharging the battery at night if no isolation 

diode is used. 

6. To protect the array in case of fault. 

Typical means of array control include: 

1. Series contactors or switch elements, usually with series 

diodes in all but some low voltage configurations. 

2. Parallel switch elements acroll the solar array, with a 

series diode batween array strings and the battery. 
FINAL REPORT 

4. Switching DC-DC converier elements between array and battery 

usually providing maximum power control. 

The control signals required by these schemes are different. Series 

or shunt regulators require a digital signal for each array string. 

A parallel shunt element might require no signals, or might have a 

digital input to modify the set point voltages for equalization. The 

switching converter requires a pulse width modulated square wave at 

the switching frequency, typically 2kHz to l00kHz being extreme 

values and 20kHz most common. 

Instrumentation of such systems over and above what is needed for 

control, would normally provide one voltage and one current 

measurement for each array string. Since the instrumentation 

provisions are the same, design of the controller must concentrate on 

providing signals for control in the various cases. The first two 

cases (series or parallel) require the same signals. Since 

dissipative shunts are cost effective only in small systems, the 

third case has no impact on microprocessor system design. The last 

case is very well matched to microprocessor systems capabilities. 

Note that many systems are cost effective without built -in 

instrumentation, but with provision for multimeter readings via test 

points. 

Therefore, the most useful way to deal with the series, shunt and 

switching converter array control options was to provide a different 

ROM sub-program for the same basic system design. The maximum number 

of independent subarrays to be controlled must be set and 5 

optoisolated or 10 direct coupled output signals was chosen as good 

number. This number of optoisolated output signals must then be 

supplied, and could be used for either array inputs or load busses 

depending on system requirements and ROM programming. 

Next, considering the option of maximum power control, the ability to 

distinguish small changes in the combined output voltages and current 

generally limits maximum power tracker performance. Therefore, 

careful treatment of the signal to noise ratio and the filtering of 

the input signals is important. This was carefully analyzed during 

design. 

Typically, the power is an insensitive function of the duty cycle 

near a maximum. Therefore, a 2% change in duty cycle F produces a 1% 

change in output power. In the resistive load case, Vo and Io may 

each change 1/28. Therefore, to find the max power point within 18, 

6 bit resolution of duty cycle F and 8 bit resolution of V and I are 

required. Since the system must run at a fraction of full scale, an 

extra 3 bits is needed. Therefore, use of a 10 bit plus sign A/D 

gives adequate resolution. Filtering must recognize the presence of 

20kHz and its harmonics as switching noise, and must produce the 

cleanest differences possible at 100 msec intervals. This means 

averaging a number of samples in the 100 msec window. Four samples 

were averaged. 

Timer capability for 8 bit duty cycle resolution requires, for 20 kHz 
FINAL REPORT 

carriers, a timer speed of 5 mHz. 'This is fast for CMOS, so perhaps 

a 7 bit capability would suffice, or a non-CMOS timer could be used. 

The non-CMOS timer was implemental. 

It is necessary to recognize when some other limit is operating to 

disable the max power tracker. In such a case, no change in output 

occurs except noise, and the duty cycle should then move toward a 

nominal value or remain fixed. Remaining in a "ditherw pattern was 

chosen. 

Ability to manually move the duty cycle up or down can be useful for 

array string testing, although it is not often required in an 

operating system. Therefore a test/cal mode was implemented. 

Based on our experience, it is felt that up to 10 power elements 

should be driven by one MPC controller, each with a separate buffered 

output. These may be assumed to have their outputs in parallel, with 

separate subarrays. Therefore, 10 buffered outputs, all with the 

same pulse width modulated signal were provided. 10 DC currents and 

one output voltage were sampled. 

With present production power modules rated a 500W, TriSolarCorp 

could handle up to 5 kW with one controller. Larger systems could 

use multiple controllers or a larger power module (perhaps 3 to 5 kW) 

could be developed. 

There are two basic cases in our experience when it is use'ful to have 

two max power controllers (MPC) operating from the same solar array. 

The first occurs with a shunt wound DC motor driving a pump or other 

device. The field winding requires power for start-up and so must 

have high priority on solar input from a portion of the PV array. 

After 30% sun or so, the field winding is fully excited and the rest 

of the Oower from this portion of the array can be used by the 

armature. The field usually represents 3% to 5% of the total power 

dissipation at full load. Use of separate arrays and MPC's results 

in waste of 6% to 10% of the system output at full run. Idealy, this 

can be recovered by using extra DC-DC converters to divert some power 

from the field portion of the array to the armature. 

A secqnd instance occurs when a water pump and battery charger are 

combined. The battery may be small and ideally, after the battery is 

charged, the water pump could be used for excess energy use. 

Separate arrays waste the PV output to the battery when it is fully 

charged. Running the pump off the battery requires a bigger battery 

and loses energy in the battery. 

Ideally one set of DC-DC MPC drives would power the field of the 

motor or charge the battery until it reached a limit. Then another 

set of MPC drives would pull extra energy from the same PV strings 

for variable load use. 

Each maximum power controller function added to the control unit 

requires whatever power conditioning elements are needed, extra 

output V and I sense lines, and extra PWM timer, an output on-off 
FINAL REPORT 

control bit, a few bytes of RIM, and a small anount of extra ROM, 

plus the program execution time on a 100 millisecond loop. Since the 

power conditioning can be used as needed, the inputs and timer are 

the biggest penalty to a minimal control element configuration. For 

the prototype, the second MPC was not implemented, but the provision 

of an extra timer was made to allow later implementation. 
FINAL REPORT 

2.2.5 - Load Control Considerations - 

A variable load would be controlled by a proportional analog signal 

of 0-10 volts. Therefore, one such output was provided, with 

programmable direction, and SOC programmable set points for load 

shedding and load restoration. Resolution is not important since 

only approximate energy useages need to be controlled. 

Most loads are not continuously power controlled and up to 5 discrete 

outputs should be provided for. These would be 1 bit isolated 

outputs, with programmable SOC "ON" and SOC "OFFw set points. These 

could also include back-up generators or other such devices. 

Manual override capability is probably best placed in the loads 

themselves rather than in software. However, for self-test purposes, 

artificial counting up and down of the SOC control signals should be 

possible. Therefore, a manual SOC setting capability was included. 

At least one output circuit for latching relay drive should be 

provided. However, this was left for external hardware rather than 

internal software. 

Multiple variable DC loads must be assumed to be in parallel, 

otherwise the number of PWM counters becomes unmanageable for a 

single CPU controller and controller networking is required. 

AC loads, to be variable, would require a variable voltage'and 

frequency inverter. Drive signals for the poles of such an inverter 

might be useful, but might be used for this function only when it is 

needed, for variable speed AC pumps or compressors. These were not 

included. 

Product'storage can occur in a number of forms. Examples of this 

are : 

1. Water tankage (pumping). 

2. Ice making (refrigeration). 

3. Phase change thermal storage (refrigeration or heat pump). 

4. Fertilizer making. 

5. Water heating (resistive). 

6. Salinity (water desalination). 

Because of the diversity of types, the control interface must be 

relatively simple to be standardized. Typically, the product storage 

system must indicate when it is full and when it is empty. Provision 

for this can be flexibly accomodated with two relay contact inputs, 

one normally closed and one normally open. Either one in the 

abnormal state should cause the PV system to turn OFF, under the 

assumption that product storage capacity has been reached. In most 

cases, a pair of level switches or thermostats can provide the 

desired signals. The capability of accepting other analog inputs 

would be provided in hardware anyway. One algorithm for sharing 

power between an analog measured product and a battery was be 

developed. 
FINAL REPORT 

Output to load control may have to operate over hundreds of feet in 

electrically noisy environments. Grounding of such signals can cause 

problems for the control system. Therefore, all discrete load 

control signals were optoisolated. In low cost applications, the 

optoisolators can be omitted to avoid excessive cost of unnecessary 

options. (This same consideration applies to discrete array control 

signals for series or shunt regulated systems. The same outputs can 

be used, with a programming change.) 

Predictive load control algorithms must take into account primarily 

the state of charge of the battery, and secondly the time of day and 

present insolation. This allowed correction of the load shed 

threshold to a perhaps 10% lower value if the time were 8 to 71 AM 

and the array current was 20% of the maximum, for example. This 

would avoid innecessary cycling of loads. Further use of predictive 

control requires algorithm development and field experience which is 

a good subject for research, but was not currently available for 

implementation in this controller. The controller will facilitate 

the data logging required to obtain parameters for evolutionary 

development of these methods. 

2.2.5 7 User Service Considerations 

As a minimum, any controller must allow the user to turn the MPC ON 

and OFF, and display the battery status. Given the data available to 

this controller, it also provides readouts of all sampled voltages, 

currents, or temperatures. It also provides alarm functions for 

system malfunctions (for example: output over voltages, output over 

current,motor over temperature, array string output zero for more 

than 24 hours) and perhaps some diagnosis of problems (power module 

shorted). Most alarms are visual, with provision for an audio option 

for critical failures. 

Also, parameters of the system might to some extent be field or user 

reprogrammable to allow a single stock controller design to be 

produced for distribution. These parameters might include state of 

charge, number of power modules or array strings, motor voltage, 

battery voltage or capacity, The use of a back-up battery for 

internal memory or electrically reprogrammable ROM (EPROM) becomes 

necessary for this. It was decided to provide manual reassignment of 

load priorities, but all other parameters were fixed in EPROM. 

The interface itself waschosen to be a low cost ($5 to $10) membrane 

switch keypad for input, and a 4 1/2 digit display for output. A 

buzzer or loudspeaker would be optionally plugged in. These features 

were mounted on an inner hinged panel, behind the weatherproof NEMA 

front panel and in a location protested from user contact with any 

live parts. 

This also allows initiation of self-diagnosis routines from the 

keypad, which could test all elements of the processor and 

interfaces. 
FINAL REPORT 

Further diagnosis might be done via-an RS-232 port. This port could 

also provides for data logging of the signals sampled by the 

processor. These included array string input voltages, output 

voltages, and MPC power module output currents. From our experience, 

these facilitate fault diagnosis and isolation as well as permitting 

delivered power and efficiency calculations. 

2.2.6 -- Self Test Considerations 

At the highest level, the processor tests the solar array strings to 

determine if one is weaker than the other. It.warns if the battery 

is too deeply discharged. It announces if a load draws much current. 

At the next level, the controller tests itself. A test of RON, RAM, 

and all output audible and visible alarms is performed on demand. A 

watchdog timer checks of the processor is running at all times. 

To allow both production testing and field repairs, an RS-232 

interface and a small monitor program is useful to exercise the data 

collection, processing, output control, and timing functions of the 

controller under manual control. With only the keypad input and LCD 

readout, a more limited manual checkout of the system and the 

controller is possible. This simply displays voltage and current on 

demand, and allows manual unit turn ON and OFF, plus a scan of all 

parameter settings in the controller. 

A standard hexadecimal 16 keypad suffices for the development systems 

with two preliminary letter keystrokes for function and numbers 0-9 

for string or parameter identification. In production quantities, 

the letters could be replaced by more explicit labels of the 

functions. 

2.2.7 Other Considerations 

In addition to the these functional requirements, the need for a 

product which is easily reproduced without custom drawings for each 

application is important. Also the adaptability of the unit to a 

particular system without large numbers of selector switches, ports, 

jumpers or custom trimmed resistors is vital. Extensive use of 

EPROM, for system parameter and algorithm specification was chosen as 

the most viable approach. The use of replaceable modules at the 

board level into the unit, was found to be necessary for user 

acceptance in locations where PV is to be used. 

Finally, the unit has to be very reliable if it is not to compromise 

the inherent advantage of reliable electric power which makes PV 

systems attractive. This implies use of proper temperature range 

components and minimization of parts count. 

2.3. OPTIONS DEFERRED 

In designing the controller, a number of decisions were made which 

might be re-examined at some future date as component technology 

changes. These are described here to facilitate such future project 
planning. 

FINAL REPORT 

2.3.1 "Zero Optionw 

In looking at the market analysis for PV controllers, it appears 

that there may be a place for a very inexpensive (well under $100) 

controller without many of the features needed in large systems. 

Such a controller would be simply a battery regulator, with a single 

array input'and a single load output. It would be intended for 

systems from 100 watts to 1kW peak, where the site access cost for 

battery maintenance or replacement would make state of charge control 

worthwhile. It would have no instrumentation or data logging. 

capabilities, no sequential load shedding, no maximum power point 

reacking, and would be designed only for 12 or 24 volt batteries. 

However, it would provide a readout of battery state of charge based 

on ampere-hour accumulation and would provide better battery charge 

control than the ten dollar voltage limiter with temperature 

compensation which would compete with it. Such a controller would 

require very little memory (RAM or ROM) and could be implemented with 

an 80C48, 146805, or equivalent processor. Inputs for voltage, 

current and temperature of the battery would be adequate. Latching 

relay drives would be appropriate for input and output. 

The economics of such a controller are marginal at present. In the 

future, sufficient volume (several thousand per year) would allow a 

masked-ROM memory and an inexpensive 8 bit multiplexed input, 

resulting in parts costs under $40. Until such time as this market 

becomes better defined, the viability pf such a product is not clear. 

However, a specification has been generated for future reference. 

The concept is labelled the "Zero Optionw because it is not one of 

the five recommended options for the next phase of this contract. 

Figure 2.3.1-1 gives these specifications. 

2.3.2 Larger - Power Stages - for Maxpower Control 

The TriSolarCorp MPC power modules available at present are rated 

500W each. The control of systems larger than about 5kW requires 

that more than 10 such power modules be used. This can be 

accomplished using the present MAC microprocessor controller only if 

not all of them are monitored, or if more than one MAC be used, or if 

relays instead of MPC power modules are used. A better solution is 

to develop power modules of near 5kW power rating. This requires 

interfacing to the MAC with a pulse modulated waveform of the proper 

frequency, since 20K HZ implemented at present may be too fast for 

larger devices. Also the dynamics of the control functions must be 

compatible with the slower filters of a larger power module. 

This development was beyond the scope of the present contract. 

2.3.3 Multiple - MPC Control 

In many systems more than one max power control function is needed, 
SPECIFICATIONSFOR "ZERO OPTIONn CONTROLLER 

Array Voltage : 

Array Configuration: 

Array Control : 

Single Ended Inputs: 

Differential Input: . 

Control Inputs: 

Battery: 

Battery SOC Control : 

Battery Voltage Limits: 

Control Digital Outputs: 

Manual Entry or I/O: 

Display : 

Single input 

Discrete ON/OFF 

Battery voltage, battery 

temperature sensed by 10k ohm 

thermistor 

- +100mV battery current shunt 

Relay contact closures, One NC, One 

NO 

12V or 24V Nominal, 10 to 10,000 

ampere-hours, required for 

opera tion 

Ampere-hour accumulator, accuracy 

- +lo%, precision 22% 

Maximum absolute limit, maximum 

temperature-compensated limit, 

minimum absolute limit 

One for array, one for load, 

latehing relay drives 

None 

Battery SOC, 2 1/2 digits, LCD 

FIGURE 2.3.1-1 
FINAL REPORT 

since more than one power flow path from an array to a load must be 

controlled. No extra hardware in the CPU would be needed to 

implement the feature, but extra power conditioning hardware would be 

needed as well as appropriate software. This was not implemented in 

the prototype since no specific use was foreseen at present. 

2.3.4 Variable - MPC Control 

The ability to drive standard sumersible AC motors for pumping 

applications would enhance the controller. However, the relation 

between an AC motor and its variable speed drive is particularly 

intimate in terms of protective features and optimal drive 

strategies. 

Implementation of this function was left for a separate unit, with a 

simple interface to the MAC controller via an analog control voltage 

0-10V F.S. This task is well worthwhile when resources are available 

to support it. 

2.3.5 Multiple Battery Strings 

If a large system consists of several parallel-connected battery 

banks, it is possible to compute the state of charge of each one and 

check that each is sharing the load. However, this is not critical to 

the PV system control task and so was not implemented at this time, 

since it impacts the size and speed of the controller. 

2.3.6 System Topologies 

The most fundamental choice in applying a microprocessor controller 

to large PV systems is the overall topology. How many controllers 

will be used, and how will they communicate? Three basic topologies 

were studied. These are described as follows: 

Distributed -- Controller 

The distributed controller is conceptually a number of independent 

microprocessors, each performing a different function in the overall 

system and each located with the equipment it controls. For example, 

in a village power system some control elements might be array 

controllers or max power controllers for separate subarrays, another 

might perform battery management, another control load management 

functions, and another might perform data logging and display 

functions. Only a small amount of slowly changing information would 

be exchanged between them via a bus structure of some kind. Any one 

controller could function in a backup mode without any information 

from other controllers. 

- Star Controller 

In the star configuration, a master controller operates the central 

elements of the system and communicates with remote slave units ar 
FINAL REPORT 

the ports of the "star". These slave elements are simpler, more 

sprcialized units and communicate only with the master controller. 

In a village power system, for example, the master unit might perform 

battery and load management and data logging functions while the 

array controls or max power controllers were slaves. Diagnostic 

displays might be divided among the elements as required. 

Information on battery status would flow from the master unit, and 

array status would return to it. Backup operation would require 

manual control of the battery and loads. 

Central Controls 

In a central control scheme, all control functions reside in one 

controller with no processor or "smartw controls in any other place. 

In a large village system, all array switches or max power trackers 

and loads have their operating states set by the central controller. 

All data logging and most of the instrumentation would also be 

centralized. This configuration allows the most complex algorithms 

since a;; data is available for all functions. It also provides the 

least redundancy and backup capability, unless the central controller 

has it built in. 

Assuming a microprocessor of even minimal complexity at each mode, a 

trade-off study showed that the central topology was the least 

expensive for all but the smallest systems. This was basically 

because the cost of memory, power supply, enclosures, and so on was 

too high for very small units of the distributed or star networks. 

Therefore, the central topology was pursued as the basic requirement 

for the MAC controller. 

However, it should be noted that the MAC can be used in either 

distributed or star configuration under some circumstances. 

If a large system required independent operation of several parts for 

higher reliability, several MAC units could be operated 

independently. No information would be exchanged between them, 

unless further development of a multi-station RS232C bus were 

completed. 

Also, if a system had a number of "dumbM controllers such as the low 

cost TriSolarCorp BCR unit, each of these with its subarray could be 

treated as a discreet-switched string and controlled and monitored by 

a sequentially switched segmented array control, a very good way to 

handle large low voltage DC systems. The MAC would provide 

everything except max power tracking for such a system. The three 

basic topologies are diagrammed in Figure 2.3.6-1. 

As part of the trade-off of system topologies, a Failure Mode and 

Effects Analysis (FMEA) was done for each option. Figure 2.3.6-2 

shows the system level failure modes of the unit and their results. 

Figure 2.3.6-3 takes these failure modes and compares the impact of 

each of failure on overall system operation. As is easily seen, the 

impact of distributed system failures is far less than star system 
DISTRIBUTED: 

STAR: 

- 

CENTRAL : 

m Array 

5 kW 

Array 

* 2 

a Array 

5 kW 

Array 

u Array 

Variant 2 Variant 2 I Variant 2 I 

I 

Variant 1 Printer 

I I i 

I 

FIGURE 2.3 6-1 

I 

C 

Variant 1 RS 232 

- - --- 

I 

J 

Loads C 
MA, SYSTEM LEVEL 

Function 

Lost 

Array Control 

Partial 

Total 

Battery Control 

Load Control 

Instrumentation 

Data Logging & 

Communications 

Self Test 

~iitributed Star 

Reduced output Reduced output 

until scheduled until scheduled 

maintenance maintenance 

Greatly reduced Greatly reduced 

output until output until 

scheduled main- scheduled maintenance tenance 

manual operation manual operation 

modular replace- master unit replacement 

Manual load Manual operation, 

operation, mod- Master unit reular replacement placement 

Operationa1,sched- Operational, 

uled maintenance scheduled maintenance 

Manual operation, Manual operation, 

modular replace- modular replacement men t 

Operational, - Operational, 

scheduled mainte- scheduled maintenance nance 

Centralized 

Reduced output 

until scheduled 

maintenance 

Total shutdown 

controller replacement 

totally manual 

. operation,controlier replacement 

Totally manual 

operation, controller replacemen t 

Manual operation 

Con troller replacement 

Operational, 

scheduled maintenance, modular 

replacement 

Operational, 

scheduled maintenance, controller 

replacement 

FIGURE 2.3.6-2 
FMEA IMPACT CHART 

ANY ONE ELEMENT: FAILURE DISTRIBUTED STAR CENTRAL 

Power Supply 

Low 

High 

A/D Converter 

Calibration 

No output 

Display and Interface 

Partial 

Total 

Array Control 

Partial 

Total 

UART/RS-232 

Total 

CPU & Memory 

Total 

Current Meas. Max or Analog Mix 

Partial 

Tota 1 

NOTE: l=degraded performance, scheduled maintenance 

2=manual operation until maintenance 

3=total failure 

FIGURE 2.3.6-3 
FINAL REPORT 

failures, which in turn are less than central system failures. 

2.3.7 Other Processors 

The choice of processor is very fundamental to the realization of the 

controller. Based on the previous decisions, we needed a processor 

with 8-bit data bus, 16-bit address bus, and instruction times below 

5 microseconds. A list of these are attached in Figure 2.3.7-7. In 

addition, memory requirements were estimated to be 2K of RAM and 12K 

of EPROM. 

This was too much for the chips with on-chip memories which were 

available for the "zero optionw. Also, using a chip with all address 

and data lines available allowed system expansion for larger 

applications. 

Major considerations then became power level (CMOS preferred), 

availability, support, and cost. These reduced the field to two 

major competitors, the national NSC 890 and the various suppliers of 

the 6502. The main attractions of the NSC800 were availability 

and low power. In particular, the modular MA2000 version of the 

NSC80Q looked attractive as a compact package. However, availability 

of the MA2000 in the time frame required was a problem, and the cost 

of the NSC80Q in any form was higher because of the interfacing 

needed for its address and data busses. Development support for the 

65C02 was more available at the facilities which needed it, and the 

cost was very low, the CPU only $10 in large quantities. After 

evaluations of samples from both GTE and Rockwell, this bacame the 

choice for the project. The availability of NMOS versions of most of 

the family at lower cost for breadboarding was also useful. 

Analysis of the cost of the 65C02-based processor, which is suitable 

for any-of the three geometries and can meet all the preliminary 

design requirements, shows that its hardware cost, in small quantity 

production, in materials alone will exceed the $300 cost target, 

*meant to include labor and overhead as well. This problem motivated 

a careful look at lower cost alternatives which could be used in some 

topologies (perhaps as a peripheral unit of a star configuration) or 

with reduced capabilities. The number of analog inputs and load bus 

controls, plus the WART support requirements, were the driving force 

behind the processor choice. Therefore, a lower cost alternative was 

generated which approached the operational requirements of the system 

with less input and output. 

The dramatic cost reduction possibilities lay in the use of a single 

chip computer with inboard EPROM. The chip selected for closest 

approach to the 65C02 in instruction set and largest memory capacity 

was the MC1468795G2. This has 2106 bytes of EPROM, 172 bytes of RAM, 

internal timer, 32 I/O lines, bootstrap programming and is plug 

compatible with a masked ROM version for future cost reduction in 

larger quantities. It combines CMOS power levels with a versatile 

instruction set. Its limitations for our application are expected to 

be the number of 1/0 lines and the amount of ROM. Its advantage is a 

cost reduction of almost a factor of two. 
1-4EHCOCEHto2=1— (

fsO. •

P-•<EHXto<, «<EH•O<ca

>~EH:*oH o«oEXH

I-H:

:*_

toCCacc0ocaCOo. c0c*—o

 »

c0otoEaC^Q•<

r3

tl «<

>->• ,J . •J

«s;

t— ( C0Cca^o^o

30

E P- 0

ca -a: ^.

E E M COcccaEHCO

tl coaccEH

ex. CC C

O

CC J

ca ca

EH >•

2: ca

ti j

Hte 2inX^

I—I

.^^ca

O — ' >-i 0 X•< ca E EH ^ co 2: 2S I-H

•-i E

•~S.

CQ^^

>•« O O

DC — —•

S-s- s-

E E E ca -s o E CC C

C

• • •

•~- CM f^V

ca

>—o i

•<_> =>cccaccQa; ra ' «c

COca>H

cc

EHp*

S X =) >H 0 0 •< 0 -EH < x to *—v'mD

IT•> KN"^iO*n^v^-

^«J

x>X X o -- O 0

ir> in

VO vO

i i

CO CO

0 0 E E car5oOf

C>H%Q

CC

EH

< PH

S X =i 0 0 •< 0 -£H < x to "^CM00 "

C\J CM^—

«^

toca c

o

EH ca

>-" EH

CQ >HCQ

X CO

•* CM X

,D •- CM

<^>

VO

• - ^Xs

*fcJ

>—< 1

CO

ca

w . ?H

CC

EH

CQ P-,

- X< 0^ •S. EH O CO oo

 - .

< X CMrCG

LfN ^^CM

tocaEH>HCQ

^ CO

•<3- CM

vD ^~

OMD68SC02A >—JQo *

COCC

S-| ^^

cc

X EPHH

sTx

=> o 0 -aC 0 EH < CO

cc

ca

<y s M K I-H !X r^ ^^

•>- h-< EH CO

vO

RIG1NAL P^

F POOR Ql

^j-

"S^^ CM

toca>HEHCQCM

X —co — CM CM ca o m in 0 0 co oo m vO vO O

•<*• -<3- K\

^ ^ VD

0 0 O

S EX

•<O (-

H

O X

CC. 0 o •< EH Er-> i— i

ca

>-< a.

•«or in00i

GE-I nS

AUW.

CVI•

<T>

v

•O•-^X~2inoCO8•O;o

2o;

S

PL, 3 O O vO 0 .- «C »—vO t*- K\ KN in

^^.

t

*n

CM

CO CO

ca ca

EH EH

S— * S— i

^^ r*

CQ PQ

•s^ ^- **•

^_k (^

^J N*X ^^

Pt

00 CD 00 CO

••a- -«3- •«d- •**•

0X00

o o o o 00 O 00 CO CO CO Q Pi 25 2: d, E

IH iH E E|C

C^^H

 !

O IH O 00

2O:

CL. CO

••—vOOO0•0CM

^"

x- ^*"

CO

ca co

EH ca

>H EH

CQ >HCQ

CO

!a£ CM X ^r ^ Ccut voM

CT> CK

•** •<*

0 O

CTi O O

•«* CO 00

O O P-.

O P- E

00 E EH

«t —

CO _

j - IH L:

(-> O iH CO k-
COMMERCIALLY AVAILABLE CMOS MICROPROCESORS WITH 8 BIT WIDE DATA PATHS AND INSTRUCTION TIMES BELOW 5 MICROSECONDS (CON'T) 

~OSH I BA TMP80C3GP-6 4K 2.515 

ISC 

9 6 1 16GP NO 1. 8039 NMOS COMPATIBI 

64 BYTES 'IV T 

ACCUM 2. 27 1/0 LINES 

3. NO HIGH LEVEL LANCl 

SUPPORT 

?C A 1805 64K 4/6 113 1 16GP NO 1. 8 BIT COUNTER-TIMET 

64 BYTES 2. SOME HIGH LEVEL LAP 

SUPPORT 

: IVI"I'HS1 L IN6 1 00 4K 2*5/5*5 8 1 1 ACCUM NO 1. PDP-8 INSTRUCTION 

MQ 2. 4v TO IIV OPERATIO

3. 12 BIT DATA PATH 

IOTES: A) All units have expansion I/O capability ' 

B) Memory direct addressing capability 

C) RAM on CHIP 

D) ROM on CHIP 

E) In microseconds 
FINAL REPORT 

To allow use of this chip, the array string currents are summed prior 

to sampling. The individual array string currents and voltages, if 

needed for instrumentation, must be switched manually to a metering 

input of the processor. Also, the two (not five) output bus lines 

are not measured automatically, although these too could be manually 

metered the same way. Only one PWM output is supported, with no 

analog output signal. Finally, the limited I/O of the chip will not 

support a UART for RS-232 linkage in addition to its other tasks. 

Communication via two dedicated digital inputs and one analog input 

is provided. Self test functions are minimized. 

However, with these reductions, the processor can perform the key 

array control, battery charge control, load management, 

instrumentation, and self test functions in the system design 

requirements. The unit would be able to meet the requirements of the 

many small applications at a competitive cost, with the sacrifice of 

more complex system capability. 

To meet more complex system requirements, the small processor option 

could be used in the following ways: 

1. As a peripheral unit of a star configuration, with the two 

digital and one analog input lines to the hub element, the unit 

works. The central unit might be the 65C02 based controller or 

another small controller configured with no analog inputs but UART 

interface for data logging and a sinplifies link to the peripheral 

units. 

2. As a multiple processor central unit, with one major function 

for each chip. 

As a distributed processor element, the limited I/O capability makes 

the small processor option unfeasible. The small processor was not 

implemented in the prototype. 

2.4 CONTROLLER SPECIFICATIONS - 

Having selected the important functions of the MAC unit, and deferred 

the options not to be included now, the requirements for the unit can 

be summarized as a specification. This is done in Figure 2.4-1. 

Array Voltage +10.0V to +78.0V or 

+40 to +300.0V, 

Input power under 5 watts 

Array Configuration 1 to 10 string 

40 to 500W per string 

Array Control Discrete string ON/OFF or maximum 

power control by Pulse Width Modulator 

(PWM) down converter 

Tracking Accuracy Within 1% of maximum output power 
FINAL REPORT 

Control PWM Interface 12.5V (+lV/-.05V) pulse width modulated 

20kHz CMOS losic level, up to 70 buffered 

outputs which can be connected to either 

one of 2 independent PWM drivers or are 

usable as 10 separate discrete control 

signals. 

Single Ended Sense Inputs +/- 4V DC full scale, +/- 2% accuracy, 

10k ohm source impedance maximum. 16 

voltage channels plus 2 thermistor 

channels 

Differential Inputs 

Control Inputs 

Battery 

+/- 100mV full scale, +/- 2% accuracy, 

+/- 2V common mode maximum, 1K ohm 

source impedance maximum, 16 channels 

Two contact actuated inputs, one for 

normally open and for normally closed 

contacts. One manual system is shutdown. 

Normally open is ON. Contact rating 

required is 15V DC, 2 mA DC. 

No battery is required, or with battery, 

12V to 240V nominal, 700 to 10,000 

ampere-hours . Battery SOC Controls Ampere-hour accumulator accuracy +/- 5%, 

precision +/- 1%. 

Battery Voltage Limits Maximum absolute limit, maximum 

temperature compensated charging limit, 

maximum temperature compensated float 

limit, minimum absolute limit, all 

programmable 

Control Digital Outputs Optoisolator outputs, 6 total; pairs may 

be used as latching relay drivers. 

Control Analog Output 1 output +10V full scale, accuracy +/- 2% 

resolution 8 bits minimum. 

Test and Logger Output RS232 interface, 300 baud, full duplex 

Other rates programmable by EPROM change. 

Display 

Manual Input 

Power Dissipation 

LCD 4 1/2 digit display of battery SOC, 

any analog sensed input, calculated 

parameters, or error codes. 

16-key keypad to select 'displayed 

quantities or self-test 

5 watts or less for control elements only 

not including power modules or relays 
FINAL REPORT 

Power to Other Elements i72.5~ (+lV/-0.5V) at 0 to 50 mA 

System Loads Battery, resistive DC, permanent magnet 

or wound field DC motor, inverter/battery 

Ambient Temperature Operating -25 degrees C to +45 degrees C, 

shipping -45 degrees C to +85 degrees C 

Enclosure NEMA-4 
3.0 DESCRIPTION 

3.1 HARDWARE DESCRIPTION 

The prototype microprocessor PV system controller consists of a NZMA4 enclosure containing the following major electronic assemblies: 

A. Power Supply 

B. Display and Control Interface 

C. Resistor Divider Board 

D. Power Modules (10) 

E. Processor 

A block diagram is shown in Figure 3.1-1. A photograph of the unit 

with internal cover open is shown in Figure 3.1-2. Schematic diagrams 

are attached in Appendix I. 

3.1.1 Power Supply 

The power supply consists of a wide input range DC to DC down 

converter and a multi-output flyback DC to DC converter. Total tare 

loss is 0.35 watts. The downconverter accepts 40V to 300V DC and 

produces 13.2 volts (referred to as a nominally +12V level) at up to 

0.6 amperes, with an efficiency of approximately 64 percent. This 

can charge a 12 volt battery and can directly drive the flyback stage 

whether a battery is present or not. The flyback converter produces 

regulated +5V DC at up to 0.7 amperes, plus unregulated outputs of 

nominally -5V and -72V DC. Its efficiency at the +5V output is 

approximately 84% The processor logic runs on the basic +5V output, 

the analog signal conditioning amplifiers and RS232 interface run on 

+/-12V, the analog multiplexers run on +5V, and the power modules run 

on +72V.' Total dissipation in the controller from a high voltage 

PV array, with NMOS EPEOM1s (CMOS units were not yet readily 

available) was 4.7 watts, distributed as follows: 

Processor and display 2.OW 

Power supply 2.3W 

Power modules 10 at 40mW = 0.4W 

The largest single power use is in the 9573 timer chip on the 

processor board, which uses about one watt at five volts. If a 

separate 12 volt supply or battery is used, thus avoiding down 

converter loss, total dissipation is only three watts. 

The power supply is fully short circuit protected, all outputs are 

over-voltage clamped, and the five volt output has an over-voltage 

crowbar reset by power off. 

3.1.2 Display - and Control Interface 

The display board consists of a 4-1/2 digit LCD display, a 16 key 

membrane switch pad (calculator style), an audible alarm, and three 

LED1s: RED, YELLOW, and GRZEN. The keypad allows manual control 

FIGURE 3.1-2 

MI CROPROCES SOR CONTROLLER 
(under password security) of the system and calls up any one of over 

50 different quantities to be displayed. The display normally shows 

battery state of charge but can display the voltage, current, or 

power of any array string, load bus, battery, motor, or other 

monitored point, monitored temperatures, or time of day. The LED'S 

summarize system status: The GEEEN LED shows that the processor is 

running and servicing timer interrupts. The RZD LED indicates that 

the battery is dangerously low and loads have been shed, and the 

YELLOW LED indicates that stored energy is in short supply and should 

be conserved. A listing of the keypad-accessible functions is given 

in the software section of this report. 

3.1.3 Resistor Divider Board 

The resistor divider board serves as an interface between the high 

voltages in the power system and the low voltage signals measured by 

the processor. High voltages above 40 V are attenuated by a ratio of 

1Q0 to 1 before measurement while voltages from four volt to 40 volt 

full scale are attenuated by 10 to 1. 

3.1.4 Power Modules 

The power modules are 500 watt DC to DC converters used to couple the 

180 volt nominal solar array inputs to the 120 volt nominal battery 

and load bus. These are 20kHz switching type bucking converters, 

with typical efficiency of 98 % They include internal fast current 

limiting. Ten power modules are provided in the prototype. 

3.1.5 Processor 

The processor is a large board containing the following parts: 

7. Central Processor: CPU, timer, ROM, RAM 

2. Analog input section: differential current, 

multiplexer, single-ended voltage multiplexer, 

and 10 bit plus sign A/D converter 

3. Display and control interface: UART for RS232 

interface support; PIA for keypad, LED, LCD, 

and interrupt support; six optoisolators for 

load control 

4. Array control buffers: 10 digital outputs 

which can be used as pulse width modulated 

2QkHz signals for the power modules for 

maximum power point tracking, or can be switch 

drive signals for discrete array control. 

The central processor is built around a 65C02 CPU which operates at 

1MHz with an eight bit data bus and a 76 bit address bus. This 

addresses 16k bytes of CMOS EPROM and up to 6k bytes of CMOS RAM. 

(This program requires only 2K of RAM.) Address and data bus buffers 

separate the central portion of the processor from the rest of the 

controller. A multiple timer, the AM9513, is used to generate the 

4MHz master crystal oscillator clock, IMHz system clock, the time of 

day, the two pulse width modulated 20kHz outputs, the 16X baud rate 
clock for the RS232 port, and a Ums6c interrupt used in the program. 

All "glue" chips (assorted small gates) are of the 7UHC family for 

adequate speed at CMOS power levels. An address decoder for other 

major sections of the controller is also included in this section. 

The heart of the analog input section is the AD7571 analog to digital 

converter. This new device is a CMOS low cost unit, with 10 bits 

plus sign accuracy, and internal interface to an 8 bit microprocessor 

bus. It is used in its "RAM moden, externally clocked at 500kHz, to 

give an 88 microsecond conversion time, with an external TLu31 

precision reference. Simple external address gating and buffering 

included here also provide multiplexing onto the data bus of 

converter status, as well as two time of day alarm outputs and two 

external control switch status bits. 

The input to the converter comes from an analog multiplexer. This 

consists of a low offset buffer amplifier, channel selection latch, 

three 8-input single-ended CMOS multiplexers, and input filters. 

This services inputs for 16 voltage sampling channels, 16 currents, 

two thermistor inputs, a uv reference, a ground reference, and the 

current measurement differential multiplexer. Zach voltage sense 

input, with +/-4volt range, includes a diode clamped anti-aliasing 

filter to avoid averaging errors when sampling at the 4msec interrupt 

rate, and which also filters out !?FI and protects against high 

voltage spikes. Filtering throughout the multiplexer system is 

extensive, but settling time is limited mainly by the slew rate 

requirements of the buffer amplifiers. Measured room temperature 

accuracy through the A./D converter is +/-0.2 percent. 

Current sense inputs, with +/-100mV range, utilize a differential 

muliplexer with gain of 40. This consists of an address decoder, an 

instrumentation-amplifier style buffer amplifier, four &-input dual 

CMOS multiplexers, and a differential anti-aliasing filter on each of 

76 channels. This is also clamped for spike suppression and can 

tolerate +/-3volts common mode without significant accuracy 

degradation. This is needed to allow current shunts at reasonably 

remote locations in a large system, where wiring resistance drops can 

cause common mode offsets. Accuracy of 2% can be trimmed to better 

than 15, with a DC common mode rejection ratio of 60db minimum. 

Crosstalk in each stage of multiplexing is less than 0.7%, channel to 

channel, occuring with 7Qk signal sources at the voltage sense lines. 

This is limited by the "offw resistance of the low cost multiplexers 

used, and is adequate for this application but could be improved, 

since a worst case effective offset of just under +/-2% could result. 

Anti-aliasing filter design of the current sense inputs is based upon 

the possibility of 180 or 720Hz square waves on the battery current 

line, sampled at the Umsec rate and averaged 16 times, resulting in 

an accuracy of better than five percent. 

The display and control interface consists of a 65SC21 peripheral 

interface adapter (PIA) and an octal latch. The latch drives six 

4N32 optoisolator outputs via a hex buffer and series resistors. 
These resistors determine the output drive capability, and are 

presently set for 30 ma output drive. 

The PIA provides two programmable 8 bit input/output ports and two 

pairs of dual programmable interrupt latches. The input/output ports 

service the LCD display, the keyboard, and the signals for the LZD's 

and audio alarm, and are inputs for the UART status flags. The 

interrupts provide for the 4msec timer and the panic shutdown switah 

functions as well as UART service. 

The RS232 port is provided by an IM6402 CMOS UAPT, which with a few 

discrete driver elements, makes a complete bi-directional 

asynchronoeus communications interface. At present, the parity, 

frame, and overflow error flags are ignored because a single system 

setting of baud rate and framing bits make these errors unlikely and 

error recovery in an unattended, stand alone system is impractical. 

This port allows data logging to an external printer, automated 

testing during manufacture, or computer interfacing in special 

applications. 

The array control funotions consist of a set of latches, gates, and 

buffers allowing 72 digital outputs to be driven as independent relay 

drive signals for discrete array control, or as separately buffered 

pulse width modulated 2QkHz signals for maximum power point tracking. 

A watchdog timer turns off the array control and load outputs if the 

processor fails to reset it within 8Qmsec. An additional analog 

output, Q to 10 V, is available for continuous analog control of 

variable loads such as variable speed motor drives. This is realized 

by low pass filtering of a second PWM signal. Alternatively, the 42 

array control outputs can be partitioned between the two PWM signals 

to provide max power tracking into two independent loads, although 

the present software doesn't yet fully support that mode of 

operation. 

3.2 SOFTWARE DESCRIPTION 

The software design was based on two decisions. First, the software 

is modular. This allows an orderly linking of software moudles using 

the principles of structured programming and allows modules to be 

modified without interfering with the rest of the program. Second, 

the modules were defined using "pseudocodev, an explicit definition 

of each algorithm in plain English with a program format. This 

allowed clear communication between system designer, hardware 

designer, and software designer in advance of actual programming and 

eased the task of uniting assembly language code, 

The MAC unit is designed to operate without needing any human 

intervention. It performs the following functions automatically: 

1. Battery Control 

2. Array Control 

3. Load or auxiliary display on the 

control panel 

4. Status display on the control panel 
5. Self-test 

6. Data logging via RS232C port 

In addition, the MAC unit provides the following facilities for 

manual control: 

1. Manual battery charge initialization 

2. Manual array control 

3. Manual load or auxiliary charger control 

4. Control panel display of system 

operating parameters 

5. Manual test calibration mode and time of 

day 

6. Remote control and parameter measurement 

or automated testing via the RS232C port 

Zach function is described below, with the automatic and manual 

functions described together for ease of understanding. A complete 

pseudocode listing by subprograms is given in Appendix TI. The key 

parameters for a sample system personalization of the MAC are given 

in Figure 3.2-1. A detailed listing of the object code is available 

in the Task 111 Interim Peport. 

3.2.1 Battery Control 

The state of charge describes the battery's condition at an instant 

in time. The state of charge of the battery is defined to be a 

percentage equal to 100 times the number of ampere-hours the battery 

can deliver at 25 C at its specified rate, divided by the battery's 

rated ampere-hour capacity at 25 degrees centigrade. This is always 

less than 100 percent. 

The corrected state of charge is defined to be a percentage equal to 

100 times the number of ampere-hour capacity at 25 C. Note that this 

can be greater than 100 percent. 

The initial battery state of charge can be entered manually from 

either the keyboard or the RS232C terminal. This can be based on a 

hydrometer reading of battery acid density, or simply an estimate. 

If it is wrong, the system will eventually correct it without damage 

to the battery. Default value at power-up is 50 percent. 

The state of charge is increased by the number of ampere-hours 

flowing into the battery, and decreased by the number of ampere-hours 

flowing out of the battery. Bate of increase is modified by a 

tabulated coulombic charging efficiency which depends on state of 

charge as follows: 
Array Voltage 

Array String Current 

Number of Strings 

Battery number of Cells 

series 

Ampere-hour Capacity 

Float VoltagejCell 

Equalization Vol ts/Cell 

Min. Vol tage/Cel 1 

Battery Current 

Charger Current Limi t 

Load Current Limit 

CONTROL PARAMETER LIST 

MAC-P 10 S.N. 00 1 

Temperature Measurements 

Charger String Current Limit 

Number of Load Busses 

MIN TYP MAX UNITS 

volts 

amps 

----- 

A-Hr 

volts 

volts 

volts 

amps 

amps 

amps 

deg. C 

amps 

FIGURE 3.2-1 
CHARGING EFFICIENCY 

- SOC ZFFICIZNCY 

If the battery voltage reaches 97% of its float voltage (corrected 

for temperature), it is automatically determined that the battery's 

state of charge is increased at one percent per second until that 

value is reached. 

Battery capacity at temperature is estimated by an increase of 0.2% 

per degree C above 25 C, and reduced by 0.75% per degree C below 25 

degrees centigrade. 

If the battery voltage drops below the minimum allowed, it is 

automatically determined that the battery's real state of charge is 

lower than the estimate, and the estimaed state of charge is reduced 

at 7% per second until the voltage rises above minimum due to load 

shedding or until 0 state of charge. 

For every ampere-hour of discharge by the battery, one equalization 

fraction ampere-hour of extra or equalization charging is 

automatically programmed when energy becomes available and 100% state 

of charge has been reached. This is needed to bring all cells up to 

full charge and to stir the acid by generating small amounts of gas. 

This prolongs total percentage to avoid excessive water useage. 

If the battery goes through many partial charge and discharge cycles 

before equalizing, the total equalization charge is limited to the 

equalization total percentage to avoid excessive water useage. 

During charging and equalization, the battery is allowed to rise to 

the equalization voltage. After equalization is completed, the 

battery voltage is limited to the float voltage, which is below the 

point of significant gassing and so uses up less water. This float 

level charge makes up for internal battery self-discharging, 

The float and equalization voltages are equal to a nominal voltage 

per cell minus 0.22% per degree C above nominal (temperature in 

degrees C minus 25 C), or equal to the absolute maximum battery 

voltage, whichever is lower. The battery minimum voltage has the 

same temperature compensation and an absolute minimum value. 

The result of these calculations, then, are the battery voltage 

maximum limit, the battery voltage minimum limit, the state of 

charge, the temperature corrected state of charge, and the 

equalization charge needed. 

Battery state of charge is channel DO0 and battery corrected state of 

charge is channel D40 on the LCD display and the serial port. These 
are the most frequently read values, and so corrected state of charge 

is put on the display by default at power up or after a data dump at 

half hour intervals. A diagram of the battery control algorithm is 

given in Figure 3.2.1-1. 

3.2.2 Array Control 

If the battery is not fully charged and equalized, the voltage limit 

is the equalization voltage. If fully equalized, the voltage limit 

is the float voltage. Until reaching voltage limit, the solar array 

charges the battery as much as the available energy allows. 

There are two automatic modes of array control resident in the 

program. The first is discrete array control. This turns strings 

on, one per second as long as the battery voltage is less the 94% of 

its maximum limit. It makes no change until the battery voltage 

reaches 97% of its maximum limit. Between !I?$ and 100% of its 

maximum limit, strings are turned off one per second. Above 100% of 

maximum limit, all strings are turned off. The battery voltage used 

for this algorithm is averaged over four samples to minimize noise 

problems. 

The second mode is maximum power tracking. The controller drives up 

to 10 power modules with a 20kHz pulse width modulated drive signal, 

13 volts = high = OFF, 0 volts = ON. The pulse width is set in l/u 

microseconds increments. It is initialized to 0 and changed in small 

(7/4 microseconds) or large (2 microseconds) steps every 100 

milliseconds. At each step, the tctal delivered power is calcualted 

and compared with the power delivered at the previous duty cycle. If 

the power changed by less than 7.5$, and if no limiting conditions 

were encountered, small steps are used, otherwise big steps are used 

to speed up the process. 

If the power level was found to be constant or increasing, the next 

step is taken in the same direction as the last. Ifvthe power was 

found to be decreasing, the direction of step in duty cycle is 

reversed. Therefore, the duty cycle is adjusted to the maximum power 

operating point, and hunts there +/- one or two small steps, 

representing an operating point within +/- 1% of maximum power. 

If the charger current limit or battery maximum voltage limit is 

reached or if switch S2 is open, the duty cycle is always decreased 

one step. This converts the controller into a constant voltage or 

constant current power supply, normally used for finishing charge of 

batteries or for motor starting without batteries. 

Also, if the inhibit switch S1 is closed, the duty cycle is set to 0, 

turning off the solar array. Switch 52, normally closed, is usually 

used as a motor thermostat, while S1 is often used as a water tank 

float switch level control. A manual switch in parallel with S1, 

normally open, provides a manual array shut-off function, 
BATTERY STATE OF CHARGE CONTROL ALGORITHM 

soc 

(State-Of-Charge) 

Load Control & 

Warning Lights 

FIGURE 3.2.1-1 
The sequence of events for max power tracking is as follows: 

7. Pulse width is set on the previous program pass. 

2. 12 milliseconds settling time elapses. 

3. 76 values of each of the 10 charger string currents, the battery 

voltage, & the battery current are stored in an array. The table is 

filled by taking a sample of all values once every 4 milli-seconds, 

which generates a column of uinstantaneous" data. After 6u milliseconds, all the rows of data are full and average values are 

calculated. 

u. User output power is calculated. In order to avoid start-up 

problems with low impedance (motor) loads, the actual parameter to be 

maximized is (total charger amps) X (battery volts + 100). 

5. Old and new power are compared. If power is increased, the 

direction of pulse width step is left the same. If power is 

decreased, the direction is reversed. 

6. The size of the pulse width change is calculated based on the size 

of the power level change. This is a novel feature which allows fast 

acquisition and accurate tracking of the max power points. 

7. The pulse width is changed, and the process repeats at 100 

millisecond intervals. This algorithm is diagrammed in 

Figure 3.2.2-1. 

3.2.3 Load or Auxiliary Charger Control 

The battery is assumed to be loaded by up to five separate load 

busses, with separate voltage sensing, current shunts in the negative 

load, and relay control responsive to the optoisolator output 7-5 of 

the controller. (Optoisolator ON=load ON.) These may in fact be 

auxiliary energy sources as well as loads. 

Each load bus is automatically monitored for excessive current. If 

current exceeds 120 percent of the nominal value (5DmV on the shunt), 

the load is turned OFF, the audio and red LZD alarms turned ON, and 

manual reset is required via keyboard or serial port. Under normal 

conditions, each load bus has two corrected state of charge 

thresholds; one below which the load is turned OFF (shed) and one 

above which the load is turned ON (restored). By reversing the 

function of the optoisolator, an auxiliary generator can be properly 

controlled the same way. This provides fail-safe operation, since 

the optoisolator going off turns loads OFF and generators ON. Note: 

for either case, shed level is less than restore state of charge by 

an amount which avoids cyclic behavior. A list of sample control 

levels is given in Figure 3.2.3-1. 

Each load or charger bus can also be manually controlled from the 

keypad or the serial port. To be turned ON, (Load ON, Charger OFF, 

Optoisolator ON), an optoisolator must be ON according to all 

automatic control algorithms and the manual control function. 

Otherwise, it is in the load OFF/charger ON condition. 

It is often desirable to use more energy if it's going to be a sunny 

day. This may be to avoid short cycles of load useage or simply to 

increase energy useage efficiency. Therefore, between 8AM and 
MAXIMUM POWER CONTROL ALGORITHM 

f 

FILTERING AND 

AVERAGING 

FIGURE 3.2.2-1 
K 

W 

V) 

I 

0 

J 

n 

V) 

7 

T m 

I- s I I 

Y 

-r 

w W U w 

(3 ro V) 

n L 0 

a WOOOOO I1 I II- - 

a INO~~L~ I1 I I U. In fn II I I L CD E 

I aJ CV r 3 fn V) 

0 Cz 0 

0 3 > 

C n om EY 

U- 0 s 00 

0 2 E row Ln? 

3 ctl 

0 E 0 0 II I! 

W a -7 A 

I- - X II 4v 

d rn II om 

ZC S LnN 

I- cur 

V) 

Z PC, 

0 0 ro 

n H . . L1. C, 

n Q-rJMc;tLn F-tW - C 

W 0 U van fnw aJ -1 0 <I-0 wl 

I- E 

fn n: 0 x --ccro n V) 

0 IJ- I- d -~r L 'r C, 

4 -1 0 0 3 s 

W I- ZZOn:ZC, 0- 3 

a -la o o n: I- om w TV) 

W0H-I-Z 

a fn L 

OI- I- I- Z 0 LC, 

0 Q40VaJU 

C3U N N U m 3 ctl 

2 3V) 

0 H H 2C Lo 'r m .F 

Hfn-A -1)- U 1x50 - 

Z <<<I-rL 

E -r v L tr: =>3cf~vn X ma 

0 wwn:3 3 or 

E WU<~ < dl- 
12Noon, if the sunlight level is high enough to provide at least 10% 

of the maximum charger current limit to the battery, all the battery 

corrected SOC levels for load shed and restoration are decreased by a 

constant preset SOC, called DZLTA SOC. This allows loads to turn ON 

earlier on a sunny morning than would otherwise be the case. 

The MAC can perform a control strategy to allocate available energy 

into two different forms of storage. One of these is electrical 

energy stored in a battery. The other is a form of "product 

storage." This might be water stored in a tank, or thermal storage of 

cold in a refrigerator, freezer or ice stored in an icemaker. 

To use this capability, it is necessary to be able to measure the 

amount of product stored or at least to indicate one of three product 

storage levels: 

1. There is less than the critical minimum amount of product (water 

level or cold temperature in the freezer) and it has a high priority: 

PROD < PROD 7 

2. There is an adequate amount of product, but more can be stored if 

energy is available. PROD 1 < PROD < PROD 2. 

3. The product storage level is full (tank is full of water or 

refrigerator is at minimum temperature): PROD > PROD 2. 

This product is ass'umed to be produced or pumped using energy from 

the same battery which is used to supply other electrical loads. To 

avoid over-discharge of the battery and to be sure the other loads 

get their share of energy, various state of charge (SOC) of the 

battery are defined: 

7. Battery minimum charge: below this, the battery is below its 

minimum allowable state of charge and all load are off, above this 

non-product electrical loads are allowed: SOCl 

2. The battery can be used to produce product but not other 

electrical loads above this point: SOC2 

3. The battery can power both electrical loads and non-critical 

product levels above this point, but only non-product electrical 

loads below this point: SOC3 4. The battery will power all loads 

above this point: SOC4 

This combination of trip points creates a set of four states of the 

controller, defined by the amount of product stored and the battery 

state of charge. This state diagram is shown in Figure 3.2.3-2. By 

setting various values for the boundary parameters, various 

priorities can be placed on the use of energy. To avoid limit cycles 

during operation, a buffer or hysteresis of specified amount is added 

to each boundary value when crossed in the increasing direction. The 

parameters for the product storage algorithm are given in the tables 

in Figure 3.2.3-3 
PRODUCT STORAGE ALGORlTHM 

Increasing Battery State of Charge 

STATE 1 

Electrical Loads 

OFF 

Product Load OFF 

STATE 3 

Electrical Loads OFF 

Product Load ON 

I Product Load OFF 

FIGURE 3.2.3-2 
PRODUCT STORAGE ALGORITHM THRESHOLDS 

(Percent) 

PROD = (25 - T2) *3.3 T2 in degree C 

DEFINITION SYMBOL VALUE HYSTERESIS VALUE 

Elect loads above S 0 C 1 2 0 BUF SOCl 10 

High Priority 

PROD only above SOC2 5 0 BUF SOC2 2 0 

Low Priority PROD SOC3 7 0 BUF SOC3 10 

above 

Low Priority PROD SOC4 7 0 BUF SOC4 10 

& Elect above 

High Priority PROD1 5 0 BUF PROD1 10 

PROD only ti1 

No PROD above PROD2 80 BUF PROD2 10 

FIGURE 3.2.3-3 
FINAL REPORT 

3.2,4 Control Panel Functions 

The control panel has a keypad for manual inputs, a 4-7/2 digit LCD 

display for selected quantities, a set of red, yellow, and green 

LED'S for quick status summary, and an audio alarm. There is also an 

emergency switch located at the bottom of the unit which, when turned 

OFF, will turn OFF all array strings and loads. When turned ON, it 

will initialize the controller. 

The audio alarm will sound if any "circuit breakern function 

(overcurrent on a load bus) is activated, or if an array fault is 

detected. 

The red LZD will light if any circuit breaker function is tripped or 

if bus NO.l has been shed due to low state of charge (extreme low 

battery). The LCD "Low Battery" warning will also turn ON. 

The yellow LED will light is load bus N0.5 has been shed due to low 

state of charge, but load bus N0. 1 has not. This is intended to 

signal that energy is in short supply, but not an emergency. (Lower 

number loads usually have higher priority.) 

The green LED is lit as long as the program is running. If a 

watchdog timer is not reset by the program, this LZD goes out and the 

array is turned OFF. 

The LCD display can be thought of as a multimeter which will display 

one of a menu of system parameters. The default condition is state 

of charge, and after a data dump each half hour, it returns to this 

parameter. It can also display any array string voltage, any charger 

output string current, (not the array current, but the converted 

output from that string at the battery voltage level), the delivered 

string power to the battery, the battery voltage current or power, 

any of five load bus voltages or currents or powers, the battery 

temperature, one other temperature (used here for freezer product 

measurement), the pulse width, the equalization charge needed, the 

system zero voltage and 4.00 volt reference level, the temperature 

corrected state of charge, the time of day, and the software version 

number. See the attached signal channel list. Enter the desired 

channel code (a letter, two numbers, and a +I) for display. The +i 

sign has the effect of an "enterw command. The * sign cancels an 

incomplete entry. A list of public acess functions is given in 

Figure 3.2.4-1. In addition, after entry of a password on the 

keyboard, an additional set of protected functions becomes available, 

listed in Figure 3.2.4-2. 

3.2.5 Self-testing 

The keypad can also be used to change control functions. To do this, 

the correct password must be entered: 4 digits followed by a !I. 

Password accessible functions are summarized on the attached command 

list. These include setting a new load and restore thresholds for 

each load bus, setting initial state of charge and setting the manual 

control for each load bus optoisolator to "ON = 1" or "OFF = 0". 
SEQUENCE 

* 

PUBLIC FUNCTIONS 

FUNCTION 

Clear Function 

Activate password-accessi ble functions 

if user password matches (see below) 

Read channel nn voltage (mult) 

Read channel nn current (mult) 

Read channel nn power (mult) 

Read misc data channels (mu1 t) 

Di splay software version number 

Read time, hours and minutes (mult) 

Initiate "dump" of machine state to 

serial port 

not used 

FIGURE 3.2.4-1 
PASSWORD ACCESSIBLE FUNCTIONS 

SEQUENCE 

Ann)mm# 

Bnnimni# 

device 0 

device 1-6 

device 7-11 

device 12-17 

device 18-23 

device 24-25 

FUNCTION 

Set load shed threshold for load 

n at mmm 

Set load restore threshold for load 

n at mmm 

Set the initial percentage SOC at 

mmm% 

Set device nn to condition m, where m 

must be either a "1" (ON) or a "0" (OFF) 

Audible alarm 

User load requests 1 through 6 

Overload trip resets for loads 1 through 5 

PWM buffer #I controls 1 through 6 

P!4M buffer #2 controls 1 through 6 

Yellow and Red LEDs 

Initiate lamp and annunciator test 

(accessable only in test/cal mode) 

Toggle from run to test/cal mode 

(system comes up in the run mode) 

Set time, hours and minutes 

Cancel password authorization 

FIGURE 3.2.4-2 
FINAL RZPOFT 

Also, the unit can be placed in a test/cal mode where data is 

refreshed but the states of charge, max power tracking and load 

controls do not automatically change. This allows them to be 

manually set and measurements taken. For example, a fixed pulse 

width can be set from the serial port, or a lamp test can be 

performed. Note that this mode is not well protected and the system 

should not be left in this condition unattended. 

A lamp and audio alarm test can be performed in this mode. This 

lights all LZDs, sounds the alarm and put test digits in the display. 

The keypad in password-access mode can also be used to set the time 

in hours and minutes on a 24-hour clock and can cancel the passwordaccess mode. 

The display performs one more automatic test. If one of the charger 

power module output currents is less than a constant (1 amp) below 

the average of all such currents, the "Continuityn segments of the 

LCD is turned ON. This means that one string of the array or one 

power module of the charger is either shadowed or broken. 

Zxamination of array voltages and currents will show the cause. 

Besides these external tests, the unit performs an automatic test of 

its PAM and !?OM access whenever it is started up. When running, any 

error causing the program not to execute properly will result in a 

watchdog timer fault turning off all loads and the solar array and 

causing the green LED to go out. 

3.2.6 Serial Port Functions 

The manual test/cal mode was partially described in the previous 

section. However, with an RS232C terminal, much more extensive 

manual testing is possible. A standard debug monitor is implemented 

which can examine memory locations, insert bytes into memory, begin 

execution at a given memory location, insert or remove breakpoints, 

and download a program into memory. 

In addition, any of the keyboard command functions can be performed 

from the serial port. A list of these commands, plus the debug 

monitor commands is in the serial port section of the command list. 

Note that no password is requried via the serial port. The debug and 

monitor functions are listed in Figure 3.2.6-1, and the maintenance 

functions are listed in Figure 3.2.6-2. 

A data dump of all system voltages, currents, temperatures, switch 

positions and states of charge is sent to the serial port every half 

hour or whenever requested. A printer there will provide data 

logging. The format of this data is given in Figure 3.2.6-3. , 

This powerful access allows many possible uses. The processor can be 

automatically tested during manufacture. A printer attached at the 

site can serve as a data logger. A telephone modem or other 

communication interface would allow automatic remote data logging or 

even, remote system control. A tape recorder will allow postprocessing of recorded data. 
DEBUG MONlTOR FUNCTIONS 

SEQUENCE FUNCTION 

^H, backspace, del 

^U 

^ z 

M addr 

G addr 

B addr 

X 

1 addr 

F start - addr end addr datum 

Deletes last character entered. Echoes 

backspace, space, backspace to allow 

overwriting the 1 ast character entered when 

a CRT terminal is used 

Causes CPU to ignore present command line 

Return to command mode 

Opens a memory location at the specified ' 

address (requires 4 hexadecimal digits). 

Successive "" (space) characters increment 

through memory, whi 1 e "-I' characters decrement 

through memory. At any time the contents of a 

location may be a1 tered by entering the new 

data followed by a carriage return. 

Begins execution at the specified address. If 

no address is specified, execution begins at 

the present PC location 

Places a breakpoint at the specified address. 

This trace mode will only work on code located 

in RAM 

Removes existing breakpoint 

This permits a program to be downloaded from a 

host machine to memory starting at the specified 

address 

Fills the specified memory range with specified 

byte of data 
MAINTENANCE and LOGGING 'FUNCTIONS 

SEQUENCE 

W pwrn timer no. duty cycle 

0 digit no. value 

Enn 

Inn 

Pnn 

Dnn 

Qnn 

FUNCTION 

Set the Power Module duty cycle to 

specified value. If duty cycle 

max pwm, the default duty cycle is 

set to max pwm. 

Display the value in the specified 

digit on the LCD display. 

Read channel nn voltage 

Read channel nn current 

Read channel nn power 

Read misc data channels 

Query channel nn for "raw" A/D data 

FIGURE 3.2.6-2 
DATA FORMAT 

TIME: hh:mm 

EOO = xxx.x VOLTS 

E01 = xxx. x VOLTS 

E02 = xxx.x VOLTS 

E03 = xxx.x VOLTS 

E04 = xxx.x VOLTS 

E05 = x x x . x VOLTS 

E06 = xxx.x VOLTS 

E07 = xxx.x VOLTS 

E08 = xxx.x VOLTS 

E09 = xxx.x VOLTS 

El0 = xxx.x VOLTS 

E31 = xxx.x VOLTS 

E32 = xxx.x VOLTS 

E33 = xxx.x VOLTS 

E34 = xxx.x VOLTS 

E35 = xxx.x VOLTS 

D36 = xxx.x DEG C 

E38 = x.xxx VOLTS 

DO0 = xxx% 

D41 = xxx% 

I00 = x x x . x AMPS 

I01 = xx.xx AMPS 

I02 = x x . x x AMPS 

I03 = xx. xx AMPS 

I04 = xx. xx AMPS 

I05 = xx.xx AMPS 

I06 = xx.xx AMPS 

I07 = xx.xx AMPS 

I08 = xx.xx AMPS 

I09 = xx.xx AMPS 

I10 = xx.xx AMPS 

I31 = x.xxx AMPS 

I32 = x.xxx AMPS 

I33 = x.xxx AMPS 

I34 = x,xxx AMPS 

I35 = x.xxx AMPS 

D37 = xxx.x DEG C 

I39 = x.xxx VOLTS 

D40 = xxx% 

042 = xxx% 

TOT CHGR I = xxx.x AMPS 

NOTE : 1=ON, O=OFF 
FINAL REPORT 

The use of a small RS232C terminal by a repair technician allows 

fault isolation and diagnosis beyond the capabilities of the keypad 

and display, since small special test routines can be run. Software 

modification is greatly eased as well. 

3.3 SYSTEM CONFIGURATION 

To utilize these rather sophisticated control algorithms is very 

simple. Typical system configurations for a pumping unit without 

batteries is shown in Figure 3.3-1. Note that this is just the 

minimal amount of wiring required for such a system. Similarly, the 

system configuration for a battery-type system is shown in Figure 

3.3-2. The processor contains all the control complexity, making the 

system designer's job easier. The functions performed by the 

processor are summarized in Figure 3.3-3. To implement these, only 

the proper system parameters need be inserted in the processor ZPPOM 

memory. In this way, the user or installer needs the minimum 

knowledge of system theory to be able to use the controller. 

4.0 PRODUCTION COST ANALYSIS 

4.1 MANUFACTURUNG COST 

The results of costing the system can be summarized by several 

points. Zach extra analog channel to be measured is expensive 

because the filtering and multiplexing associated with each channel 

quickly adds 3 to 5 dollars per channel to the overall cost. The 

analog input section of the processor represents almost half the PC 

board area and about 7/3 of the cost. 

The largest single area of cost is the CPU itself, dominated by 

memory cost, mainly from ZPROM's. These are rapidly becoming less 

expensive, and in a few years, a single larger ZPROM and a single 2K 

RAM will probably enable the entire system to be built at lower cost 

and less power. 

The power supply, rather expensive at present, can be simplified for 

most applications in the future, since the total controller power can 

be reduced. Also, a separate +12V output from the flyback stage is 

not needed, and -5V power can be derived from a Zener diode operated 

from the -12V supply. This cuts its cost by perhaps 1/3. 

Availibility of a CMOS timer chip with the capabilities of the 0513 

would help a great deal in reducing power and perhaps costs. In 

general, the increasing industrial use of CMOS is expected to bring 

costs of many components down. The power handling section of the 

controller, consisting of DC to DC power conversion modules, can be 

replaced in low cost battery systems with electromechanioal or 

mercury displacement relays or solid state DC switches and the 

discrete array control algorithm. It will also cost half as much. 

This will be the direction of choice for battery charging as solar 

arrays become cheaper. Also, eliminating these PWM outputs would 

allow replacement of the 9573 timer chip with a lower power, less 

expensive timer. However, for many motor drive applications, the 
- 

0 

- 

< - 

z 

111 

+ I + 'I 

d 

I 

11 1 

I .. 1 .L 1 

em. QT -I: ec-. cc - 

fxE Clrr rT: 

at- < + 

v, cJ9 

MICROPROCESSOR CONTROL FUNCTIONS 

BATTERY CONTROL 

A. State-Of-Charge Estimation and Correction 

B. Equalization Charging 

C. SOC Initialization and Enunciation 

D. Warning Lights 

PHOTOVOLTAI C ARRAY CONTROL 

A. Discrete Subarray Switching 

B. Maximum Power Point Tracking 

LOAD MANAGEMENT 

A. Priority Load Sector Management 

0. Backup Generator Control 

C. Manual Load Control 

D. Product Storage Energy Allocation 

SYSTEM STATUS 

A. DC Voltages, Currents, Power Levels 

B. Temperatures 

C. Battery SOC, Corrected SOC 

D. Variable :Control Level 

E. Relay Status 

AUTOMAT I C TEST I NG 

A. Processor Sel f-Test 

B. Load Circuit Breaker Functions 

C. Array Continuity Test 

D. Battery Level 

E. Audible and Visual Alarms 

DATA LOGG I NG AND COMM(IN I CAT IONS 

A. System Status Log Each 30 Minutes 

B. Remote Telemetry 

C. Remote Control 

D. RS 232 Port 
FINAL REPORT 

MPC arrangement is superior. 

The power module is the only proprietary element in the controller. 

It is a standard product of TriSolarCorp. 

A material cost breakdown of the controller subsystems is given below 

for present day quantities of 10: 

DESCRIPTION COST 

Current Measurement Mux 

Analog Mux 

A/D Converter 

PWM Buffers and Array Control 2Q.75 

CPU 108.29 

Power Supply 83.111 

Display and Interface Board u9.82 

Resistor and Interface Board 5.00 

--------I-------------

Processor Subtotal 499.56 

The resulting material costs are then calculated below for the 1KW, 

5KW, and 15 KW systems: 

- 1 KW - 5KW - 15KW 

-- No MPC - MPC - MPC 

POWZR SZCTIONS 100.00 1721.20 3363.60 

ENCLOSURE 165.00 165.00 405.00 

TZRMINALS 20.00 27.00 87 .OO 

HZAT SINKS 0.00 138.00 416.64 

SHUNTS AND HARDWARE 36.25 36.25 68.75 

TOTAL MATERIAL 780.87 . 1987.89 4984.55 

Material prices are assumed to be reduced by 25% for each 10X 

increase in quantity. 
FINAL RZPORT 

Labor costs are very volume dependent. Use of automatic test 

equipment, wave soldering or automatic component insertion are 

examples of labor-saving techniques which can be applied at various 

levels of production. 

Total labor costs for various models and production levels are 

estimated below: 

MODZL 

QUANTITY/YEAF 

Labor is broken down into wage levels. For example, for each model 

given, the following hours are needed for quantities of 1,000 per 

year : 

Class 7 22.60 I 2 3 

Class 2 13.50 3 6 10 

Class 3 7.00 15 2 0 4 0 

These labor estimates are conservative; the actual number for such ' 

volume of production will probably be lower. However, these seem to 

be reasonable based on our limited experience with the protopype 

unit . 

Resulting total direct costs per 5KW unit, including labor and 100% 

overhead plus material are therefore just under $2400 in quantities 

of I00 per year. The 1KW unit in the same quantities costs under 

$1200. These are quite reasonable costs compared to alternative 

custom designed controllers. The real payoff, of course, occurs at 

higher volumes. 

The total direct cost of the three models, including material, labor, 

and 100% overhead is summarized in the following table. 
FINAL REPOFT 

4.2 MODELLING OF INDUSTRIAL PRODUCER 

In order to capture all the costs associated with producing this 

controller in a rapidly growing commercial environment, a model was 

constructed of a company which would make only this unit in 

quantities of 10; 100; 1,000; 10,000; and 700,000 per year in 

successive years. Industry standard or typical ratios were used for 

the computer electronics industry in Massachusetts, based on advise 

of consultants experienced in this area. Overhead, inventory, 

equipment, G&A, and other costs were captured in this model. The 

result gives a picture of cash flow and return on investment as well 

as profitibility. 

The costs of the controller are used for this hypothetical company 

producing various quantities of 1, 5, and 15kW controllers, the 

resulting income statement, balance sheet, and cash flow projections 

apply. Note that for quantities under 1000/year, a dedicated company 

for just this purpose is not feasible, and losses result. For very 

small numbers of units (10) per year, costs go up and prices reflect 

the custom nature of the product. However, for larger volumes, 

prices are quite reasonable and return on investment becomes very 

attractive. Figure 4.2-1 (3 pages) shows these figures. 

The first three lines show the unit sale price of each of the 

three controllers: 1=tkW, 2=5kW, 3=15kW. The next three lines, 

labelled unit sales, show projected sales numbers for each type. The 

following three lines, labelled number of people, give the number of 

employees needed at each of three salary levels, defined on three 

wage level lines immediately below. The following three material 

cost lines give cost of material per unit for each of the three types 

of controller. The last line, micro dollars per unit, indicates the 

equivalent material cost of the PV panel needed to power the 

controller. The interest rate for each year is indicated below. 

The next section is an income statement for the model company. 

Sales and cost of sales are computed from the above values. G and A 

and overhead are calculated using typical electronics industry 

ratios. The resulting net after tax shos profitability after sales 

pass a few million annually, and look good at large volumes as a 

fraction of sales. 

The next lines are a balance sheet showing assets and 

liabilities. Typical industry ratios for inventory, receivables, and 

payables are used. The line marked lfplugw represents extra 

capitalization needed, loan or equity, to fund this rate of rapid 

expansion. 

The last page shows cash flow, and points up the negative cash 

flow from operations due to the rapid growth rate. The use of 

investment cash is divided mainly between inventory increase and 

purchase of fixed assets. The return on investment can be seen by 

company increase in long term debt with net after tax profits. 
ORBC8;;2JPd= &'d:,L-I I 

W POOR QUALiIEV 

SALES PRICE I 1700 1600 1400 

, UNIT SALES 1 Z 

j 2 a 

I Or PEOPLE LEVELl 

LEVEL2 

LEVEL3 3 5 11 

VAGE LEVEL1 47000 47000 47000 47000 

2 1911 - 1491 1111 

HlCRO S PER WIT 

INTEREST RATE 

- 

SALES 

, COST OF SALES 

CROSS HARGIX 

OTHER INCOKE 

NET INCOKE 

NET AFTER TAX 

CURREKT A55ETS 

CASH 

ACCOlRCTS RECEIVABL 

DEPOSITS 

INVEKrORI 

OTHER 

TOTAL 

fIIED ASSETS 

--_-_____ FIGURE 4.2-1 

66 
Tl57iSH3P 

OFf I CE fGUIPHEh7 

DEPRECIATION 

OTHER LESS MORT 

TOTAL 

TOTAL ASSETS 

-------- 

CURREKT LIABILITI 

-------- 

hCCOUNTS PAYABLE 

NOTE PAYABLI 

TAI VITHHELD 

ACCRUED EXPENSES & 

PROGRESS BILLIHCS 

TOTAL 

LONG TEM DEBT 

------ 

NOTES 

TOTAL 

TOTAL LIABILITIES 

-------- 

EOUITI 

COMOli STOCX 7r 

ADD PAID IN CAPITL 

BETAINED EARNINGS 

TOTAL EOUITI 

EQUITY L LIABILTYS 

------- 

PLUG 

SOUBSES 01 CASX 

-------- 

SALE s 

FIGURE 4.2-1 B 
. - . - - - - -- 2 t.LL :!::.A: 

TOTAL 

TIPEKSES 

LESS KOIICASH EXPEN 

CHG DEPOSITES 

CHG INVEATOBY 

CHG MHER 

CHG ACCT PAYABLE 

CHC NOTE PAYAELE 

CEG VITHHOLDING 

CHG ACCRUED EXPELS 

CKG FROSRESS BILL 

TOTAL OP CASH USE 

CAEH ruon OPER 

SALE Of FIIED ASST 

I?lCX LNG T29E DEE7 

CHG STOCK &PI! It< C 

TOTAL 50UBCES 

USES OF CASE 

. -------- 

PUECHASE FIXED ASS 

DECP.ELSE LllG Z DT 

TOTAL USES 

IXCIDEC IP CASH 

FIGURE 4.2-1 C 
FINAL !?%PORT 

5.0 TESTING 

The MAC 5 kilowatt prototype was tested in several stages. Its basic 

hardware was tested at TriSolarCorp. Its software was tested at the 

Mellon Institute. Then the integrated hardware and software was 

extensively tested at TriSolarCorp, resulting in further development 

of some algorithms. Finally, testing in four system configurations 

was planned for NASA's STF system test and completed at TriSolarCorp 

The test facility included a 2.4kW power supply, a 480W solar PV 

array, a 100A-hr 108V lead acid battery bank, a 5kW resistive 

adjustable load, a 1HP DC motor driving a jack pump with adjustable 

hydraulic load, and assorted control and sense elements. A schematic 

of the test set-up is included in Appendix A. The first set of tests 

used power supplies to calibrate the various inputs and to simulate 

battery charge and discharge cycles. These tests showed that all 

systems worked properly, with accuracy within the +/- 2% 

specification. It became clear that accuracy better than 1% could be 

attained by replacing the discreet.resistors on the divider board 

with precision resistor networks, a change involving very little 

extra cost. During this test phase, a subtle program bug in the 

battery state of charge subroutine was found and fixed. Power module 

efficiency was verified to be 97 to 98% at these voltages. The 

second test phase used the controller with the battery, solar array, 

and resistive loads. 

The battery charge control algorithm works as described. Its 

estimate of the available capacity is limited mainly by the accuracy 

of the battery's rated capadity at a given discharge rate. This 

figure is reproduceable only to about 10% accuracy, and is usually 

based on 5 years or fixed cycle life end of life capacity. The 

initial capacity increases for a few cycles then slowly decreases 

with life. Therefore, the displayed battery capacity and the load 

management algorithm tend to be conservative by 10 to 20% over the 

first years of battery life. Long term low current operation is 

limited by internal battery self-discharge, typically 1% to 2% per 

week, and current effect errors of 0.1% of maximum, which is often a 

similar percentage per week. This is corrected whenever the battery 

is fully charged, so that batteries cycled daily or weekly are not 

affected. 

The array control modes, both max power tracking and discrete 

switching, work very well and provide a nice tapered current 

finishing charge for a battery with very low water loss. 

Load management in response to battery state of charge is very good. 

It is free of the chattering and instability characteristics of many 

voltage-related load management schemes. 

Instrumentation of the system using the keypad and LCD display is 

very effective. A permanently posted list of command codes on the 

unit near the keypad was found to be useful. 

Data logging via the RS232C terminal to an inexpensive printer will 

be very helpful in village systems. Of less use in smaller 
FINAL EXPORT 

applications, it is quite helpful for maintenance or fault diagnosis 

using a small hand-held battery powered RS232 terminal. The 

possibilities inherent in a phone coupler or other communications 

port for remote system control have not been explored, but they are 

potentially very interesting. The self-test functions of the 

controller are an effective means of allowing unskilled personnel to 

monitor a complex ?V system. 

The third set of tests used the MAC to operate a jack pump without 

batteries. Combinations of insolation (simulated by moving the 

array), total dynamic head, and load-levelling flywheel size were 

compared. The controller successfully performed its maximum power 

tracking task here as with a battery load, unless the variation in 

load current was faster than a fraction of a second over a range of 

over 50% change in load current. The MAC was also compared to 

previous models of max power trackers. The max power tracking with 

two steps sizes is a real advance in the state of the art, as it 

provides a combination of more accurate tracking of a static max 

power point load and faster acquisition time for a varying load or 

insolation. A chart comparing these performance figures is given 

here. Note that this control method is proprietary and a patent has 

been applied for. 

COMPARISON OF MPC FUNCTIONS 

PRZVIOUS STATE OF THE ART MAC 

EQUIPMENT 

Acquisition Time 3 sec 

Max Dither, stable 3 % 

Product 9 

1 sec 

7 % 

7 

This means, for example, a volumetric pump or other slowly 

cycling loads can be dynamically matched to the solar array with 

reduced need for expensive or costly load levelling mechanisms such 

as large flywheels, batteries, etc. This opens up additional 

applications for the controller. Flywheels previously sized for 5 

strokes of energy for the pump at full speed can now be made to store 

only 1 stroke of the pump at full speed, saving considerable cost and 

energy. 

In fact, operating the jack pump without any flywheel resulted in no 

loss of output. However, system parameters were poorly controlled 

under this condition, and the array and motor voltage varied for 
FINAL REPORT 

short periods of time over a wide range. 

In very low light levels (dawn or dusk) the operation of the 

controller was irregular as it alternately started and stopped 

internal operation. This is common with many solar devices, and it 

caused no damage or loss of output, but it is not well controlled. 

A change of control parameters is suggested to improve this: reducing 

the step size at small pulse widths, and redueing the minimum pulse 

width. 

The last set of tests used the battery, array, power supply, 

resistive load, and simulated product storage to test the product 

storage dual-use algorithm. This operated as it should, but showed 

sensitivity to the programmed threshold values and was difficult to 

diagnose. It may be a bit complicated for remote village use, 

although it can be used to allocate energy between several uses. Its 

sophistication makes it difficult for a user to verify that it is 

operating properly, and this may make it less popular than other 

approaches based solely on battery status. 

The overall result of the testing was that the MAC unit works and 

works very well. In comparison with other existing controllers, the 

microprocessor automatic controller worked as well as, or better 

than, any existing PV system control equipment, and can be adapted to 

a wide variety of systems simply by plugging in an EPROM. This makes 

it a very attractive controller for PV systems where large size (over 

2kW), remote location or special control requirements justify this 

type of unit. 

6.0 CONCLUSIONS 

The battery charge control algorithms in the MAC provide stable, 

predictable operation of the system and will do a good job of 

extending battery life, minimizing maintenance, and accurately 

estimating state of charge. The load management controls are 

flexible and provide good prioritized control without any problems of 

chatter or noise sensitivity. 

The array controls work well in either the maxpower tracking, pulse 

width modulated mode or in the discrete array switching mode with 

sequential operation. In the maxpower tracking mode, the dual step 

size algorithm is a real advance in the state of the art and allows 

tracking of varying loads which is both faster and more accurate than 

previous controllers. 

The metering and data logging functions provide a good picture of 

overall system status. The self-test functions auch as array string 

continuity testing will be very useful in substituting for skilled 

operators at remote sites and allowing scheduled system maintenance. 

The potential for remote system control and monitoring is 

considerable. The full use of the RS232 port capabilities of this 

controller have not yet been fully explored. Remote system 

monitoring or control, various types of data logging, or other 
FINAL RZPORT 

maintenance or communications functions are possible. This may make 

the microprocessor controller attractive in other kinds of systems, 

such as utility interactive PV systems or non-PV applications. 

The success of this development will allow rapid production of the 

unit for field application. 
APPENDIX I 

SCHEMATIC DIAGRAM 
FINAL REPORT 

APPENDIX f 

The following drawings show the microprocessor automatic PV 

system controller at the system level, PI0 (5 kilowatt) box 

level, and the board level. 

The drawings attached include: 

Microprocessor Power Supply 

Microprocessor Controller Test Configuration 

Microprocessor Display and Control Logic 

D02-00413-01 Microprocessor PI0 Wiring Diagram - Busses 

D02-00413r02 Microvrocessor PI0 Wiring Diagram - Single Wires 

D02-00420-00 Sheet 1 Mjcroprocessor Schematic - Central Processor 

D02-00420-00 Sheet 2 Microprocessor Schematic -' PWM Buffers &d Array Controls 

D02-00420-00 Sheet 3 Microprocessor Schematic - A/D and Interface Logic 

D02-00420-00 Sheet 4 Microprocessor Schematic - Analog Multiplexer 

D02-00420-00 Sheet 5 Microprocessor Schematic - Current Measurement Mux 

PRECDW PAGE BUUYK NOT FlL&a 

I- 

$ 

Z 

eti 

"li 

1 

: 

.. - 1 

: '. 








APPENDIX I1 

PSEUDOCODE LISTING 
APPENDIX I1 

SUMMARY OF SOFTWARE DESIGN 

MAXIMUM POWER TRACKINGPHOTOVOLTAIC SYSTEM CONTROLLER 

prepared by Thomas A. Maier 

Fe L Low 

MeLLon Institute Computer Engineering Center 

March 22, 1984 
-iCONTENTS 

- 1, - --- The Use of Pseudocode 

- 2. - General Comments - 2 

2.1. - Analog to Digital Converter Interrupt Routine 2 

2.1.1. - A/D Channel Aliocations 3 

2.1.2. - Signal Averaging 4 

2.1.3. - A/D Channel Storage Locations 6 

2.2. - Operator Interface 7 

2.2.1. - Hexadecimal Keypad Functions 8 

2.2.1.1. - Public Functions 9 

2.2.1.2. - Passuord-Accessible Functions 9 

2.2.7.3. - Debug Monitor Functions 10 

2.2.1.4. - Maintenance and Logging Functions 11 

2.3. - Calculating And Interpreting System Parameters 12 

3. - Appendix #1 - Generating System Lookup TabLes - - - 14 

4. - Appendix P2 - Pseudocode Listings - - 
- 1. --- The Use of Pseudocode 

The majority of the information regarding the software package 

developed by the Hellon Institute Computer Engineering Center (MI/CEC) 

for the captioned TriSoLar project is contained in. the pseudocode 

Listings which accompany this summary. The pseudocode is a fictitious 

high Level Language used to document and describe the assembly code 

used in each of the routines. The use of flowcharts has, in the past, 

been cumbersome to keep updated as corrections and modifications are 

incorporated into a piece of code. A pseudocode Listing, on the other 

hand, is easily understood and can be incorporated as part of the 

comments in the assembly Language code. The size of the source code 

file in this particular project, however, required that the pseudocode 

be kept in a separate file. 

The syntax of the pseudocode generally fotlows the PL/M-86 

Language which was selected because it was more "engtish-Like" than 

many of the other programming Languages. It should be pointed out 

that occasionally constructs not supported by PL/M-86 were required. 

When this happened, the syntax rules were "bent" somewhat to allow 

english phrases or carefully selected syntax from other Languages to 

fill the void. The meaning is still clear to anyone with familiarity 

with programming in general. 

By first writing the routines in the pseudocode and then 

translating the resulting pseudocode, Line by Line, very c Lean, 

structured assembly code can be generated. If this technique was 

carefully adhered to, routines containing hundreds of lines of code 

can be generated with few, if any, errors. 

2. General Comments - 

The remainder of this summary details some of the other 

information that is not reflected in the pseudocode listings, such as; 

information about the A/D routine, A/D channel altocations, Signal 

Averaging and similar topics. 

I 

2.1. Analog to DigitaL Converter Interrupt Routine - - - 

As a result of a negative transition on the 4 millisecond NMI 

Line, the A/D interrupt handler gathers 13 channels of data, one at a 

time, and stores the results in memory. To accomplish this, the 

routine sets a mux channel address, waits for settling to occur, 

st-arts the conversion, polls for conversion complete, formats and 

stores the result and then repeats the process for each successive 

channel. In order to conserve time, the formating, which amounts to 

rearranging the word bit pattern and changing from sign magnitude to 

2's completement notation, is interleaved with the 80 microsecond 

conversion time of the next channel. 

The data read from the A/D is returned in 2 bytes, shown here 
msbyte first: 

b7 b6 bS b4 b3 sign b9 b8:bsy tl sw2 swl u b2 .b1 b[ 

where bX = data bit X 

sign = sign bit, "1" = negative 

bsy = A/D busy Line, "1" = done 

tl = 30 minute alarm signal 

w = watchdog/panic interrupt line 

swl = inhibit switch, 

sw2 = motor thermostat 

uhich must be rearranged to the form: 

sign sign sign sign sign sign b9 b8 : b7 b6 b5 b4 b3 b2 bl b0 

Notice the extended sign bit and the elimination of thl 

misceLLaneous input bits. It is important to retain the other dat, 

bits, which are used elseuhere, because random reads to the A/I 

(without a corresponding urite, to initiate a conversion cycle) plact 

the A/D into an indeterminate state. Since these data bits art 

available during each read of the A/D, they are retained when the A/f 

is read during the seldom read channel and are stored in atarm 30 for - 

use at a Later time. 

Channel Allocations 

Channels are broken up into two groups, the "often-read's" and 

the "setdom-read's". As implemented in version 1.X of the software, 

the first group contains 12 channels (i.e. 10 branch currents and the 

battery current and voltage) that are read every time the routine is 

called. The Latter group contains all of the other channels and are 

read in a "round robin" fashion, one per pass thru the routine. The 

follouing is a List of the "often read" and "seldom read" channels 

showing the mux addresses and chanFel number associcatad with each. 

OFTEN READ CHANNELS 

signal name 

battery volts 

battery current 

branch #1 current 

branch #2 current 

branch #3 current 

branch #4 current 

branch #5 current 

branch #6 current 

mux often-read 

address channel number 
branch #7 current $27 d 

branch #8 current 628 

branch #9 current $29 

branch #I0 current S2A 

signal name 

SELDOM READ CHANNELS 

mux seldom-read 

address channel number 

branch #I volts $01 

branch #2 volts $02 

branch #3 volts $03 

branch #4 volts $04 

branch #5 volts $05 

branch #6 volts $06 

branch #7 volts SO7 

'branch #8 volts $1 0 

branch #9 volts $1 I 

branch #I0 volts 81 2 

load bus # 1 volts 81 3 

Load bus # 2 volts S1 4 

load bus # 3 volts $1 5 

load bus # 4 volts $1 6 

load bus # 5 volts $1 7 

Load bus #I current $28 

Load bus #2 current $2 C 

Load bus #3 current S2D 

load bus #4 current S2E 

load bus #5 current f 2 F 

battery temp 83 0 

freezer temp $40 

80% of Vref $50 

zero voltage reference S70 

--- 2.1.2. Signal Averaging 

The raw, often read channel data is stored (2's complement form) 

in a 12 x 16 WORD array based at often read base (at Location $03201. 

 he array is arranged in the following ianney. The table shows the 

address at which the Lsbyte of each reading for each channel of the 

"often - read's" is stored. 
Signal Averaging Array 

channel numbers--> 

0 1 

reading 

number 

Note often - read - base = 

When 16 sets of data have been gathered the dataset ready flag i! - 

set. This flag is used as the handshake semaphore. UhiLe tht 

dataset ready flag = 1, the background program has not, as yet, 

converted an3 used the Last data set. When the dataset - ready flag i! - 

found to be asserted, the signal av routine, uhich runs in tht 

background, sums the 16 individua [-readings of each channel (i .e. ont 

of the above columns) and divides the result by 16 to produce ar 

average for that channel. This result is placed into the proper 

Location in the dump - state array. 

The calculation of total chgr I, i.e. the total array current is 

done in this routine as uelT. ~bch of the branch currents is summed 

and the total is stored in the dump state array as outlined below. 

Since the A/D reading of any given granch is a maximuw of 10 bits, the 

sum of the 10 strings can never exceed the 16 bit word reserved for 

it. 

ALL of the seldom read channels are loaded directty into 

dump - array as they are read uithout signal averaging. 

The follouing figure shous the arra.ngement of the data in the 

"dump - state" array. 
--- 2.1.3. -- A/D Channel Storage Locations 

addr - 

0008 

OOOA 

OOOC 

OOOE 

0010 

001 2 

001 4 

001 6 

0018 

OOlA 

001 C 

001 E 

Often Read Channels: 

variable 

battery V: 

battery-I: 

branch17 

branch2: 

branch3: 

branch4: 

branch5: 

branch6: 

branch7: 

branch8: 

branch9: 

branchlo: 

Seldom Read Channels: 

br - voltsl: 

br-volts8: 

brmvolts9: 

br-voltsl0: 

bus voltsl: 

bus-volts4: 

bus-volts5: 

bus-amps1 : 

bus-amps2: 

bus-amps3: 

bus-amps4: 

busmamps5: 

bat-temp: 

frer temp: 

v re?: 

zero ref: 

tota-i: - chgr - I: 

description 

averaged battery voltage 

averaged battery current 

averaged branch 1 current 

averaged branch 2 current 

averaged branch 3 current 

averaged branch 4 current 

averaged branch 5 current 

averaged branch 6 current 

averaged branch 7 current 

averaged branch 8 current 

averaged branch 9 current 

averaged branch 10 current 

branch 1 voltage 

branch 2 voltage 

branch 3 voltage 

branch 4 voltage 

branch 5 voltage 

branch 6 voltage 

branch 7 voltage 

branch 8 voltage 

branch 9 voltage 

branch 10 voltage 

Load bus #1 voltage 

Load bus #2 voltage 

Load bus #3 voltage 

Load bus #4 voltage 

Load bus #5 voltage 

Load bus #1 current 

Load bus #2 current 

Load bus #3 current 

Load bus #4 current 

load bus #5 current 

battery temperature 

freezer temperature 

reading of .8 Vref 

zero voltage reference 

current total charger current 

Since the 4 mi llsecond interrupt is the onLy means for providing 

system timing, the one-second and 80 msec timers and flags are both 

controlled by this routine. Both timers (Located in memory) are 

decremented each pass and reloaded when they reach 0. When either 
-7- mIGINK PAGE t3 

caa% eosR QUALITY 

timer "times out", the respective flag is set to indicate to th 

background routine that the time period has eltapsed. 

Settle time is set by the max pwr track routine every time that 

change is msde to the PwM counters: ~f-settle time is non-zero,. at L o 

the data gathering code in this routine is skirted. This gives th 

power module time to settle before data is again taken. 

This routine also invokes scan kybd on each pass to handle th 

scanning of the hex keypad on the fyont panel. 

- 2.2. - Operator Interface \ 

The following four sections outline the functions tPtat ar 

available to the user either via the hexadecimal keypad on the fron 

panel or the serial port (300 baud only). The channel numbers use 

for accessing the different quantities are as follows: (Kote th' 

difference between the user channel number and the raw channel number, 

which is used only with the Q command through the serial port.) 

OFTEN READ CHANNELS 

signal name 

battery volts 

battery current 

branch #1 current 

branch #2 current 

branch #3 current 

branch #4 current 

branch #5 current 

branch #6 current 

branch #7 current 

branch #8 current 

branch #9 current 

branch #10 current 

signal name 

user ch user ch display rau ch 

number number pattern number 

(serial) (keypad) 

EOO 

100 

I01 

102 

I03 

I04 

I05 

106 

ADO 

BOO 

B01 

802 

803 

804 

50 5 

B06 

B07 

808 

809 

01 0 

SELDOM READ CHANNELS 

QOO 

QOl 

QO2 

Q03 

QO4 

Q05 

006 

Q07 

Q08 

Q09 

Q10 

a11 

user ch user ch display raw ch 

number number pattern number 

(serial) (keypad) 

branch #1 volts E0 1 A01 . xxx.x 912 

branch #2 volts EO2 A02 xxx.~ Q13 

branch #3 volts E03 A03 xxx.~ Q14 

branch #4 volts E04 A0 4 xxx.~ Q15 

branch #5 volts ED5 A05 xxx.~ Ql6 

branch #6 volts E06 A06 XXX.X Q17 
branch #7 volts E0 7 A07 xxx.~ 

branch #8 volts E08 A08 xxx-x 

branc9 #9 volts E09 A09 xxx.~ 

branch #I0 volts EO 1 A1 0 xxx.~ 

load bus #1 volts E3 1 A3 1 xxx.~ 

lead bus #2 volts E3 2 A3 2 xxx.~ 

load bus #3 volts E3 3 A3 3 xxx.~ 

load bus #4 volts E3 4 A3 4 xxx.~ 

load bus #5 volts E3 5 A3 5 xxx.~ 

Load bus #I current I3 1 B3 1 xxx.~ 

load bus #2 current I3 2 83 2 xxx.~ 

Load bus #3 current 13 3 B3 3 xxx.~ 

Load bus #4 current I3 4 83 4 xxx.~ 

Load bus #5 current 13 5 83 5 xxx.~ 

battery temp D3 6 D3 6 xxx.~ 

freezer temp D3 7 D37 xxx.~ 

80% of Vref E3 8 A3 8 x.xxx 

zero voltage reference E39 A3 9 x.xxx 

total charger current I40 840 xxx.~ 

state of charge DO0 DO0 xxx 

corrected state of chg D40 D40 xxx 

equal count D41 D41 xxx 

pwm-vat~e ~42 ~42 x x x 

The following are calculated at display time: 

signa L name 

battery power 

branch #I power 

branch #2 power 

branch #3 power 

branch #4 power 

branch #5 power 

branch #6 power , 

branch #7 power 

br-anch #8 power 

branch #9 power 

branch #I0 power 

user ch user ch display 

number number pattern 

(seria L) (keypad) 

COO XXXXX 

C01 XXXXX 

C02 X X X X X 

C03 xxxxx 

C04 xxxxx 

C05 xxxxx 

C06 xxxxx 

C07 xxxxx 

C08 x x x x x 

C09 xxxxx 

C10 XXXXX 

--- 2.2.1. Hexadecimal Keypad Functions 

Some of the following functions, i.e. those noted with (mutt), 

are "multimeter functions". This means that when this function is 

selected, every 320 msec the quality is measured, converted as 
necessary and redisplayed. 

D e f i n i t i o n o f notation: 

a - any of the alphanumeric keys (i.e. not "*" or "#") 

nn - channel/device specification consisting of any two numeric keys 

mm or mmm - data specification consisting of any two or three numeric 

NOTE: all inputs are assumed to be "fixed format" i.e., if the specif 

calls for 3 digits, Leading zeroes must be added to make the input 3 

long. 

2.2.1.1. Public Functions - - - - 

sequence function 

---------------------------------------------------------------------. 

--------------c------------------------------------------------------. 

* clear function 

activate password-accessible functions 

if user password matches(see below) 

Ann# read channel nn voltage (mult) 

Bnnt 

Cnn# 

read channel nn current (mutt) 

read channel nn power (mutt) 

read misc data channels (rnult) 

display software version number 

read time, hours and minutes (mult) 

initiate "dump" of machine state to 

serial port 

DD# not used 

Password-Accessible Functions 

In order to access these functions, the user must have 

successfully entered the 4 character password 

sequence function ....................................................................... 
se? Load shed threshold for Load n at mmm 

set Load restore threshold for Load n at mmm 

set the initial percentage SOC at mmmX 

set device nn to condition m, where m must be 

either a "1" (ON) or a "0" (OFF) 

device 0 audible alarm 

device 1-6 user Load requests, 1 thru 6 

device 7-11 overload trip resets for Loads 1 thru 5 

device 12-17 PWM buffer #I controls 1 thru 6 

device 18-23 PWM buffer #2 controls 1 thru 6 

device 24-25 Yellow, and Red LEDs 

initiate Lamp and annunciator test 

(accessable only in test/caL mode) 

toggle from run to test/caL mode 

(system comes up in the run mode) 

CChhmm# set time, hours and minutes 

DD# cancel password authorization 

---- 2.2.1.3. Debug Monitor Functions 

These functions are accessed via the serial port. They are 

listed in upper and Lower case Letters for comparison with the 

commands above. In order to permit maximum flexibility with respect to 

terminals, either case is useable in practice. 

sequence function .......................................................................... .......................................................................... 

^H, backspace, deL Deletes Last character entered. Echoes 

backspace, space, backspace to allow 

overwriting the Last character entered 

when a CRT terminat is used. 

Causes CPU to ignore present command Line 

Return to command.mode 

Opens a memory location at the specified 

address (requires 4 hexadecimal digits). 

Successive " " (space) characters increment 

thru memory, whi Le "-" characters decrement 

thru memory. At any time the contents of 
OR!C$PdAL PAGE, 99 

OF POOR Q&8 a Location may be altered by entering the 

new data followed by a carriage return. 

Begins execution at the specified address. 

no address is specified, execution begins 

the present PC Location 

Places a breakpoint at the specified addre 

This trace mode wilt only work on code 

Located in RAM. 

X Removes existing breakpoint. 

This permits a program to be downloaded fr~ 

a host nachine to memory starting at the 

specified address. 

Fcstart - adcr end addr datum> - 

Fills the specified memory range uitf, spec. 

byte of data. 

Maintenance - and Functions 

Many of the following functions are essentially identical t 

those invoked fror, the hexadecimal keypad, the exceptions beins thos 

comn~ands requiring password authorization.. The main difference i 

that the system response is returned via the ser3al port. This coul 

be used for data Logging by having an external device reauest th 

desired data. 

sequence function ..................................................................... ..................................................................... 

U<pwrc timer no.><duty cycle> 

Set the Power Module duty cycle to specified 

value. If duty cycle > max purr, the default 

duty cycle is set to max - pwm 

Ocdigi t no.><va lue> DispLay the value in the specified digit on t 

LCD display. 

Enn Read channel nn voltage 

Inn Read channel nn current 

Pnn Read channel nn power 

Dnn Read mise data channels 

Qnn Query channel nn for "raw" A/D data 
N 

T 

Snmmm 

Rnmmm 

Y imm 

Jnnm 

Display software version number 

Read time, hours and minutes 

Set load shed threshold for Load n at rnmm 

Set load restore threshold for load n at mmm 

Set the initial percentage SOC at mmm% 

Set device nn to condition m, where m must be 

either a "1" (ON) or a "0" (OFF) 

device 0 audible alarm 

device 1-6 user Load requests 1 thru 6 

device 7-11 overload trip resets for Loads 1 thru 5 

device 12-17 PWM buffer #I controls 1 thru 6 

device 18-23 PWM buffer #2 controls 1 thru 6 

device 24-25 Yellow, and Red LEDs 

Initiate Lamp and annunciator test 

(accessable onLy in test/caL mode) 

Toggle between run and test/caL mode, note 

the system comes up in the test/caL mode 

Chhmm Set time, hours and minutes 

K Initiate "dump" of machine state 

Calculating - And Interpreting System Parameters 

In order to calculate the hexadecima L values used for system 

parameters, it is first necessary to cLassify the type, because each 

type of parameter must be calculated somewhat differently. 

Currents are broken into two types. Battery and load currents 

have a maximum value of 102.3 amps while the branch currents have a 

maximum of 10.23 amps. Hence, full scale, i.e. S3FF has two different 

meanings depending bn which current you are referring to. In the first 

case the reading corresponds to the number of "l/lO1s" of amps being 

measured, while in the second case to the number of "1/100's" of amps. 

Once the desired current has been expressed in the proper units, 

converting the decimal number to hexadecimal results in the correct 

parameter value. For example: 

1. battery - I = 82 amps 

= 820 "1/10's of an amp" 

= (3 * 256) + (3 * 16) + (4 * I) 

= SO334 
2. branch1 = 7.2 amps 

= 720 "l/lOO1s 6f an amp" 

= (2 * 256) + (13 * 16) 

= So200 

Calculating voltages is somewhat simpler because, with only 3 

exceptions, all voltages are based on a full range value of 409.2 

volts. As with the current measurements, most voltage readings 

represents the number of "l/lOts of a volt". However, in the case of 

the thermister signals (frez temp and bat temp) and V ref the rav A/D 

count represents the numbTr of "1/100~'s of a volt". A full scale 

reading of S3FF corresponds to 1023 (base 10). If this nurber is 

shifted Left 2 places, S3FF becomes SFFC which corresponds to 4092. 

Hence, to convert fror decimal volts to hexadecimal volts, divide the 

voltage by 4 and convert the result to hexadecimal. For example: 

1. V - ref = 4.092 volts 

= 4052 "1/1ODD's of a volt" 

4092/4 = 1023 

= (3 * 256) + (15 * 161 + (15 * 1) 

= bC3FF 

2. abs - min - bat - volt = 95 volts 

= 950 "l/lO1s of a volt" 

95014 = 237 

= (14 * 16) + (13 * .11 

= SOOED 

Binary percentages for state - of chg, equal count and similar 

variables are represented by a 8 Kit number wTth the binary pcint 

located 1 bit in from the NSB, as shown here. 

RSB 

I 

X.XXXXXXX 

I 

binary point 

To calculate binary percentages, use this relation: 

binary X = ((decimal X * 1281/100) expressed in hexadeciral 

For example: 

1. maximum binary X = (100% * 128>/100 

= 128 

= (8 * 16) 

= $80 

2. shed th = (20% * 128)/100 .=- 
To calculate the constant used for state - of - chg use the following 

relation: 

iscal - bat - cap = 5.49 * 10-10 * iscal * l/bat - cap 

For example, if iscal = 1/45000 and bat - cap = 40 A-H then, 

iscal - bat cap = 5.49 * 10-10 * (1/(45000 * 40)) - 

= 30470 

- 3. Appendix - #I - Generating System Lookup Tables 

Appendix 1 contains copies of the programs, written in the "C" 

programming language, for the generation of tables to speed the 

calculation of those variables involving corrections for battery 

temperature. "C" is commonly used in academic circles and is becoming 

quite popular in industry. It was used for ggneration of the values 

since it is the normal Language used here at MI/CEC. The algorithms 

are quite straight-forward and can be easily translated to BASIC or 

any other Language of choice. For the details of the lookup 

technique, refer to the Pseudocode Listings for the appropriate 

tables. The first program generates tables for float voltage, 

equalization voltage and minimum battery voltage, uhi Le the second 

generates the table of values for use with the corrected state of 

charge routine. Notice that the program outputs each of the tables in 

two different formats; human readable and machine readable. For 

examples of the output, see the pseudocode Listings for catc - sys - volts 

and correct - stat - of - chg. 
APPENDIX #I 

PROGRAM #1 - Generates tables for float-V, equal V and min bat V. - - - 

#include <math.h> 

#include <stdio.h> 

main0 

C 

int j, i, v, t; 

float x; 

double value, temp; 

/* NOTICE!!! THE CONSTANT 2.5 FOUND IN THE EQUATIONS BELOW COKES FROK 

THE FACT THAT THE VOLTAGES ARE STORED IN A FORM THAT IS EQUAL TO 

THE NUMBER OF TENTHS OF VOLTS. FOR DISPLAY THIS VALUE IS MULTIPLI 

BY 4, SINCE $3FF --> 1023 --> 409.2 VOLTS. 

so, stored value = (input volts * 10>/4 

or, stored value = (input volts * 2.51 

printf("\n\t\tFLOAT VOLTAGE TABLE\n\nM); 

for(i=OxD;i <= 66; i=i+l) 

i 

temp = 25-.02092*((64*i)-25601; 

vaLue=2.4 * 54 * 2.5 * (1 + (.OD22 * (25-temp))); 

t=i*64; 

v=va lue; 

value=value * .4; 

printf("X4.0f deg C\t%O2x\tX03x\tX04x\tX4.lf\n",temp, 

i-QxD,t,v,va lue1; . 

1 

printf("\nU1; 

for(i=OxD;i <= 66; i=i+8> 

C 

printf(".word\tW); 

for(j=O;j <= 7;j=j+l) 

C 

temp = 25-.02092* ((64* (j+i) 1-2560); 

vaLue=2.4 * 54 * 2.5 * (7 + (.0022 * (25-terr~) 

v=va lue; 

printf("$%04x, ",v); 

3 

printf("\n"); 

3 

printf ("\l4"); 

printfC"\n\t\tEQUALIZATION VOLTAGE TABLE\n\nU); 

for(i=OxD;i <= 66; i=i+l> 

i 

temp = 25-.02092* ((64*i )-25601; 

value=2.5 * 54 * 2.5 * (1 + (.OD22 * (25-temp))); 

t=i*64; 

v=va Lue; 

vaLue=value * .4; 

printf("X4.0f deg C\tX02x\tX03x\tX04x\t%4~1f\n",temp, 

i-OxD,t,v,va Lue); 

3 

printf ("\nW); 
temp = 25-.02092*((64*(j+i))-2560); 

vaLue=2.5 * 54 * 2.5 * (1 + (-0022 * (25-temp))); 

v=va Lue; 

printf ("%%04x, ",v>; 

3 

printf("\nM); 

3 

printf("\l4"); 

printf("\n\t\tMINI~~M BATTERY VOLTAGE TABLE\n\nU); 

for(i=OxD;i <= 66; i=i+l) 

i 

temp = 25-.02092* ((64*i 1-2560); 

vaLue=l.9 * 54 * 2.5 * (1 + (.0022 * (25-temp))); 

t=i*64; 

v=va Cue; 

vatue=vatue * .4; 

printf("X4.0f deg C\t%02x\tX03x\tX04x\tX4.lf\n",temp, 

printf(".word\t"); 

for(j=O;j <= 7;j=j+l) 

i 

temp = 25-.02092*( (64*(j+i) 1-2560); 

vaLue=1.9 * 54 * 2.5 * (1 + (-0022 * (25-temp))); 

v=va tue; 

printf ("$%04x, ",v>; 

3 

printf("\n"); 

> 

PROGRAM #2 - Generates table for correct state of chg, - - - 

#include <math.h> 

#include <stdio.h> 

main0 

.c - 

int j, it V, t; 

f Loat x, coeff; 

double value, temp; 

printf("\n\tCORRECT STATE OF CHARGE TABLE\n\nW); 

for(i=OxD;i <= 66; i=i+l) 

i 

temp = 25-.02092*((64*i)-2560); 
if (temp > 25) 

coeff = .0022; , 

else 

coeff = ,0075; 

va lue=256 * (1 + (coeff * (temp-25) 1); 

t=i*64; 

v=va lue; 

value=value/2.56; 

printf("X4.0f deg C\tXO2x\t%03x\tX04x\t%4.0f%%\n",te 

i-OxD,t,v,va lue); 

3 

printf ("\nu); 

for(i=OxD;i <= 66; {={+a) 

i 

printf (".uord\tW); 

for(j=O;j <= 7;j=j+l) 

C 

temp = 25-.02092* ((64* (j+i) 1-25601; 

if (temp > 25) 

coeff = ,0022; 

e Lse 

coeff = -0075; 

va Lue=256 * (1 + (coeff * (temp-25) 1); 

t=i*64; 

v=va lue; 

printf ("%%04x, I1,v); 

3 

printf("\nfl1; 

1 
- 4. Appendix - #2 - Pseudocode Lis-tings 

The following is a table of contents for the pseudocode listings. 

Note that the order of modules is the same as in *he machine code 

PRQMs. 

TABLE OF CONTENTS FOR PSEUDOCODE LISTINGS 

module name page no. ............................................... ............................................... 

abs cnvt 

adc-hndlr 

a to h 

battTry - state - of - chg 

break 

bf divlO 

ca-i-c - equal-count 

calc-sys volts 

calc-state of chg 

chk Tor ovytdcmd-i ntyp 

cnt-F~ pwm-output 

correct-state - of - chg 

deter mach state 

discrTte ayray - cntrl 

display clr 

display-digi ts 

display-error 

display-hndlr 

di splay-huh - 

do - o - watts 

do - p - watts 

d to h 

dGm p-a m p s 

dump-arrays 

dump-soc 

dump-state 

dump-sw states 

dump-t e6p 

dump-total I 

dump~vo lt sdwnld 

fi.1 1 

find amps 

f indWpercent 

f i nd-prod 

f ind-time 

f i nd-t emp 

find-volts 

find-watts 

getbTte 

get - data 
- h - nyb - to a - 

h to a 

h to - d - word 

kQy - intrp 

kill password 

lamp-test - 

max pouer track - 

mD Ziv 

mp-mu t 

ms; hndlr 

msgmhndlr wo 

mulTimete7 func - 

open mem 

out time 

out-amps 

out-csoc 

out-data channel 

out-equaT 

~ut-~wm 

out-soc 

out-version 

out-volts 

out-uat t s 

put-amps 

putFyt e 

putbyte no 

putcharputchar uo - 

put csoc 

put-data - - cttanne 1 

put equa 1 

put-huh 

put out of range - - 

put:pwm 

put-raw channel 

put-socput-t ime 

put-t emp 

put-version 

put-vo l t s 

put-ra t t s 

rem-brkpt 

run-task mastei 

sea; kyb';? 

seribl port 

set - biT 

set brkpt 

set-digi t 

set-duty cyc Le 

set-init-soc 

set-load-shed 

set-load-restor 

set-tim Tybd - 

11-22 
set tim term 

setIup Gump 

set-upmdump kybd 

shed restor-loads - 

shifT 14 

signai-av 

sp mult 

teFt (initialization) 

test string I 

toggTe - run - Fit 
Feb 17 12:17 1984 /u/tam/solat/PSEUDOCODE Page 1 

xxxxx 

X X 

X X 

X X 

X X 

xxxxx 

XXXXX XXXXX XXXX X X 

X X X X X X XX XX 

X X X X X X XXXX 

XXXXX XXXXX X X X X 

X X X.X X X X 

X X X XXXX X X 
Feb 17 12:17 1984 /u/tam/soLar/PSEUDOCODE Page 3 

putchar: 

disable system interrupts; 

call putchar wo(accum); 

enable syste;; interrupts; 

end putchar; 

............................................................................ 

; This routine places the string defined by the starting address in string p- - 

; and place it, character by character into the output buffer by calling 

; the putchar routine that does not re-enable system interrupts, putchar wo. - 

; This routine is used in the serial port handler. 

............................................................................ 

Pseudocode: 

msg - hndlr - uo: 

save regs; 

i = 0; 

do uhile (string ptrri3 <> 0) 

cat L putchar-wo(string - - ptrCi1; 

i=i+q; 

end; 

unsave regs; 

end msg - hndlr - wo; 

............................................................................ 

; This routine is identical to the above, except that it uses putchar insteal 

; of putchar - wo and is to be used under normal string output circumstances. 

............................................................................ 

Pseudocode: 

msg - hndlr: 

save regs; 

i = 0; 

do while (string ptrCi3 <> 0) 

call putcharTstring - ptrCi3; 

i=i+I; 

end; 

unsave regs; 

end msg - hndlr; 

............................................................................ 

; his routine retrieves the next two ascii characters in the command buffer 

; converts them into a single hexadecimal value and return it via the- 

; accumulator. Should either of the characters be something other than 

; 0-9, a-f or A-F; the ascii hex flag is cleared. 

;***************************T***T******************************************* 

Pseudocode: 

getbyte: 

save regs; 

accum =-command bufferEcrnd in ptrl; - cmd in - ptr = cma in ptr +7; - - 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 4 

call a to h(accum); 

if (acTum-<> SFF) 

then do; 

temp = accum << 4; 

accum = command bufferfcmd in ptr3; 

cmd in ptr = cm7 in ptr +?;- 

calT a-to h(accuT1;- 

if (accum-<> SFF) 

then do; 

accum = accum + temp; 

ascii - hex - flag = 1; 

end; 

else ascii-hex - flag = 0; 

end; 

else ascii - hex - flag = 0; ~@~~i~j?ifa, !mi; lr: t lc 

unsave regs; 

end getbyte; 

......................................................................... 

; This routine retrieves the next two ascii characters in multimeter dat 

; converts them into a single hexadecimal vatue and return it via th; 

; accumulator, Should either of the characters be something other than 

; 0-9, a-f or A-F; the ascii hex flag is cleared. In this way it is alm - 

; identical to the previous routine, except for the location that the 

; data is retrieved from. This routine is used by multimeter func. 

........................................................................ 

Pseudocode: 

get - data: 

save regs; 

accum = multimeter data; 

call a to h(accurn); 

if (accum-<> SFF) 

then do; 

temp = accum << 4; 

accum = multimeter data + 1; 

call a - to - h(accum)r 

if (accum <> SFF) 

then do; 

accum = accum + temp; 

ascii - hex - flag = 1; 

' end; 

else ascii - hex - flag = 0; 

end; 

else ascii-hex - flag = 0; 

unsave regs; 

end get - data; 

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

; This routine takes the hexadecimal value in the accumulator, converts 

; it into two ascii characters and places them into the output buffer. 

; This routine assumes that the system interrupts are to remain disabled, 

; so that it uses putchar uo instead of putchar. ................................................................
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 5 

Pseudocode: 

- 

call h to a(accum); 

call pGtcxar wo(ascii chars+l); 

call putchar-wo(ascii-chars); - - 

end putbyte - wo; 

............................................................................ 

; This routine takes the hexadecimal value in the accumulator, converts 

; it into two ascii characters and places them into the output buffer. 

; This routine wants to turn off the system interrupts so that the serial po 

; handler cannot interfere so it uses'putchar instead of putchar wo, 

............................................................................ 

Pseudocode: 

putbyt e: 

call h to a(accum); 

call pLtc?;ar(ascii chars+l>; 

call putchar(ascii-chars); - 

end putbyte; 

............................................................................ 

; This routine converts the ascii character contained in the accumulator to 

; the corresponding hex value which is returned in the accumulator. If the 

; character is something other than 0-9, a-f or A-F; SFF is returned instead ............................................................................ 

Pseudocode: 

a - to - h: 

save regs; 

if (accum >= $30) 

then do; 

if (accum <= $39) 

then accum = accum - $30; 

else do; 

accum = accum AND $DF; I* force to upper case *I 

if ((accum >= 541) AND (accum <= $46) ) 

then accum = accum - $37; 

else accum = $FF; > end; 

end; 

else accum = SFF; 

unsave regs; 

end a - to - h; 

............................................................................ 

; This routine converts the hexadecimal value contained in the accumulator 

; into two ascii characters for transmission. The two characters are stored 

; in the word value, ascii chars 

............................................................................. 

Pseudocode: 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 6 

h - to - a: 

save regs; 

temp = accum; 

call - h - nyb to a(accum1; 

Lsbyte of aFciT chars = accum; 

call - h - nyb to ;(temp >> 4); 

msbyte of aYciT - chars = accum; 

unsave reg; 

end h - to - a; 

........................................................................ 

; This captive subroutine converts the Lower nybble of the accumulator 

; into the corresponding ascii character and returns it in the accurrolat 

........................................................................ 

Pseudocode: 

- h - nyb to a; - - 

accum = accum AND $OF; 

if (accum < $A> 

then accum = accum + 530; 

else accum = accum + $37; 

end - h - nyb - to - a; 

......................................................................... 

; This subroutine shifts the contents of dec value into the accumulator 

; 4 bits at a time, and converts the nybble Fnto ascii by clearing the ur 

; nybble and adding $30. It is assumed that only decimal digits will be 

; in dec value. 

;*******T*****************************************************

Pseudocode: 

shift - L4: 

shift dec value << 4; 

place 4 mSb's into accum; 

accum = accum AND $OF; 

accum = accum OR $30; 

end shift - L4; 

......................................................................... 

; This routine converts the 16 bit hexadecimal word contained in the cnvt 

; into a packed decimal word that is returned in dec value. 

;***************************************************T******************** 

Pseudocode: 

h - to -- d word: 

save regs; 

dec value = 0; 

memzbyte = (lsbyte of cnvt - data) AND $OF 

if (mem byte <> 0) 

the; dec value = table lfmem byte]; 

mem - byte = (71sbyte of cnvT - data7 AND SF01 >> 4; 
Feb 17 12:17 1984 /u/tam/soLar/PSEUDOCODE Page 7 

if (mem byte <> 0) 

the: dec value = dec value + table 16Cmem byte]; - 

mem byte = (msbyte of cnvt - data) AND $5~ 

if Tmem byte <>O) 

they dec value = dec value + table 256Cmem byte]; 

- mem byte = (?msbyte of cxvt - data) AND ~FO) >> x;. 

if Tmem byte <>O> 

then dec - value = dec value + table 4096Cmem byte]; - - - 

unsave regs; 

end h - to -- d word; 

.---------------------------------------------------------------

........................................................................... 

I HEXADECIMAL TO DECIMAL CONVERSION TABLES .----------------------------------------------------------

........................................................................... 

I 

table - 1: 

.byte $00, $01, $02, $03, $04, $05, $06, $07, $08 

.byte $09, $10, $11, $12, $13, $14, $15 

tabte - 16: 

.word $0000, $0016, $0032, $0048, $0064 

.word $0080, $0096, $0112, $0128, $0144 

.word $0160, $0176, $0192, $0208, $0224 

.word $0240 

table - 256: 

.word $0000, $0256, $0512, $0768, $1024 

.word $1280, $1536, $1792, $2048, $2304 

,word $2560, $2816, $3072, $3328, $3584 

.word $3840 

table - 4096: 

.byte $00,$00,$00, $96,$40,$00, $92,881,$00 

.byte $88,$22,%01, $84,$63,%01, $80,$04,$02 

.byte $76,$45,$02, $72,586,502, $68,$27,$03 

.byte $64,$68,$03, $60,$09,$04 

; This routine is used to convert the packed decimal byte in the accumulator 

; into its hex equivalent. If either nybble is > $9, the over 10 flag is se 

; The result is returned via the accumulator. To accomplish txis; the most 

; significant nybble is multiplied by 10 and added to the least significant 

; nybble. 

8 

I Since 10X = (2 + 8)X = 2X + 8X, it follows that: 

I 10X = ~Xcshifted left by 1) + X(shifted Left by 3) 

I trick: 10 * X = (8 * XI + (2 * X) 

Pseudocode: 

d - to - h: 

save regs; 

temp1 = accum; 

over - 10 - flag = 0; 

accum = accum AND SFO; 

if (accum < $A01 

then do; 

temp2 = (accum >> 1) + (accum >> 3); 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 10 

display - digits: 

save regs; 

dsply port = #dsply clk off OR dsply sel dsb; 

dsply-port = dspty - port-^^^ #dsply - set - exb; 

doi=Dto4 

temp = digitsCi3; 

do j =Oto7 

if (digitsti3 AND #$Dl) 

then dsply port = dsply port OR #send 1 bit; 

else dspty-port = dsp~~-~ort - AND #sen2 - - bit; 

digitsti3 = digits~il >> 1; 

dsply port = dsply-port OR #dspty ctk on; 

dsply-port = dsply - port AND #dspt'j; ctF off; - - 

end; 

digitsti3 = temp; 

end; 

dspty port =dspLy port OR #ds~ly sel dsb; 

i - o - fTags = i - o - fTags AND #lcd dspty-dun; - - 

unsave regs; 

end display - digits; 

......................................................................... 

; This routine will set up the array display word with "blanking" informi 

; in all digits, and then call display hndtr7) in order to clear the LCD - 

; display. .......................................................................... 

Pseudocode: 

display - clr: 

save regs; 

display wordt43 = 0; 

disptay-wordt33 = #$80; 

di spt ay-wordI23 = #%80; 

display-uordI73 = #$80; 

dispt ay-word~03 = #$80; 

call. display - hndlr; 

unsave regs; 

end display - clr; 

.......................................................................... 

; This routine, called from the terminal, allows the user to set one digit 

; of the LCD display to a specified character, white blanking the rest of 

; the display. The accessible digits are the rightmost 4, and they are 

; number 1 - 4 starting from the right. ;**************+****************************,****************************** 

Pseudocode: 

set - digit: 

save regs; 

if ((command bufferfll < $31) OR (command bufferr13 > S34)) 

then calT msg - hndlr('INVAL1D LCD DIGIT NUMBER'); 

else do; 
'eb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 11 

i = command buff6rfl3 - #$31; 

if ((cornman3 bufferC23 < $30) OR ((command buffer123 > $39) - 

AND ?command bufferC23 < $41) OR 

(com'i;;and bufferC23 > $46)) 

then call msg - hndLr(T~~~~~ OUT OF RANGEv); 

eLse do; 

j = command bufferC23 - #$30; 

if( j> $09)- 

then j = j - #$07; 

muttirneter flag = 0; 

do k = 3 to 0 step -1; 

display wordLk3 = #880; 

display-wordL43 = 0; 

display-word~i3 = j; 

call display - hndtr; 

end; 

end; 

end; 

unsave reg; 

end set - digit; 

........................................................................... 

This routine is an unsigned multiply that takes the two 16 bit words in 

mutt1 and mutt2 and produces a 32 bit product which is returned, 

surprisingly enough, in "product". The technique used is the commonly 

used shift and add algorithm. 

........................................................................... 

seudocode: 

p - mutt: 

save regs; 

product = 0; C Zero out product memory Location 3 

scratch = muLt2; C Load multiplicand into tower 2 bytes 3 

C of scratch area in memory 3 

C Zero out upper two bytes of scratch area 3 

do y - index = 0 to 1; C For both Lower & upper byte of multiplier 1 

accumulator = mutt1 + y index; C get the multiplier byte 3 

do x - index = 8 to 0 stFp -1 C For each bit in the byte 3 

accum = accum >> 1; C shift it right to see if bit 3 

C is set.... 3 

if (carry bit = 1) C If so, then ... 3 

then 20; 

product = product + scratch; 

C add (shifted) multiplicand 3 

( to product 3 

scratch << 1; C In any case, shift the 3 

end; C go to next bit of multiplier 3 

end; C get next byte of multiplier 3 

end; 

unsave regs; 

end mp - muLt; 

........................................................................... 

This routine is au unsigned multiprecision division where the 32 bit 

dividend is stored in, get this, dividend; and the 16 bit divisor is 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 12 

; stored in divisor. The algorithm used was a "brute force" shift and 

; subtract. The quotient is- returned. ..yep, you guess it. ..in quotient. 

; As for the remainder, well you get the picture. To save space in terc 

; page, quotient and remainder overlay dividend. 

; In order to test to see if there will be an overflow, i.e. if the quot 

; will be bigger than 16 bits we compare the divisor with the upper tuo 

; of the dividend. If the dividend is less, then we're OK, since the up 

; two bytes can be no more than 32768 * the divisor and the result of th 

; divsion must then be less than 32768 (16-bits, max.). 

........................................................................ 

Pseudocode: 

mp - div: 

save regs; 

if divisor = 0 

then set - div - by - flag; 

else do; 

if (dividend > SFFFF * divisor) 

then set - div - overflow - flag; 

else do; 

tempquot = 0; C zero out temporary quotient ar 

tempdivr = divisor * $10000; 

C upper two bytes of tempdivr get divis 

C and Lower tuo bytes get 0 > 

for x index = 2 to 1 step -1 C Do two bytes uor 

for bit - cntr = 8 to 1 step -1 

C Do a shift for each bi 

tempqout CC 1; 

tempdivr >> 1; 

tempdiff = dividend - tempdivr; 

i Long word operation > 

if (tempdiff >= 0) 

then do; 

tempquot = tempauot + 1; 

dividend = tempdiff; 

< Rake subtraction real 

end; 

end; 

end; 

quotient = tempquot;i load up quotient in correct ar 

end; 

end; 

unsave regs; 

end mp - div; 

; This routine reads the contents of the Time of Day counters in the 

; Am9513 timer and stores the hours and minutes information away in zero 

; Locations "minutes" and "hours" for use by out time and put time. 

........................................................................ 

Pseudocode: 

find - time: 

. save regs; 
:eb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 13 

timer csr = #%A3; 

timer-csr = #%19; 

i = timer data; 

i = i OR Timer - data; 

if (i = 0) 

then do; 

timer csr = #%A2; 

timer-csr = #%IA; 

end; 

minutes = timer- data; 

hours = timer - data; 

unsave regs; 

end find - time; 

........................................................................... 

This routine reads the contents of the zero-page locations "minutes" and 

"hours" and formats the information for display on the LCD display. ........................................................................... 

seudocode: 

ut - time: 

save regs; 

display word = minutes AND #$OF; 

display-uordtl = ((minutes AND #SF01 >> 4); 

displaycuord+2 = hours AND #%OF; 

display-uordt3 = ((hours AND #%FO) >> 4); 

display-wordt4 = #%02; 

call digplay - hndlr; 

unsave regs; 

end out - time; 

This routine locates the "raw A/D count" for a specified channel and 

converts it into decimal volts and formats the value for the front panel 

display. 

k********'****************************************************************** 

~t - volts: 

save regs; 

mem byte = get data(); 

if Tascii - hex - ?lag = 1) 

then do; 

call find volts; 

if (errormflag = 0) 

then 20; 

dec value = h to d word(cnvt - data); 

if Tdec value->=-l~000) 

the; do; 

accum = $03; 

call display-error; 

end; 

else do; 
Feb 17 12:17 1984 /u/tarn/solar/PSEUDOCODE Page 14 

do index = 3 to 0 step -1; 

call shift L4; 

display - woTd~index3 = aceurn; 

end; 

end; 

display - uordt43 = dot position; /* this includes - 

sign flag dat 

call display - hndtr; 

end; 

end; 

else call display - huh; 

unsave reg; 

end out - volts; 

......................................................................... 

; This i.s the subroutine which actually does the location of the "raw A/I 

; count" for a specified channel from the dump array, put volts or out vc 

......................................................................... 

Psuedocode: 

find - volts: 

save regs; 

if (mem byte <= $39) 

the: do; 

if ((mem byte = $38) OR (mer - byte = S39)) 

thencdot position = 3; 

else dot-position = 1; 

mer byte = vFltage channelstmern byte); - 

if Tmem byte <> SFF> 

the; do; 

error flag = 0; 

cnvt Zata = dump arrayfrner - byte*23; 

if (Tnvt - data < b> 

then do; 

cnvt data = 2's camp (cnvt - data); 

sign-flag = 1; 

end; 

else sign - flag = 0; /* sign flag is in wsb of 

dot - position */ 

cnvt - data = cnvt - data << 2; 

end; 

I etse error - flag = 1; 

end; 

else error - flag = 1; 

unsave regs; 

end find - volts; 

,------------------------------------------------------------------------. .----------------------------------------------------------

t USER VOLTAGE CHANNNEL LOOKUP TABLE .......................................................................... 

voltage - channels: 

.byte $00, SOC, SOD, SOE, $OF, $10, $11, $12 

.byte $13, $14, SFF, SFF, SFF, SFF, SFF, SFF 
ORI~?~~~~~m ;w 4- ; 

-. * .d 

Feb 17 12~17 1984 /u/tam/solar/PSEUDOCODE Page 15 OF PCB@ ~~t$&m~ 

,byte $15, SFf, $FF, SFF, SFF, $FF, SFF, SFF 

.byte SFF, SFF, SFF, SFF, SFF, SFF, SFF, SFF 

.byte SFF, SFF, SFF, SFF, SFF, SFF, SFF, SFF 

.byte SFF, SFF, SFF, SFF, SFF, SFF, SFF, SFF 

.byte SFF, 516, $17, 518, $19, SIA, SFF, SFF 

.byte $22, 523 

; ~hts routine Locates the "raw A/D count" for a specified channel and 

; converts it into decimal ampss and formats the value for the front panel 

; display. 

............................................................................ 

Pseudocode: 

out - amps: 

save regs; 

mem byte = get data0; 

if Tascii hex - Tlag = 1) 

then 30; 

if (mem byte = $40) 

the; do; 

cnvt data = abs - total - chgr - I; 

dot position = 1; 

if Ttotat chgr I < 0) 

then sign ilag = 1; 

dec - value = b7 - divlO(cnvt - data); 

end; 

else do; 

cat L find amps; 

if (error-flag = 0) 

then Jec - value = h - to -- d word(cnvt - data); 

end; 

if (dec value >= 10000) 

the; do; 

error num = $03; 

cat t 2isplay - error; 

end; 

else do; 

do index = 3 to 0 step -1; 

call shift L4; 

display - wo~d~indexl = accum; 

, end; 

display wordC43 = dot - position; 

cat 1 diFplay - hndlr; 

end; 

end; 

else call display - huh; 

unsave reg; 

end out - amps; 

........................................................................... 

This is the subroutine which actually does the location of the "raw AID 

count" for a specified channel from the dump array, put-amps or out amps. *********************************************7**********************
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 16 

Pseudocode: 

find - amps: 

save regs; 

if (mem byte <= $35) 

the; do; 

mem byte = current channelsCmern byte]; 

if Tmem byte <> SF~) - 

the; do; 

if ((mem byte <= S10) AND (mem byte <> 0) - 

then-d~t-~osi tion = 2; 

else dot position = 1; 

error flag =-0; 

cnvt Jata = dump arrayCmev byte*23; - 

if (cnvt data < 5) 

t hen-do; 

cnvt - data = 2's comp(cnvt data); 

sign - flag = 1; /* sign bTt is rns bit o 

dot - pcsition */ 

end; 

else sign - flag = 0; 

end; 

else error flag = 1; - 

end; 

else error - flag = 1; 

unsave regs; 

end find - amps; 

current - channels: 

.byte $01, $02, $03, $04, $05, $06, $07, $08 

.byte $09, SOA, $FF, SFF, $FF8 SFF, SFF, $FF 

.byte $06, SFF, SFF, SFF, SFF, SFF, SFF, $FF 

.byte $FF, SFF, SFF, SFF, SFF, SFF, SFF, $FF 

.byte SFF, SFF, SFF, SFF, SFF, SFF, SFF, SFF 

.byte SFF, SFF, SFF, SFF, SFF, SFF, SFF, SFF 

.byte $FF, $18, SlC, $ID, SlE, SlF 

........................................................................ 

; This routine displays or arranges for the display of 6 data channels t 

; the front panel LCD display. The data channels are: 

8 channel 00 - state of charge 

I channel 36 - battery temp 

8 channel 37 - freezer temp 

8 channel 40 - corrected state of charge 

8 channel 41 - equalization count 

8 channel 42 - pwm value ........................................................................ 

Pseudocode: 

out - data - channel: 

save regs; 
:eb 17 12:17 1984 /u/tam/soLar/PSEUDOCODE Page 17 

mem byte = get data(); 

if Tascii hex - Ttag = 1) 

then do; 

if (mem byte = 0) then call out soc; 

e Lse rf (mem byte = $40) then-cal l out csoc; 

else if (Gem byte = $41) then call out equal; 

else if (;em - byte = $42) then cat L out - pwm; 

else do; 

call find temp; 

if (errormftag = 0) 

then do: 

if ((div by - zero = 0) AND (div - overflow) = 0) 

then dz; 

dec value = h to d word(cnvt data); - 

if Tdec value->=-l~000) 

then 30; 

accum = $06; 

call display - error; 

end; 

else do; 

do index = 3 to 0 step -1; 

call shift L4; 

display - wordrindex3 = accum; 

end; 

display wordC43 = dot - position; 

call display - hndlr; 

end; 

end; 

else do; 

error num = $06; 

call zisptay - error; 

end; 

end; 

else call display - huh; 

end; 

else call display - huh; 

unsave regs; 

end out - data - channel; 

........................................................................... 

This routine Locates the msbyte of state of chg, cstate of chg, pwm value, - - - - 

or equalization count (depending on the entry point), converts it into a 

percentage and retur'ns the value in dec - value ready for shifting and output 

State - of - chg is stored: X.XXX XXXX XXXX XXXX 

implied binary point 

Where this va tue represents (decimal percent)/100) * 32768 

To convert back to decimal for display, we first multiply by 200 (base 10) 

resulting in: 

(decimal percentage/100) * 32768 * 2 * 100 = (decimal percentage) * 65566 

So, by taking the msbyte of the result, rounding it up or'down by Looking 

- 11-37 
Feb If 12:If 1984 /u/tam/solar/PSEUDOCODE Page 18 

; at the msb of the previous byte, and converting to decimal ue have a V; 

; for output. Although the pseudocode shows this to be 5 separate routi~ 

; in the assembly code they are condensed to just one, with 4 entry poin. 

......................................................................... 

Pseudocode: 

out~csoc :

save regs; 

msbyte of multl = msbyte of cstate of chg; - - lsbyte of multl = $80; 

call - display - soc0; 

unsave regs; 

end out - csoc; 

out-soc: 

save regs; 

msbyte of mutt1 = msbyte of state of chg; 

lsbyte of mutt? = 2nd msbyte of sTatT of chg; - - call - display - soc0; 

unsave regs; 

end out - soc; 

out - equa 1: 

save regs; 

msbyte of mutt1 = msbyte of equal count; 

lsbyte of mutt7 = 2nd msbyte of eGual count; - call - display - soc0; 

unsave regs; 

end out - equa t; 

out-pwm: 

save regs; 

msbyte of cnvt data = 0; 

lsbyte of cnvt-data = pwm value >> 2; - 

call - display - pwm: 

unsave regs; 

end out - pum; 

- display soc: procedure; rnGlt2 = 200; 

call mp mult; 

cnvt daia = productf23; 

if (~roductfl3 AND bit 7 <> 0) 

then cnvt - data = cnvt - data + 1; I* round up if necessary */ 

- display pwm: dzc value = h to d uord(cnvt data); - - - 

display uordfzl = 0; 

display-uordt33 = $80; 

call shrft L4; 

call shift-~4; 

if (accum = $30) 

then display word123 = $80; 

else display-word~23 - = accum; 

call shift L1; 

display - woTd113 = accum; 
:eb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 19 

call shift L4; 

display woyd~03 = accum; 

call display hndlr; 

end - display - sac; 

Thi3 routine calls the proper routines to retrieve the channel current 

and-voltage, multiply them and places the result to the serial output 

buffer. 

........................................................................... 

seudocode: 

ut watts: - 

save regs; 

call do - p watts; - 

if (error - flag = 0) 

then do; 

if (dot position AND $80 <> 0) 

the: call putchar('-'); 

call putchar(msbyte of dec - value + $30); 

call shift L4; 

call putchar(accum); 

call shift L4; 

call putchar(accum); 

call shift L4; 

call putchar(accum); 

call shift 14; 

call p~tchar(accum); 

call msg - hndlr (~WATTS~); 

end; 

else call msg - hndlr('1NVALID CHANNEL OR DATA'); 

unsave regs; 

end put - watts; 

This routine calls the proper routines to retrieve the channel current 

and voltage, multiply them and sets up the result for the front panel 

LCD display. Notice that the maximum power that can be displayed is 

19999 watts. ........................................................................... 

seudocode: 

save regs; 

call do - o watts; - 

if (error flag = 0) 

then 70; 

if (dec value >= 20000) 

the; do; 

error num = $03; 

call Tisplay - error; 

end; 

else do; 

do index = 3 to 0 step -1; 
feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 20 

call shift L4; 

* display - wordfindex1 = accum; 

end; 

if (msbyte of dec value = 1) 

then display Lordt43 = dot position OR sCO; 

else display-wordl43 = dot-posi tion; - call display - hndTr0; 

end; 

end; 

else call display huh; - 

unsave regs; 

end out-watts; 

-*****************************************************************+***** 

; This routine does the actual retrieving, multiplying and conversion tc 

; "displayable watts" for out uatts and put watts. 

;****************************~*************T******************

Pseudocode: 

find - watts: 

save regs; 

sign flag = 0; 

if (;em byte <= 10) 

t hen-do; 

save-watt-ch num = mem byte; 

merr! - byte = 0; /* This forces battery - V to be used f 

the calculation */ 

call find - volts; 

mem-byte = save - uatt ch num; - - 

end; 

else call find volts; 

if (error flag = 07 

then 30; 

volt sign = dot position; /* get volt sign */ 

mutt7 = cnvt data; 

call find amps; 

if (error-flag = 0) 

then 20; 

dot - position = (dot - position XOR volt sign) AKD ! 

/* include-amp sign *, 

mult2 = cnvt data; 

cat1 mp mutt: 

dividena = product; 

if ((mem byte >= 31) OR (mem byte = 0)) - 

then-divisor = 100; 

else divisor = 1000; 

call mp div; 

cnvt daTa = quotient; 

dec - Falue = h - to -- d word(cnvt - data) 

end; 

end; 

unsave regs; 

end find - watts; 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 21 

; This routine retrieves the channel number, tests to see that it is 

; acceptable and calls find watts if it is. Otherwise it sets the error fla! 

; Both find - amps and find vzlts test for channels, but there are couple Ethel 

; channels, such as channel 38 that are not meaningful in this context. Hen, 

; the double-check. Notice, that although the pseudocode implies that there 

; 3 routines, they are actually written as one routine with 2 entry points. 

............................................................................ 

Pseudocode: 

do - p - watts: 

save regs; 

cmd-out-ptr = 1; 

mem byte = getbyte0; 

catT - do - watts; 

unsave regs; 

end do - p - watts; 

do - o watts: - 

save regs; 

mem byte = get data0; 

calT do watts: 

unsav'i- regs; 

end do - o - watts; 

- do - watts: procedure; 

error flag = 0; 

if (ascii hex - flag = 1) 

, then 50; 

if (mem byte < 36) 

the; call find watts; 

else error - flag = 1; 

end; 

else error - flag = 1; 

unsave regs; 

end do - watts; 

........................................................................... 

This routine routes or arranges for the routing of 6 data channels to 

the serial port. The data channels are: 

channel 00 - state of charge 

channel 36 - battery temp 

channel 37 - freezer temp 

channel 40 - corrected state of charge 

channel 41 - equalization count 

channel 42 - pwm value .......................................................

seudocode: 

ut - data - channel: 

save regs; 

cmd out ptr = 1; 

mem-byte = getbyte(); 

if Tascii hex - flag = 1) 

then do: 
2 pp.F%y .;,* Feb 17 12:17 1984 lu/tam/soLar/PSEUDOCODE Page 2ZoF po(ik- Fe4Lrr54 ., " rea 

%L "' 

if (mem byte = 0) then call put soc; 

else Tf (mem byte = $40) then-call put csoc; 

else if (;em byte = $41) then call Eut equal; 

else if (;em byte = $42) then call out pwm; - else call dump - temp; 

end; 

else call put - huh; 

unsave regs; 

end put - data - channel; 

........................................................................ 

; This routine locates the msbyte of state of chg, cstate of chg, pun-va - - - - 

; or equalization count (depending on the entry point), converts it intc 

; percentage and returns the value in dec value ready for shifting and c 

8 

- 

I State - of - chg is stored: X.XXX XXXX XXXX xXXX 

8 

imp1 ied binary point 

8 Where this value represents (decimal percent)/lOO) * 32768 8 

; To convert back to decimal for display, we first multiply by ZOO (base 

; resulting in: 

; (decimat percentagelloo) * 32768 * 2 * 100 = (decimal percentage) * 6 8 

; So, by taking the msbyte of the result, rounding it up or down by Look 

; at the msb of the previous byte, and converting to decimal we have a v 

; for output. Although the pseudocode shows this to be 5 separate routi 

; in the assembly code they are condensed to just one, with 4 entry poin 

......................................................................... 

Pseudocode: 

put-csoc: 

save regs; 

msbyte of mutt1 = msbyte of cstate of chg; 

1sb.yte of multl = 580; - - 

call put - soc0; 

unsave regs; 

end - csoc; 

put - soc: 

save regs; 

msbyte of multl = msbyte of state of chg; 

Lsbyte of multl = 2nd msbyte of sTatT of chg; 

call put soc0; 

- - 

- 

unsave regs; 

end - soc; 

put - equa 1 : 

save regs; 

msbyte of multl = msbyte of equal count; 

Lsbyte of multl = 2nd mrbyte of exual count; - . call - display-soc0; 

unsave regs; 
eb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 23 

end put - equal; 

~lt - pwm: 

save regs; 

msbyte of cnvt data = 0; 

- lsbyte of cnvt-data = pwm - value >> 2; 

-: call - put - pwm: 

unsave regs; 

end put - pwm; 

3ut - SOC: procedure; 

mutt2 = 200; 

caL 1 mp-mu1 t; 

cnvt data = productC23; 

if (productC17 AND bit 7 <> 0) 

then cnvt - data = cnvt - data + 1; /* round up if necessary */ 

3ut - pwm: 

dec value = h to - d - word(cnvt - data); 

calT shift ~47 

call shift-14; - 

if (accum = $30) then accum = $20; 

call putchar(accum); 

call shift L4; 

call putchar(accum); 

call shift L4; 

call putchar(acc~m); 

call putchar('%'); 

end - put - soc; 

k************************************************************************** 

This routine locates the "raw A/D count" for a specified channel and 

converts it into decimal volts and formats the data for the serial 

port. 

k************************************************************************** 

~t - volts: 

save regs; 

cmd out ptr = 1; 

mem-byte = getbyte(); 

if Tascii hex - flag = 1) 

then 50; , 

Jmp - Volts: 

call find volts; 

if (error-flag = 0) 

then To; 

dec value = h to d word(cnvt - data); 

if Tdec va tue->=-lb000) 

the; call msg - hndlr('READ1NG OUT OF RANGE'); 

else do; 

if (sign flag = 1) 

then-do; 

call putchar('-9; 

sign - flag = 0; 

end; 
-I. n 

-h w 

C 

n C 

r) m 3-7 -h 

a 1 a. 

303 

2.Q la 

I 

no -hw nI *. - 3 

m*a< wv -3-(Ow cow 

wan- I. nn 2.nnnn-I. m31<: It 

ww +wwwb+~nw 0 F r- C Ow,-11 w 

rc ~cc.-c~*. -C r+ a. UI .-(05 

UUllOUUlUu,~. 1 

C Jm*C JCIcP 3 v* 

rt-a.31 rta.r*a.3 w If0 

n-h un-hn-h I n o rt r* 1 la 

wl w w wl wl 3- 01 7.t- 30.: 

n&-r*n*n*W a00 w ** 2. b ** w *. -01 

o -on n rt 1-a n c=Io n J n n 

C~,CC(O n 3 m113 3 3 XJ 3 v~ww m < *e wN*e *e 17 b rt 

7- 

n 0, ul F-UQ 

- -2cu 8 0 rt 

- u cu u cow *. r+ C *. n -4 5 

cuo 

-I n 

1 [U 

3 

v 

m a.3 n w .. 4.m 3 w 3 a< 

I I a 

+cuuo 

5WY C 7 

aor*rtm 

3 a co a. -I. g m + a I1 r* *. 

03- 1 

r\*. a a 

art3 xm II 

m I rt 

wm3 +w-, 

#-Y I. 

a w cu rt 

aou ma 

Ow* n 

*.-ID Ilv 

F *. 

II --r 

u w 

C W r* CS 

lo 

rt - 

0 

rt 

w 

1- W 

. 

*. *. I. I. *. * * 

*un --I * 

*005* 

*lY-J.* 

*r*<w * *@ a * * 71* 

* *o * * mc* * rt * * -a. -I. * * r*3 * * a * * -I. * * 3-* 

* r+O * * oo* 

4 cu * * a** * am* * nm* * 2. * * 3r+* 

* cuJ* * Fa * * * 

4 w :* * 31* 

* vcu* * mz* * * * cuZI* * 3.-* 

4 aa* 

4 * * 3rn * * OO* 

4 7C* * 33* * curt* * rt :* *W * * -4, * * do * * 31 * 

4a * 4 w * 

*a* 

* cum* * *-fJ * * cum* * 0 * * +-I.* 

* O+* * la.* 

* a * * *a* *5* 

* mo* * 3- * * mcu* * a3* * 73* 

* -~.m* * 01-4 

*-* 

* cu * * 3 * * a. * * * * * * .L 

7J c 

C 3 

r* m 

Icu 

<<ma 

0 a -3 

F ma. 

+la*. 

m a *. m 0 

** 0, 

C 

c ma 

#- 3 

-0 ma 

C a ** 

I& 0 

5 cu 

c 7 

3- C 

. u 

c 

rt 
eb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 25 

if (dot position = 1) 

the; call putchar('.'); 

call shift L4; 

cat 1 p~tchar(acc~m); 

call msg - hndlr('ampsB); 

end; 

end; 

else call put - huh; 

end; 

else call put - huh; 

unsave reg; 

end put-amps; 

This routine takes the raw channel number from the command buffer and 

uses it as an offset into the dump - array and outputs the c-dntents in 

ascii format to the serial port. 

........................................................................... 

seudocode: 

ut - raw - channel: 

save regs; 

cmd-out - ptr = 1; 

offset = getbyte(); 

if (ascii hex - flag = 0) then call put - huh; 

else 50; 

if (offset > $37) then call put huh; - 

else do; 

if (offset = $37) then offset = $36; 

offset = d to h(offset1; 

offset = (offset*2) + 1; 

mem byte = dump arraytoffsetl; 

cali p~tbyte(mem - byte); 

offset = offset - 1; 

mem byte = dump arrayCoffset3; 

catT putbyte(me;K - byte); 

end; 

end; 

cmd-out - ptr = 0; 

unsave regs; 

end put - raw - channel; 

Thib routine outputs the current time to the serial output port. It is 

called by itself and also from dump state. ............................................................................. 

seudocode: 

ut - time: 

save regs; 

call msg hndlr('T1ME:'); 

call put?;yte(hours); 

call putchar(':'); 

call putbyte(minutes); 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 26 

call putchar('CR'); 

call putchar('LF9;. 

end put - time; 

........................................................................ 

; This routine collects the "raw A/D count" for the specified channel, 

; converts it into a decimal temperature, format it and outputs it to tt 

; serial port. ........................................................................ 

Pseudocode: 

put-t ernp': 

save regs; 

cmd out ptr = 1; 

mern-bytT = getbyte(); 

if Tascii hex - flag = 1) 

then 70; 

dump - temp: 

call find temp; 

if (error-flag = 0) 

then 20; 

if (div by zero = 1) - - 

then call msg hndLr('DIV1DE BY 0'); 

if (div overflow 1) 

then call msg hndLr('D1VIDE OVERFLOW~I; 

dec value = h to 5 word(cnvt data); - if Tdec va lue->=-1n000) 

then call msg - hndLr('READ1NG OUT OF RANGE1); 

else do; 

if (sign flag = 1) 

then-call putchar('-'); 

call shift L4; 

call putchar(accum); 

call shift L4; 

cat L putchar(accurn>; 

call shift L4; 

call p~tchar(acc~m); 

call putchar('.'); 

call shift L4; 

cat 1 putchar(a~cum); 

call msg - hndlr('DEG C1); 

end; 

end; 

else call put - huh; 

end; 

else call put - huh; 

unsave reg; 

end put - temp; 

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

; This routine is where the actual look up and conversion to degrees of t 

; "raw A/D count" is accomplished. The final value is actually 10*Ts to 

; permit display of temperature to 1 decimal place. Only channels 36 and : 

; are considered valid. 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 27 

............................................................................ 

Pseudocode: 

find - temp: 

save regs; 

error flag = 0; 

sign Tlag = 0; 

- dot Fosition = 1; 

if ?(mem byte = $36) OR (mem - byte = $37)) 

t hen-do; 

mem byte = mem byte - $16; 

cnvF data = durnp arraytmem byte); 

cnvt-data = cnvt-data << 27 

cnvt-data = cnvt-data - 2560; 

if (cnvt data < 5) 

t hen-do; 

cnvt data = 2's comp (cnvt - data); 

sign-flag = 1; 

end; 

strobe watchdog timer; 

cnvt-data = cnvt data * 2092; 

cnvt data = cnvt-data / 10000; 

if (sign flag = 1) 

then-cnvt - data = 250 + cnvt data; - else do; 

cnvt data = 250 - cnvt data; - if (cnvt data < 0) 

t hen-do; 

cnvt data = 2's camp (cnvt - data); 

sign-flag = 1; 

end; 

else sign - flag = 0; 

end; 

end; 

else error - flag = 1; 

end find - temp; 

This routine sets the Time of Day counters to a new value (i.e. sets the 

clock). User input is checked for two types of errors: 1) if an entry 

is not between 0 and 9; and 2) if the hours value > 23 or the minutes 

value > 59. If error type 1 is encountered, an Er04 is signalled to 

the LCD or the messa'ge "Bad digit value for set tim\n" is sent to the 

terminal. If error type 2 is encountered, an ~705 is signalled to the 

LCD display or the message "Invalid hours/minutes value" is sent to the 

terminal. This routine has two entry points. Which one is used depends 

upon which input device generated the command, terminal keyboard, or 

front panel keypad. Although the pseudocode indicates 3 routines, the 

assembly code is actually 1 routine with 2 entry points. 

.......................................................................... 

eudocode: 

t-tim - term: 

, cf lag = 0; 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 28 

set tim10; 

end xet - Tim - term; 

set - tim - kybd: 

cflag = 1; 

set timl 0; 

end xet - Tim - kybd; 

- set - t iml : 

save regs:; 

i = 1 + cflag; 

minutes = 0; 

hours = 0; 

k = (hours << 8) OR minutes; 

do j = 3 to 0 step -1; 

if((command bufferfil < $30) OR (command bufferCi3 > 939)) 

then do; - 

if (cflag = 1) 

then call display error(#%04); 

else call msg hndTr('D1~1~ OUT OF RANGE1); 

goto set - time - don:; 

end; 

else do; 

k = k << 4; 

k = k OR (command - bufferfil - #530); 

i=i+1; 

end; 

end; 

minutes = k AND #fFF; 

hours = (k >> 8) AND #SFF; 

if ((hours > 23) OR (minutes > 59)) 

then do; 

if (cflag == 1) 

then call display error(tS05); 

else call msg - hndTr('1~~~11~ HOURS/PINUTES VALUE1); 

end; 

else do; 

timer csr = #SC3; 

t imer-csr = #S09; 

t imer-data = #800; 

timer-data = #SOO; 

timer csr = #$OA; 

timer-data = #S00; 

t'imer-data = #too; 

timer csr = #$43; 

timer-csr = #SOA; 

timer-data = minutes; 

timer-data = hours; 

timer-csr = #SOF; 

if ((Finutes >= #800) AND (minutes < #$30)) 

then do; 

timer data = #$30; 

t imer-data = hours; 

end; 

else do; 

timer - data = #SOO; 
'eb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 29 

timer - data = hours + 1; 

end; 

timer csr = #$43; 

timer-csr = #$OA; 

timer-data = #$00; 

timer-data = #$00; 

timer-csr = #%23; 

end; 

s~t - time - done: 

unsave regs; 

end - set - timl; 

........................................................................... 

This routine which can be called from both the front panel keypad and the 

serial port, sets the load shed threshold of the indicated Load to the 

level specified. 

........................................................................... 

seudocode: 

et - .load - shed: 

save regs; 

mern byte = command bufferC13; 

toaz num = a to h(gern byte); 

if (Ttoad nu; <y %FF>-AND (Load nurn <= 5) AND (load nurn <> 0)) - - then 30; 

crnd - out - ptr = .2; 

prcnt = find percent(); 

if (accum <>-SFF) 

then shed threshC2oad - num-13 = msbyte of prcnt; 

else ~all-~ut - huh; 

end; 

else if (kybd cmd flag = 1) 

then call-disElay huh; 

else call put - huh; 

unsave regs; 

end set - load - shed; 

............................................................................ 

This routine which can be called from both the front panel keypad and the 

serial port, sets the load restoration threshold of the indicated load to 

the level specified. 

seudocode: 

~t - load - restor: 

save regs; 

mem byte = command bufferfll; 

loaa nurn = a to hGem byte); 

if (Ttoad num <y $FF)-AND (load num <= 5) AND (load nurn <> 0)) - - then 30; 

cmd - out - ptr = 2; 

prcnt = find percent(); 

if (accum <>-SFF) 

then restor - threshfload - num-13 = msbyte of prcnt; 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 30 

else call put - huh; 

end; 

else if (kybd crnd flag = 1) 

then call-display huh; 

else call put - huh: 

unsave regs; 

end set-load-restor; 

.......................................................................... 

; This routine which can be called from both the front panel keypad and th 

; serial port, sets the initial battery state of charge to the Level spec 

.......................................................................... 

Pseudocode: 

set - init-soc: 

save regs; 

crnd out - ptr = 1; 

prcnt = find percent(>; 

if (accum <> SFF) 

then do; 

2 msbyte's of state of chg = prcnt; 

3 Lsbyte's of statemof-chg - - = 0; 

end; 

else if (kybd crnd flag = 1) 

then call-display huh; 

else cal t put - huh; 

unsave regs; 

.......................................................................... 

; This routine is used by the pervious 3 routines to convert the 3 characl 

; in the command buffer starting with the position pointed to by cmd - in - pi 

; into the fraction corresponding to the percentage of state of charge. 

; This value is returned in percent. For example, 

8 

I 100 percent results in a value of XlOOO 0000 0000 0000 

I 75 percent results in a value of XOllO 0000 0000 0000 

I 50 percent results in a value of XOlOO 0000 0000 0000 

I 25 percent results in a value of XOOlO 0000 0000 0000 

I 1 percent results in a value of XOOOO 0001 0100 0111 

8 

; If the 3 characters represent a value over 100% or contain digits over 

; 9, SFF is returned in the accumulator. 

.......................................................................... 

Pseudocode: 

find - percent: 

save regs; 

temp = cmd - out - ptr; 

cmd out ptr = cmd-out - ptr + 'I; 

mem-byte = getbyte(); 

if Tascii hex - flag = 1) 

then 30: 

mem - byte = d - to - h(mem - byte-); 
:eb 17 12:lf 1984 /u/tam/solar/PSEUDOCODE Page 31 

QWIG~P~AL ,p$i*$x 

mem byte = mem byte * 2; L~ POOR QUALITY 

if Tover 10 flaga= 0) 

t hen-do: 

if ((mem byte = 0) AND (command bufferCtemp3 = $31)) 

then-prcnt = percent tblt~~~l; 

else if ((mem - byte 0) AND 

(command bufferttempl = #30) 

then prcnt = percent tb-r~rnem - byte]; 

else accumulator = STF; 

end; 

else accumulator = SFF; 

end; 

else accumulator = SFF 

unsave regs; 

end find - percent; 

,--------------------------------------------------------------------------- ........................................................................... PERCENT TABLES FOR FIND - PERCENT ,--------------------------------------------------------------------------- ........................................................................... 

)ercent - tbl: 

.word $0000, $0147, S028F, S03D7, $051E, 

.word tOA3D, $0885, SOCCC, SOE14, $OF5C, 

.word $147A, $15C2, f170A, 51851, 51999, 

.word $1EB8, $2000, 52147, $228F, 523D7, 

.word S28F5, $2A3D, $2885, $2CCC, S2E14, 

.word $3333, S347A, 535C2, $370A, 53851, 

.word S3D70, S3EB8, $4000, $4147, $428F, 

.word $47AE, S48F5, $4A3D, $4885, $4CCC, 

.word $51EB, $5333, $547A, $55C2, S570A, 

.word 95C28, 85D70, $5EB8, $6000, 56147, 

.word $6666, $67AE, $68F5, S6A3D, 56885, 

.word $70A3, $71EB, $7333, $747A, S75C2, 

.word S7AE1, S7C28, S7D70, $7EB8, $8000 

............................................................................ 

: This routine, called every 100 msec. by the run task master, provides the 

' absolute values of battery V and total chgr - I for use by the max power 

I tracking routine as well as several otKers. ............................................................................ 

~bs cnvt: -. 

save regs; 

if (battery V < 0) 

then abz battery V = -battery V; 

else abs-battery-v = battery - v; 

if (total chFr I < 0y 

then abs total chgr I = -total chgr I; 

else abs-total-chgr-I - - - = total - chgr - y; 

unsave regs; 

end abs - cnvt; 

............................................................................ 

: This routine is called to dump the current total charger current as part 
Feb 17 12:17 1984 /u/tam/solar/PSE~D0CO~E Page 32 

; of the dump state routine. The put total I entry point is used by OU - - 

; data channeT and put data channel. 

........................................................................ 

Pseudocode: 

dump-totaL I: 

save regs; 

call msg - hndLr('T0T CHGR I ='I; 

~ut - total I: 

cxvt data = abs total chgr I; 

dec value = bf div10(7nvt - zata); 

if Ttotal chgr-I < 0) 

then call put - char('-'); 

call shift L4; 

cat 1 putchar(accum); 

call shift L4; 

cat 1 putchdr(actum); 

call shift L4; 

call putchar(accum1; 

call putchar('.') 

call shift L4; 

call putchar(accum>; 

call msg - hndLr('ampst); 

unsave reg; 

end dump - total - I; 

........................................................................ 

; This routine does a BRUTE FORCE divide by 1.0 (base 10) of the number i 

; cnvt data and returns the quotient in dec value because due to this cl 

; algorithm, it is also converted into deciFal at the same time(!). ALL 

; of this is necessary to convert the current in the form xx.xx to 0xx.x 

........................................................................ 

Pseudocode: 

bf - divl0: 

save regs; 

dec value = 0; 

do Fhile (cnvt - data > 1000 1; 

cnvt - data = cnvt data - S3E8; 

dec - value = dec - yalue + 100; 

end; 

do uhile (cnvt - data > 100 ); 

cnvt'data = cnvt data - $64; 

dec - value = dec - Lalue + 10; 

- end; 

do uhile (cnvt data - > 10 1; 

cnvt data = cnvt data - $A; 

dec - Falue = dec - yalue + 1; 

end; 

unsave regs; 

end bf - div - 10; 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 33 

XXXXXX 

X 

XXXXX 

X 

X 

XXXXXX 

XXXXX XXXXX XXXX X X 

X X X X X X XX XX 

X X X X X X XXXX 

XXXXX XXXXX X X X X 

X XXX X X X 

X X X XXXX X X 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 34 

....................................................................... 

; This routine, called at system reset, and from the serial port for te 

; will turn on all segments of the LCD display, all warning LED indicat 

; and the warning buzzer for a period of (about) 1 second. After the t 

; delay, the routine will return the LCD display, warning buzzer, and 

; indicator LEDs to their original state before this routine was called 

....................................................................... 

Pseudocode: 

lamp-test: 

save regs:; 

if ((compute - flags AND #run - flag) <> 0) 

then do; 

digitsf43 = #dspy - sync - ctrl OR #BOF; 

digitsf33 = #SFF; 

digitsC23 = #fFF; 

digits113 = #$FF; 

digitsf03 = #%FF; 

call display digits(); 

led out latex = stow - Leds OR #leds on; - 

disable-interrupts; 

kybd wr port = -(cbtumn - number AND #$OF) OR #bell - on; 

enabTe fnterrupts; 

do i = 2 to 0 step -1; /* uaste ' 1 second */ 

do j = 255 to 0 step -1; 

do j = 255 to 0 step -1; 

end; 

end; 

end; 

led out latch = stow - Leds; 

dissble-interrupts; 

if(alarm flags < 0) 

then-kybd wr port = -(column number AND #$OF) OR #bc 

else kybd-wr-port = '(column-number - AND #BOF); 

enable interrcpts; 

call display - hndlr0; 

end; 

unsave regs; 

end lamp - test; 

........................................................................ 

; his routine performs the "HULTIMETER FUNCTION". Five-of the front pi 

; display functions operate continuously like a multimeter. Each time t 

; routine is called, uhich is once every '100 msec , it reactivates the c 

; function whose starting address is stored in multimeter addr. If - 

; multimeter flag is zero, this routine is skirted. ......................................................................... 

Pseudocode: 
Feb 17 12:17 1984 /u/tam/soLar/PSEUDOCODE Page 35 

multimeter - func: 

save regs; 

if (multimeter flag = 1) - 

then do; 

call display - function @ multimeter addr; - end; 

unsave regs; 

end multimeter - func; 

......................................................................... 

; This routine "opens" memory at the indicated address and sends the 

; contents to the serial port, Successive CR's cause the next Location 

; be read, while 'I-" characters will back up to the previous location. 

; Any location can be changed by entering the neu data and hitting eithc 

; a CR or a "-". The CR will take you foruard, white the "-" will take 

; backwards. ........................................................................ 

Pseudocode: 

open - mem: 

save reos; 

cmd out ptr = 1; 

msbyte cf mem addr = getbyte0; 

if (ascii hex-flag = 0) 

then puT - hu5; 

else do; 

lsbyte of rnem addr = petbyte0; 

if (ascii hexWflag = 0) 

then p';;t - hih; 

else do; 

call show mem; 

do uhile (cntrl - z - flag = 0); 

do while (serial cmd flag = 0) 

strobe watchdog tTmer; 

end; 

serial cmd flag = 0; - 

mem byye = getbyte(); 

if ((ascii hex flag = 0) AND (command bufferr03 <> - 

then do; - 

call put huh; 

crnd out ptr = 0; 

commandLbuffer~03 - = 0; 

end; 

else do; 

if (command bufferC03 <>0) 

thQn memrmem - addr3 = mem - byte; 

if (Look bkuard = 1) 

then 20; 

look bkuard = 0; 

decr-mern addr; 

call shzw men; 

call 5sg - hTidtr(8~~~~8); 

end; 

else do; 

incr mem addr; 

~REC~~NG PAGE BLANK F~LME~ 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 36 

- call - show - mem; 

end; 

end; 

end; 

end; 

end; 

cntrl - z - flag = 0; 

unsave regs; 

end open - mem; 

- show - mem: 

call putbyte(mem addr+l); 

call putbyte(mem-addr); 

call putchar(' IT; 

mem byte = memrmem addrl; 

calT putbyte(mem - byte); 

cmd out ptr = 0; 

end - S~XW - mem; 

: This routine is called from the 4 MSec interrupt handler to control keyboa~ 

: scanning. If no key is pressed, reset the debounce counter and skip to thc 

: next keyboard column. If a key is pressed, decrement the debounce counter, 

: and if we've reached zero, interpret the key. After the key has been 

: interpreted, parse it: if it's a NAK (Control-U) clear the cmd in ptr; 

: if it's a NULL (EOF), null terminate the command buffer and seT tKe 

: kybd cmd flag bit; otherwise just shove the character in the command buffei 

: update txe cmd - in - ptr (adjust it for overflow if necessary) and continue 

: scanning. 

............................................................................ 

;can-kybd: 

save regs; 

row number = ('kybd rd port) AND $FO; - 

if Trow number = 0)- 

the; call no key pressed; 

bounce count = bzunce count -1; 

if (bounce - count <= 07 

then do; 

if ((i - o - flags2 AND #key - parsed flag) = 0) - 

t'hen do; 

i - o - flags2 = i - o - flags2 OR #key - parsed flag; - 

j = key intrpcrow - number); 

if (j <-01 

then do; 

if (j = $81) 

then column number = $01; 

call no - key - pressed(); 

end; 

else if (j = 0) 

then do; 

command bufferCcmd - in - ptrl = j; 

cmd in Ftr = j; 

i - o-flags = i - o - flags OR #kybd - cmd - flag; 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 37 

'end; 

else if (j = $15) 

then cmd - in - ptr = 0; 

else do: 

command bufferccmd in ptrl = j; 

cmd inptr = cmd ix pTr + 1; 

if Tcm7 in ptr =-$2b) 

the; do; 

call display huh; 

cmd - in - ptr =-0; 

end; 

end; 

end; 

end; 

unsave regs; 

end scan - kybd; 

no - key - pressed: 

i - o - flags2 = i - o - flags AND "#key - parsed - flag; 

bounce count = max bounce - count; 

column-number >> 1: 

if (co-rumn number = 0) 

then column number = $08; 

if (alarm flags-< 0) 

then To; 

kybd - wr - port = (('column - number) OR ($20 AND write - port - 

OR #be1 1 on; 

write - portb = ((-column - number) ZR ($20 & write - port - b)) 

OR #bell - on; 

end; 

else do; 

kybd - wr - port = (("column number) OR ($20 & write port b) 

write - portb = ((-column - ;umber) OR ($20 & write - port - F)l 

unsave regs; 

end no - key - pressed; 

........................................................................ 

; The following routine is called with a (hopefully) non-zero value in t 

; accumulator which represents the sensed keyboard row mask (in bits <7- 

; This row number and the corresponding column number are mapped into ar 

; index into an array of ASCII values. The appropriate ASCII value for 

; the key pressed is returned in the accumulator. If a zero row mask wa 

; provide to this routine, $80 is returned. If the column number was OL 

; of Its allowable range $81 is returned. If more than one key is press 

; (row mask has more than one bit set), the "first key" (first bit set) 

; is t.he one that is mapped to an ASCII value. The "#" key is mapped to 

; ~~~'ASCII value $00 so that it can easily be recognized--as the EOF 

; character. 

8 

; If the mapped ASCII value is a number (0-9) then the front panel displ 

; is updated by scrolling the new digit in from the right (least signifi 

; digit). If the "*" key was pressed indicating an operator entry error 

; we get real fancy and clear the display. 

Pseudocode: 
:eb 17 12:17 1984 /u/tam/soLar/PSEUDOCODE Page 38 

.ey - intrp: 

save regs; 

if ((j = row-maptva Lue >> 43) >= 0); /* j = $80 */ 

then do; 

j = j + cot mapCcotumn number]; 

if ((j = keybrd - map~j3-j- > 0); /* j = $81 or j = 0 */ 

then do; 

if (j = $151 

then do; 

do i = 3 to 0 step -1; 

display wordCi3 = #880; 

display-wordC43 = 0; 

call diyplay - hndlr; 

end; 

else if (cmd - in - ptr = 0) 

then do; 

do i = 2 to 0 step -1; 

display wordCi3 = #$SO; 

muttimeTer - flag = 0; 

end; 

k = keybrd hexCy3; 

do i = 3 t< 0 step -1; 

display wordCi3 = display - wordCi-17; 

di spl ay-wordC03 = k; 

display-word~43 = 0; 

call display - hndlr; 

end; 

end; 

end; 

end; 

unsave regs; 

end key - intrp; 

........................................................................... ........................................................................... KEY - INTRP TABLES ........................................................................... ........................................................................... 

The following array provides the mapping for converting the sensed keyboard 

row number into the next Level array index. This array also performs the 

function of finding the "first set bit" (in case multiple keys are pressed) 

and returns an error value ($80) for no key pressed at all. 

ow-map: 

.byte $80,503,$02,$02 

.byte $01,501 ,SO1 ,SO1 

.byte ~00,500,$00,~00 

.byte $00,500,$00,$00 

The following array provides the mapping for converting the "column scanned 

mask into an array index that can be added to the index from the row map 

in order to find out which one key has been pressed. For index valuFs 

into this array that have none or more than one bit set, a 'lnext-LeveL" 

index is returned that will map into an invalid ASCII key value (i.e. 

the key will be $81). 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 39 

cot - map: 

.byte $10,$OC,$08,$10 

.byte ~04,~10,$10,$10 

.byte $00,$10,$10,$10 

.byte $1 0,$10,$10,$10 

I 

; This array is the one that actually produces an ASCII value corresponc 

; to the key pressed. It also produces error indications for malformed 

; column scan values. 

I 

keybrd - map: 

.byte $44,$43,$42,$41 ; "D","C","BH,"A" 

.byte $1 5,$37,$34,$31 ; "*" I "7","4","lW 

.byte $81,$81,$81,$81 ; Column scan error return 

I 

; This array is analagous to the one above except that it contains hexac 

; values of the keys pressed to speed up the display update function. : 

; having to convert ASCII back to HEX. 

I 

keybrd - hex: 

.byte $OD,$OC,$OB,SOA 

.byte $00,$09,$06,$03 

.byte $00,$08,$05,$02 

.byte $00,$07,$04,$01 

........................................................................ 

; This routine tests for rcve and xmit interrupt condx from the serial i 

; port, services all valid ones and aborts if none exist. This routine 

; not a true subroutine, in that, it Lies "in-Line" as part of the over; 

; IRQ service routine which also includes break. 

I 

I It supports such user amenities as: 

I 

I 1. ^H, del, backspace - delete last character 

8 

I 2. ^U - "flush" command - buffer 

I 

I 3. adds a LF whenever a CR is received 

I 

I 4. ^Z - return to cmd - intrp 

I 

- 5. "-11 - 8 used to "backup" when using the open memory 

I command in the monitor 

I 

; UpeR receipt of a CR, a LF is sent out, and the serial Zmd flag is set - - 

; All spaces are deleted as they are input. 

I 

; The command buffer is assumed to be 32 bytes Long and linear, i.e. the 

; pointers must be zeroed when the data has been used by the called func 

........................................................................ 

Pseudocode: 

serial - port: 
Feb 17 12:17 1984 /u/tarn/solar/PSEUDOCODE Page 40 

save regs; 

uart-status = pia portb; 

if (uart status AKD bit 7 <> 0) 

t hen-do; 

cntrl - z - flag = 0; 

char = uart; 

if (char < $20) 

then do; 

if (char = $08 OR char = $7F) 

then do; 

call msg hndlr('^H ^H'>; 

cmd - in - ptr = cmd - in - ptr - 1; 

end; 

else if (char = $OA OR char = $OD) 

then do; 

call putchar('CR1); 

call putchar('LF1); 

command bufferrcmd in ptrl = 0; - - cmd in ptr = 0; 

serial-crnd - - flag = 1; 

end; 

else do; 

call putchar('^'); 

char = char + $40 ; make it printable 

cat 1 putchar(char1; 

if (char = $15) 

then do; 

cmd in ptr = 0; 

calT pctchar('~~'); 

call putchar('LF1); 

call putchar('*'); 

end; 

if (char = S1A) 

then do; 

cntrl - z - flag = 1; 

call putchar('CRt); 

call putchar('LF1); 

end; 

end; 

end; 

else do; 

call putchar(char1; /* echo the character */ I command bufferCcmd in ptr3 = char; 

crnd in ptr = crnd iT pTr + 1; 

if Trnuitimeter fiag-= 1) 

then rnultiGeter addr = @display - default - 1; 

if (char = f2D) then Look bkward = 1; - 

end; 

end; 

if (uart status AND bit 6 <> 0) 

t hen-do; 

if (byte count <> 0) 

t hen-do; 

usrt = output bufferrput - out3 

put OU~ = putrout + 1; 

decT byte - count; 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 41 

end; 

else disable xmit ints; 

end; 

unsave regs; 

end serial - port; 

........................................................................ 

; This routine services the BREAK instruction trap and the IRQ interrup 

; It determines which of the two it was that vectored the CPU to this 

; routine. If it was a breakpoint, it continues, if an IRQ occurred in 

; control is passed to serial port for servicing. 

........................................................................ 

Pseudocode: 

break: 

if (B flag <> 1) then go to serial - port; 

eise do; 

x reg stor = contents of X reg; 

accum-stor = contents of accumulator; 

flags-stor = psw popped off stack; 

y reg-stor = contents of Y reg; 

pop "useless" PC off stack; 

pc stor = brkpt addr; 

sp-stor = contezts of the stack pointer; 

caTL msg hndlr ('PC = '1; 

call put'l;yte (msbyte of pc stor); 

call putbyte (Lsbyte of pc-stor); - 

call msg hndlr (' A = '1; 

call putFyte (accum - stor); 

call msg hndlr (' Y = '1; 

call putgyte (y reg - stor); 

call msg hndlr 71 X = '1; 

call put%yte (x reg - stor); 

call msg hndLrT1 SP = '1; 

call putKyte (sp stor); 

call msg hndlr (' P = '1; 

call put6yte (flags stor); 

call msg hndlr ('cR~F'); 

cat 1 rem-brkpt; 

enable interrupts; 

go to run - 'task - master; 

end; 

end break; 

........................................................................ 

; hi$ routine begins execution at the current user PC location or at tl 

; location specified in the command buffer, if any. A, X, Y, P, and S i 

; always loaded from their respective storage Locations. ........................................................................ 

Pseudocode: 

go: 

cmd out ptr = 1; 

if Tcommand - bufferC13 <> 0) 
Feb 17 12:17 1984 /u/tam/soLar/PSEUDOCODE Page 42 

then do; 

msbyte of pc stor = getbyte0; 

if (ascii hey - flag = 0) 

then do: 

cmd out ptr = 0; 

catT put huh; 

go to en3 go; 

end; 

Lsbyte of pc stor = getbyte0; 

if (ascii hey - flag = 0) 

then do: 

cmd out ptr = 0; 

cati p~T - huh; 

go to end go; 

end; 

end; 

unsave 8 addresses and regs saved by cmd intrp; - 

cmd out ptr = 0; 

stack pzinter = sp stor; 

X reg = x-reg - stor: 

Y reg = y-reg-stor; 

accumulator = msbyte of pc - stor; 

push accumulator; 

accumulator = Lsbyte of pc - stor; 

push accumulator; 

accumulator = flags - stor; 

push accumulator; 

accumulator = accum - stor; 

rti 

end go; 

............................................................................ 

: This function places a "BRK" opcode ($00) at the address specified in the 

; command buffer. Only one breakpoint is supported. The replaced opcode is 

; stored in rep - opcode. The breakpoint address is stored in brkpt - addr. 

............................................................................ 

;et - brkpt: 

save regs; 

cmd out ptr = 1; 

msbyte of brk,pt addr = getbyte0; 

if (ascii hex fTag = 0) 

then cail - huh; 

else do; 

tsbyte of brkpt addr = getbyte0; 

if (ascii hex fiag = 0) 

then caT~ - huh; 

else do; 

rep opcode = mentbrkpt - addr3; 

memybrkpt - addr3 = 0; 

end; 

end; 

unsave reg; 

end set - brkpt; 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 43 

......................................................................... 

; This routine returns the opcode that was replaced with the "BRK". It 

; be called by the user and also the break subroutine. 

......................................................................... 

Pseudocode: 

rem - brkpt: 

save regs; 

memtbrkpt - addrl = rep - opcode; 

unsave regs; 

end rem - brkpt: 

........................................................................ 

; This 'routine set the dump state flag to initiate dump state from the - 

; serial port or the front panel reypad. 

........................................................................ 

Pseudocode: 

set up dump-kybd: 

set-upIdump: - 

save regs; 

dump - state - flag = 1; 

unsave regs; 

end set-up-dump; 

........................................................................ 

; This routine, called from the front panel keypad, clears the valid - pas 

; flag. ........................................................................ 

Pseudocode: 

ki L L - password: 

save regs; 

valid - password = 0; 

unsave regs; 

end ki 11 - password; 

........................................................................ 

; This routine is called via the serial port and the hex keypad and "tog 

; the-state of the run-bit so that the system alternates between RUN and 

; TEST/CALIBRATE modes. 

........................................................................ . . .. . . - - - 

Pseudocode: 

toggle - run - bit: 

save regs; 

compute - flags = compute - flags XOR run flag; - 

unsave regs; 

end toggle - run - bit; 
Feb 17 12:17 1984 /u/tam/soLar/PSEUDOCODE Page 44 

; This routine is called whenever the dump state flag is set to dump out the 

; "state of the machine" to the serial pory. he output is composed of the 

; contents of the dump array with each element converted <nto the appropriatt 

; units. The format fzr the output is as follows: 

8 

I TIME: hh:mm 8 EOO = XXX.X VOLTS IOO = XXX.X AMPS 

8 ED1 = XX.XX AMPS 101 = XX.XX AMPS 

I E02 = xx.xx AMPS I02 = xx.xx AMPS 

? E03 = xx.xx AMPS I03 = xx.xx AMPS 

r E04 = xx.xx AMPS I04 = xx.xx AMPS 

r E05 = xx-xx AMPS I15 = xx.xx AMPS 

r E06 = XXX.X VOLTS 106 = XXX.X VOLTS 

r E07 = xxx.x VOLTS I07 = xxx-x VOLTS 

r EOB = XXX.X VOLTS 108 = XXX.X VOLTS 

E09 = xxx.x VOLTS I09 = xxx.x VOLTS 

El0 = xxx.x VOLTS I10 = xxx.x VOLTS 

E31 = xxx.x VOLTS 131 = xxx.x VOLTS 

E32 = xxx.x VOLTS I32 = xxx.x VOLTS 

E33 = xxx.x VOLTS I33 = xxx.x AMPS 

E34 = xxx.x AMPS I34 = xxx.x AMPS 

E35 = xxx.x AMPS I35 = xxx.x AMPS 

036 = xxx.x DEG C D37 = xxx.x DEG C 

E38 = x.xxx VOLTS E39 = x.xxx VOLTS 

DO0 = xxxX D40 = xxxX D41 = xxxX D42 = xxxX 

S1-1 S2-0 L1-1 L2-0 L3-1 L4-0 L5-1 L6-0 

Al-1 A2-1 A3-1 A4-1 A5-1 A6-1 81-1 82-1 83-1 84-1 85-1 86-1 

TOT CHGR I = xxx.x AMPS NOTE: 1=ON, O=OFF 

Each line is formated and placed into the serial output buffer. The 

routine is called again when the buffer is empty. When all of the data 

has been transmitted, the dump state flag and valid password are both 

cleared. In addition, the add-Fess 07 the proper display default routine 

is loaded into multimeter addr, the channel data (in ascii), if needed, 

is loaded into multimeter-data and finally, the multimeter flag is set. 

Every one second after thTs, the indicated display routine-is re-initiated. 

........................................................................... 

seudocode: 

ump - state: 

save regs; 

if (cntrl - z - flag = 1) then goto cntrl - z - crash; 

if (dump channel = 0) then call zut - time; 

dump couKt = 0; 

do uFile ((dump count <= 1) AND (dump - channel < soc - channel num)); - 

accum = LabTl listfdump - channel]; 

cat 1 putchar(icc~m); 

mem byte = user ch tablefdump - channel]; 

calT putbyte(mem byte); 

call msg hndlr('-= '1; 

conv dump addr = conv dump tabLeCdump - channeL*23; 

call-convert and output roctine; 

dump - channel-= dump - channel + 1; 

end; 

if (dump - channel = soc - channel - num) 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 45 

then do; 

call dump soc; 

call dump-sw - states; 

call dump arrays; 

call dump-total I; - 

call msg - Fnd~r(~ NOTE: 1=ON, O=OFF1); 

- 'cntrl - z - crash: 

dump channel = 0; 

dump-state flag = 0; 

vali3 passiiord = 0; 

multi6eter flag = 1; 

multimeter-addr = @display - default - 1; 

call putch<r('~~'); 

call putchar('LF1); 

call putchar('*'); 

end; 

else do; 

call putchar('CR1); 

call putchar('LF1); 

end; 

unsave regs; 

end dump - state; 

.--------------------------------------------------------------

--------------------------------------------------------------------

I 

I DUMP - STATE LOOKUP TABLES .----------------------------------------------------------------

....................................................................... 

Label - List: .ascii M~~

user - ch - table: 

.byte $00, $00, $01, $01, $02, $02, $03, $03, $04, $04, $05, I 

.byte $06, $06, $07, $07, $08, $08, $09, $09, $10, $10, $31, 4 

.byte $32, $32, $33, $33, $34, $34, $35, $35, $36, $37, $38, 3 

conv - dump - table: 

NOTE: The -1 in each of the following is due to a peculiarity 01 

6502. Namely that the address stored on the stack during a jsr 

1 LESS THAN the return add~ess. So in order to use the stack ar 

RTS to impliment an indirect JSR, the address stored in the tab1 

must conform to this rather "arbitrary" condition. 

.word - .word 

. wo r d 

-. . wo rd 

.word 

.word 

.word 

. word 

.word 

.word 

.word 

.word 

. word 

.word 

dump volts - 1 

dump-amps - 1 

dump-volts - 1 

dump-amps - 1 

dump-volts - 1 

dump-amps - 1 

dump-volts - 1 

dump-amps - 1 

dump-volts - 1 

dump~amps - I 

dump volts - 1 

dump~amps - 1 

dump-volts - 1 

dump - amps - 1 
>m>m>m>m>m>m>a>m>mt't'>> 

llllllllllllllilllllll 

EEEEEEEEEEEEEEEEEEEEEE 

annnnaananannnnana~nnn 

r 

OI 

00 

UUUUUUUUUUUUUQUUDUUUUU 

h LLLLLLLLLLLLLLLLLLLLLL 

w 

* I 

* mt' 

* t' 

* mc 

* U.r 

* 

* 

'4-u 

* OaJ * C * aJ *r 

* 

*t'm 

At' 

* 

*nc 

0 

* 

*mu 

aJ * .r aJ 

* 

C'4-L .r m 

* 

*WE 

* 

n3 

* at' * m 

* mT] 

* 

* J= aJ 

* +'I 

* .r t' 

* 3 * -0 

* 

*urn 

*EC 

a * u, 

* Ccn 

C .r aJ 

* L 

* cu * 0-0 

* .r m 

* m * aJm * LC 

* 'f- 

* 

*uu 

UC 

* .r Q, 

* 't 

* .r QI 

* ur 

* at' * a 

* 

*In\ 

U) 

* InU) 

* aJ 

C'rU 

*dm 

CdL 

a 

* 

*'tmL 

aJ * aJ m't * CCU- * .r .r 3 

* 

ct'crn 

3L 

c omu 

* Lt'C 

* cnm 

*In E 

C'raJ E 

+ rr o * I-C u 

- 

* - - . . . . . - . 

.5 

A= 

3 

I 

I 

+.' 5 

3 n

a u

aJ

es--' t' 

n X

11

aJU +

t' aJ

XC cn 

n aJ 

t' 11 

0, t' 

0, L

n u 

110 ur

m

L II d 

u t"4

730, L 

mm (D

mb t'Q

rt"4- c0

1, 

11 mx 't

t' 0, 0.

L U)Z 

*bC, I.* aJ 

v, n'4--r ow 

0, l0.r -0 X

0 n 

L3aJInQ,tn

OW m u,-'.+- 

(1, Ix-d .. >un a, 

aJ m E In+ 

u In U E.r 

u 

0 

U 

0 

.' 

3 - 

aJ 2 

U) *r 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 47 

. else do; 

do while (ending addr - start - addr >= 01 

memrstart addr? = mem - byte; 

incr starT - addr; - 

end; - 

end; 

end; 

end; 

end; 

end; 

end; 

cmd - out - ptr = 0; 

unsave regs; 

end fill; 

; This routine handles the storage function of data which is downloaded 

; another computer via a serial link. The selected download format is 1 

; used with the DATA 1/0 PROM Programmer, i.e.: 0. 

I ^B$Acaddress>, XX XX XX XX XX ...^ CS<checksum>,zzzzzzzzztz 

where 1. XX = ascii encoded hex digits 

2. address and checksum are represented ir 

I hex digits 

I 3. the acceptable delimiters are space, Cf 

I LF. 

I 

; In order to maintain as much universality as possible, it is desireabl 

; make the routine independent of interrupt service routines which may i 

; buffers of undefined form. Hence, IRQ's are disabled for the duratior 

; the down Load. 

Pseudocode: 

dwnld: 

turn off interrupts; /* this routine uses potted ACIA only *r 

checksum = 0; 

first nyb flag = 0; 

error-f tag = 0; 

char = p getchar0; 

do while-(char <> $02); /* look for ^B */ - char = p getchar0; - 

end; 

do white ((char <> $03) AND (error flag = 0)); /* Look for ^C i - 

- if (char = '3') - 

then do; 

char = p getchar0; 

do white-(char <> 'A'); 

char = p - getchar0; 

end; 

mem addr = p - getword0; /* get the address */ 

offset = 0; 

call p - getcomma0; /* get the comma */ 

end; 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 48 

else do; 

if (char <> SOA) OR (char <> SOD) OR (char <> ") 

then do; 

if (first nyb - flag = 0) 

then 30; 

nybble 1 = a to - h(char); 

if (ny'f;ble I-= BFF) then error - flag = SF 

first - nyb - ilag = $FF 

end; 

else do; 

nybble 2 = a to - h(char); 

if (nyFble 2-= BFF) then error - flag = $F 

byte = nybEle 1:nybble - 2; 

memf mem addr3-= byte; 

checksu; = checksum + byte; 

first nyb - flag = 0; 

mem - azdr = mem - addr + 1; 

end; 

end; 

end; 

char = p - getchar(); 

end; 

if (error flag <> 0) 

then call p - msg - hndlr('bad - datav) 

else do; 

char = p getchar(); 

do while-(char <> 'S'); /* look for the S */ 

char = p - getchar0; 

end; 

xmt chk sum = D aetword0: ' -" 

if Tchecksum <> xmt chk s;m) 

then call p - msg-hndTr('~~D - RUN'); 

else call p-msg-hndlr('~~~~ - - RUN'); 

end; 

end down load; 

............................................................................ 

; This routine obtains the current version number of this software, and 

; transmits it to the serial port. 

I IMPORTANT: the assumption is that the version number is always 

8 two BCD digits of the form H.N ............................................................................ 

Pseudocode: 

put-version: 

save regs; 

accum = (version num AND $FO) >> 4; 

call putchar(acc~m): 

call putchar('.'); 

accum = version num AND $OF; 

call putchar(accum>; 

unsave regs; 

end put - version; 
Feb 17 12:17 1984 /u/tam/so lar/PSEUDOCODE Page 49 

; This routine obtains the current version number of this software, and 

; displays it, properly formatted on the hexpad display panel. 

I 

I IMPORTANT: the assumption is that the version number is always 

I two BCD digits of the form M.N - ........................................................................ 

out - version: 

save regs; 

display wordC41 = 3; 

display-wordC31 = (version num AND SF01 >> 4; 

display-wordC21 = version - :urn AND $OF; 

display-wordC13 = $80; 

di splay-wordC01 = $80; 

call display - hndlr; 

unsave regs; 

end out-version; 

........................................................................ 

; This is a 8 x 8 multiply similar to mp mult except used only for sing1 

; precision multiplication. The multiplyer is loaded into sp multl, the 

; multiplicand in sp-muLt2 and the 16 bit product is returned-in sp proc 

;******************************************************************T**** 

Pseudocode: 

sp - mutt: 

save regs; 

msbyte of sp - mutt2 = 0; 

sp-product = 0; 

do i = 0 to 7; 

sp multl = sp multl >> 1; 

if-(carry = 17 then sp product = sp - product + sp - mult2; 

sp - mutt2 = sp-mutt * 27 

end; 

unsave regs; 

end sp - mutt; 

........................................................................ 

; This routine sets the duty cycle of the selected PWM timer to the desi 

; value. The value input by the user is given as a %-age duty cycle, wi 

; the input %-age being the "time high". The value for selecting the ti 

- ; can-be either "1" or "2". If invalid entries are made, error messages 

; ar.e sent to the terminal. ........................................................................ - 

- 

Pseudocode: 

set - duty - cycle: 

save regs; 

if ((command bufferC13 < #$31> OR (command bufferr13 > #$32)) 

then cali msg hndlr('D1GIT NOT 1 OR 2'y; 

else do; 

temp = command - bufferC13 - #$31; 

11-70 
Feb 17 12:17 1984 /u/tam/soLar/PSEUDOCODE Page 50 

cmd - out ptr = 2; 

x = getLyteO; 

if ((i o flags & #ascii hex flag) = 0) 

thPn-call msg - hndlrT'~1-dI~ OUT OF RANGE 0-FBI; 

else do; 

y = d to h(x) * 2; 

if ((compute flags & #over 10 flag) != 0) 

then calT msg - hnd~r(~~r~1i OUT OF RANGE 0-9'); 

else do; 

if (y > #$AE) 

then call msg hndLr('DUTY CYCLE VALUE OUOF RANGE 0-87%'); 

else do; 

timer csr = #SEO; 

if (tFmp == 0) 

then do; 

timer csr = #$C4; 

timer-csr = #SOB; 

timer-data = duty low tblCy7; 

timer-data = d~t~-low-tbl~~+

timer-data = duty-hi tblCy3; 

pwm value = duty Ti T~Lc~J; 

timer - data = duty - hT - ~~L[Y+IJ 

timer csr = #SE3; 

timer-csr = #524; 

end; 

else do; 

timer. csr = #SC8; 

timer-csr = #%OC; 

timer-data = duty Low tbLCy3; 

timer-data = duty-tow-tbl~y+l 

timer-data = duty-hi - Tblry3; 

timer-data = duty - hi - tbLCy+l3 

timer-csr = #$E4; 

timer-csr = #$28; 

end; 

unsave regs; 

end set - duty - cycle; 

........................................................................... ........................................................................... PERCENT DUTY CYCLE TO PWM COUNT TABLE ........................................................................... ........................................................................... 

uty - Lo - tbl: 

.byte $C6,~00,~C6,$00,~C4,~00,$C2,~00 

.byte $CO,$OO,$BE,$OO,BBC,~OO,$BA,~OO 

.byte ~B8,$00,$B6,$00,$~4,$00,!b~2,~00 

.byte $BO,SOO,%AE,~OO,$AC,~OO,$AA,~OO 

.byte %A8,$00,SA6,$00,$A4,$00,~~2,SOO 

.byte $A0,%00,S9€,$00,~9C,$00,$9A,$00 

.byte $98,$00,~96,~00,$94,$00,$92,~00 

.byte $90,~00,%8E,$00,$8C,~00,$8A,$00 

,byte $88,~00,$86,$00,$84,$00,~82,$00 

.byte $80,$00,$7E,$00,$7C,$OO,$7~,$00 

.byte $78,$00,~76,$00,~74,~00,~72,~00 

.byte $70,$00,$6E,$00,$6~,~00,$6~,$00 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 51 

duty - hi - tbl: 

.byte 

.byte 

.byte 

.byte 

.byte 

.byte 

.byte 

.byte 

.byte 

.byte 

.byte 

.byte 

.byte 

.byte 

.byte 

.byte 

.byte 

.byte 

.byte 

.byte 

.byte 

.byte 

........................................................................ 

; This routine, called from either the terminal or the front panel keypt 

; allows the user to set and clear individual bits that control various 

; "devices". These devices are divided into various "classes" which del 

; which section of code handLes the device specific functions. The "deb 

; which can be controlled include the audio buzzer, the warning LEDs, tt 

; user's load requests, the PWM control ports, and the load current over 

; trip control bits. 

I - 

I device 0 audible alarm 

I device -1-6 user load requests 1 thru 6 

I device 7-11 overload trip resets for eoads 1 thru 5 

t device 12-17 PWM buffer #I controls 1 thru 6 

I device 18-23 PWM buffer #2 controls 1 thru 6 

I device 24-25 Yellow, and Red LEDs 

I 

; If a digit out of the range of 0 to 9 is entered for either digit of t 

; bit number or out of the range 0 to 1 for the desired state (I=ON>, or 

; the bit number exceeds 25, then an appropriate error message is sent t 

; controlling 110 device (terminal or keypad). In addition, if the user 

; attempts to set a bit in the range 6 - 10, the equivalent of "tripping 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 52 

; a Load's circuit breaker, a wa-rning message is displayed and no action is 

; taken. 

..........................................................................

Pseudocode: 

set - bit: 

save regs; 

if((command - bufferC13 < $30) OR (command bufferC13 > $39)) - then do; 

if (command bufferC03 = 'D') 

then calT display error(#804); 

else call msg hndTr('D1~1~ OUT OF RANGE 0-9'); - end; 

else do; 

sb temp = command bufferr11 << 4; 

ifT(command - buffeTC21 < $30) OR (command bufferr27 > $39)) - 

then do; 

if (command bufferr03 = 'Dm) 

then catT display error(#$04); 

else call msg - hndir('~1~1f OUT OF RANGE 0-9'); 

end; 

else do; 

sb temp = sb temp OR (command bufferr23 AND #$OF); 

if-( (command-buf f err31 < $30)-OR 

(command - bufferC33 > $31)) 

then do; 

if (command bufferr03 = 'Dl) 

then calT display error(#SO?); 

else call msg - hndir('~1~1~ NOT A '1' OR '2"); 

end; I 

else do; 

if (command bufferr31 = $30) 

then cfTag = 0; 

else cflag - = 1; 

if(sb - tem~ >= max num devs) 

then do; 

- - /* max - num - devs = #526 *I 

if(command bufferr03 = ID') 

then caTt display error(#S09); 

else call msg - ~~~T~('INVALID DEVICE NUMBER 

end; 

else do; 

if (sb temp >= $20) 

thFn sb temp = sb temp - #$OC; 

else ifTsb temp >: $10) 

then do: 

sb-temp = sb temp - #$06; 

sb - temp = sbmtemp << 1; 

i = sb msk tglrsb temp]; 

j = sb-msk-tbl+l[Tb - - - temp]; 

switch (j); 

case 0: 

if (cflag = 1) 

then alarm flags = alarm flags OR i; 

else alarm-flags = alarm-flags AND "i; 

11-73 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 53 

break; 

case 1: 

if(cf1ag = 1) 

then user Ld reg = user Ld req OR -i; 

else user-ld-req - - = user-ld-req - AND -i; - break; 

case 2: 

if (cflag = 1) 

then do; 

ovrld trip = ovrld trip AND "i; 

ovrld-cnt = ovrld cnt max(sb temp - 7); - - - i = #gnable bell; 

alarm - flags-= alarm - flags AND 'i; 

end; 

else do; 

if (command bufferC03 = 'D') 

then catT display error(#$08); 

else call msg hndir('c~~'~ TRIP OVERLOAD - PROTECTOR'); 

end; 

break; 

case 3: 

ifccflag = 1) 

then call cntrl pwm output(i OR #$80); 

else cat 1 ~ntrl-~wm-out~ut(i); - - break; 

case 4: 

if(cf1ag = 1) 

then stow - leds = stow leds OR i; - 

else do; 

stow leds = stow leds AND 'i; - 

led - out - latch = stow leds; - 

end; 

break; 

end; 

end; 

end; 

end; 

unsave regs; 

end set - bit; 

._-------------------------------------------------------....................................................................... 

P SET BIT MASK TABLE .___----------------------------------------------------

..................................................................... 

sb msk tbl: - .- . . 

= .byte 

.byte 

.byte 

.byte 

.byte 

.byte 

.byte 

.byte 

.byte 

.byte 

$80,$00 ; audio buzzer, Class $0 1- 

$08,$01 ; User load requests 1 - 6, Class 1 

$10,$01 

$20,$01 

$40,$01 

$80,$01 

$04,$01 

$08,$02 

$10,$02 

$20,$02 

; Overload trip controls 1- 5, Class 2 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 54 

$40,$02 

$80,$02 

$00,1603 ; PWM Control arrays 1 & 2 (6 outputs each) 

501,503 ; Class 3 

802,$03 

$03,$03 

$04,$03 

$05,$03 

$06,$03 

$07,$03 

$08,$03 

$09,$03 

$OA,$03 

$OB,$03 

$01,$04 ; LED controls (YelLow,Red) Class 4 

$02,$04 

............................................................................ 

; This routine takes as its input the contents of the accumulator and 

; sets or clears the selected PWM control output bit. The contents of 

; the accumulator are encoded as follows: Bit 7 is a "1" if the PWM control 

; bit is to be set, a "0" if the PWM control bit is to be cleared. its 0-3 

; are the number (or "address" if you will) of the bit to be set/cleared. 

; Values between 800 and $05 are in PWM control array 1, and values between 

; $06 and SOB are in PWM control array 2. The bit number is used as an 

; index into the array pwm msk tbl whose entries are the bit pattern to 

; be used in turning on or-off-the PWM control. In addition, if bit 7 of thc 

; pwm-tbl-msk array entry is on then the mask is for PWM control array 2. 

............................................................................ 

Pseudocode: 

cntrl-pwm - output: 

save regs; 

i = pwrn msk - tblfvalue AND #$OF3 

if (i > 0) 

then do; 

if (value < 0) 

then do; 

stow pwml = stow pwml OR i; 

array - sell = stoc - pwml; 

end; 

else do; 

stow pwml = stow pwml AND "i; 

array - seI.1 = sto';; - pwml; 

end; 

end; 

else do; 

i = i AND #$7F; 

if (value < 0) 

then do; 

stow pwm2 = stow pwm2 OR i; 

array - set2 = sto; - pwm2; 

end; 

else do; 

stow - pwm2 = stow - pwm2 AND -i; 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 55 

array - set2 = stow - pwm2; 

end; 

end; 

unsave regs; 

end cntrl - pwm - output; 

.-------------------------------------------------------------

----------------------------------------------------------------------. 

- - I PULSE MASK TABLE FOR CNTRL - PWM - OUTPUT .---------------------------------------------------------------

--------------------------------------------------------------

pwm - msk tbt: - 

.byte $01,$02,$04,$08,$10,$20 

.byte $81,$82,$84,$88,$9O,$AO 

; This routine converts the AID reading in frez temp into a "%-age coldr 

; product, which is an indication of the state of the freezer load. 

........................................................................ 

Pseudocode: 

find - prod: 

save regs; 

if (frez tempt13 < 0) 

then-i. = 0; 

else do; 

i = frez tempt13 >> 1; 

save flags; 

i = i >> 1; 

save flags; 

i = (frez tempt01 >> 3); 

unsave flZgs; 

if (carry bit = 1) 

then i = i OR $40; 

unsave flags; 

if (carry bit = I) 

then i = i OR $20; 

i = i - $50; 

if (i C 0) 

then i = 0; 

else if (i > $35) 

then i = $35; 

end; 

prod = p~od - pct - tblCi1; 

- unsave regs; 

end find - prod; 

% ,-------------------------"-"---------------------------------------------- .----------------------------------------------------------

I PERCENTAGE OF PRODUCT TABLE FOR FIND-PROD 

,----------------------------------------------

.----------------------------------------------------------

prod - pct - tbt: 

-byte 2, 4, 6, 8, 10, 12, 14, 16, 20, 22, 24, 26 

-byte 28, 30, 32, 34, 36, 40, 42, 44, 46, 48, 50, 52 

.byte 54, 56, 60, 62, 64, 66, 68, 70, 72, 74, 78, 80 

-byte 82, 84, 86, 88, 93, 92, 94, 98, 100, 102, 104, I06 
Feb 17 l2:17 1984 /u/tam/solar/PSEUDOCODE Page 56 

............................................................................ 

; This routine, called on a one second interval, tests to see if any of the 

; string currents have fallen below a specified level, i.e. if the following 

; expression is false for any of the strings, then the string fault flag is - 

; set. 

r 

: branch current(N1 >= (total chgr I/number of strings) - str fault offset 

.............................................................................. 

'suedocode: 

:est - string - I: 

save regs; 

lsword of dividend = total - chgr - I; 

msword of dividend = 0; 

lsbyte of divisor = num - pwr - strings; 

msbyte of divisor = 0; 

quotient = mp - div0; 

x = 0; 

quotient = quotient - str fault offset; 

do while ((x < num - pwr - S~~~~~S)-AND (branehlC x 3 >= quotient)) 

x=x+l; 

end: 

if (X = num pwr strings) 

then stFing-fault = 0; 

else string-fault = 1; 

unsave regs; 

end test - string - I; 

This routine handles the dumping of state of chg, corrected state of charge - - 

equalization count and pwm value for the Jump state routine, 

***************************T*********************************************** 

seudocode: 

ump-sac: 

save 

call 

call 

call 

call 

call 

call 

call 

call 

call 

cat 1 

call 

call 

call 

call 

call 

regs; 

putchar('D1); 

putbyte(S00); 

msg hndlrc' = '1; 

put~soc; 

putchar(S20); 

putchar(S20); 

putchar('DS); 

putchar(S40); 

msg - hndlr(' = '1; 

put-csoc; 

put char(S20); 

putchar(S20); 

putchar('D'); 

putchar(S41); 

msg - hndLr(" '1; 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 57 

call put equal; 

call putFhar($2~); 

call' putchar($20); 

call putchar('D8); - 

call putchar($42); 

call msg hndlr(' = '1; 

cat 1 put-pwm; 

call putchar(l~~'); 

-. call putchar('LF1); 

unsave regs; 

end dump - soc; 

........................................................................ 

; This routine handles the dumping of the switch and load states for thc 

; dump state routine. ........................................................................ 

Pseudocode: 

dump - sw - states: 

save regs; 

call putchar('S1); 

call putchar('1 '1; 

accum = alarm 30 - AND inhibit - bit; 

call put on; 

call putchar('~l); 

call putchar('2'); 

accum = alarm - 30 AND motor - temp; 

cat 1 put on; 

call put char('^'); 

call putchar('ll); 

accum = stow leds AND bit3; 

call put off; 

call putchar('ll); 

call putchar('2'); 

accum = stow leds AND bit4; 

call put off; 

call put char('^'); 

call putchar('3'); 

accum = stow leds AND bits; 

call put off? 

call putchar(l~l); 

call putchar('4'); 

accum = stow leds AND bit6; 

cat 1 put off: 

- call put'char('~'); 

call putchar('S8); 

accum = stow leds AND bit7; 

- call put off: 

call putchar(l~l); 

call putchar('6'); 

accum = stow leds AND bit2; 

call put off? 

call putchar('~~l); 

call putchar('LF1); 

unsave regs; 
eb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 58 

end dump - sw - states; 

put - on: 

call putchar('-9; 

if (accum = 0) 

then call putchar($31>; 

else call putchar(S30); 

call putchar(' '1; 

end put-on; 

put - off: 

call putchar('-'); 

if (accum = 0) 

then cat 1 putchar($30); 

else call putchar($31); 

call putchar(' '1; 

end put - off; 

............................................................................ 

: This routine dumps the state of the 12 array enable Lines during dump state 

:**********************************************************************T**** 

'seudocode: 

lump - arrays: 

save regs; 

temp = stow pwml; 

do i=31 to T6; 

call putchar('AV); 

call putchar(i1; 

call putchar('-'); 

temp = temp >> 1 

if (carry = 0) 

then call putchar('O1); 

else call putchar('ll); 

call putchar(' '1; 

end; 

temp = stow pwm2; 

do i=31 to -56; 

call putchar('A'1; 

call putchar(i); 

call putchar('-'); 

temp = temp >> 1 

if (carry = 0) 

then call putchar('0'); 

else call putchar('lw); 

call putchar(' '1; 

end; 

call putchar('CR'1; 

call putchar('LF1); 

unsave regs; 

end dump - arrays; 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 59 

XXXXXX 

X 

XXXXX 

X 

X 

X 

XXXXX XXXXX XXXX X X 

X X X X X X XX XX 

X X X X X X XXXX 

XXXXX XXXXX X X X X 

X X X X X X X 

X X X XXXX X X 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 60 

............................................................................ 

; This is the "main" control module. This module invokes all of the other 

; modules, either directly or indirectly. The routines called directly by 

; this module are listed below. The functions of the run task-master are man - 

; but they are broken down into 4 regimes. 

I 

r 1. background regime - the most fundamental Loop for the system to 

I be in if nothing is happening. 

I 

I 2. dataset ready regime - entered only when the new dataset is 

I available Tor signal averaging. 

I - I 3. 100 msec regime - within the dataset ready regime. It is within 

I this area that the signal averaging mutTimeter functions and max 

I power control are done. 

I 

I 4. 1 second regime - this area is devoted primarily with the 

I handling of the clock and machine state considerations. ............................................................................ 

Pseudocode: 

run - task - master: 

do while (1); 

if (dsply pend flag = 1) then call display - digits; 

if (datasTt ready - f tag = 1) 

then do; 

strobe watchdog timer; 

if (serial cmd f!ag OR kybd - cmd - flag = 1) 

then cbll cmd int rp; 

if (pwm - m - flg = 1T 

then do; 

call abs cnvt; 

if (run 'ilag = 1)); 

the: do; 

call battery state of chg; 

if (max pw cntrt =-I)- 

then cat1 max pwr - track; 

if ((dump - state fTag = 1) 

~~~-(b~te count = 0)) 

then call dump - state; 

end; 

dataset ready flag = 0; 

pwm-m fig = ~j 

mmf - update = mmf - update - 1; 

end; 

if (mmf update = 0) 

the; do; 

call multimeter - func; 

mmf - update = 3; 

end; 

end; 

if (one - sec - flag = 1) 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 61 

then do; 

call test string - I; 

call find-time; 

if (alarm-30 AND bit6 <> 0) 

then 30; 

"reset" the 30 min alarm; 

dump - state - flag = 1; 

end; 

if (run flag = 1) 

the; do; 

if (max DW cntrl = 0) -' -- 

then call discrete array - cntrl; 

call correct state - of - chg; 

call deter - mach - state: 

end; 

else stow leds=led - out - latch=stow - leds XOR #sled 

call chk for ovrld; 

one - sec - ilag-= 0; 

end; 

end; 

end run-task-master; 

......................................................................... 

; This routine is awakened when the pwm m flg is set to indicate that - - 

; it is time to update the control point. 

I 

I Note:if (direction <> 0) then duty cycle incr's 

@ if (direction = 0) then duty cycle decr's 

I 

......................................................................... 

Pseudocode: 

max - power - track: 

save regs; 

old - power = new power; 

new power = (abs - battery - V + $100) * abs - total - chgr I; - 

delTa power = new power - old power; 

if ((Telta power 7 0) AND (di'F; - chg - cntr = 0)) 

then dz; 

direction = direction XOR 1; 

dir chg - cntr = 2; 

step = small; 

end; 

else jf (delta - power > old power * 2^(-big)) - - then step = large; 

else step = small; 

if (pwm value <= min - pwm) 

thex do; 

direction = 1; 

step = large; 

end; 

if ((pwm - value >= max pwm) OR ((total chgr I > max chgr I) - - 

OR (a?;s - battery V > bat - V - iimit) 

OR (motor temp = 1) 

OF (string - 1 - V < min - array - volts) 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 62 

then do; 

direction = 0; 

step = small; 

end; 

if (direction bit = 0) then step = - step; 

pwm value = pwm-value + step; 

if tpwm value > max pwm) 

the; if (directTon <>O) 

then pwm value = max - pwm; 

else pwm-value = 1; 

if ((pwm value (-1 count) OR (inhibit = 0)) 

t hen-do; 

pwm value = 1; 

tur: - on - flag = 0; 

end; 

else turn - on - flag = 1; 

do; 

disable ints; 

timer-csr = SOB 

timer-data = SC8 - pwm - value; I* Load downtime */ 

timer data = $00 

timer-data = pwm value; /* load uptime */ 

timer-data = $00- 

if (tern - on - flag = 1) 

then array sell=array sel2=stow pwml=stow pwm2 = #83F; 

else array~sell=array-se12=stau-pwml=sto~wm2 - - - - = #SO; 

end; 

enable ints; 

end; 

settle time = $03; 

if (di7 chg cntr <> 0) 

the: di7 - chg - cntr = dir chg cntr - 1; - - 

unsave regs; 

end max - power - track; 

This routine looks through a table of commands for a match to the first 

character that it finds in the command buffer. The next two locations in 

the table hold the jump address of the-routine to handle the requirement. 

The corresponding routine is invoked. Since the data in the command buffer 

could be the password, this is checked first. Failing this test, the input 

is tested to see if it is one of the possible command words. If so, that 

task is initiated. If no command word is matched a "WHAT?" message is 

sent to the appropriate port. 

If the msb of the table character is set, it indicates that the function is 

a multimeter display function. In this case, the ascii representation of 

the channel number in the command buffer is moved to multimeter data, 

the display function starting address is retained in multimeter-addr and - the multimeter - flag is set. 

Upon completion of this task the following actions are taken: 

1. control is returned to cmd - intrp 

2. a prompt, "CR LF *", is sent to the serial port, using 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 63 

I msg - hndlr 

I 

I 3. clear secial cmd flag or the kybd cmd flag as appropr ;******************************T***T****************T***T*************** 

Pseudocode: 

cmd - i=ntrp: 

save regs; 

cmd out ptr = 0; 

if Tkybccmd-flag OR serial - cmd - flag = 1) 

then do; 

if (kybd cmd - flag = 1) 

t hen-do; 

index = 0; 

do while ((command bufferrindex1 = passwordCinde 

ANT (index < 4) 1; 

index = index + 1; 

end; 

if (index = 4) 

then do; 

valid password = 1; 

call ';risplay - clr0; 

end; 

else do; 

call display clr0; 

if ((command-bufferr13 - < $3A)> 

then do; 

if (valid - password = 0) then 

base addr = - cmd tablel; 

else base-addr = - cmd-table3; - 

call find fuFc; 

kybd cmd fTag = 0; 

cmd out ptr = 0; 

cmd-in - - 'i;tr = 0; 

end; 

else do; 

cmd out ptr = 1; 

if Tvalid - password = 0) then 

base addr = - cmd table2; 

else base-addr = - cmd-tabte4; - 

call find fuFc; 

kybd cmd fTag = 0; 

cmd out Ftr = 0; 

cmd-in - - ptr = 0; 

end; 

end; 

end; 

else do; 

base addr = cmd - tables; 

call- find func; 

call Fsg hndlr(prompt); 

serial cm'd flag = 0; 

cmd OUT ptT = 0; 

cmd-in - - Ftr = 0; 

end; 
eb 17 12:17 1984 /u/tam/soLar/PSEUDOCODE Page 64 

end; 

unsave regs; 

end cmd - intrp; 

- find func: procedure; iKdex = 0; 

do while ((command bufferCcmd out ptrl 0 

($7F AFD base addTCinTex3)) AND 

(base-addr~index3 - <> 0)); 

index = index + 3; 

end; 

if (base addrtindexl AND $80 0 0) 

t hen-do; 

multimeter flag = 1; 

multimeter-data = command buffertll; 

multimeter-data+l = commaEd bufferf23; 

multimeter-addr - = base - addr-findex + 13; 

end; 

if (base addrtindexl = 0) 

then-do; 

if(kybd cmd flag = 1) then call display - huh; 

els7 tail put - huh; 

end; 

else do; 

jump addr = base addrtindex + 11; 

call-routine located @ jump - addr; 

end; 

end - find - func; 

........................................................................... 

This routine gathers N channels of data, sequentially, and stores the 

results in memory. The routine set the mux channel number, waits for 

settling, starts the conversion, polls for conversion completion and then 

stores the result. 

Note: entry-num, next-seldom and pass num are zeroed at init ........................................................................... 

seudocode: 

dc - hndlr: 

save regs; 

temp = pia csra; 

if (temp A~D bit 6 <> 0) 

then call knock down; 

if (temp AND byt 7 <y 0) 

then do; 

decr pwm mod timer; 

if (pwm God - Timer = 0) 

t hen-do; 

pwm mod timer = 25; 

pwm-m - fig = 1; 

end; 

ca L 1 scan kybd; 

if (settle time = 0) 

then do; 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 65 

if (dataset - ready - flag = 0) 

then do; 

"OFTEN READS" 

next often = 0; - 

do wFile next often <= num - of - oftZen reads; 

select thg often - read mux channel; 

adc lo = 0; to start convers' 

if Tnext often = 0) 

else 20; 

rearrange adc va lue; 

if (adc - value-< 0) then remove sign be 

complement the value; 

often - read~entr~. - num, (next often-1)*3; 

adc - value: 

end; 

do while (adc - lo AND adc not busy = 0); 

end; po 1 1 Tor conversion compl 

adc - value = adc - hi:adc - lo; 

next - often = next - often + 1; 

end; 

rearrange adc value; 

often - readCenTry - num,(next - often-1 )*323 = adc - v; 

"SELDOM READS" 

if (next seldom > num - of - seldom reads) - 

then Text seldom = 0; 

else next-seldom = next seldom + 1; 

select seldom - read mux chaEne1; 

adc lo = 0; to start conversion 

if Tpass num >= max - pass - num) 

then 30; 

dataset - ready - flag = 1; 

pass-num = 0; 

entry - num = 0; 

end; 

else do; 

pass-num = pass num + 1; 

entry - num = entTy - num + 1; 

end; 

do while (adc - lo AND adc not busy = 0); 

end; poll Tor conversion comp 

seldom - readCnext - seldom3 = rearranged adc; 

end; 

end; 

else settle - time = settle time - 1; 

this is The settle time tkat is set 

when the PWM value-has been changed. 

A value of 5 for settle time will 

suppress any current measurements for 

20 msec 

if ((one sec flag = 0) AND (one - sec - timer = 0)) 

then one sec timer = 250; 

else if Tone-sec - flag = 0) 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 66 

then do; 

decr one-sec - timer; 

if (one - see - timer = 0) then one - sec - flag = 1; 

end; 

if ((alarm 30 AND inhibit - bit <> 0) AND (alarm 30 AND panic<> 0) - then inxibit = 1; 

else inhibit = 0; 

if (alarm 30 AND panic = 0) 

then call knock - down; 

end; 

unsave regs; 

end adc - hndlr; 

- knock down: 

stoc Leds = Led out latch = stow Leds AND $03; 

user-td req = inhibit = array - seT~ = array - set2 = 0; 

stroFe iatchdog timer; 

end - knock - down; 

............................................................................ 

; This routine is the "main" routine that calls all of the routines that 

; deal with the elements of calculating the state of charge of the battery. 

; It is fully executed only when the dataset ready flag is set. When all of 

; these calculations are complete, this routine assigns a new value to 

; bat - V - timit: 

............................................................................ 

Pseudocode: 

battery - state - of - chg: 

save regs; 

call calc sys volts; 

call catc-staTe - of - chg; 

cat t catc-equal count; 

if (state-of chg < 1) OR (equal - count >O) 

then Fat-v -- Limit = equal V; 

else bat - V - limit = float-V; - 

unsave regs; 

end battery - state - of - charge; 

............................................................................ 

; This routine takes the value of bat temp, shifts it right by 4 subtracts 

; $D and uses the result as an index into the each of three tables. The 

; first one is the fboat voltage table, the second one is the equalization 

; voltage table and the last is the minimum voltage table. This technique 

: greatly reduces the execution time and simplifies the software. 

............................................................................ 

:aLc-sys - volts: 

save regs; 

index = bat temp >> 4; 

index = index - $D; 

if (index < 0) 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 67 

U 

end c 

then index = 0; 

ndex = index * 2; 

Loat V = float tab\eCindexJ; 

f (fToat V > a6s - max bat V) 

then Float V = abs ma: bat - V; 

quaL V = equai table~rndeT1; 

f (e6ual V > aFs - max bat V) 

then ;qua1 V = abs ma? bat V; 

in bat V = mi; bat ta'i;leCrndeF3; 

f Tmin-bat V <-abs-min - bat V) 

the: mi; - bat - v = abs - mi; - bat - V; 

nsave regs; 

alc - sys - volts; 

The following are the Lookup tables for float - volts, equal - volts and 

min - bat - volts for the equation: 

value = base - voltage/cell * nurn of bat cells * 

(1 + -0622-* (70.92 * (Vt - 2.561)) 

where base - voltage/cell = 2.4 for float V 

= 2.7 for equalLv 

= 1.9 for rnin - b$t - V 

In order to find the index to a value in the table, take the raw A/D 

value for Vt, shift right 4 bits and subtract $OD. 

NOTICE: Vt, as shown below, is represented in "real volts" format, i.e, 

the number represents the number of 1/1000~s of volts. To convert this 

value to what is actually stored in memory, it must be divided by 4. 

FLOAT VOLTAGE TABLE 

temp index Vt hex value dec value 

61 deg C 

60 deg C 

58 deg C 

57 deg C 

56 deg C 

54 deg C 

53 deg C 

52 deg C 

50 deg C 

49 deg C 

48 deg C 

46 deg C 

45 deg C 

44 dcg C 

42 deg C 

41 deg C 

40 deg C 

38 deg C 

37 deg C 

36 deg C 

34 deg C 
:eb 17 12:17 1984 /u/tam/soLar/PSEUDOCODE Page 68 

33 deg C 

32 deg C 

30 deg C 

29 deg C 

28 deg C 

26 deg C 

25 deg C 

24 deg C 

22 deg C 

21 deg C 

20 deg C 

18 deg C 

17 deg C 

16 deg C 

14 deg C 

13 deg C 

12 deg C 

10 deg C 

9 deg C 

8 deg C 

6 deg C 

5 deg C. 

4 deg C 

2 deg C 

1 deg C 

-0 deg C 

-2 deg C 

-3 deg C 

-4 deg C 

-6 deg C 

-7 deg C 

-8 deg C 

-10 deg C 

880 

8CO 

900 

940 

980 

9CO 

A0 0 

A40 

A80 

ACO 

BOO 

B40 

880 

BCO 

coo 

C40 

C80 

cco 

DO0 

D40 

D80 

DCO 

EOO 

E4 0 

E80 

ECO 

FOO 

F40 

F80 

FCO 

1000 

1040 

1080 

Loat - table: 

.word $012A, $0128, $012C, SOlZD, $012E, $012~, $012~, $0130 

.word $0131, $0132, $0133, $0134, $0135, $0136, $0137, $0138 

.word $0139, $013A, $0138, $013C, f013D, $013~, $013F, $0140 

.word $0141, $0142, $0143, $0144, $0144, $0145, $0146, $0147 

.word $0148, $0149, $014A, $0148, $014C, $014D, $014~, $014~ 

.word $0150, $0151, $0152, $0153, $0154, $0155, $0156, $0157 

.word 50158, $0158, $0159, $015A, %015B, S015C 

EQUALIZATION VOLTAGE TABLE 

temp index ' Vt hex value dec value 

61 deg C 

60 deg C 

58 deg C 

57 deg C 

56 deg C 

54 deg C 

53 deg C 

52 deg C 

50 deg C 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 69 

49 deg C 09 

48 deg C 0 A 

46 deg C 08 

45 deg C OC 

44 deg C OD 

42 deg C OE 

41 deg C OF 

40 deg C 10 

38=aeg C 11 

37 deg C 12 

36 deg C 13 

34 deg C 14 

33 deg C 15 

32 deg C 16 

30 deg C 17 

29 deg C 18 

28 deg C 19 

26 deg C 1 A 

25 deg C 1 B 

24 deg C I C 

22 deg C 1 D 

21 deg C 1 E 

20 deg C 1 F 

18 deg C 20 

17 deg C 2 1 

16 deg C 22 

14 deg C 23 

13 deg C 24 

12 deg C 25 

10 deg C 26 

9 deg C 27 

8 deg C 28 

6 deg C 29 

5 deg C 2A 

4 deg C 28 

2 deg C 2C 

1 deg C 2D 

-0 deg C 2E 

-2 deg C 2 F 

-3 deg C 30 

-4 deg C 31 

-6 deg C 32 

-7 deg C 33 

-8 deg C 34 

-10 deg C - 

35 

equal - table: 

,word $0136, 

.word $013E, 

.word $0146, 

.word $014E, 

.word $0156, 

.word $015E, 

.word $0166, 

580 

5CO 

600 - 

640 

680 

6CO 

700 

740 

780 

7CO 

800 

840 

880 

8CO 

900 

940 

980 

9CO 

A00 

A40 

A80 

ACO 

BOO 

840 

B80 

BCO 

COO 

C40 

C80 

cco 

DO0 

D40 

D80 

DCO 

EO 0 

E4 0 

E80 

ECO 

FOO 

F40 

F80 

FCO 

1000 

1040 

1080 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 70 

MINIMUM BATTERY VOLTAGE TABLE 

temp index Vt hex- value dec value 

61 deg C 

60 deg C 

58 deg C 

57 deg C 

56 deg C 

54 deg C 

53 deg C 

52 deg C 

50 deg C 

49 deg C 

48 deg C 

46 deg C 

45 deg C 

44 deg C 

42 deg C 

41 deg C 

40 deg C 

38 deg C 

37 deg C 

36 deg C 

34 deg C 

33 deg C 

32 deg C 

30 deg C 

29 deg C 

28 deg C 

26 deg C 

25 deg C 

24 deg C 

22 deg C 

21 deg C 

20 deg C 

18 deg C 

17 deg C 

16 deg C 

14 deg C 

13 deg C 

12 deg C 

10 deg C 

9 deg C 

8 deg C 

6 deg C 

5 deg C 

4 deg C 

2 deg C 

1 deg C 

-0 deg C 

I -2 deg C 

-3 deg C 

-4 deg C 

-6 deg C 

-7 deg C 

340 

380 

3 C 0 

400 

440 

480 

4CO 

500 

540 

580 

5CO 

600 

640 

680 

6CO 

700 

740 

780 

7CO 

800 

840 

880 

8CO 

900 

940 

980 

9CO 

A00 

A40 

A80 

ACO 

BOO 

840 

880 

BCO 

COO 

C40 

C80 

CCO 

DO0 

D40 

080 

DCO 

EOO 

E4 0 

E80 

ECO 

FOO 

F4 0 

F80 

FCO 

1000 

OOE C 

OOEC 

OOED 

OOE E 

OOE F 

OOE F 

OOFO 

OOFl 

OOF2 

00 F2 

00 F3 

OOF4 

00 F 5 

OOF5 

OOF6 

OOF7 

OOF8 

OOF8 

OOF9 

OOFA 

OOFB 

OOFB 

00 F C 

OOFD 

00 F E 

OOFE 

OOFF 

01 00 

01 01 

01 02 

01 02 

01 03 

01 04 

01 05 

01 05 

01 06 

01 07 

01 08 

01 08 

01 09 

01 OA 

01 OB 

01 OB 

01 OC 

01 OD 

01 OE 

01 OE 

010F 

0110 

0111 

01 11 

0 1 1 2 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 71 

-8 deg C 34 1040 01 13 110.2 

-10 deg C 35 1080 0114 110.5 

min - bat - table: 

; This routine is called to calculate the running "sum of coulombs" whic 

; the battery state of charge. The basic algorithm calls for the follow 

; calculation to be performed: 

I 

I state - of - chg = state-of-chg + (battery - I * iscal /battery - cap) 

I 

; The basic problem here is dealing with the extremely large range of thl 

; numbers involved. State-of-chg is stored as a 40 bit number with a 

; maximum value of 1. (followed by 39 zeros). or values of iscal and 

; battery capacity of 1/45000 and 400, respectively, and battery - I store, 

; the form, xxx.x, this equation reduces to: 

I 

I state-of - chg = state-of-charge + (555 * battery - I * (lo)^-11) . 

I 

; If, for the purposes of calculation, we make the binary point right ju! 

; by multiplying thru by (2)-39, the equation becomes: 

I 

; (5.49 * (10)^11) * state of chg = 

I (5,49-* (10)^11) * state of chg + I (5.49 * (10)^11) * (555-* battery - I * (lo)^-1 

I 

; Which reduces further, in general, to: 

I 

; (5.49 * (10)^11) * state of chg = - - I (5.49 * (10)^11) * state of chg + 

I (iscal - bat - cap *-baFtery - I) 

I 

; Hence, to calculate a new value of state of chg, multiply battery - I by 

; parameterized value, iscal bat cap, whicx is equal to: 

I 5.49 * 10^10-* iscal * l/bat cap. 

; and add (or subtract) the result to (or from) the running 40 bit value 

; state - of - chg. ' - 

I 

; To read the value of soc, mentally move the binary point Left to the or 

; post-tion (i.e. divide by (21-39) and read the value. - 

- I 

; If the battery is charging, i.e. the net current is flowing INTO the ba 

; the battery current is multiplied by the coulombic efficiency which is 

; function of the state of chg as follows: - - I 

I State - of - chg coulombic eff - I decimal binary decimal binary 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 72 

Pseudocode: 

calc - state - of - chg: 

save regs; 

if (battery - I >O) 

then do: 

if (state of chg >= soc - brkl) 

then co~lo~bic eff = coul - effl; 

else if ((state - of - chg >= soc brk2) 

AND (state 'i;f charge < soc brkl)) - 

then coulombic eff = coul Gff?; - 

else if ((state - of chg >= soc brk3) 

ANT (state of-charge < soc - brk2)) 

then coulombic eff = coui e-ff3; - 

else coulombic-eff = 1.0: 

battery - I = battery - f * cout&mbic - eff; 

end; 

state of chg = state-of-chg + (battery - I * iscal - bat - cap); see above 

if (sTat-i; of chg > 1) 

then XtaTe of chg = 1; 

if (state of cKg 7 0) 

then ZtaTe - of - chg = 0; 

unsave regs; 

end calc-state - of - chg; 

............................................................................ 

: This routine is called to calculate a running total of equalization counts. 

: For details about dealing with the Large (40 bits!) equalization count, 

: see calc state of chg. 

: Since thFre was och frac to deal with, a section of the code for this 

: routine is a "hardwrred" multiply routine so that it woutdntt be necessary 

: to use the Long 16 by 16 multiply routine. It is assumed, in order to make 

: this routine as fast as possible, that the fraction is only 7 bits long, 

' and that it is left justified with the binary point at the left end, like 

L a fraction should be. In order to minimize the code and the requirement 

for additional zero page storage Locations for the interim solutions, some 

of the variable locations used in mp - mutt are also used here, as shown belc 

temp - och - frac 

/ 

1 iscal bat - cap I bat mutt2 

-1 - 1 / I 1 I I I I I I 1 

1 I I I I I I I I I mutt1 I mutt2 I product I 

The product of bat mutt2 * och frac is shifted as it is multiplied, into 

the two bytes occu'f;ied by multz. Temp och frac is overwritten. 

........................................................................... 

Iseudocode: 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 73 

calc-equal - count: 

save regs; 

if (battery-I < 0) * 

then do; 

temp = (battery I * och frac)/256; 

equal - count = e6ual-couEt + (temp * iscal-bat -- - cap); 

end; - 

- - - if (state of chg >= 1) 

equa'i- count = equal - count - (battery - I * iscal - bat - cap) 

then state of chg = 1; 

if (equal counT <-01 . 

then equal count = 0; 

if (equal - counT > max - equal - count) 

then equal - count = max-equal - count; 

unsave regs; 

end calc - equal - count; 

....................................................................... 

; This routine corrects the current state - of - chg value for battery 

; temperature. ....................................................................... 

Pseudocode: 

correct-state - of - chg: 

save regs; 

if ((abs battery - V >= -99 * equal-V) OR (state - of - chg > soc - top 

then-do; 

state of chg = state of chg + -01; 

if (statF - of - chg > 1:0)-then state - of - chg = 1.0; 

end; 

if (abs battery - V < min - bat - V) 

the; do; 

state of chg = state of chg - -01; 

if (stat; - of - chg < 07 tren state - of - chg = 0; 

end; 

index = (bat temp >> 4) - $D; 

if (index < 8) 

then index = 0; 

cstate-of - chg = state - of - chg * csoc - tableCindex3; 

unsave regs; 

end correct - state - of - chg; 

The following are the lookup table for the values in the expression: 

- 

value = (1 + coeff * (20.92 * (Vt - 2.56))) 

where coeff = -0022 for temperat-ures > 25 deg I 

= -0075 for temperat-ures < 25 deg ( 

In order to find the index to a value in the table, take the raw A/D 

value for Vt, shift right 4 bits and subtract $OD. 

NOTICE 1: The value stored in the table is assumed to have a hexadecimz 

point in the center of the word, e.g. $0112 corresponds to $1.12 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 74 

JOTICE 2: Vt, as shown below, is represented in "real volts" format, i,e. 

the number represents the number of 1/1000~ of volts. To convert this 

~alue to what is actually stored-in memory, it must be divided by 4. 

CORRECT STATE OF CHARGE TABLE 

temp index Vt hex value percent 

61 deg C 

60 deg C 

58 deg C 

57 deg C 

56 deg C 

54 deg C 

53 deg C 

52 deg C 

50 deg C 

49 deg C 

48 deg C 

46 deg C 

45 deg C 

44 deg C 

42 deg C 

41 deg C 

40 deg C 

38 deg C 

37 deg C 

36 deg C 

34 deg C 

33 deg C 

32 deg C 

30 deg C 

29 deg C 

28 deg C 

26 deg C 

25 deg C 

24 deg C 

22 deg C 

21 deg C 

20 deg C 

18 deg C 

17 deg C 

16 deg C 

14 deg C 

13 deg C 

12 deg C 

10 deg C 

9 deg C 

8 deg C 

6 deg C 

5 deg C 

4 deg C 

2 deg C 

1 deg C 

340 

380 

3 C 0 

400 

440 

480 

4CO 

500 

540 

580 

5CO 

600 

640 

680 

6CO 

700 

740 

780 

7CO 

800 

840 

880 

8CO 

900 

940 

980 

9CO 

A00 

A4 0 

A80 

ACO 

BOO 

840 

880 

BCO 

COO 

C40 

C80 

cco 

DO0 

D40 

080 

DCO 

EO 0 

E40 

E80 

0114 

0 1 1 3 

0112 

0112 

0111 

01 10 

OlOF 

OlOF 

01 OE 

01 OD 

01 OC 

OlOC 

01 OB 

01 OA 

01 09 

0 1 0 9 

01 08 

0 1 0 7 

0 1 0 6 

01 06 

0105 

01 04 

01 03 

01 03 

01 02 

01 01 

0 1 0 0 

01 00 

00 F D 

OOFA 

00 F 8 

OOF5 

00 F3 

OOFO 

OOE E 

OOEB 

00E8 

00E6 

00E3 

OOEl 

OODE 

OODC 

00D9 

OOD6 

0004 

OODl 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 75 

-0 deg C 

-2 deg C 

-3 deg C 

-4 deg C 

-6 deg C 

-7 deg C 

-8 deg C 

-10 deg C 

ECO 

FO 0 

F40 

F80 ' 

FCO 

1000 

1040 

1080 

OOC F 

oocc 

OOCA 

OOC7 

OOC4 

ooc2 

OOB F 

OOBD 

- - 

csoc - table: 

; This routine, called once per second, performs the actual control of t 

; loads connected to the system, as determined by the state variables 

; prod mask (created by determine mach state), user Id req (set by the u 

; from-the terminal or keypad), and overld trip (set by chk for overld). 

; Depending upon the state of charge of the battery (as indTcatQd in 

; cstate of chg), various loads are turned on or off so as to maximize 

; battery lffe. In addition, various warning indicators (RED and YELLOW 

; LEDs, and the Low Battery indication on the LCD Display) are turned on 

; or off to alert the operator to unusual or dangerous conditions. 

........................................................................ 

Pseudocode: 

shed - restor - loads: 

save regs; 

if ((hours >= #SO81 AND (hours < #$I21 AND 

(total chgr I > (5.12 * 0.1 * *num Load strings))) - 

then deltam= #delta - soc; /* delta - soc = 0.1 */ 

else delta = 0; 

j = stow Leds; 

do i = 4-to 0 step -1; 

if ((cstate - of - chg + delta) < shed - threshCi1) 

then do; 

j = j AND shed msk tblfil; 

ignore the nexF stztement and continue Loop; 

- end; 

if ((cstate of chg + delta) >= restor threshCi3) - 

j =-j ER restor - msk - tblfil; 

- e n d ; - 

j = (j OR #ld6 on) AND prod mask); 

if ((j & restoT msk tblt43)-<> 0) 

then j = j AND ayled off; 

else j = j OR #yled zn; 

if ((j AND restor msk ~~LCOI) <> 0) 

then j = j ANT #ried off; - 

else do; 
Feb 17 12:17 1984 /u/tam/soLar/PSEUDOCODE Page 76 

! j = j OR #rled on; 

j = j AND #yle> - off; 

end; 

sr - temp = j; I j = user-ld-req OR #leds on; - 

sr temp = sr temp AND j; 

ifW((sr tempe& #rled on) <> 0) 

the; alarm flags-= alarm flags OR #enable Lobat; 

else alarm-flags = alarm-flags AND #disabTe - lobat; 

if (ovrLd trip-<> 0) 

then 20; 

j = sr temp AND 'ovrLd trip; 

stow - leds = j ( #rled - on; 

end; 

else stow leds = sr temp; 

led - out - latch-= stow - leas; 

unsave regs; 

end shed - restor - Loads; 

............................................................................ 

; This routine, called every second, checks the currents in the 5 load 

; strings and if a current exceeds a limit for more than a certain number 

; of times (this "count" being load specific), the bit corresponding to 

: the load number that has suffered the overload is set in the ovrld trip 

: mask, and the load is immediately turned off (as opposed to waiting for 

: the next execution of the shed/restore Load routine). 

............................................................................ 

'seudocode: 

hk - for - ovrld: 

save regs; 

do i = 4 to 0 step -1; 

if (bus - ampsCi3 < 0) 

then sr temp = - bus ampsCi3; 

else sr-temp = bus a~psCi3; 

if (sr temp-> ovrld - thyeshfil) 

thyn do; 

ovrLd cntEi3 = ovrld cntCi3 - 1; 

if (ovrld cntCi3 = 07 

then zvrld - trip = ovrld - trip OR ovrld - trip - mskCi3; 

end; 

else ovrld - cntCi3 = ovrLd - cnt - rnaxCi3; 

end; 

if (ovrld trip <> 0) 

then 30; . stow leds = stow leds AND 'ovrld trip; 

stow-leds = stow-leds OR #rled - OF; 

led out Latch = stow leds; 

aLa7m - fiags = alarm - ilags OR #enable - bell; 

end; 

unsave regs; 

end chk -- for - ovrLd; 

.......................................................................... 

The function of this routine is to determine if more or less array branches 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 77 

; should be connected. This routine is entered every time the one sec f 

; is set. The pattern for the two PWM latches are held in bits 0 thru-6 

; stow pwml and stow pwm2. .......................................................................... 

Pseudocode: - 

discrete - array - cntrl: 

-. save reg; 

if (abs battery - V > bat V limit) - - 

the; do; 

stow pwml = 0; 

stow-pwm2 - = 0; 

end; 

else if (abs - battery - V > (bat V Limit * 31)/32) - - then do; 

if (stow pwm2 = 0) 

then-do; 

stow pwml = stow pwml >> 1; 

st0w-~wm2 = st0w-~wm2 >> 1; 

end; 

end; 

else if Cabs - battery - V < (bat V limit * 30)/32) - - 

then do; 

stow pwml = (stow pwml << 1) + 1; 

if (stow pwml AND-$40 <> 0) 

t hen-do; 

stow pwml = stow pwml AND $3F; 

st0w-~wm2 = (sto'E; pwm2 << I) + I; 

stow-pwm2 - = stow - pwm2 AND S3F; 

end; 

end; 

array sell = stow pwml; 

array-set2 = st0w-~wm2; 

unsave regs; 

end discrete - array - cntrl; 

; The routine determines which of the four states of the machine (descri 

; below) that the machine should be in based on state of chg and product 

; levels and then sets up those conditions. It is assumTd that the prio 

; of functions is: 

I 

I 1. charging the battery 

I 2. running the load 

I - 3. making product 

I 

; state #I battery is so low that product and Load relays are all 

I off (statel = 00000000) 

I 

; state #2 battery partially charged, load reeays closed, 

I product relay open (state2 = 11111000) 

I 

; state #3 battery close to full charge, load relay open, 

I product relay closed (state3 = 00000100> 

I 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 78 

; state #4 battery close to full charge, load relays closed, 

I product relay closed (state4 = 11111100) 

I 

I note 1: When refering to-the fact that the load relays are closed, tt 

I presumes that the overload threshold has not been exceeded, 

I 

fl note 2: The product relay is load #1, the load relays operate as a 

I unit (in so far as this routine is concerned), so that 

I loads 2 thru 5 are turned off and on together. 

I 

; State Diagram: 

8 (00) ---- I >STATE 1-->-- 

I I 

I 

I v 

(corr soc<socl) I 

- I (corr soc>socl+buf socl) 

1 - I 

v 

\ / 

\ / 

\ / 

\ (F8) / 

-<----<----<---<--<--STATE 2<---->--->---->---->----- 

1 / \ 

v / \ 

I 

v 

(prodcprodl / \ (prodl<prod<prod2) 

AND I \ AND 

(corr - soc>soc3+bufsoc3) 

I 

I (corr - soc<soc2> I v 

1 (prod>prod2+bufprod2> 

v I OR I 

I 

(corr - soc<soc3) 

STATE 3<----<---- <-- 

1 (04) 

I 

-<----<---- 

I 

1 - 1 

I (prodCprod1) 

AND <----<----<----<----<---- 

I I 

I STATE 4 

I (corr - soc<soc4> 1 (FC) 

v 

I 

---- ~(prod>prodl+bufprod1)0R(corr soc>soc4+bufsoc4)-- I 

- 

jeter-mach - state: 

save regs; 

if (prod mask = statel) 

then-if (cstate of chg > socl + bufsocl) 

then prod mask state2; 

else if (pros mask = state21 - 

then do; 
, cu ,, Ir; I r rrur /u/tam/solar/PSEUDOCODE Page 79 

if (cstate - of - chg < socl) ***case2*** 

then prod mask = statel; 

else if (Tprodl <= prod < prod21 

AND (cstate of chg > soc3 + bufsoc3)) ***case3i 

then prod mask sTate4; 

else if (Tprod < prodl) 

AND (cstate of chg > soc2 +-bufsoc2)) **c: 

then prod mask = state3; - - 

end; 

else if (prod - mask = state31 

then do; 

if (estate of chg < soc2) ***cases*** 

then prod Kask = state2; 

else if (Tprod > prod1 + bufprodl) OR 

(cstate of - chg > soc4 + bufsoc4) ***caseb* 

then prod - mask = state4 

end; 

else if (prod mask = state4) - then do; 

if ((prod < prod11 AND (cstate of chg < soc4)) - - then prod mask = state3; ***case?*** 

else if (Tprod > prod2 + bufprod2) 

OR (cstate of chg < soc3)) ***case8*** 

then prod - mask =-stTte2; 

end; 

call shed - restor - loads; 

unsave regs; 

end deter - mach - state; 

.......................................................................... 

; This routine handles all of the initialization duties, runs the RAM 

; and lamp test. 

........................................................................ 

Pseudocode: 

test: 

disable interrupts; 

make sure we're in decimal mode; 

stack pointer = $FF; 

pia csra = ddr sel; 

pia-csrb = ddr-set; 

pia-ddra = pad';jr mask; 

pia csra = pa edge sel OR ddr desel; 

~ia-porta = dsply ye1 dsb AND-~S~L~ clk off; - - - pia-ddrb'= pbddr {ask: 

pia-csrb = pb edge - sel OR ddr desel; - pia-portb = $BF; . led-out - latch = $00; 

do 5; = 0 to $FF 

$OOOOCxI = $FF; 

end; 

do x = 0 to $FF 

if ($OOOOCX~ <> $FF) 

then call ram error; - 
end; 

do x = 0 to $FF 

~0000Cx3 = $00; 

end; 

do x = 0 to SFF 

if (S0000Cx3 <> $00) 

then call ram - error; 

- end; 

rom ptr = $0100; 

do Fhile (rom ptrCl3 < max - ram - size) 

$0000[rom-~t - rl = SFF; 

rom - ptr = rom - ptr + 1; 

end; 

rom ptr = $0100; 

do ;hike (rom ptrCl1 < max ram size) 

if (~0000Trom ptr3 <> TFF)- 

then cal t-ram error; 

rom - ptr = rom-ptr-+ 1; 

end; 

rom ptr = S0100; 

do Ghite (rom ptrC11 < max - ram - size) 

$0000f r~m-~t - r1 = $00; 

rom - ptr = rom - ptr + 1; 

end; 

rom ptr = #$0100; 

do white (rom ptrC13 < max ram size) 

if (~0000Trom ptr~ <> TOO>- 

then cat 1-ram error; 

rom - ptr = rom-ptr-+ 1; 

end; 

pia-portb = bell - on OR $OF; 

call Lamp test; 

pia - portb-= $OF; 

nit - timer: 

timer - csr = timer-reset; 

timer csr = tdatt - timers; 

timerrcsr = $OF; 

timer data = $00; 

timer-data = $00; 

timerzdata = master model; 

timer - data = master-modeh; - 

timer - csr = $01; 

imerl: 

timer-data = cntrl model; 

timer data = cntrl-modeh; - 

timer-data = $00; 

timer-data = $00; 

timer-data = $00; 

timerIdata = $00; 

imer2: 

timer data = cntr2 model; 

timer-data = cntr2-modeh; - 

timer-data = $00; 

timer-data = $00; 

timer-data = $00; 

timerIdata = $00; 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 81 

timer - csr = $43; 

timer csr = $OA; 

timer-data = $59; 

timer-data = $23; 

timer-data = $00; 

timer-data = $00; 

timer3: 

timer data = cntr3 model; 

=-- timer-data = cntr3-modeh; 

timer-data = cntr3-ld reg; 

timer-data = cntr3-ld-reg+l; 

timer-data = cntr3-hoTd reg; 

timer-data - = cntr3-hold-reg+l; - - 

timer4: 

timer data = cntr4 model; 

timer-data - = cntr4-modeh; 

timer data = cntr4-ld reg; 

timer-data = cntr4-ld-reg+l; 

timer-data = cntr4-ho-rd reg; 

timer-data - = cntr4-hold-reg+l; - - 

timers: 

timer data = cntr5 model; 

timer-data = cntr5-modeh; 

timer-data = def baud rate; 

timer-data = def-baud-rate+l; - - 

start - timers: 

timer csr = $73; 

timer-csr = $OA; 

timer-data = $00; 

timer-data = $00; 

timer-csr = $E3; 

timer-csr = $E4; 

timer - csr = $2C; 

init - zpg: 

compute flags = compute - flags OR run flag; - 

sp stor-= $FF; 

coTumn number = $08; 

pia portb = column number AND $OF; 

write portb = coluin number AND $OF; 

bouncQ count = max b-dunce count; - - 

stow lTds = $00; 

Led out latch = $00; 

Sto; Pwm~ = $00; 

array sell = $00; 

stow Fwm2 = $00; 

- array seL2 = $00; 

next seldom = $18; 

do x 4 to 0 step -1 

overld cnttxl = overld cnt maxrxl; - 

shed t~resh~xl = shed ThCxT; 

restor - threshCx3 = restor - thCx1; 

end; 

state of - chgC43 = $40; 

inhibTt = $01; 

one sec timer = 250; 

cal'r msg - hndlr('WELC0ME TO THE TRISOLAR DEBUG MONITOR1); 
Feb 17 12:17 1984 /u/tam/solar/PSEUDOCODE Page 82 

call display-clr; - 

i - o - flags = i - o - flags OR dataset ready flag; 

pia csra = pa edge - sel OR ddr - deTel 0~~x4 - msec enab; - 

ena?;le interrGpts; 

goto run - task - master; 

ram - error: 

call display error(2); 

call display-digits; - 

loop: 

got0 loop; 

end ram - error; 

............................................................................ 

: This routine is called every 100 msec to average the 16 readings of each 

: of the 12 often read channels. :****************z********************************************************** 

'suedocode: 

iianal - - av: 

do next often = 0 to num - of - often - reads; 

adc tem~ hold = 0: 

adc - temp - hold = often - readCpointer,next - often*323 

+ adc temp - - hold; 

end; 

often - readCnext - often3 = adc - temp hold/l6; - 

end; 

total chgr I = 0; 

do-inde; = 2 to num of often reads; 

total - chgr - I = dump-arrayTindex3 - + total - chgr - I; 

end; 

end signal - av; 
I 1. Report No 

NASA CR-?I4723 

2 Govtrnmnt Accar~on No. 3. Rcc~p~cnt'r Gralop No. 

4. Ttrle and Subtctlr 

Development of a Microprocessor Controller for 

Stand-Along Photovoltaic Power Systems 

7. Authorfs) 

Alan R. Millner 

9. Pnfamrng Ofplnrza~tcm Name and Addrw 

TriSolarCorp 

10 De Angelo Drive 

Bedford, MA 01 730 

12. Sponsortns Agency N,~C and AQbrtr$ 

U.S. Department of Energy 

Division of Photovol taic Energy Technology 

Washington, D.C. 20545 

15. Supplementary Notes 

5 Rcwrc Date 

June, 1984 

6. Pcrform~ng Orgntxal~~ Code 

TSC 210F -. 

8. Performtng Organczat~on Report No. 

10. Wak Un~t No. 

11. Contract or Grant NO. 

DEN3-310 

13. Type of Repon and Pnlod Cbrrrcd 

Con tractor Report 

14. Spomoring Agency Report Number 

DOE/NASA/0310-1 

Final Report. Prepared under Interagency Agreement DE-AI01-79ET20485. Project . Manager, R. DeLonbard, Energy Techno1 ogy Division , NASA Lewis Research Center, 

Cleveland, Ohio 441 35. 

16 Abrtran 

A controller for stand-alone photovoltaic systems has been developed using a 

low power CMOS microprocessor. It performs battery state of charge estimation, 

array control, load management, instrumentation, automatic testing, and 

communications functions. Array control options are sequential subarray 

switching and maximum power control. A calculator keypad and LCD display provides manual control, fault diagnosis and digi ta1 mu1 timeter functions. 

An RS-232 port provides data loggi~g or remote control capability. A prototype 5kW unit has been built and tested successfully. The controller is expected 

to be useful in village photovoltaic power systems, large solar water pumping 

installations, and other battery management applications. 

. 

- 

17. Kay Words (Sumred bv Authorlsll 

Photovoltaic, Controller, 

M$croprocessor, Battery, State-ofCharge, Load Management 

18. Otstrtbut~on St~rtrnent 

Unclassified-unl imi ted 

STAR Category 44 

DOE Category UC-63 

19. Secur~ry Clruti to! this report1 

Unclassified 

' For s~le by the N~t~onal Tcchntcal Inlormatron Service. Spr~nefreld Virpnta 22161 

20 Sccur~ty Classtf. (of thrs pgc) 

Unclassified 

21. No of Pager 

160 

22 Rtc*.