Activity Programming The Battery Charger

With the circuit built it's now time to program the BASIC Stamp module for this application. As before, let's start with updating the program name and declaring the variables.

You may enter the program by typing in the code shown below, or you may download it from the Experiments with Renewable Energy product page at www.parallax.com.

V In the BASIC Stamp Editor, open ADCTest.bs2

V Select File, then Save as; rename the program BatteryCharger.bs2

V Update the title to read as follows:

' Experiments with Renewable Energy v1.0 - BatteryCharger.bs2 ' Programmable Battery Charger which charges, drains, and keeps a record ' of the voltages and currents, to be replayed via StampPlot.

Add the following code to the Declarations section, below the other declared variables for the Plot It and A/D Converter subroutines:

' ----- For Experiment 1: Programmable Battery Charger -------

ChargeLed PIN 13 ' Charge LED (green)

DrainLed PIN 11 ' Drain LED (red)

ReplayLed PIN 9 ' Replay LED (yellow)

ChargeBatt PIN DrainBatt PIN

l5 4

to charge transistor base to drain transistor base codePtr VAR Nib codePtr = 0

dataPtr VAR Word

DataPtrMax CON 4 00

BattFullChg CON 150

True CON 1

counter VAR Byte avgVolts VAR Word avgCurrent VAR Word

MinVolts CON 100

maxVolts VAR Byte doneDraining VAR Bit doneCharging VAR Bit pointer to code block to execute starting at 0 (Exp_1_Init) EEPROM pointer for data logging maximum EEPROM pointer value ~3.00 V for both batteries in series Boolean true/false counter for averaging every 64 sec. average battery voltage storage average battery current storage ~2.00 V for both batteries in series maximum measured battery voltage tell whether battery drained tell whether battery charged

Now it is time to follow up with adding the code for Experiment 1. First we'll add an explanation that documents the purpose of the subroutine. Then, we'll add the executable commands between the Exp_i: and Exp_i_End: labels, filling in this "floor" of our program "building."

V Enter the following commented code at the beginning of the Experiment 1 section to document the subroutine that will come next, as shown below:

Subroutines

Experiment 1: Programmable Battery Charger

Based on codePtr, branch to the appropriate subroutine Exp_1_Init codePtr = 0

Exp_1_Charge codePtr = 1

Exp_1_Drain codePtr = 2

Exp_1_Replay codePtr = 3

Exp_1_Init

Halt charging and discharging Extinguish all LEDs Zero relevant variables Read last codePtr value from EEPROM, increment it test for overflow Write codePtr back to EEPROM Exit

Exp_1_Charge

' Check to see if battery is done charging. If not,

' Enable charging

' Disable discharging

' Flash the charging LED

' Average the battery voltage & current for 256 PlotIt cycles (64 seconds)

' Abort charge cycle if the battery voltage is too high at the beginning

' Else, store the average of the sampled voltage and current to EEPROM

' Increment the EEPROM pointer

' Test to see if the timed charge cycle is complete (dataPtr=DataPtrMax)

' If so, set doneCharging = True to begin draining the battery next loop

' Check to see if battery is drained already. If not,

' Disable charging

' Enable discharging

' Flash the discharging LED

' Sample the discharge voltage and current

' If battery voltage is below minimum set doneDraining = True,

' turn the Drain LED on, and deactivate any more draining.

Exp_1_Replay

' Disable charging and discharging

' Flash the replay LED

' For each data pair in EEPROM sampled during the charge cycle

' Display the charge voltage and current using StampPlot, using

' the PlotIt routine's 250 ms delay as a timer for each sample pair

V Next, fill out the subroutine by adding the code between the between the Exp_1: and Exp_1_End: labels, as shown below.

BRANCH codePtr,[Exp_1_Init,Exp_1_Charge/Exp_1_Drain/Exp_1_Replay]

Exp_1_Init:

LOW ChargeBatt

LOW DrainBatt

LOW ChargeLed

LOW DrainLed

LOW ReplayLed halt battery charging and discharging and extinguish all LEDs maxVolts = 0 counter = 0 dataPtr = 0

avgVolts = 0 avgCurrent = 0

zero the average battery charging voltage zero the average battery charging current zero the maximum measured voltage zero the 64 second loop counter zero the EEPROM data logging pointer

READ DataPtrMax+1,codePtr select the routine to execute codePtr=codePtr+1 IF codePtr>3 THEN codePtr=0 WRITE DataPtrMax+1,codePtr GOTO Exp_1_End

Exp_1_Charge:

IF (doneCharging = True) THEN

HIGH ChargeBatt LOW DrainBatt TOGGLE ChargeLed LOW DrainLED LOW ReplayLED

a2dMuxId = a2dMuxId3 GOSUB A2D

ch3 = (2 55-a2dResult) avgCurrent = avgCurrent+ch3

a2dMuxId = a2dMuxId2 GOSUB A2D ch2 = a2dResult avgVolts = avgVolts+ch2

by incrementing the codePtr test for overflow then...

write it's value back to EEPROM

and exit...the selected subroutine will run based on the BRANCH instruction above the next time thru

codePtr = 1 : charge batteries Jump out if battery is charged already GOTO Exp_1_End activate battery charging transistor deactivate battery discharging transistor flash the charge LED extinguish the others sample the battery charge current (BCI) and add it to avgCurrent I = (Vdd - Vcollector)/10 ohms sample the battery voltage (BV) and add it to aveBattVolt

' abort charge cycle - battery is charged

IF (ch2 > BattFullChg) AND (dataPtr <10 ) THEN

doneCharging = True ' set flag

HIGH ChargeLed ' turn charge LED on steadily

LOW ChargeBatt ' deactivate battery charging transistor ENDIF

counter = counter - 1 ' decrement the averaging counter

WRITE dataPtr,avgVolts.HIGHBYTE dataPtr = dataPtr+1

WRITE dataPtr,avgCurrent.HIGHBYTE dataPtr = dataPtr+1

exit if not zero, else store avg. charging voltage to EEPROM increment the EEPROM pointer store avg. charging current to EEPROM increment the EEPROM pointer

IF avgVolts.HIGHBYTE > maxVolts THEN maxVolts = avgVolts.HIGHBYTE IF avgVolts.HIGHBYTE =< maxVolts - 10 THEN codePtr=2:GOTO Exp_1_End avgVolts = 0 avgCurrent = 0

reset for the next set of data

IF (dataPtr = DataPtrMax) THEN ' charge cycle complete doneCharging = True ' set flag so we don't charge any more

HIGH ChargeLed ' turn charge LED on steadily

LOW ChargeBatt ' deactivate battery charging transistor

ENDIF

GOTO Exp_1_End ' beginning with the next time thru

Exp_1_Drain: ' codePtr = 2 : discharge batteries

' Jump out if battery is drained already IF (doneDraining = True) THEN GOTO Exp_1_End

LOW ChargeBatt ' deactive battery charging transistor

HIGH DrainBatt ' activate battery discharging transistor

TOGGLE DrainLED ' flash the DrainLed

LOW ChargeLed ' extinguish the others LOW ReplayLed a2dMuxId = a2dMuxId0 ' sample the load voltage (BLV)

GOSUB A2D

ch0 = a2dResult a2dMuxId = a2dMuxId2 ' sample the battery voltage (BV)

GOSUB A2D

ch2 = a2dResult a2dMuxId = a2dMuxId1 GOSUB A2D

ch1 = ch2 - a2dResult

IF (ch2 < MinVolts) THEN doneDraining = True HIGH DrainLed LOW DrainBatt ENDIF

sample the load current (BLI)

ch1 = I = (Vbatt-Vcollector)/10 ohms test battery voltage for below min

Set a flag so we don't drain anymore

Turn Drain LED on steadily deactivate battery discharging transistor

GOTO Exp_1_End

Exp_1_Replay: ' codePtr = 3 : replay charge cycle

LOW ChargeBatt ' deactivate battery charging transistor

LOW DrainBatt ' deactivate battery discharging transistor

TOGGLE ReplayLed ' flash the replayLed

LOW ChargeLed ' extinguish the others LOW DrainLed

READ dataPtr,avgVolts.LOWBYTE

ch2 = avgVolts.LOWBYTE ' display the voltage and ...

dataPtr = dataPtr+1

READ dataPtr,avgCurrent.LOWBYTE

ch3 = avgCurrent.LOWBYTE ' current from the last charge dataPtr = dataPtr+1

IF (dataPtr => DataPtrMax) THEN datePtr = 0

HIGH ReplayLed ' turn replay LED on solid

ENDIF

Exp_1_End: RETURN

V Whew!!! Save your work!! If you typed this all in by hand rather than downloading the program, you may want to click on the checkmark icon in the BASIC Stamp Editor. This will test your program to see if it tokenizes. If it does not, follow the error message hints to check your code.

How BatteryCharger.bs2 Works

First, the Declarations section additions define useful constants and pin numbers used in the battery charger.

ChargeLed

PIN

13

DrainLed

PIN

11

ReplayLed

PIN

9

ChargeBatt

PIN

15

DrainBatt

PIN

4

The names in front of the pin declarations give meaning to the individual pins. The names make following the code understandable and meaningful, since instead of saying high 15 to enable the battery charging circuit, it is more obvious to say high ChargeBatt. Similarly, to flash the individual LEDs, saying toggle ChargeLED is more "illuminating" as compared with saying toggle 13. This is why programmers came up with symbolic names in the first place - to make the program code more readable. Also notice that the names for pin declarations begin with a capital letter. This is according to the Parallax "Elements of PBASIC Style", which can be viewed at anytime by clicking on the Help icon on the top line of the BASIC Stamp Editor.

Now let's look at the declared variables and constants.

codePtr

VAR Nib codePtr = 0 dataPtr

VAR Word

CON 150

CON 1

DataPtrMax

BattFullChg

True counter VAR Byte avgVolts VAR Word avgCurrent VAR Word

MinVolts CON 100

maxVolts VAR Byte doneDraining VAR Bit doneCharging VAR Bit

Starting with the variable codePtr, first notice that it and all the other variables begin with a lower-case letter, and constants with an upper case letter. Once again, this is according the Parallax "Elements of PBASIC Style". It's mentioned here to acquaint you with how variable names and program labels are portrayed in PBASIC, so that you can begin to write your own code with the same consistency and style. Sloppy code is just that... sloppy! Do it right the first time, and you'll be rewarded with knowing that you're programs not only work well, but also look professional.

Also notice that just under the codePtr declaration (a 4-bit nibble) we initialize it to zero. We can do this here or in the program code, however making codePtr=0 here gives special meaning to the operation of the program, so please keep this in mind. We'll discuss why we did it here very quickly.

The next two variables deal with a pointer to EEPROM (dataPtr) and its maximum allowed value (DataPtrMax), which the program code uses to store voltage and current data in EEPROM during the charge cycle.

The BattFullChg variable is set to a constant, or con, of 150 that is equivalent to 3.00 volts. Recall that each level of the A/D converter output represents approximately 0.02 volts, so 150 x 0.02 = 3.00 volts.

The constant True is set equal to the value of 1. This allows the programmer to check whether something is true just by using the symbolic constant.

Next comes the counter variable, which is set to an 8-bit byte value and is used by the program to help in timing the charge cycle. Remember, an 8-bit byte can have up to 256 states and the program uses all of them.

The avgVoits and avgCurrent, both 16-bit Word variables, store the sum of 256 battery voltage and current values, respectively. You'll see a neat trick (make that "sophisticated programming example" ;) as to how to compute the average value of these 256 summed readings when we get into the code.

Next come the MinVoits constant, 100, that corresponds to 2.00 volts by the same reasoning as the BattFuiichg variable, and the maxVoits, a byte that will keep track of the maximum voltage experienced during the charge cycle.

Rounding out the list are bit-sized variables named doneDraining and donecharging. These two items act as "flags" to keep track of which state the program is in. For instance, when the batteries are charged, the donecharging variable will be set to True (1). Each time the Exp_i subroutine is called, the program knows which state it was in -if donecharging is True, the program simply turns on the Red LED steadily and exits.

Now with some degree of understanding of the variables and constants involved, let's look at the first instruction of the Exp_l subroutine to see how the battery charger program code begins to do its thing.

BRANCH codePtr,[Exp_1_Init,Exp_1_Charge,Exp_1_Drain,Exp_1_Replay]

When the Main routine calls this subroutine with gosub Exp_l, the first instruction it encounters is the branch where the codePtr variable determines which of four branches, or jumps, that it will take; i.e., Exp_i_init (codePtr=o), Exp_i_charge (codePtr=l), Exp_i_Drain (codePtr=2) or Exp_i_Repiay (codePtr=3). Remember when we declared the variables for this experiment a few paragraphs before, we set codePtr=o immediately after declaring it. What this does for us is to make sure that we branch to Exp_i_init after first loading and running the entire program...and ... after every reset.something that is quite important to how we cycle through the rest of this subroutine.

Next, the Exp_1_Init subroutine deactivates both the charge and discharge transistors and, also, extinguishes all three LEDs and clears some important variables by the following set of code:

Exp_1_Init:

LOW ChargeBatt LOW DrainBatt LOW ChargeLed LOW DrainLed LOW ReplayLed avgVolts = 0 avgCurrent = 0 maxVolts = 0 counter = 0 dataPtr = 0

Now comes the interesting part. The next instructions not only increment the codePtr variable and test for overflow (codePtr > 3), they also read and write a byte of EEPROM memory.

READ DataPtrMax+1,codePtr codePtr=codePtr+1 IF codePtr>3 THEN codePtr=0 WRITE DataPtrMax+1,codePtr GOTO Exp_1_End

So why not store codePtr in RAM (Random Access Memory) after it's incremented? Why EEPROM?

The answer lies in the fact that EEPROM does not lose its data after power is removed .. .or... after a reset. As a matter of fact, the program code we're discussing is also stored in EEPROM, and will remain there, intact, even when power is removed and reapplied and, also, after the reset button on the Board of Education is pushed. And this is the important part. That is, we can step the program code though the charge, discharge and replay cycles each time the reset button is depressed and released. simply by keeping the codePtr variable in EEPROM. You'll learn more about EEPROM in Experiments 4 and 5.

Now look at the above code again.

Each time the reset button is pushed and released, the entire program begins executing from the beginning where the variables and constants are declared and initialized. This includes the codePtr variable where it is set to zero. So when the branch instruction is encountered, a branch will always be made to Exp_1_Init after every reset. It is here that the codePtr variable is changed based on its current value in EEPROM.

For example, let's see how codePtr is used to step the program through all four states. The codPtr in EEPROM can start at any value from 0 to 255, but lets assume it starts at 0. Here's what a series of four reset button depress and release actions will accomplish...

First Reset

• codePtr initialized to zero in declarations

• BRANCH instruction goes to Exp_1_Init

• codePtr is read from EEPROM

• codePtr is incremented from 0 to 1

• codePtr is written back to EEPROM

• program exits (returns to Main)

• BRANCH instruction goes to Exp_1_Charge

• program stays in Exp_1_Charge indefinitely until

Second Reset

• codePtr initialized to zero in declarations

• BRANCH instruction goes to Exp_1_Init

• codePtr is read from EEPROM

• codePtr is incremented from 1 to 2

• codePtr is written back to EEPROM

• program exits (returns to Main)

• BRANCH instruction goes to Exp_1_Drain

• program stays in Exp_1_Drain indefinitely until...

Third Reset

• codePtr initialized to zero in declarations

• branch instruction goes to Exp_l_init

• codePtr is read from EEPROM

• codePtr is incremented from 2 to 3

• codePtr is written back to EEPROM

• program exits (returns to Main)

• BRANCH instruction goes to Exp_1_Replay

• program stays in Exp_l_Replay indefinitely until...

Fourth Reset

• codePtr initialized to zero in declarations

• branch instruction goes to Exp_1_Init

• codePtr is read from EEPROM

• codePtr is incremented from 3 to 4

• codePtr is written back to EEPROM

• program exits (returns to Main)

• BRANCH instruction goes to Exp_1_Init

• codePtr is read from EEPROM

• codePtr is incremented from 0 to 1

• codePtr is written back to EEPROM

• program exits (returns to Main)

• BRANCH instruction goes to Exp_1_Charge

• program stays in Exp_1_Charge indefinitely until

... and so forth. As you can (hopefully) see by now, additional reset actions will continue to step the program through all four states, in order, thus allowing you to step from one program state to another by the push of a button.

As we stated at the beginning of this section, the branch instruction is one of the most powerful and versatile instructions in PBASIC. Besides eliminating a lot of if...then statements to test the codePtr variable, the branch instruction can be used for more sophisticated coding techniques, such as multi-tasking, or quickly switching between program labels without any button pushing, something that we won't do here, but that you should keep in mind as your coding skills advance to more elaborate programs.

DIY Battery Repair

DIY Battery Repair

You can now recondition your old batteries at home and bring them back to 100 percent of their working condition. This guide will enable you to revive All NiCd batteries regardless of brand and battery volt. It will give you the required information on how to re-energize and revive your NiCd batteries through the RVD process, charging method and charging guidelines.

Get My Free Ebook


Post a comment