Universal Programmable NiMh Battery Charger

Universal Programmable NiMh Battery Charger

 

Roughly around this time last year I first started experimenting with an Arduino based programmable current source, trying to regulate the current from an LM2576 switching regulator and failing miserably in my first attempts. Back then the programmable NiMh charger was just a concept I had come up with when finishing up one of my blogs on a similar subject, the device that I envisioned would be able to charge a single AA 1.2 V NiMh cell upto 12 AA NiMh cells in series and with a maximum regulated current output of 2.2 A and a minimum current output of 100 mA for slow timed charging needs.

There was no plan from the beginning and the venture started off as an experiment rather than a serious attempt at a complete prototype, the LM2576 decision has been criticized from the very start, as a MOSFET seemed like a suitable and simple option for current regulation as opposed to the messy controlling scheme for an LM2576, but like I said there was no plan and the part selection wasn’t planned either, I took one thing at a time and addressed issues as they came up, when the LM2576 scheme started to yield promising results I started concentrating all my efforts towards improving that design, I implemented a PID controller, bypassed the feedback mechanism of the LM2576 through software to get the desired result, it took a while before I got the PID steady state error within 1% tolerance of the set point, and I am pretty sure that even now with better component choice this can be reduced further.

The PID current controller is an integral part of the whole concept as the term “programmable” demands for a circuit that can regulate the output current once a set point is passed to the software, the rest of the building blocks include a means of interacting with the charger and a controller that implements a smart charge termination method using the negative delta V charge termination algorithm. Apart from this, as we’ll go along we’ll see the necessity and implementation of certain safety and self diagnostic features I built into the final prototype to help the user troubleshoot faults and determine the state of the charger and probably save the components involved from permanent malfunction.

The PID current controller and its evolution into it’s final state is covered in great detail in the following posts that I have published leading up to this,

Programmable Switching Current Source Using Arduino as a PID Controller

Making the PID Controlled Current Source Better

Improving and Porting the PID Controlled Current Source Design Over to an ATtiny85

The PID controller still remains an ATtiny85 based module as was last published, in fact I am using the same board for this final prototype since I was rushing to complete this project, not much has changed, the only addition has been in the software, lets discuss the individual segments of the NiMh programmable charger project to achieve a better understanding of whats lies ahead.

 

Changes In the ATtiny85 PID Controlled Programmable Current Source

To understand the small changes in the PID controller this time around lets just look at a crude paint drawn basic block diagram of the system we have on our hands.

Universal charger
Basic Block Diagram

The PID current source works largely independent of the master charge controller, once power is applied to the system the PID block initializes and goes into a constant state of waiting, the master controller knows of this state through the status signal which is either a logic LOW or HIGH coming from the PID controller to the master charge controller, this signal is also shared by the LM2676 regulator as an ON or OFF signal for switching to start, once we get to the actual circuit diagram things will become more easy to understand.

A logic LOW read by the master controller tells the master controller that the PID is currently waiting for a set point to be transferred to it, where as a logic HIGH tell the master controller that the PID has received a set point and is ready to start regulating the current once permitted by the master controller.

The communication between the master controller and the PID is a one wire simplex, with the master controller acting as the transmitter and PID as the receiver all the time.

I became interested in implementing a simple one wire simplex protocol for transferring of simple digits once I realized that I was forced to use an external ADC reference for the ATtiny85 PID block to attain a certain level of accuracy, and since the external reference and the SDA pin for I2C communication share a common physical pin on the ATtiny85 therefore I knew I had to look in a different direction, of course I could have used another controller for the PID block with more pins or could have thought of a way to multiplex the functionality where initially the pin would be used for I2C communication and once that is taken care of the pin can then be used for reading external ADC reference, the possibilities are endless with their respective pros and cons but I chose to go down this way and ended up writing up a simple “interrupt counting” protocol which in essence enables the ATtiny85 based PID block to count the number of interrupts on one of its input pins and calculate the time between two consecutive interrupts and based on conditions in the code determines if the received bit change was for a “count up” purpose or was an end of communication signal.

Another crude drawing will help to visualize the concept better,

int counter_1
Basic timing diagram for the interrupt counting protocol

So basically the above diagram implies that if the master is fed in with a current set point of 1.5A, the value will firstly be multiplied by 10, shifting the decimal place and converting the value into a whole number, the master controller will then fire 15 consecutive pulses at the PID pin which is configured to read interrupts, followed by a communication ending bit with a longer time value, the PID block on the other hand is programmed to treat every bit change after a particular time period as count up pulses that adds a one every time to the set point, when a pulse of considerably longer length, for which the limit is already defined in the software, is received the PID considers this as an end of communication signal and then goes about regulating the current from the LM2576, the state of the PID as discussed earlier is known by reading the state of another output pin of the ATtiny85 which is a shared signal for enabling the LM2576 and the status monitoring at the ATMega328P master controller board. Though the actual implementation and calculation in the codes for the master controller and the PID block might differ a little but this largely explains the basic idea behind how the interrupt counting is supposed to work.

Why Monitor The PID Status at The Master Controller?

I did not realize the need for this until the very last stage of the project, the above scheme seems simple and straight forward, and yes it does work rather well but unfortunately power supply noise is a very real phenomenon, specially when working with a noisy SMPS that I am using in this case, it is very likely that the PID receives false interrupts leading to premature activation of the unit resulting in no or very high current flow once the charging starts, since the communication between the PID and the master charge controller is a simplex therefore the only means to monitor the PID status is to monitor the output from the PID which enables the LM2576, in case of a premature activation the master controller can reset the PID once before transferring the set point to it, although the likelihood of a false activation has been greatly reduced by coupling the high frequency noise to ground via a 0.1uF ceramic capacitor.

The PID monitoring is done by the master controller before transferring the set point and during the charge cycle, in case of an ambiguity during the charge cycle the charging is terminated with a dynamic PID error. This is very essential since the two controllers are working largely independent of each other so implementing these checks in the master controller adds an extra degree of control over the process.

 

The ATMega328P based Master Charge Controller

The master controller is basically an off the board Arduino UNO with additional peripherals on the board to support its functionality, the master controller has a few important functionalities, some of which are,

1- Monitors the battery voltage for negative delta V charge termination.

2- Presents the LCD interface to the user for configuration of the charger at start up.

3- Monitoring of the entire process, processing of safety checks, keeping track of errors and  presenting the user with error messages on the LCD to serve as a diagnosis aid, also preventing the battery and charger electronics from damage.

Lets have a look at the simplified block diagram of the master charge controller.

master controller
Basic Block Diagram of The Master Controller & its Different Building Blocks

A few core elements of the master controller are highlighted above, the most important component other than the ATMega328P is the external 15 bit ADC, the ADS1115 which communicates to the micro-controller via the I2C bus plays in integral part in monitoring the battery voltage during charging allowing the master controller to detect a voltage dip of as low as 2mV and that too after having divided the voltage through a voltage divider resistor network. Lets look briefly at each one of these individual components and why these choices were made.

The Negative Delta V Charge Termination & The ADS1115 ADC Module

I have discussed charge termination methods in my very first blog, back then I was using delta T/delta t charge termination method which required a thermistor mounted onto the battery to monitor it’s temperature, however this time around it’s different since I will be charging a range of AA batteries from a single cell of 1.2 volts up to a maximum of 12, 1.2 volt series connected AA cells which counts up to 14.4 Volts. Therefore it was not practical to go with a temperature based charge termination since I would have surely faced issues with thermistor contact at the different range of batteries I wish to use.

The negative delta V is an established charge termination method for the NiMh and NiCad batteries and many commercially available fast chargers use this method of charge termination so I decided to go ahead and experiment with this method.

nickel_chargers_001
Charging Graph of The NiMh Cell

Taking a look back at this picture again helps understand this particular charge termination method, the battery is fed with a constant current of 1C and it’s terminal voltage rises and reaches a peak value, the controller keeps on updating the peak value until a point arrives where the terminal voltage starts to decrease, hence the negative change or the negative delta V occurs, the controller sees this as an end of charge signal and terminates the charging.

For NiMh batteries I selected a safe value of 2mV/cell drop in terminal voltage which will serve as an end of charge signal. However it isn’t that straight forward, the negative delta V charge termination method suffers from the problem of false peaking where an NiMh battery would false peak early on during the charge cycle causing the charge to terminate before the battery is fully charged, however this only seems to happen during the first 10 minute of a charge cycle and especially when the battery was fully drained before the charge cycle, to avoid this problem the charger has a built in function which if enabled will ignore the any peaks that occur during the first 7 minutes of the charging cycle, which is a recommended safe time when employing such peak ignoring features, however not all NiMh suffer from these problems and if your batteries are false peaking a lot which they tend to do near the end of their service life then it’s probably a good idea to replace those batteries.

Lets go back to our charger specs for a second and recall that we are planning to charger batteries from 1.2Volts up to 14.4 volts, and when charging a 14.4V battery pack the terminal voltage during charge can go as high as 18 to 20 volts, since the safe limit for many electronic devices or in this case the ADS1115 ADC is 5 volts therefore it’s understood that the battery voltage has to go to the ADS1115 through a resistor divider network to keep it under safe limits, but why use an external ADC in the first place and why not just work with the built in ADC of the Arduino UNO?

To answer this lets take a look at an example from the actual circuit we will be dealing with.

Capture1
A 1.2V NiMh cell connected across a resistor divider at the moment of having reached it’s peak charged value of 1.8V
Capture2
The terminal voltage falls by 2mV at the end of charge and goes down to 1.798V

The above two Multisim simulations demonstrates that a 2mV drop in the terminal voltage of the battery going through to the ADC (assuming you are using the built in ADC of the Arduini UNO) through the 10K and 2.2K resistor divider network only constitutes to a change of 0.361mV at the micro-controller’s analog input pin. Now for an Arduino UNO’s 10 bit built in ADC the lowest internal voltage reference is of around 1.1V, which means that you can basically read a minimum voltage of, 1.1 / 1024 = 1.074 mV, with which it won’t be possible to detect a voltage change of 0.361mV, of course we can change the resistor values but these values are chosen with the maximum battery voltage during charge in mind, now we can either reduce the reference voltage or increase the ADC bits, the ADS1115 does both for us very conveniently while offering a simple I2C interface for the micro-controller.

The ADS1115 is basically a 16 bit ADC (one bit reserved for voltage polarity, so effectively 15 bits when measuring positive voltage) that offers an I2C interface and has an inbuilt PGA that basically means that there are a number of reference voltages that can be selected depending on the kind of operation. Plus the ADS1115 module that I am using comes in a small package that has a very small footprint and requires no additional external components.

ADS1115
The ADS1115 Module

Luckily there are libraries available from Adafruit for this particular module that allows for easy setting up for a single ended operation using an Arduino.

Talking of programmable references here is a list of reference that can be used for a particular operation with this module.

ADSreference
Specs from the ADS1115 datasheet

The code for the master controller is written such that based on battery voltage selected the master charge controller configures the ADS1115 automatically to use a suitable reference voltage during the entire charge cycle.

Finally in order to provide good noise immunity, the battery voltage is fed into the ADS1115 after being passed through a precision op-amp configured as a voltage follower which then feeds a rather slow response low pass filter, with a 10K resistor and a 2200uf capacitor. I am not happy with the filter design and I feel this is a definite area of improvement and a good design can help reduce the battery temperature once it reaches end of charge, I might work on improving it in the future, however even though right now the measured voltage takes time to catch up to the actual terminal voltage of the battery but this does offer good noise immunity, when I tried experimenting with lower value capacitors the response did improve but this also increased the fluctuation in the measured voltage, any suggestions on this would be welcomed but for now the performance is some what acceptable.

 

The LCD Interface & Button Functions

The aim of the LCD user interface was to present the user with a simple setting up procedure and display important status and error information regarding the state of the charger whenever necessary.

The setting up of a charge cycle demands a minimum of two values, the battery voltage and the current at which the user wishes to charge the battery, the charger can be operated by simply using the four buttons on the front panel as shown below.

IMG_20170523_001839
Not the most elegant of finishes but gets the job done

The user is presented with RESET, CYCLE UP / INCREASE, CYCLE BACK / DECREASE and ENTER buttons, as the name implies the RESET button restarts the charger completely, the CYCLE UP is used to increase, say the battery voltage selection value or run through a menu, similarly the CYCLE BACK decreases the value in a voltage or current selection menu and also serves to enter a hidden service menu when a predefined sequence of operation is followed, and lastly the ENTER button selects an option of interest.

Lets take a moment to briefly look at the interface we are presented with when the charger is first turned ON,

1
The first screen that appears when the charging station is turned ON
2
Charger initializes processes in the background

After the first greeting message the initialization screen displaying the software version is displayed, while this is done, the master charge controller initializes variables, resets the PID controller, carries out depletion of main filter capacitor and checks the Temperature monitoring thermistor mounted on the LM2576’s heat sink (more on this later)

3
Voltage check of the main 24V PSU used for charging exclusively

Afterwards a check is made on the 24V SMPS supply used exclusively for charging only and an indication is forwarded to the LCD that the 24 V supply is above it’s minimum specified level and the charger is ready to proceed. This is important since the master charge controller uses a separate 5 volt power supply which will enable the charger to boot up normally even if the 24 V SMPS is not working, the scheme will become clear once we look at the schematic later on. In case the 24 V supply is below the specified limit an error will be displayed and charging function would be disabled even though the charger can proceed in a test mode for service purposes.

4
Ask the user to connect both charging terminals and press enter

The master controller then asks the user to connect both the charging terminals together and press enter, this is a preparation step for the next battery detection sequence to follow, once enter is pressed the below screen is displayed.

5
Once enter is pressed this screen is displayed for a few seconds, the dots in the second row appear one after the other indicating the sequence is in process and once completed, a sequence completed message is displayed

The charger then instructs the user to connect the battery, +ve to +ve and -ve to -ve this is very important! as currently the charger does not have reverse polarity protection!

6
Battery connection instruction

Once this display is shown the user is expected to connect the battery and press enter, the master controller then goes through a sequence of identifying if the battery is in fact connected or not and while doing so the below screen is displayed.

7
While the master controller is looking for the battery

While this screen is displayed the battery is connected to the internal circuitry with a relay, the in built ADC on the ATMega328P looks for an analog signal at one of it inputs to see if a voltage is present indicating a battery is connected, this scheme works well for a battery that isn’t fully discharged and has some terminal voltage, however for deeply discharged batteries this approach doesn’t work and an error message is displayed indicating that a battery is not found, the charger then asks if the user wants to do an active testing of the battery, if enter button is pressed the battery is fed with 600 mA of charging current and in case a battery is connected a voltage lower than what would normally appear due to the voltage divider in case of no battery connection is read by the controller and is acknowledged as an indication that a battery is present. In both case when the battery is detected the below confirmation screen is displayed followed by an option to select the battery voltage.

19
Battery detection confirmation

In case no battery is detected the master controller assumes the battery is faulty and further operation is not possible, the screen displays that the battery is faulty and a restart must be carried out.

8
Battery voltage selection screen

Once the initial setup is completed successfully the LCD displays a menu to enter the battery voltage of the connected cell, the CYCLE UP or CYCLE DOWN buttons can be used to enter the desired voltages. The voltage can be increased or decreased in 0.1 V intervals by pressing either the cycle up or cycle down button respectively.

9
Working with a 9.6 V battery

Once the voltages are selected the user presses enter and the next screen is shown, which requires the user to enter the desired charging current.

10
Ampere selection screen

The battery current is to be selected in the same way as described above, one can select a minimum of 0.1 A up to a maximum of 2.2 A, it is worth mentioning here that the 0.1 A range is a bit unstable with current’s reaching up to 115mA due to certain constraints with the accuracy of the components used, however operation is reasonable from 0.2 A up to the full capacity current of 2.2 A.

11
Selected 0.9 A current for demonstration purposes

Once the current is selected, pressing enter now will basically start the charging process, before doing so the master controller performs a safety check on the PID controller, transfers the current set point to it, in this case 0.9 A, and starts the charging process, however I feel there should be one more stage of confirmation where all the values are reconfirmed and the user is asked to press enter one more time before charging is started, I might do it in a later version of the code.

12
Once the current is selected and enter is pressed and the charger starts the initiation sequence a series of checks are performed which were too quick for my phone camera to capture, however here is one such screen that displays information about the ADC reference that is selected based on the user provided data
13
Display while charging is under way

The above screen is displayed when the charging has started, the current battery voltage is displayed in the bottom row whereas the battery sign in the top row serves as a rough battery charging meter, the flash sign just to the right of the battery flashes constantly indicating that the charger is running through its sequence loop and hasn’t halted. During the charging process the master controller keeps track of certain status signals of the charger and displays an error if a malfunction occurs, terminating the charging process as well, however we wish that that doesn’t happen.

At this point it is important to mention that the charger by default assumes that the user wants to fast charge the battery and hence use the negative delta V charge termination method that only works when the battery is charged at a rate of above 0.5C therefore entering a lower current value than whats specified will not result in a successful charge termination causing the battery to overheat and causing damage to it, since I always charge my batteries at 1C when fast charging therefore that is something that I don’t have to worry about however I haven’t tested this charger in ranges lower than 1C therefore I am not sure what the performance is going to be like, the delta V will be definitely smaller and harder to detect in that case, so I would highly recommend to always use a 1C rate when fast charging with this charger since the delta V will be flatter and flatter with decreasing charging current or like some NiMh’s the peak might not occur at all and voltage might just flatten out as the end of charge is reached. As a second line of defense I have built into the charger a timer that counts and cuts off the charge after around 1 hour 30 minutes.

As an additional safety feature I believe a voltage max level should at some point be defined in the software for terminating the charge whenever that level of voltage is reached for a particular battery pack to act as another line of defense against over charging. Like I said the software can be altered according to needs and is something that I do wish to do in the future as more and more problems are identified.

However if the user do wish to charge at a slower rate then the charger can be configured for a slow timed charging mode by selecting the relevant option in the hidden service menu.

The hidden service menu offers a few options and can be accessed once the charger goes into battery detection mode and displays, “Looking for batt” on the screen.

7
While on this screen keep the CYCLE DOWN button pressed

Once the charger detects that the battery is connected and displays the battery detected message it looks for the status of the CYCLE DOWN button and if the pin remains HIGH (by pressing the button) for a predefined time a hidden service menu is displayed.

14
The service menu starts by displaying this screen for a few seconds first

After this a series of screens are displayed and the user can simply press CYCLE UP to go to the next option in the service menu, once you leave an option you can not go back to it and in order to get back to that option that charger needs to be restarted and the service menu should be re-entered using the above described procedure.

15
First screen of the service menu

The first screen of the service menu displays the real time value of the 24 V DC supply and serves as diagnostic tool only in case you have encountered a low DC bus voltage error in the beginning, pressing CYCLE UP takes you to the next option.

16
Temperature monitor can be disabled

The temperature monitoring of the LM2576 heat sink can be disabled if required, during the start up of the charger the temperature monitor circuit is probed and if a deviation is recorded it is necessary to disable the temperature monitor to proceed with the charging process, if not disabled the charging wont start.

Under normal circumstances when no initialization error of the temperature monitor is detected, it serves a monitoring purpose displaying a warning on the charging screen (the thermometer symbol as shown above) once the temperature gets above a specified value alerting the user that something might be wrong. If the temperature doesn’t go down after a set interval the charging is terminated with a thermal shutdown error displayed on the screen.

17
Disable peak detection during start for batteries that false peak

The next option in the menu allows the user to disable peak monitoring during the first 7 minutes of a fast charging cycle to ignore false peaking of NiMh batteries and premature charge termination. To remind the user that this option is enabled, the symbol as displayed on the top right hand corner in the above picture is displayed on the charging screen indicating that peaks are being ignored, once the 7 minutes are over the symbol disappears and charger works normally and starts recording peaks.

The above shown option can be selected by pressing enter or the next option can be displayed by pressing CYCLE UP.

18
Slow timed charging option

Once enter is pressed on this option the negative delta V charge termination method is disabled and the user is then directed to enter the number of hours he or she wishes the charge cycle to last for, once this is enabled, on the charging screen the hour glass symbol as shown above and the peak delay symbols are displayed through out the charging cycle to indicate that no peak recording is being done and the charger is operating in a timed charge mode.

It is very important to mention that a high current selection for a timed charging mode can easily destroy the battery as charging will only end once the timer expires and by that time the battery might get overcharged! Hence it is imperative to select a low and safe charging current whenever using this mode of operation.

This was a brief overview of what to expect from the LCD user interface, errors and warnings haven’t been discussed here as most of the errors can’t be recreated easily for documentation purpose however the errors and possible diagnosis will be discussed below later on.

 

The Circuit Diagram

I think it is high time now to look at the actual circuit diagram and see all the components that are involved, I have divided the circuit diagram into three main sections,

1 – The power supply section

2- The PID controlled current source

3 – ATMega328P charge controller and master board

Unfortunately the entire circuit diagram is too big and complicated to be posted as pictures here, to get a better understanding of the diagram a PDF of the three page schematic can be downloaded from here (Circuit Diagram of the Programmable NiMh Battery Charger)

Once you have downloaded the circuit diagram we can now look at some important sections of the schematic diagram and discuss them in detail.

 

The Power Supply Section (Changes in the SMPS Design)

Once you have downloaded the Circuit diagram you can see on the first page that in order to provide power to charge the batteries I am now using an unregulated power as  supply as opposed to my earlier design of a 24 volt regulated power supply using an isolated feedback to shut down the IR2153 chip once the required voltage is reached. However I gave up on that design due to certain problems that faced once I put the circuit together. The power supply generated a lot of audible noise once under heavy load conditions, I faced multiple issues with the output inductor heating up and the MOSFET’s failing suddenly, I have no real explanation for these random behavior but I believe a poor layout was to blame for the condition, plus the shutdown pin on the IR2153 isn’t meant for regulation I believe, instead it shuts down the chip completely as a safety feature, I have yet to probe further regarding these suspicions of mine and I might do it at a later time but in order to complete the project and get a more reliable performance out of the SMPS I decided to go with an unregulated type power supply, using the center tap common line on the ATX transformer and two rectifier diodes in the final stage I was able to get a SMSP voltage output which doesn’t go below 24 volts under maximum desired load of 2.2 A which is just whats needed for this particular operation.

The basic configuration still remains the same the IR2153 is driving two IRF840 MOSFET’s in a half bridge configuration that supplies an ATX transformer primary and from the secondary side after the voltage is stepped down is rectified to get the final voltage. The Output then goes through a Pi filter, capacitors are placed in parallel to get a low effective ESR value which helps reduce ripple on the output, the capacitors bank on the output has a combination of ceramic and electrolytic capacitors, ceramic capacitors are important to suppress high frequency noise and I wish I could place more but this particular combination works fine for this project.

Unregulated SMPS
SMPS Board Layout

To give a basic idea of the kind of board layout I am using for this particular SMPS (since board layout is very important) you can have a look at these pictures.

IMG_20170428_022740
Another view of the SMPS board, the filter caps and the load resistors are on a separate piece of perf board

 

Current Spike Protection at Power Turn OFF (The PID Controller Current Source)

The PID current controller section remains largely unchanged this time around, however at the very end of the project I discovered a problem with the current controller circuit, while I had my multi-meter hooked up for reading the current on the milli-Amps range, as I turned off the charger with my multimeter connected the fuse on the milli-Amps range blew out. In order to diagnose the problem I hooked up the multimeter in the Amps range and turned off the charger and I could see 3 Amps flowing through my load as soon as the charger turned off for a good 1 to 2 seconds which was enough to blow out the 440mA fuse on the mili-Amps range in my multimeter.

It was immediately obvious that when the charger turned off the LM2576 no longer had a HIGH logic on its ON/OFF pin to keep the regulator off and since the 24 V PSU  will most likely have some voltage at it’s output capacitors for some time even after the charger is turned off so with the PID OFF and no feedback to control the LM2576 and ON/OFF pin in a floating state (which is effectively ON) the regulator pushes the maximum allowable current of 3 amps through the load connected at its output. I had to come up with a method to tap the LM2576 regulator after the ATTiny85 PID had turned off and I needed to do so until the 24V SMPS had gone below a certain minimum voltage level which wont be significant enough to push any kind of current through the connected load or in our case, batteries. In the simplest of manners the LM2576 can be pulled up to the supply voltage without a problem and that would have done the job but I wanted to take this opportunity to add to a visual (LED) indication to the whole process which would also help me judge the state of the PID.

InkedCurrent protection_LI
Current Spike Protection Circuit

Above is a section taken from the second page of the schematic in the PID current controller section highlighting the simple solution I came up with to protect the current spike at charger power OFF. I have simply placed an 1N4007 diode is reverse going through a 2.2K resistor and LED combination at the output of the 7400 chip which previously used to drive the LM2576 directly. The LED is an orange colored one with a forward voltage drop of 1.9 V in my particular case, the circuit operates in a rather simple manner, when the 7400 NAND gate IC’s output is HIGH telling the LM2576 to be OFF the diode on the output is reverse biased since the LED’s forward voltage drop is 1.9V, the LED lights up and 1.9V is applied to the LM2576 ON/OFF pin and as the datasheet indicates any voltage above 1.5V turns the LM2576 OFF, now as soon as the 7400 output goes low the diode is forward biased and since TTL is a sinking logic the LED’s Anode gets pulled LOW at around 0.8 Volts turning the LED OFF and the LM2576 ON.

During power OFF since the resistor LED combination is fed by the 24 V SMPS the LM2576’s ON/OFF pin receives 1.9 V even when the power is turned OFF and the capacitor banks on the SMPS has a voltage, during this time you can see the LED is still lit up which keeps the LM2576 OFF and successfully eliminates the current spike problem.

The LED with the largest forward drop is chosen to stay clear of the 1.5 V turn ON limit of the LM2576. Of course the inclusion of the LED is not essential but this serves the purpose of a visual diagnostic option which can come in handy.

 

The LM339 Temperature Threshold Detection Circuit

The LM2576 gets hot when operating at maximum current levels of 2.2 A, for cooling purposes I have mounted a 12 volt fan near the LM2576 however since the temperature can effect the current set point and the chip might heat up to an extent that the LM2576 is damaged especially in case the fan fails, therefore in order to monitor the heat sink temperature of LM2576 I have employed a simple temperature monitor circuit based on an LM339 comparator circuit that can be seen on the third page of the circuit diagram.

temp monitor
The simple temperature monitor circuit interfaced with the master charge controller

The set point for the temperature warning can be set by the 10K trimmer shown above, as soon as the value goes above the set value the LCD screen displays a warning symbol and if the raised temperature persists for a predefined time then the charging is terminated with a Temperature shunt down trigger error. For now I have set the temperature at over 60 degree Celsius.

 

A Brief Look At The Charge Controller

The charge controller as must be evident by now simply controls the charging process and displays relevant data on the LCD screen, however lets just briefly look at the pin functions of each of the utilized pins as it would serve to better understand the hardware features of the master charge controller as well.

Since I am using the ATMega328P which is the same chip that the Arduino UNO comes with and since it’s programmed using the Arduino IDE so its only logical to discuss the pin functionality by referring to these pins as they are labeled in the Arduino UNO board. I won’t go into much details but I have made a rather simple list briefly describing all the pin functions.

pin data charger
Pin Configuration and Function

Well most of whats stated above must be quite clear by now but the only thing I believe that might be a bit confusing right now is the functionality of PIN A3 and why do you need to discharge the main CAP going into the ADS1115 16 bit ADC, well that is for occasions when the ADC’s input exceeds its defined reference voltage (why would this happen in the first place? well more on this later when we discuss the error states the master controller is programmed to detect)

Depleting the capacitor should quickly lower the voltage at the ADC’s pin just to make sure damage is prevented to some extent, although a voltage at the ADC pin is OK as long as its within the supply voltage but overloads of this nature do create an undesirable condition which in my opinion should be cleared up soon.

 

Safety Monitoring, Error States and Critical Charge Termination Errors

This is a rather complex design for my standards, it’s probably the most complicated project I have taken up since the 2 years I have been actively involved in personal projects. I am not sure if any of you are aware but my day job is as a field service technician for Heidelberg Printing presses and I indulge in electrical troubleshooting on a regular daily basis, therefore I have learned to appreciate the need of self diagnostic error messages where the equipment has pre-programmed checks and conditions built into the software to guide the service technician in the direction of the actual fault, so this to me is very important and a lot of inspiration from my daily work has gone into this charger project when it came down to menu designing and trying to build in some degree of self diagnostic functions and error messages that would not only alert the user but most importantly perform steps to safeguard the electronics. There are not many but I have built in a few essential error conditions into the charger which I will discuss briefly.

1- TEMP MONITOR DEFECTIVE!

This is an initialization state error, when the charger starts up it reads the LM339 temperature monitor circuit’s input and if it isn’t HIGH, this error will be displayed, just so that the user know the user can proceed with normal charge cycle only after the Temperature Monitor has been disabled in the Service Mode as discussed before.

2- WARNING! BUS VOLTAGE TOO LOW

This message like the one discussed above is also an initialization error when the charger reads whether the 24VDC bus voltage is present or not, this is essential since even without the 24V the charger can be turned ON since it’s powering through a separate 5 volt supply. If this error occurs the user can only proceed in a test mode where inputs for the battery voltage and current set point can be selected but charging can’t be started. Upon trying to start the charge the process terminates with a “CHARGE NOT POSSIBLE-RESTART”error, this also happens when you try to start a charge without disabling the temperature monitor after the TEMP MONITOR DEFECTIVE error had occurred at initialization.

3- FAULTY BATTERY! RESTART NEEDED

The charger has two modes to detect that a battery has been connected, one is the default passive testing mode and in case that fails for a deeply discharged battery the active test should be performed, during this active testing a current of 600mA is made to flow through the battery and if the controller under this condition detects a voltage above the maximum threshold then this error is generated and charging can no longer work and a restart must be performed.

4- ERROR! – VOLTAGE TOO LOW

In the voltage selection menu if the user presses the enter button while the voltage is at 0.0V then this error is displayed however the user is taken back to the voltage selection menu after displaying the above error for a few seconds.

5- ERROR! – CURRENT VALUE TOO LOW

Same as the one discussed above, if the selected current value is 0.0 A then this message is displayed.

6- PID RUNAWAY ERROR DETECTED!

Before transferring the set point to the PID, the master charge controller checks its status and if an abnormality is detected the above message is displayed, however this message is self clearing and the master charge controller resets the PID and then transfers it the set point to clear out this condition.

7- EXCESS TEMP SHUT DOWN TRIG!

Once the charging cycle starts the master charge controller monitors the state of the temperature monitoring circuit, if a logic LOW is read by the controller then a thermometer warning sign is displayed on the LCD screen, if this conditions persists for a preset time and the temperature doesn’t fall below the limit in the specified time then the charging is terminated with the above error and the process has to be restarted, this particular condition does not immediately trigger a shut down as the output from the LM339 temperature monitor could in certain cases fluctuate due to noise in the system.

8- INTERNAL ERROR! ADC OVERLOAD

If for example the battery is disconnected during charging then the effective load the LM2576 sees due to the voltage divider network that feeds the battery voltage to the ADS1115 is around 12K ohms, this guarantees that close to 24 Volts will appear across the voltage divider and the voltage at the ADS1115’s pin will gradually or in some cases instantly rise above the selected reference voltage overloading the ADS1115, this is an undesirable condition but also represents an opportunity for the charge controller to eliminate charging if any such condition arises due to either human error or system hardware failure. The ADC isn’t supposed to reach it maximum number of increments under any charging combination and when this happens the charging is immediately terminated with the ADC overload error, disconnecting the battery by the internal relay and depleting the filter capacitor feeding the ADS1115.

9- DYNAMIC PID ERROR DETECTED!

During the charge cycle the charge controller repeatedly monitors the status of the PID current controller, if a deviation if found the charging cycle is immediately terminated with the above error and a charge cycle has to be restarted.

Finally every error message is accompanied by a sign at the end that alerts the user about the nature of the message, the below picture shows a typical error along with the error symbol at the end.

Capture3
The LCD showing an error condition with a symbol at the end common for all error messages.

Knowledge of these error messages should make it easy for the user to determine the nature of the problem faced with the charger, in fact after having written all of this I am not entirely sure if I designed this charger keeping in mind the common user. Well I guess complications are always fun.

 

The Final Code & The Arduino Crystal Oscillator Mode

Before we go into the final code, I think it is extremely important to discuss a problem a I faced while testing my design. During my testing I discovered that bringing my hand or finger close to the master controller board would cause the circuit to behave abnormally, the LCD would refresh and would display random characters, the battery connection relay would start clicking, basically the controller would go crazy and only a restart would normalize things.

The Arduino uses Low Power Crystal by default burnt into its fuse bits, this consumes less power but is more prone to malfunction in a noisy environment, in such cases it is recommended to use Full Swing Crystal Oscillator which requires changing of the fuse bits and burning the boot loader again to the Arduino chip.

In order to do proceed with this using IDE version 1.8.1, locate the board.txt file in your computer open the file with text editor and locate,

uno.bootloader.low_fuses=0xFF << lower four bits here select the clock source

uno.bootloader.high_fuses=0xDE

uno.bootloader.extended_fuses=0x05

In order to change to Full Swing Oscillator mode change 0xFF to 0xF7 and reburn the bootloader.

#include <Wire.h>
#include <Adafruit_ADS1015.h>
#include <LiquidCrystal.h>
float peakVoltage = -50.0;
float minimumVoltage = 50.0;
float gainSelect = 0.0;
float voltage = 0.0;
unsigned long timer = 1;
int peakDelay = 0;
byte peakdelayEnable = 0;
int tempMonitor = 0;
byte count = 0;
byte ignore = 0;
byte chargedisable = 0;
byte noTempmon = 0;
byte slowTimed = 0;
int tinyReset = 8;
int cycle = 13;
int enter = 9;
int cycleback = 7;
int capDep = A3;
int battConnect = A2;
float deltaV = 0.0;
float voltset = 0.0;
float currentset = 0.0;
byte tempCount = 0;
byte thermometer[8] =
{
B00100,
B01010,
B01010,
B01110,
B01110,
B11111,
B11111,
B01110
};
byte battery[8] =
{
B00001,
B00001,
B00000,
B01101,
B10010,
B10110,
B11110,
B11110
};
byte peak[8] =
{
B11111,
B01110,
B00100,
B01110,
B11011,
B10001,
B10001,
B11111
};
byte hourGlass[8] =
{
B00000,
B11111,
B10001,
B01110,
B00100,
B01010,
B10101,
B11111
};
byte charging[8] =
{
B00001,
B00010,
B00100,
B01111,
B11110,
B00100,
B01000,
B10000
};

byte errorCode[8] =
{
B01100,
B01100,
B01100,
B01111,
B01111,
B00011,
B00011,
B00011
};
LiquidCrystal lcd(12,11,5,4,3,2);
Adafruit_ADS1115 ads(0x48); /* Use this for the 16-bit version – connect ADDR to GND */
//Adafruit_ADS1015 ads; /* Use thi for the 12-bit version */

void setup(void)
{
byte enterButton [8] =
{
B00001,
B00001,
B00001,
B00101,
B01101,
B11111,
B01100,
B00100
};
long amp = 0;
long longcurrent = 0;
byte cut = 0;
float busvoltage = 0.0;
byte tempchargedisable = 0;
byte meanTime = 0;
pinMode(1,INPUT_PULLUP);
analogReference(DEFAULT);
pinMode(tinyReset,OUTPUT);
digitalWrite(tinyReset, HIGH);
pinMode(6,OUTPUT); //Enable power chip
pinMode(10,OUTPUT); //pwm communication to ATtiny85
digitalWrite(10,LOW);
pinMode(tempMonitor,INPUT_PULLUP);
pinMode(cycle, INPUT);
pinMode(enter, INPUT);
pinMode(cycleback,INPUT);
pinMode(capDep, OUTPUT);
pinMode(battConnect, OUTPUT);
digitalWrite(capDep, HIGH); //Deplets capacitor
lcd.begin(16,2);
lcd.clear();
lcd.createChar(1,thermometer);
lcd.createChar(2,battery);
lcd.createChar(3,peak);
lcd.createChar(4,hourGlass);
lcd.createChar(5,charging);
lcd.createChar(6,enterButton);
lcd.createChar(7,errorCode);
lcd.setCursor(0,0);
lcd.print(” UNIVERSAL NiMh “);
lcd.setCursor(0,1);
digitalWrite(tinyReset, LOW);
lcd.print(“CHARGING STATION”);
delay(2000);
digitalWrite(tinyReset,HIGH);
lcd.clear();
lcd.print(“INITIALIZING..”);
lcd.setCursor(0,1);
lcd.print(“Ver 1.0”);//BETA 3 incorporates 24VDC monitoring and disabling charge if DC bus voltage is lower than 23 volts, also includes active menu in service mode to monitor actual voltage, BETA 4 detects if a battery is connected, doesn’t allow charging for battery voltage lower than 0.1 volts,
delay(2000);//simulate user delay //BETA 5 adds changes to the voltage calculation equation required for the hardware addition of a TL431 precision zener shunt,//BETA 7 improved charge termination, auto ADC reference selection
//digitalWrite(capDep, LOW); //Diabale capacitor depletion
if(digitalRead(tempMonitor) == LOW)
{
delay(1000);
if(digitalRead(tempMonitor) == LOW)
{
lcd.clear();
lcd.print(“TEMP MONITOR”);
lcd.setCursor(0,1);
lcd.print(“DEFECTIVE!”);
errorDisplay();
delay(3000);
tempchargedisable = 1;
}
}
if(analogRead(A0) >= 428) //
{
lcd.clear();
lcd.print(“24 V BUS VOLTAGE”);
lcd.setCursor(0,1);
lcd.print(“LEVEL OK”);
delay(2000);
//digitalWrite(battConnect, HIGH);
digitalWrite(capDep, LOW);
lcd.clear();
lcd.print(“SHORT CHARGING”);
lcd.setCursor(0,1);
lcd.print(“TERMINALS”);
lcd.setCursor(15,1);
lcd.write(6);
while(digitalRead(enter)!= HIGH)
{
delay(300);
}
lcd.clear();
lcd.print(“PREPAIRING….”);
lcd.setCursor(0,1);
int displaySecond = 0;
while(displaySecond <= 15)
{
lcd.setCursor(displaySecond,1);
lcd.print(“.”);
displaySecond++;
delay(500);
}
lcd.clear();
lcd.print(“SEQUENCE”);
lcd.setCursor(0,1);
lcd.print(“COMPLETED!”);
delay(3000);
lcd.clear();
lcd.print(“CONNECT BATTERY”);
lcd.setCursor(0,1);
lcd.print(“& PRESS ENTER”);
while(digitalRead(enter) != HIGH)
{
delay(300);
//waits for user to connect battery and then press enter
}
digitalWrite(capDep, HIGH);
lcd.clear();
lcd.print(“LOOKING FOR BATT”);
lcd.setCursor(0,1);
lcd.print(“?—–|:|:—–?”);
delay(10000);
digitalWrite(capDep, LOW);
digitalWrite(battConnect, HIGH);
delay(4000);
if(analogRead(A1) >= 30)//Battery detection is done by UNO//changed from 15 to 30
{
lcd.clear();
lcd.print(“BATTERY DETECTED”);
lcd.setCursor(0,1);
lcd.print(“OK—-|:|:—-OK”);
delay(2000);
}
else
{
lcd.clear();
lcd.print(“BATT NOT FOUND!”);
lcd.setCursor(0,1);
lcd.print(“—-X-|:|:-X—-“);
delay(2000);
lcd.clear();
lcd.print(“TEST BATTERY?”);
lcd.setCursor(0,1);
lcd.print(“PRESS ENTER”);
while(digitalRead(enter) != HIGH)
{
delay(300);
}
lcd.clear();
lcd.print(“ACTIVE BATT TEST”);
lcd.setCursor(0,1);
lcd.print(“I–>–|:|:–>–I”);
batteryTest();//battery testing procedure
delay(500);
}

}
if(analogRead(A0) < 428)
{
chargedisable = 1;
lcd.clear();
lcd.print(“WARNING! BUS”);
lcd.setCursor(0,1);
lcd.print(“VOLTAGE TOO LOW”);
errorDisplay();
delay(2000);
lcd.clear();
lcd.print(“PROCEED IN TEST”);
lcd.setCursor(0,1);
lcd.print(“OPERATION MODE?”);
while(digitalRead(enter) != HIGH)
{
delay(300);
}
lcd.clear();
lcd.print(“TEST MODE!”);
lcd.setCursor(0,1);
lcd.print(“CAN NOT CHARGE”);
delay(2000);
}
if(digitalRead(cycleback) == HIGH)
{
delay(2000);
if(digitalRead(cycleback) == HIGH)
{
lcd.clear();
lcd.print(” SERVICE MODE”);
//lcd.setCursor(15,0);
//lcd.write(7);
delay(2500);
lcd.clear();
lcd.print(“ACTUAL BUS VOLTS”);
while(digitalRead(cycle) != HIGH)
{
//lcd.clear();
// lcd.print(“ACTUAL BUS VOLTS”);
lcd.setCursor(0,1);
busvoltage = analogRead(A0);
busvoltage = (busvoltage*5.0/1024)*11; //Change power input to 12 volts at Vin
lcd.print(busvoltage);
lcd.setCursor(5,1);
lcd.print(“V”);
delay(200);
}
delay(300);
lcd.clear();
lcd.print(“DISABLE TEMP”);
lcd.setCursor(15,0);
lcd.write(1);
lcd.setCursor(0,1);
lcd.print(“MONITOR?”);
lcd.setCursor(15,1);
lcd.write(6);

while(digitalRead(cycle) != HIGH)
{
/*lcd.clear();
lcd.print(“DISABLE TEMP”);
lcd.setCursor(0,1);
lcd.print(“MONITOR?”);*/
if(digitalRead(enter) == HIGH)
{
lcd.clear();
lcd.print(“TEMP MONITOR”);
lcd.setCursor(0,1);
lcd.print(“DISABLED!”);
tempchargedisable = 0;
noTempmon = 1;
delay(2000);
break;
}
delay(200);
}
delay(300);
lcd.clear();
lcd.print(“ENABLE PEAK”);
lcd.setCursor(15,0);
lcd.write(3);
lcd.setCursor(0,1);
lcd.print(“DELAY AT START?”);
lcd.setCursor(15,1);
lcd.write(6);
while(digitalRead(cycle) != HIGH)
{
//lcd.clear();
//lcd.print(“ENABLE PEAK”);
//lcd.setCursor(0,1);
//lcd.print(“DELAY AT START?”);
if(digitalRead(enter) == HIGH)
{
lcd.clear();
lcd.print(“PEAK DELAY”);
lcd.setCursor(0,1);
lcd.print(“ENABLED!”);
peakdelayEnable = 1;
delay(2000);
break;
}
delay(200);
}
delay(300);
lcd.clear();
lcd.print(“ENABLE TIMED”);
lcd.setCursor(15,0);
lcd.write(4);
lcd.setCursor(0,1);
lcd.print(“CHARGE MODE?”);
lcd.setCursor(15,1);
lcd.write(6);

while(digitalRead(cycle) != HIGH)
{
//lcd.clear();
//lcd.print(“ENABLE TIMED”);
//lcd.setCursor(0,1);
//lcd.print(“CHARGE MODE?”);
if(digitalRead(enter) == HIGH)
{
lcd.clear();
lcd.print(“SLOW TIMED”);
lcd.setCursor(0,1);
lcd.print(“MODE ENABLED”);
peakdelayEnable = 1;
slowTimed = 1;
delay(2000);
lcd.clear();
lcd.print(“SELECT TIMER”);
while((digitalRead(enter) != HIGH)&& (timer >= 1))
{
if(digitalRead(cycle) == HIGH)
{
timer = timer + 1;
}
else if((digitalRead(cycleback) == HIGH)&&(timer > 1))
{
timer = timer – 1;
}
delay(200);
lcd.setCursor(0,1);
lcd.print(timer);
if(timer == 9)
{
lcd.setCursor(1,1);
lcd.print(” “);
}
lcd.setCursor(2,1);
lcd.print(“Hour”);
}
break;
}
delay(200);
}
}
}
timer = timer*60*60;
delay(300);
lcd.clear();
lcd.setCursor(0,0);
lcd.print(“SELECT BATT VOLT”);
lcd.setCursor(0,1);
//while(digitalRead(enter) != HIGH)
while(cut == 0)
{
if(voltset == 0)
{
if(digitalRead(enter) == HIGH)
{
lcd.clear();
lcd.print(“ERROR! – VOLTAGE”);
lcd.setCursor(0,1);
lcd.print(“TOO LOW”);
errorDisplay();
delay(1500);
lcd.clear();
lcd.print(“SELECT BATT VOLTAGE”);
}
}
if(voltset > 0)
{
if(digitalRead(enter) == HIGH)
{
cut = 1;
}
}
if(digitalRead(cycle) == HIGH)
{
if(meanTime >= 12)
{
voltset = voltset + 1.0;
}
else {
meanTime++;
voltset = voltset + 0.1;
}
}
else if(digitalRead(cycleback) == HIGH)
{
voltset = voltset – 0.1;
if(voltset < 0.0)
{
voltset = 0.0;
}
}
else
{
meanTime = 0;
}
delay(200);
lcd.setCursor(0,1);
lcd.print(voltset);
lcd.setCursor(5,1);
lcd.print(“V”);
}
cut = 0;
deltaV = voltset;
deltaV = deltaV/1.2;
deltaV = deltaV*0.002;
lcd.clear();
lcd.print(“deltaV = “);
lcd.print(deltaV,3);
lcd.print(“V”);
delay(2000);
lcd.clear();
lcd.setCursor(0,0);
lcd.print(“SELECT BATT AMP”);
lcd.setCursor(0,1);
delay(200);
while(cut == 0)
{
if(currentset > 0)
{
if(digitalRead(enter) == HIGH)
{
cut = 1;
}
}
if(currentset == 0)
{
if(digitalRead(enter) == HIGH)
{
lcd.clear();
lcd.print(“ERROR! – CURRENT “);
lcd.setCursor(0,1);
lcd.print(“VALUE TOO LOW”);
errorDisplay();
delay(2000);
lcd.clear();
lcd.print(“SELECT BATT AMP”);
}
}
if(digitalRead(cycle) == HIGH)
{
currentset = currentset + 0.1;
if(currentset > 2.2)
{
currentset = 0.0;
}
}
if(digitalRead(cycleback) == HIGH)
{
currentset = currentset – 0.1;
if(currentset < 0.0)
{
currentset = 0.0;
}
}
delay (200);
lcd.setCursor(0,1);
//discur = currentset/10;
lcd.print(currentset);
lcd.setCursor(4,1);
lcd.print(“A”);

}

delay(300);
lcd.clear();
lcd.print(“CHECKING PID”);
delay(1000);
if(digitalRead(1) == HIGH)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print(“PID RUNAWAY”);
lcd.setCursor(0,1);
lcd.print(“ERROR DETECTED!”);
errorDisplay();
delay(2000);
lcd.clear();
lcd.setCursor(0,0);
lcd.print(“REINITIALIZING”);
lcd.setCursor(0,1);
lcd.print(“PID CONTROLLER”);
digitalWrite(tinyReset, LOW);
delay(500);
digitalWrite(tinyReset, HIGH);
delay(7000);
}
lcd.clear();
lcd.setCursor(0,0);
lcd.print(“TRANSFERING”);
lcd.setCursor(0,1);
lcd.print(“SETPOINT TO PID”);
delay(1000);
currentset = currentset*10;
longcurrent = currentset;
longcurrent = longcurrent – 1;
while (amp != longcurrent)
{
digitalWrite(10, HIGH);
delayMicroseconds(100);
digitalWrite(10, LOW);
delayMicroseconds (100);
amp++;
}
digitalWrite(10,HIGH);
delayMicroseconds(1000);
digitalWrite(10,LOW);

gainSelect = voltset*0.66;
gainSelect = gainSelect + voltset + currentset*0.01;
gainSelect = gainSelect*2.1760/12.1760;

if((gainSelect > 0.256) && (gainSelect < 0.512))
{
ads.setGain(GAIN_EIGHT);
gainSelect = 0.512;
}

else if((gainSelect > 0.512) && (gainSelect < 1.024))
{
ads.setGain(GAIN_FOUR);
gainSelect = 1.024;
}
else if((gainSelect > 1.024) && (gainSelect < 2.048))
{
ads.setGain(GAIN_TWO);
gainSelect = 2.048;
}
else //if((gainSelect > 2.048) && (gainSelect < 4.096))
{
ads.setGain(GAIN_ONE);
gainSelect = 4.096;
}
//else
//{
// ads.setGain(GAIN_TWOTHIRDS);
// gainSelect = 6.144;
//}

 

lcd.clear();
lcd.print(“ADC REFERENCE”);
lcd.setCursor(0,1);
lcd.print(gainSelect, 4);
lcd.setCursor(6, 1);
lcd.print(“V”);
delay(2000);
lcd.clear();
//lcd.print(“”);
lcd.print(“CHARGING ON”);
lcd.setCursor(0,1);
lcd.print(currentset/10);
lcd.setCursor(4,1);
lcd.print(“A”);
//Serial.println(“Hello!”);

//Serial.println(“Getting single-ended readings from AIN0..3”);
//Serial.println(“ADC Range: +/- 6.144V (1 bit = 3mV/ADS1015, 0.1875mV/ADS1115)”);
//lcd.begin(16,2);
//lcd.clear();
// The ADC input range (or gain) can be changed via the following
// functions, but be careful never to exceed VDD +0.3V max, or to
// exceed the upper and lower limits if you adjust the input range!
// Setting these values incorrectly may destroy your ADC!
// ADS1015 ADS1115
// ——- ——-
// ads.setGain(GAIN_TWOTHIRDS); // 2/3x gain +/- 6.144V 1 bit = 3mV 0.1875mV (default)
// ads.setGain(GAIN_ONE); // 1x gain +/- 4.096V 1 bit = 2mV 0.125mV
// ads.setGain(GAIN_TWO); // 2x gain +/- 2.048V 1 bit = 1mV 0.0625mV
// ads.setGain(GAIN_FOUR); // 4x gain +/- 1.024V 1 bit = 0.5mV 0.03125mV
//ads.setGain(GAIN_EIGHT); // 8x gain +/- 0.512V 1 bit = 0.25mV 0.015625mV
// ads.setGain(GAIN_SIXTEEN); // 16x gain +/- 0.256V 1 bit = 0.125mV 0.0078125mV

 

ads.begin();

if((chargedisable == 0)&&(tempchargedisable == 0))
{
digitalWrite(6,HIGH);//Enable LM2576 power chip
}
if((chargedisable == 1)&&(tempchargedisable == 1))
{
lcd.clear();
lcd.print(“CHARGE NOT”);
lcd.setCursor(0,1);
lcd.print(“POSSIBLE-RESET”);
errorDisplay();
for(;;){}
}
if(slowTimed == 0)
{
timer = 5400;
}
if(slowTimed == 1)
{
lcd.setCursor(13,0);
lcd.write(4); //
}

}

void loop(void)
{
int16_t adc0;

adc0 = ads.readADC_SingleEnded(0);
voltage = (adc0*gainSelect)*12.1760/32768/2.1760; //TL431 precision zener version
voltage = voltage – (currentset*0.01);
//Serial.print(“AIN0: “); Serial.println(adc0);
//Serial.print(“AIN1: “); Serial.println(adc1);
//Serial.print(“AIN2: “); Serial.println(adc2);
//Serial.print(“AIN3: “); Serial.println(adc3);
//Serial.println(” “);
/* lcd.setCursor(0,0);
lcd.print(“ADC “);
lcd.print(adc0);
lcd.setCursor(0,1);
lcd.print(“Volts “);
lcd.print(voltage);
delay(200);*/
//lcd.clear();
batteryMeter();
if((voltage >= peakVoltage)&&(peakdelayEnable == 0))
{
peakVoltage = voltage;
count = 0;
ignore = 0;
minimumVoltage = 50.0;

}
else if((voltage < peakVoltage)&&(peakdelayEnable == 0))
{
if(voltage <= minimumVoltage)
{
minimumVoltage = voltage;
if(((peakVoltage – voltage) >= deltaV)&&(peakdelayEnable == 0))
{
lcd.setCursor(14,0);
lcd.write(2);
ignore = 0;
count++;
if(count >= 5)
{

digitalWrite(6,LOW);//turn off LM2576 when charging finished, cuts off at 12.64951 V for a 9.6 V battery
lcd.clear();
lcd.print(“CHARGE DONE!”);
lcd.setCursor(0,1);
lcd.print(“DISCONNECT BATT!”);
digitalWrite(tinyReset, LOW);
delay(1000);
digitalWrite(tinyReset, HIGH);
digitalWrite(battConnect, LOW);
delay(100);
digitalWrite(capDep, HIGH);
delay(3000);
digitalWrite(capDep, LOW);
while(1)
{
lcd.clear();
lcd.print(“CHARGE REPORT”);
lcd.setCursor(0,1);
lcd.print(peakVoltage – voltage,5);
lcd.setCursor(7,1);
lcd.print(“V Delta V”);
delay(2000);
lcd.clear();
lcd.print(“CHARGE REPORT”);
lcd.setCursor(0,1);
lcd.print(peakVoltage,5);
lcd.setCursor(7,1);
lcd.print(“V Peak V”);
delay(2000);
}
}
}
}
else if((voltage > minimumVoltage)&&(peakdelayEnable == 0))
{
lcd.setCursor(14,0);
lcd.print(” “);
ignore++;
if(ignore >= 3)
{
count = 0;
ignore = 0;
}
}
}
//Serial.println(voltage,5);
lcd.setCursor(6,1);
lcd.print(“@ “);
lcd.setCursor(7,1);
lcd.print(” “);
lcd.setCursor(7,1);
lcd.print(voltage,4);
lcd.print(“V”);
lcd.setCursor(12,0);
lcd.write(5);
delay(500);
lcd.setCursor(12,0);
lcd.print(” “);
delay(500);
if(noTempmon == 0)
{
if(digitalRead(tempMonitor) == LOW)
{
lcd.setCursor(15,0);
lcd.write(1);
tempCount++;
if(tempCount >= 200)
{
digitalWrite(6, LOW);
digitalWrite(tinyReset, LOW);
delay(200);
digitalWrite(tinyReset, HIGH);
lcd.clear();
lcd.print(“EXCESS TEMP”);
lcd.setCursor(0,1);
lcd.print(“SHUT DOWN TRIG!”);
errorDisplay();
for(;;)
{
}
}
}
else
{
lcd.setCursor(15,0);
lcd.print(” “);
tempCount = 0;
}
}

if(adc0 >= 32767)//((adc0 >= 32767)||((adc0 >= 21845)&&(gainSelect == 6.144))) //Safety for ADC protection in case of overload or battery disconnection
{
digitalWrite(battConnect, LOW);//Battery disconnected
digitalWrite(capDep, HIGH);//ADC safety cap depletion is enabled
digitalWrite(6, LOW); //turn off current
digitalWrite(tinyReset, LOW);
delay(200);
digitalWrite(tinyReset, HIGH);
lcd.clear();
lcd.print(“INTERNAL ERROR!”);
lcd.setCursor(0,1);
lcd.print(“ADC OVERLOAD”);
errorDisplay();
delay(10000);
digitalWrite(capDep, LOW);
for(;;)
{}
}

if(peakdelayEnable == 0)
{
timer–;
}
if(peakdelayEnable == 1)
{
lcd.setCursor (15,1);
lcd.write(3);
peakDelay++;
timer–;
}
if((peakDelay == 420)&&(slowTimed == 0))
{
lcd.setCursor(15,1);
lcd.print(” “);
peakdelayEnable = 0;
}

if(timer == 0)
{
digitalWrite(6, LOW);
digitalWrite(tinyReset, LOW);
delay(100);
digitalWrite(tinyReset, HIGH);
lcd.clear();
lcd.setCursor(0,0);
if(slowTimed == 1)
{
lcd.print(“TIMER EXPIRED”);
lcd.setCursor(0,1);
lcd.print(“CHARGE DONE”);
}
else
{
lcd.print(“SAFETY TIMER UP!”);
lcd.setCursor(0,1);
lcd.print(“PEAK MISSED!”);
}
digitalWrite(battConnect, LOW);
delay(1000);
digitalWrite(capDep, HIGH);
delay(10000);
digitalWrite(capDep, LOW);
for(;;)
{}
}

if(digitalRead(1) == LOW)
{
digitalWrite(6, LOW);
lcd.clear();
lcd.print(“DYNAMIC PID”);
lcd.setCursor(0,1);
lcd.print(“ERROR DETECTED!”);
errorDisplay();
for(;;)
{
}
}

}

void batteryTest()
{
int A = 0;
//ads.begin();
while (A != 5)
{
digitalWrite(10, HIGH);
delayMicroseconds(100);
digitalWrite(10, LOW);
delayMicroseconds (100);
A++;
}
digitalWrite(10,HIGH);
delayMicroseconds(1000);
digitalWrite(10,LOW);
delay(2000);
digitalWrite(6,HIGH);
delay(10000);
if(analogRead(A1) > 650) //3.07V at the voltage divider node,corresponding to a battery voltage of 17.178V, a deeply discharged battery of 14.4V (12 AA cell) max wont be charged to 17.178 volts in 10 seconds indicating theres a battery connected, changed from 630 to 650
{
digitalWrite(6,LOW); //turn off LM2576
chargedisable = 1;
lcd.clear();
lcd.print(“NO BATTERY FOUND”);
lcd.setCursor(0,1);
lcd.print(“CHARGE DISABLED!”);
delay(5000);
lcd.clear();
lcd.print(“FAULTY BATTERY!”);
lcd.setCursor(0,1);
lcd.print(“RESTART NEEDED”);
errorDisplay();
digitalWrite(tinyReset, LOW);
delay(500);
digitalWrite(tinyReset, HIGH);
for(;;){}

}
else
{
digitalWrite(6,LOW);
lcd.clear();
lcd.print(“BATTERY FOUND!”);
lcd.setCursor(0,1);
lcd.print(“OK—-|:|:—-OK”);
digitalWrite(tinyReset, LOW);
delay(500);
digitalWrite(tinyReset, HIGH);
chargedisable = 0;
delay(3000);
}
}

void batteryMeter()
{
byte batteryEmpty[8] =
{
B01110,
B11011,
B10001,
B10001,
B10001,
B10001,
B10001,
B11111
};

byte batteryLevel1[8] =
{
B01110,
B11011,
B10001,
B10001,
B10001,
B10001,
B11111,
B11111

};

byte batteryLevel2[8] =
{
B01110,
B11011,
B10001,
B10001,
B10001,
B11111,
B11111,
B11111
};

byte batteryLevel3[8] =
{
B01110,
B11011,
B10001,
B10001,
B11111,
B11111,
B11111,
B11111
};

byte batteryLevel4[8] =
{
B01110,
B11011,
B10001,
B11111,
B11111,
B11111,
B11111,
B11111

};

byte batteryLevel5[8] =
{
B01110,
B11011,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111
};

byte batteryLevel6[8] =
{
B01110,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111
};

float barGraph = 0.0;
barGraph = 1.297*voltset +0.2236;
//barGraph = 1.297*voltset +0.242;
//barGraph = barGraph – (0.111*barGraph);
//barGraph = barGraph/6;
//barGraph = (barGraph – voltset)/6;
if(voltage >= barGraph) // 1
{
lcd.createChar(0,batteryLevel6);
lcd.setCursor(11,0);
lcd.write(byte (0));
}
else if (voltage >= barGraph*0.9815) // 0.9815
{
lcd.createChar(0,batteryLevel5);
lcd.setCursor(11,0);
lcd.write(byte (0));
}
else if(voltage >= barGraph*0.963) // 0.963
{
lcd.createChar(0,batteryLevel4);
lcd.setCursor(11,0);
lcd.write(byte (0));
}
else if(voltage >= barGraph*0.9445) // 0.9445
{
lcd.createChar(0,batteryLevel3);
lcd.setCursor(11,0);
lcd.write(byte (0));
}
else if(voltage >= barGraph*0.926) // 0.926
{
lcd.createChar(0,batteryLevel2);
lcd.setCursor(11,0);
lcd.write(byte (0));
}
else if(voltage >= barGraph*0.9075) // 0.9075
{
lcd.createChar(0,batteryLevel1);
lcd.setCursor(11,0);
lcd.write(byte (0));
}
else
{
lcd.createChar(0,batteryEmpty);
lcd.setCursor(11,0);
lcd.write(byte (0));
}
}

void errorDisplay()
{
lcd.setCursor(15,1);
lcd.write(7);
}

Well the whole thing took around 1000 lines of code in total, now my programming skills aren’t that great, or in the words of Linus Torvalds, I don’t have good taste when it comes to coding, so there is much much room for optimization and improvement, and that isn’t just on the software side alone.

It is very easy to forget that we are working with two microcontrollers here, the above code is for the Arduino UNO (ATMega328P) based master charge controller, however there has been changes in the ATtiny85 based PID’s code as well, especially with the addition of set point communication protocol, the ATtiny85 is using an internal 16Mhz oscillator and details on how to program it are available in my previously listed posts on this topic, for now here is the modified code of the PID controller that I am using.

volatile int pwm_value = 0;
volatile int prev_time = 0;
volatile int cut = 0;
volatile int count = 0;
long duration, result, period;
int ON = 3;
int FB = 1;
//int comPIN = 2;
int Bias;
//int Compensate = 0, Count = 0;
float totalref = 0;
float Output;
float i = 0.0;
float Actual, lastError = 0.0, Error = 0.0, Derivative = 0.0, Integral = 0.0;
float Amp = 0.0;
float Kp, Ki, Kd;
float setPOINT = 0.0;
void setup()
{
float num = 0.0;
//interrupts();
//analogReference(INTERNAL2V56);// set internal reference to 1.1 V
analogReference(EXTERNAL);
delay(100);
pinMode(ON,OUTPUT); // ON/OFF signal for LM2576
pinMode(FB, OUTPUT); //PWM for LM2576 Feedback
//digitalWrite(ON, HIGH);
digitalWrite(ON,LOW);//Arduino controller edit
pinMode(2, INPUT);
delay(3000);
attachInterrupt(0, rising, RISING);
while(cut == 0)
{}
Amp = count;
Amp = Amp*0.1;
setPOINT = Amp*0.1*10.0*1024; // with the amplification factor included
setPOINT = setPOINT/2.47;
//Kp = pTUNE(setPOINT);
Kp = 0.03; //0.05 (send 5)//reducing or increasing has the same affect across all set points
Ki = 0.0006; //0.0008 (send 8)//The intergral sums up and reduces the error in some time completely
Kd = 0.0002;//0.0075 (send 75)
//Ki = iTUNE(setPOINT);
if(Amp == 0.1)
{
Bias = 67;
}
else
{
Bias = 68;
}
analogWrite(FB,70);
//digitalWrite(ON,LOW);
digitalWrite(ON,HIGH);//Arduino controller edit
delay(5000);

}

void loop()
{
Actual = analogRead(A2);
//delayMicroseconds(500);
Error = setPOINT – Actual;
Integral = Integral + Error;
if(Actual <= 15) //Forces the Integral to Zero when current below a certain value
{
Integral = 0;
}
if(Integral > 300000)//Limits the integral to prevent Integral windup
{
Integral = 300000;
}
if(Integral < -300000)
{
Integral = -300000;
}
Derivative = lastError – Error;
Output = Bias – (Kp*Error + Ki*Integral + Kd*Derivative);
if(Output > 255) //Limits the output to 5 volts maximum
{
Output = 255;
}
if(Output < 0)
{
Output = 10;
}
analogWrite(FB, Output);
lastError = Error;
}

void rising()
{
attachInterrupt(0, falling, FALLING);
count++;
prev_time = micros();
}
void falling()
{
attachInterrupt(0, rising, RISING);
pwm_value = micros()- prev_time;
if(pwm_value > 800)
{
detachInterrupt(0);
cut = 1;
}
}

 

Closing Remarks

Well this is it, at one point I didn’t think this was possible especially when your personal and professional life has been in termoil for the most part, but at last I have something to present and write about, the project at this point is still largely rough around the edges, I won’t be sharing any pictures of the circuits because quite frankly it’s a rats nest in there and sharing these pictures would be setting the wrong standards, also unfortunately in this part of the world access to 3D printing isn’t easy or should I say, 3D printing isn’t that mainstream yet, the future will hold better things I hope, this is primarly why I had the enclosure hand made from 4mm pastic sheets, I wish, along with all the little things, I could better this aspect of the design as well.

The techniques I have used in this project have drawn a fair share of criticism during the course of one year from online forums mainly, but I never meant to achieve anything apart from learning new things from this project, yes there are better ways of doing things but it’s essential to learn and make your own mistakes along the way, but that doesn’t imply that I don’t wish to acknowledge the valuable inputs given by more experienced members of the maker community.

Everything I have done in the past one year in summed up in this article, it’s open and free to experminet and alter, I will be really happy if someone comes forward asking for help or suggestions, finally I will say my good byes with a video of the working and the setting up of this charger, I hope to see you again soon with another exciting project, until then take good care!

 

If you think this effort was worth encouraging, please play your part by liking and sharing my blog, it brings a lot of motivation.

 

Advertisements

Regulated Half Bridge Switching Power Supply Using ATX Transformer

Regulated Half Bridge Switching Power Supply Using ATX Transformer

So far all of my projects have been powered using linear regulators, batteries, or at most a few easy to handle switching regulators, I have designed linear power supplies in the past which are pretty straight forward but I have never felt the need to design a switching power supply until very recently, this post will discuss how I went from knowing only the theory behind a switching supply to actually designing one which serves the purpose.

Well I must admit, when it comes to electronics, power is not my strongest side, up until now I was powering my NiMh charger prototypes with an external 24 volt power adapter which I never wanted to be part of the final product, it goes without saying that an integrated 24 volt switching supply was needed so the project could be powered off the AC mains directly that could feed the necessary current to the battery, the switching power supply needed to supply at least 2.5 Amps to do the job properly.

The problem? I had never tried my luck with an SMPS before which increases the likelihood of things blowing up significantly. I had a couple of IR2153 chips and a few IRF840 MOSFETs in my stack but I was delaying this until the very end. When you talk about SMPS supplies it offers certain benefits over your regular linear power supplies, first of the size as it eliminates the need to use bulky iron core transformers and instead uses light weight high frequency pulse transformers and secondly the efficiency of the design.

The Switched Mode Power Supply Working Principle

The SMPS can be implemented using several of the available topologies that suit a wide variety of power output needs, however for this particular design we will be implementing a half bridge topology and discuss its working principle.

smps_block_diagram
The basic SMPS block diagram (Courtesy google images)

The simple block diagram above shows that the switched mode power supply can be divided into a few basic sections, the AC mains are rectified directly using a bridge rectifier and energy is stored in a capacitor bank, the inverter then converts DC voltage into a high frequency AC which will be stepped down using a high frequency transformer, this high frequency AC conversion is where the two MOSFETs will be connected in a half bridge configuration which gives the topology its name, the stepped down AC voltage is then rectified again using fast recovery diodes and the output voltage is finally filtered through an LC filter. Regulation can be added to an SMPS when some part of the voltage is fed back to the inverter control chip to regulate the duty cycle or like in our case implement an ON OFF control through an isolated feedback using an optocoupler.

An ATX Supply Transformer & the IR2153 MOSFET Driving Chip

I decided to keep things simple, since finding a high frequency transformer with known parameters is almost impossible in this part of the world therefore I decided to salvage a transformer from an old faulty ATX PC power supply. However I must mention there are tons of tutorials available online which can help you to wind up your transformer catering to your personalized design needs.

atx-transformator-ei33-acilim-2
Winding configuration on my ATX transformer (courtesy 320volt.com)

This particular ATX transformer  has a single primary and two secondary windings, one winding is used for the DC 5 volt rail which is capable of delivering a current of 22 Amps and the other for the 12 volt rail that could deliver up to 6 Amps as per the rated specs for this particular supply

img_20170212_230645
Rating of the ATX supply

So the 12 volt rail can supply up to 72 watts of power, as a rough estimate 72 watts of power with an output regulated voltage of 24V can supply a current of around 3 Amps which is just over whats required for the charger application, one important thing to mention is that the transformer peak voltage on the transformer 12 volt output winding is around 50 volts, so this voltage can easily be rectified  and then regulated to get a stable voltage of 24 volts, but in order to get 134qa proper voltage output the transformer primary first needs to be fed with an alternating voltage of the right frequency, for this two transistors are used in a half bridge configuration as shown below.

img_20170212_230956
Stage1 – FET Q1 is ON & Q2 is OFF
img_20170212_231013
Stage2- FET Q1 OFF & Q2 ON

As shown above the transistors Q1 and Q2 are turned ON and OFF to produce an alternating voltage across the transformer primary, in order to drive the transistors on the high voltage side the IR2153 MOSFET driver is used.

ir2153
The IR2153 configuration

The frequency at which the half bridge is to be driven can be selected by a suitable combination of the resistor and capacitor connected between RT, CT and CT, COM respectively. Since the salvaged transformer from the ATX power supply comes without any specs therefore the ATX circuit had to be analyzed to determine what frequency it was designed for.

Looking around the circuit and after going through the datasheets for the chips installed I came across the DBL494 chip which drives the half bridge in the SMPS, the resistor and capacitor combination on pin 5 and pin 6 of this  particular chip indicates that the transformer was supplied with a frequency of round 22KHz.

img_20170212_230740
DBL494 chip on the ATX power supply

The shutdown feature on the IR2153 can be used to regulate the voltage at the output of the power supply, for this a TL431 regulator will be used to give isolated feedback through an optocoupler to the IR2153 telling it to stop switching the MOSFET’s once the output voltage of 24volts is reached.

The Circuit

Below is the circuit diagram I put together using the easy EDA design tool, not the best but is at least on a more acceptable level as compared to my hand drawn schematics.

new-schematic-2
schematic has been updated after some flaws were pointed out

I understand the above schematic might be a tad difficult to see clearly, just in case, you can see a PDF file here which should be easy to make out.

Reducing Ringing and Inductive Spiking

The schematic shown above has nothing new to be honest, in fact many variants of the same circuit are available online, however what those designs don’t address is the real world issue of ringing and inductive spiking that an SMPS is prone to, during my testing with an un-damped SPMS it was virtually impossible to use this power supply in conjunction with a micro-controller based system as the noise on the output causes frequent resets of the controller. At this point I started reading about techniques to suppress these unwanted effects at the output of the power supply and I cam across the relatively simple solution of RC snubber.

resonante_energie
High Frequency Ringing

The above picture illustrates a switching cycle from low to high and then high to low, however the transition is not smooth, instead there are high frequency oscillations which settle out after a while, this is what is known as high frequency ringing and is present at the primary and secondary side of the transformer as well. This results due to the parasitic capacitance of the switching element forming an oscillator with inductive nature of the transformer windings. The ringing frequency as evident from the above picture is several times higher than the designed switching frequency of the oscillator. As in my case for a designed switching frequency of around 22 KHz the ringing frequency at the transformer primary and secondary was 4.8 MHz and 18.6 MHz respectively when probed with an oscilloscope. However knowledge of the ringing frequency is an important info to have as it helps us determine the value of the resistor in the RC snubber network which will be placed in parallel to the transformer windings.

There is an excellent technical document by Texas Instruments covering the subject in great detail, if you want to check it out click  Here

The RC snubber greatly reduces ringing and inductive spiking reducing the overall noise in the system and can now be easily used with a micro-controller based system.

img_20170214_230452
The waveform with RC snubber

Good Layout Bad Layout

Working with perf boards and laying out the smps components can give rise to some serious issues that can easily be overlooked and can result in unwanted noise on the output of the power supply and even issues with MOSFET’s shorting out.

After having shorted out a good handful of IRF840’s I realized this fact the hard way, a few important points to consider while laying out the parts and routing the tracks are,

1- Identify the current loops and keep the board covered area for each current loop as small as possible, this goes specially for high power switching current loops.

201703051424411000

2- Avoid connecting the control circuitry to dirty ground, the control circuitry in this case is the IR2153 chip and the TL431,  the dirty ground is in between the closest capacitors before and after the switching part of the circuit.

201703051442441000

3- Keep the dirty ground trace as short as possible and avoid routing it all over the perf board, also it is highly important to avoid mixing dirty ground with clean ground.

201703051443481000

4- If the power lines have to travel to a certain length on the perf board the +ve and -ve tracks should be routed close as differential pairs.

201703051424411001

Following these general guide lines one can be assure of a clean and workable design on the project boards.

Safety Considerations and Conclusion

When dealing with direct AC mains and unpredictable loads I highly advise to use a series safety bulb of around 200 watts when powering your projects as this would  prevent components from exploding, saving you from potential injury in case of a short circuit.

trust-me
Trust me when I say this…..

Finally here are some pictures of the final circuit which isn’t all that dangerous to work with,

img_20170212_190828

img_20170212_190841

This has easily been the most frustrating part of the entire universal NiMh charger project as it took many trials and errors before a respectable performance of the SMPS was achieved, however I am late with my blogging, it’s been a while since I completed the SMPS and instead of posting an update I decided to continue working on the charger itself as a final push to complete the prototype, I am quite excited as I have figured out all the remaining issues with the charger and will be posting soon on the finished final design.

I have been getting a lot of views from all around the world and this is highly encouraging, I thank you all for your interest in my efforts, if you found this helpful please like and share my blog.

Cheers!

Improving and Porting the PID Controlled Current Source Design Over to an ATtiny85

Improving and Porting the PID Controlled Current Source Design Over to an ATtiny85

Hope things are going great for you!

So apparently the  PID regulated current source using a switching regulator is a pretty popular thing, something that is searched for online quite often, at least that is what the blog stats indicate.

In this post I will be taking things one step further, I will be discussing how and why I have ported the design to an ATtiny85 and most importantly the improvements I have made to minimize the steady state error to an almost zero. In case you haven’t been following I would recommend you to go through the two article I have published earlier leading up to this.

Arduino PID current source

Improving the PID code

For those of you who have been following and had the liberty to work with a PID controller would know very well that the time interval between each sample is very important as our integral and derivative results depend on it and if the time interval is known and fixed then that simplifies the PID calculations for the controller chip. With this as an established fact we can move forward on why this port was important.

Once again I would like to remind you that this is leading up the the universal programmable NiMh battery charger that I would like to  make.

Why Port The Design Over To An ATtiny85?

The approach that I am working with isn’t using a set defined time interval that the chip knows about instead I am cycling through the PID calculations without any delay() commands and letting the micro controller run free at the clock frequency set, this does in a way make the time interval known and constant as each instructions takes the same amount of cycles to get executed so every next instruction in the loop is reached at after a fixed amount of cycles, so in a way the controller doesn’t know about the time interval but still does, if that makes sense. This is a very important point and will help me to answer why I decided to port my design to an ATtiny85 from an Arduino UNO (ATmega328p) in the first place.

As mentioned these blog posts are a build up to a project I have taken up to build a universal programmable NiMh battery charger, earlier I had plans to use the ATmega328P as the only controller that would regulate the current using a PID loop, I was planning for the same single chip to present the user with an LCD interface where a current would be set before a charging is started and during the charge cycle the same chip would read the battery voltage and incorporate within the code an algorithm to terminate the charging using a -dV charge termination method, pretty neat huh? but! all the extra functionality needs more lines of code to be added along with the PID loop which changes the sampling time interval of the PID controller hence ruining all the effort I put into tuning the PID (which largely remains a mystery to this day), but that isn’t it, due to the nature of the LM2576 switching regulator the sampling time can’t be delayed or the current values will be all over the place and there will remain no point in having a closed loop control, you see current varies almost instantly so the sampling has to be fast to account for any rapid changes.

This was enough reason to have a separate dedicated PID block that would eventually communicate with the master controller using an I2C bus and will go about doing its work once it has received a set point from the master (which will be the ATmega328P in my case).

Since I wasn’t ready to throw in another dedicated ATmega328P for the closed loop control therefore I opted for a chip like the tiny85, the final design ends up using all the pins so that is an efficient utilization of resources I would say.

Making The New Controller Efficient And Accurate

It wouldn’t have been justifiable had I just replaced the Arduino UNO with the ATtiny85 just to take over its functionality, The first and even the second iteration of the PID controller that I had built had flaws and even this, my third iteration with all the improvements it promises introduces new issues that need to be addressed, but I am getting there slowly, this time around I have made improvements in the following two areas,

1- Improved the current feedback system to increase overall controller accuracy, completely eliminating the steady state error which became more and more pronounced with higher set points

2- Decided to move away from the internal 1.1 Volt ADC voltage reference and use the internal 2.56 voltage reference available on the ATtiny85 (however resorted to an external 2.5 V reference due to issues that will be discussed)

3- Minor tweaks in the code to get stability

We’ll look into each of these aspects briefly and discuss what I have learned with my experience and it just might help some lonely soul out there who is probably as frustrated as I was at one to hopefully find a solution.

Improving The Current Feedback Circuit

Use better OP-AMPS! when dealing with precision applications like this one always go with one with the least input offset voltage value! Yes I can’t stress this point enough as I have had nightmares with an LM324 and having practically no exposure to working with op-amps in the field before I was really scratching and hitting my head against the wall when finally people up at the arduino forum pointed this out to me, moving away from the LM324 I looked for an op-amp with a respectable input offset value and was able to get an AD820 which does the job reasonably well.

I will try to explain what input offset voltage is for those of you who might be wondering, the basic operation can be summed up in a sentence, in a negative feedback configuration the output of the op-amp must maintain a voltage such that both the -ve and +ve inputs to the op-amp are at the same voltage. Sadly we live in the real world and there are imperfections during the manufacturing which doesn’t let this happen, however the maximum possible difference between the +ve and -ve inputs to an opamp is defined in the datasheet so one can choose an appropriate device that can serve the purpose, this difference in voltage is known as the input offset voltage.

lm324-input-offset-voltage
The input offset voltage of an LM324 is a maximum of 7 mV

For an LM324 having an input offset of 7mV will cause a big error in the final achieved set point since we are using a 0.1 ohm sense resistor as feedback for the op-amp the voltages we are dealing with are already in milli volts so having a deviation of 7 mV can really ruin the day for us, where as an AD820 on the contrary has input offset voltage of around 0.7 mV which is still manageable.

Second most important point when setting up a precision gain amplifier is to always use precision resistors! yes this needs to stressed upon as well, I can’t explain how much time I spent trying to tweak my PID code (courtesy to very little experience with circuit designing) only to narrow down the problem to the 5% tolerance resistors I was using for my feedback loop. Also for the current sense 0.1 ohm should be a 1% tolerance or better even less, I had to ultimately use 10, 1 ohm 1% resistors in parallel since I couldn’t find a 0.1 ohm with a 1% tolerance, can you believe it?!

At this point lets just look at the new circuit diagram we are working with.

attiny85-pid
The new circuit diagram based on the ATtiny85, (I know people can’t take more of my hand drawn schematics)

The biggest change this time around is in the hardware, the PID code in it’s basic form works well if the gains are of the right order, but that doesn’t mean the PID constants that worked for the Arduino UNO worked with the ATtiny85, it took a lot of trial and error before I arrived at the values for the new gains, again I feel like you are never completely happy so tweak the parameters as you please and choose the ones that work the best for you.

To give an idea of the performance here’s a picture of the PID controller set for a 1.7 Amp set point charging a  9.6 volt NiMh battery pack.

pid-1-7
I know, I need to clean up my space

A significant improvement, the steady state error has been reduced to almost zero in this case, those who have been keeping up would remember that the earlier iterations faced an issue where the steady state error increased as we increased the set point, which has been completely eliminated this time around. Another important point to be careful of is that since I am working with two different circuits one of the PID controller and other one of the LM2576 based power part therefore the two grounds have to be tied together, always make sure the ground on the power part should be tapped from a point near to where the 0.1 ohm sense resistor connects to the ground this is crucial in getting the final result.

Moving Over To The 2.56 Volt Internal Reference

The prime reason why I switched over to the internal 2.56V reference can be understood once you look at this chart

2-56v-chart
Set points passed on to the ATtiny85 with 1.1 V and 2.56 V internal references

The ADC can never register decimal values so passing on set points with decimal values makes no sense and it will just compromise accuracy, so 2.56 Volt internal reference made perfect sense, right?….. Wrong! you see the internal reference of the ATtiny85 is pretty bad and according to the spec sheet can vary between 2.3V to 2.7V (if I remember the range correctly, for a confirmation you might want to refer to the data sheet), so to sum it up using the internal reference in precision applications like this is a pretty bad idea, so I had to resort to an external precision reference and for that I am using an LM336 shunt regulator which isn’t the best but gives a stable voltage. May be I can later on replace it with 2.56 precision external reference but so far it’s doing a pretty reasonable job.

However one important lesson learned here is that the internal reference should never be trusted especially for the ATtiny85, using the external error however does introduce one more problem, I am now utilizing the I2C data pin, I will just have to compensate for it in code at a later stage where I will initially use the pin for communication and receiving the set point and later one that pin will then be used for the internal reference, I am not sure if it will work though, great!

The Code

The code is largely the same, except for the inclusion of new gains specific for the ATtiny85, to further avoid integral windup I am adding another condition in the PID loop which completely disables the integral part if a zero current condition is detected, it prevent an integral windup in case the current drops to zero in the event the power circuit turns off while the controller is in operation.

Here it is very important to mention that I am using the internal 16 Mhz oscillator on the ATtiny85, the performance will not be the same or might degrade completely if any other clock is used.

Also make sure to upgrade your IDE to the latest version 1.6.12 and use the attiny core by David A. Mellis as the new cores support the ADC reference and saves a lot of hassle.

int ON = 3;
int FB = 1;
int Bias;
float Output;
float Actual, lastError = 0.0, Error = 0.0, Derivative = 0.0, Integral = 0.0;
float Amp = 0.0;
float Kp, Ki, Kd;
float setPOINT = 0.0;
void setup()
{
float num = 0.0;
analogReference(EXTERNAL);
delay(100);
pinMode(ON,OUTPUT); // ON/OFF signal for LM2576
pinMode(FB, OUTPUT); //PWM for LM2576 Feedback
digitalWrite(ON, HIGH);
Amp = 1.7;
setPOINT = Amp*1024; // with the amplification factor included
setPOINT = setPOINT/2.476;
Kp = 0.023;
Ki = 0.0005;
Kd = 0.0002;
if(Amp == 0.1)
{
Bias = 67;
}
else
{
Bias = 68;
}
analogWrite(FB,70);
digitalWrite(ON,LOW);
delay(5000);

}

void loop()
{
Actual = analogRead(A2);
//delayMicroseconds(500);
Error = setPOINT – Actual;
Integral = Integral + Error;
if(Actual <= 15) //Forces the Integral to Zero when current below a certain value { Integral = 0; } if(Integral > 300000)//Limits the integral to prevent Integral windup
{
Integral = 300000;
}
if(Integral < -300000) { Integral = -300000; } Derivative = lastError – Error; Output = Bias – (Kp*Error + Ki*Integral + Kd*Derivative); if(Output > 255) //Limits the output to 5 volts maximum
{
Output = 255;
}
if(Output < 0)
{
Output = 10;
}
analogWrite(FB, Output);
lastError = Error;
}

Temperature Dependency Of The Achieved Current Value

As current passes through the ten 1 ohm parallel combination of sense resistors they tend to heat up increasing their resistance, which causes the achieved current to decrease from the desired set point by a few milli amps, also since the current sense resistors are installed quite near to the heat sink on the LM2576 therefore it’s possible that the resistors are absorbing some of the heat from the heat sink that is close by,

img_20161018_012806
Current sense resistors installed near the heat sink

Introducing a 12 volt fan into the mix helps keep the resistors cool and for the controller to achieve the set point, well you solve one problem only to get into another. I wonder if there is anyway to eliminate the temperature dependency? Might work on it at a later stage, I think I might be better of with a precision shunt resistor made particularly for current sensing, components are hard to find here so it will be some time before I get a suitable replacement.

Final Words

Finally here’s a video of the PID controller programmed for a set point of 1.75 Amps, it wasn’t designed to regulate current up to the second decimal point but since it is working better than I had anticipated so I thought I’d try this just for the fun of it,

Some pictures of the final PID controller circuit  on a perf-board

img_20161018_013836
ATtiny85 PID controller
img_20161018_013846
Solder traces at the back of the PID board

I think I can finally give the PID chapter a rest now for a while and work on other aspects of my programmable charger, the PID has taken a lot of time but the results are finally at a stage where I wanted them, I might do a bit more testing as time goes on and might think up of some way to compensate for the temperature dependency of the design.

If you’ve found this article useful please share and like my blog post, it’d be great!

Making the PID Controlled Current Source Better

Making the PID Controlled Current Source Better

Extensive testing leads to many problems that are not revealed initially, during the time I spent tinkering and tweaking the PID code I was confronted with some problems that had to be addressed in order to make the final code reliable. By the end of this article we’ll be improving the code through logical reasoning and the simple circuit I built in the original article for a PID controlled current source using arduino as the PID controller and the LM2576-ADJ switching regulator as the current source.

Here’s a link to the previous post for your quick reference, before you go further it is absolutely necessary to read the original post in order to understand where we stand at this point.

Programmable Switching Current Source Using Arduino as a PID Controller

The problems I faced with the previous setup are briefly listed below,

1- Instability of current output at lower current set points.

2- The steady state error increased with increase in set point, the output current settled at as high as 70mA’s above the desired value.

3- Wild random oscillations when power source is turned ON after a small delay, the output current oscillates and settles down randomly and at times need a restart.

4- High current spikes at the start.

Instability of Low Current Outputs

During my initial implementation I found out that current fluctuation became more and more pronounced at low set points, secondly the output once it settled deviated quite a bit from the required value, say for a set point of 100 mA the output settled at around 150 mA, this condition was undesirable from my view point.

Since I am using a 0.1 ohm current sense therefore for a current of 100mA’s the voltage feedback going to the Arduino UNO for digital conversion will be only 0.01 volts. Using an internal reference of 1.1 volts the Arduino will read this voltage as almost 9 steps on the ADC, from a noise immunity point of view these low values of voltages are easily corruptible and cause wide deviations from the original set point, although I used a low pass filter in my initial design and it did settle out the voltage fluctuation to some extent but the desired value still deviated far from the required current.

Since I have designed this current source for a maximum of 2.2Amps which translates into a feedback voltage of 0.22 volts for the Arduino therefore a good portion of the range of the 1.1 Volts ADC reference is being wasted, amplifying the voltage will not only utilize the full range of the 1.1 volts reference but will also give the ADC reasonable amount of steps to work with at low current values which will be less susceptible to noise and give better stability at low currents.

At this point it seemed like a good idea to amplify the feedback voltage from the current sense resistor before it goes to the arduino, I am going to utilize the LM324 that’s already on board to amplify my voltage feedback from the current sense resistor by an amplification factor of 4.4 (Although the amplifier is designed for a 4.4gain factor but multiplying by a gain factor of 4.3 in the final code gives the best results, upon measuring the resistances by a multi-meter I got readings in the range of 4.32, this might be the underlying problem but things will become clear once I use precision resistors), here are the changes I have made in the circuit,

bLeeyPC1HUR7N7FH559rY7ef
The modified circuit diagram incorporating the non-inverting gain amplifier (LM324 quad-opamp chip)

The increase in the number of steps specially at low current values and better utilization of the ADC reference range helps improve stability at lower down the scale. From a 50mA deviation previously I was able to reduce the deviation down to 15mA, this is reasonable improvement.

But this is not it, through experimentation I found out the that a single set of proportional, integral and derivative constants won’t work, with a single equation the current values lower down the scale, although had less of an error than last time but showed rapid fluctuations, there is always some ripple when working with switching regulators and even if the digital multi-meter can’t display it the effect becomes obvious once you use a sensitive equipment like an oscilloscope, however for my case I settled for two different sets of constants approach since it works best and produces desirable results.

PID two sets of constants

Increasing Steady State Error With Increasing Set Point Values

The use of a gain amplifier to produce stability at low current values offered an added advantage and served to reduce the high but steady deviation at high current values, however before I accidentally stumbled upon this I did try to use a mathematical method to push back my output currents closer to the set point and it was based on a very simple idea, if I knew the deviation from set point for a particular set point I can control the situation by passing on a modified set point to the controller, for e.g if I knew the deviation for a set point of 1.9 Amps is 0.07 Amps then I can simple tell the controller to achieve a set point of 1.85 Amps giving me a value closer to 1.9 Amps and since the error increased with increasing set point the smell of a linear relationship between the steady state error and the set point was always there, however I ended up dropping this approach since my search for elegance got the best of me in this case.

For any of you who might be interested here the mathematical expression for the set point modification I used before implying the gain amplifier.

Subtraction Factor from set point = 0.01047*Set Point + 0.0529

Random Oscillations At High Set Points Which Would Settle Out Randomly or Needed a Restart

Above is the definition for a very common PID related problem known as integral windup, however I never knew how it looked like in practice up until very recently, say for example if you leave your controller running and turn off your power source, the integral term will go on summing up the errors endlessly, since the controller never reaches the set point, if at this point you put your voltmeter on the PWM output pin from the Arduino you’ll see your voltages fluctuating, that’s not a good sign, what we need it to clamp the integral term and put limits to it, I got best results by limiting my integral term in between 5000 and -5000,

Integrallimit

These limits were achieved through test and trial, once this is done it’s probably best to limit your PID outputs as well since the output of a PWM can’t go above 255 and below 0 for an arduino so it is only logical to clamp the output of the PID to these values, but putting zero volts on the LM2576-ADJ feedback pin pushes up the current drastically to the maximum current capacity of 3Amp for the LM2576-ADJ, so we can safely assume a PID output value of 0 volts is an undesirable situation in itself and should be avoided, since any value below 1.25 volts on the LM2576-ADJ feedback pin will eventually serve to increase the current, however the smaller and the farther away the voltage is from the 1.25V threshold the sharper the current rise hence resulting in unwanted peaks at times, therefore after testing out a few values I settled for a minimum PWM output of 10, it is important to state at this point that selecting a high value for the minimum output of the PID is going to affect it’s performance so since you are basically limiting PID’s ability to increase the current output from the LM2576-ADJ.

Output limit

Current Spikes At The Start

The unusual current peaks at the start might not be a problem for certain PID controlled processes but for me it could have a deteriorating affect on the battery life, this situation can however be controlled by changing the derivative equation slightly, in my previous code my derivative factor was computed by subtracting the present current value from the last current value, however when the PID starts the last and present current values will both be zero and a strong derivative action won’t kick in until a high current flows so this almost always guarantee’s a current spike at the beginning, what we can do to counter this is to compute the derivative using the below scheme,

Derivative = Last Error – Present Error

Say for a set point of 1.2 Amps which equates to 480 ADC steps the PID will get to the derivative computation part with an Error of at most 480, since the last error at this stage will be zero therefore the derivative term in the PID equation will become positive and will act to decrease the starting instantaneous current from the LM2576-ADJ

derivativemod

This change guarantees that there will always be a respectable derivative action present at the start of a control cycle to dampen out the current spikes that would have otherwise resulted without this approach.

The Complete Code

Here is what the complete code looks like,

int ON = 12;
int FB = 5;
float Actual, lastError = 0.0, Error = 0.0, Integral = 0.0, Derivative;
float Amp = 0.5;
float Output, Kp, Ki, Kd;
float setPOINT = 0.0;
void setup()
{
analogReference(INTERNAL); // set internal reference to 1.1 V
pinMode(ON,OUTPUT); // ON/OFF signal for LM2576
pinMode(FB, OUTPUT); //PWM for LM2576 Feedback
digitalWrite(ON, HIGH);
setPOINT = Amp*0.1*1024*4.3; // with the amplification factor included
setPOINT = setPOINT/1.1;
if(Amp <= 0.5)
{
Kp = 0.07;
Ki = 0.00075;
Kd = 0.07;
}
if(Amp > 0.5)
{
Kp = 0.2;//was 0.1
Ki = 0.0025;
Kd = 0.04;
}
analogWrite(FB,70);
digitalWrite(ON,LOW);
delay(500);
}
void loop()
{
Actual = analogRead(A1);
Error = setPOINT – Actual;
Integral = Integral + Error;
if(Integral > 5000)
{
Integral = 5000;
}
if(Integral < – 5000)
{
Integral = -5000;
}
Derivative = lastError – Error;
Output = -Kp*(Error) -Ki*(Integral) – Kd*(Derivative)+ 62;
if(Output > 255)
{
Output = 255;
}
if(Output < 0)
{
Output = 10;
}
analogWrite(FB, Output);
lastError = Error;
}

Final Words

There’s an excellent article online written by Brett Beauregard who is the authority on PID controllers and arduino based PID in particular, I highly recommend anyone who’s struggling with PID’s or wishes to write his or hers own PID to go check out his blog, there’s tons of priceless information there

Improving the beginners PID by Brett Beauregard

For me this would not have been possible without Brett’s article, so all credit to the guy who’s behind the Arduino’s PID library and is doing much more amazing projects.

As for the PID one can never be completely happy, it’s just the way PID is it leaves you wondering, “can I do it any better than this?” the result is countless hours of chair warming and head scratching but it all pay’s up well in the end, once again this is leading up to my universal charger design and the more I get closer to finalizing the design in my mind the more I realize that I can’t work with a single controller alone to act as a PID and monitor the battery voltage as well, the PID block needs to be separate with a dedicated chip just taking care of the PID control process and nothing else, since I was originally hoping to base my design around an Atmega328 chip and which I still am, I have started to wonder if I can have an Attiny85 in the design functioning as a separate PID block independent of the the Atmega chip and only receives the set point before it goes about doing it’s work, at this stage I am wondering how I can communicate the set point from the Atmega328 to Attiny85, I am thinking about developing a custom communication two wire protocol to simply transmit pulses to the Attiny85 and counting those pulses the tiny would be coded to compute the set point, Morris code comes to mind for a second, I have to see where I go with this though. If you like my article please share it with your friends, leave a like or a comment, your suggestions are more than welcome.

Update: The design is quiet sensitive to loose connections, using a breadboard might introduce errors in the current output, use bypass capacitors for the opamp supply, make sure voltage doesn’t fluctuate.

Programmable Switching Current Source Using Arduino as a PID Controller

Programmable Switching Current Source Using Arduino as a PID Controller

Hope you guys are doing great!

In my last couple of posts concerning the NiMh battery charger I mentioned how I would like to make a programmable universal NiMh battery charger for a number of battery voltages and current levels, I was thinking of a contraption where the user would feed in the current output value or the level at which the battery is to be charged and the charger would magically maintain that desired output current through the charging process, since in my last iteration I had converted my original charging circuit to a formal switching regulator based one so it was obvious that I wanted to  implement the universal charger with a switching regulator as well.

The universal charger is nowhere near complete at the moment and this post, as the title suggests, won’t discuss just yet how to design one either, but instead this will cover a very important aspect which will be part of the final design, Since the whole point of the universal NiMh charger rests solely on realizing a current source where the user would be able to input a current value and get that exact same current output for the entire charge cycle of the battery.

I have made great progress on the issue and have finally  managed to implement a programmable current source based on the LM2576-ADJ controlled using an Arduino acting as a basic PID controller, now the name PID itself has its fair share of nostalgia associated with it, I learned it, in theory only while in engineering university and had a very basic to almost no idea of how it worked and why do we have these three proportional, integral and derivative terms in its equation anyway let alone knowing how it performed and what kind of stability it offered. Well when the time finally came to use a PID I realized how simple it was to implement in code on an Arduino and was surprised to see how stable and reliable it was as a controlling scheme. Apart from the PID controller implementation which sits at the heart of the design I also will be discussing the design schemes that I have followed to built this current source.

Understanding the LM2576-ADJ and how to control it

The LM2576-ADJ is a highly versatile buck DC-DC regulator, fortunately as I found out in order to get a desired current output from this regulator you don’t really have to know too much about the how the internal circuitry of the chip works.

The LM2576 can be treated as a black box that has some rules in order to regulate the current output from it. The LM2576-ADJ is a simple 5 pin chip, the pins are Vin, Vout, GND, Feedback and Inverted ON/ OFF

LM2576-adj
The LM2576-Adjustable

The 5th ON/OFF pin needs to be pulled up and a zero logic can enable the chip when needed, however in order to control the output of the chip one needs to know only one thing and that is whenever we put 1.2 volts on the Feedback pin the regulator stops changing it’s output and stays where it is as long as it gets the 1.2 volts required on the Feedback pin, say if you are not happy with the output and need to decrease it a little then you have to slightly increase the voltage on the Feedback pin, the LM2576-ADJ will think that the output has increased and will regulate it’s internal oscillator to bring down the output, the opposite holds true for when you are looking to increase your output current. So just to summarize it,

1- When you want to hold a certain output stable, put 1.2 Volts on FB (feedback) pin.

2- When you want to increase your output, put FB pin below 1.2 volts, when the desired output is reached again hold the output by applying 1.2 volts on the FB pin.

3- When you like to decrease your output, put a voltage greater than 1.2 volts on the FB pin and as soon as the desired output is reached again apply 1.2 volts on the FB pin to hold that output state.

This is what we will be basing our PID design on and will be constructing our simple circuit around these simple three requirements.

PID made simple, a basic review of concepts

Well the subheading is a trap really, no one can possibly make PID simple but if approached in the right way the PID is actually easy to understand and far more simpler to code in the Arduino.

Figure_2_-_PID_equation
The general PID equation

Well this is what they have scared you with so far, but you don’t need to know integration or derivative to implement a PID controller. The PID controller can be broken up into 3 simple parts and their functions are relatively easy to understand.

Proportional part deals with the errors that are present right now or errors that are in the “present” it does so by calculating an error which is typically,

Error = set point  – Actual value

The gain Kp is multiplied by the error term to generate an output which will work to minimize the error.

The integral term looks into the past and is a summation of all the error terms in the past, as time passes and the errors are summed up the integral term after being multiplied by the gain Ki boost the controller response to control the output. But why do we need integral past isn’t the proportional term enough? Well imagine a case where an error state occurs the proportional action moves to correct the error but as the actual value gets closer to set point the error decreases causing a weakly acting proportional part and since the proportional only acts on the current instantaneous error it never quite reaches the set point this is where the integral component comes into play, all the past errors are summed up over time (this is what the integral does summation over time) and then multiplied by a Ki gain to help the controller achieve its set point. For most processes this is enough as PI is probably the most widely used controller type.

The derivative component looks into the future and tries to determine what the output or actual value will be depending on its change rate and produces an output multiplied by a gain Kd, the derivative part of the PID helps to prevent overshoots, for example if the actual value is heading towards the set point very quickly then without the derivative part the actual value might overshoot the set point before eventually settling out this isn’t a desirable condition in most process so a derivative part is implemented to prevent overshoots, did I say I was going to make it simple? Well that didn’t work out as planned but you get the picture, my understanding at the moment is quite crude as well but it might help some of you struggling folks out there.

So the above equation can be simply written in programming terms as,

Output = Kp*(Error) + Ki*(Integral) + Kd*(Derivative)

Where…..

Error = Set point – Actual Value

Integral = integral + Error

Derivative = Last value – Actual Value

Setting up The Circuit & Getting Analog Output from The Arduino

Well as discussed earlier the LM2576-ADJ needs 1.2 Volts on it’s feedback pin to hold the current output stable but we know that Arduino UNO being a micro-controller with no built-in DAC can only do zero and a logic high level, the answer lies in PWM and low pass filtering.

The Arduino has an 8 bit PWM output means it can go from 0- 255 varying the duty cycle of the PWM with 0 being the lowest and 255 being 5 volts.When you pass the PWM through a first order low pass filter you get fairly decent analog values that you can work with and that can reliably control the feedback pin of the LM2576-ADJ.

Through a simple comparison formula with analogWrite(x,0) being equal to 0 volts effectively and analogWrite(x,255) being equal to 5 volts I was able to deduce that analogWrite(x.62) passed through a low pass filter will give me close to 1.2 volts.

PID circuit
The programmed current source circuit

The circuit seems relatively simple, but that isn’t the simplest part about the design, the PID code is even simpler. Before getting to that let me just mention the feedback of the current into the battery that goes to the Arduino pin A0 is also being filtered, this gives better stability at low current values down in the range of 100 to 200 mA’s.

Setting up the PID equation

Well remember how I said that I need to have 1.2 volts on the LM2576-ADJ pin to hold the output stable?

From what we have learned so far we know that the proportional part of the equation can simply be written as,

Output = Kp*(Error)

So when the error is zero the output should be zero but what happens when you put zero volts on the FB pin of the LM2576? The output current increases until it reaches the maximum level of 3 Amps, so when the error is zero we don’t want zero volts on the output from the Arduino we want 1.2 volts or analogRead(x,62) like we discussed earlier so the proportional part is actually,

Output = – Kp*(Error) + 62,

Notice the negative sign in the equation above? that’s because the PID will be a reverse acting controller meaning in order to increase the current output the control output from the Arduino needs to be decreased and the opposite holds true to decrease the current output.

The final form of the PID equation should look something like this,

Output = -Kp*Error – Ki*Integral – Kd*Derivative + 62

The values for gain will be acquired through a manual loop tuning method that is very well documented on the wikipedia page of the PID controllers which we will also discuss briefly here.

Loop tuning, how to get suitable gain constants for your PID equation

Well in order to get reasonable gains for your PID we first set Ki and Kd gains to zero and slowly increase the Kp until we reach a point where the output current starts of with high amplitude oscillation and eventually settles not too far below the required set point and continues to oscillate at a reasonably slow pace between amplitudes close to each other, that value of Kp is halved and used as your Kp gain.

With the Kp gain set the Ki value is increased until the set point is acquired in reasonable time depending on the process you want to control. Note that too much Ki will make the loop unstable a it introduces a problem known as integral windup.

For the Derivative gain Kd, I settled for a value that gave me some stability at low set points in the milli amp ranges, before applying the derivative term my readings were fluctuating a lot.

PID_Compensation_Animated
Here is a cool little animated image from Wikipedia, helps to visualize and better understand all the gibberish

After a lot of trial and error and a lot of testing, this is the final equation that gives me the best results,

Output = -0.045*(Error) -0.0015*(Integral) -0.003*(Derivative)+ 62

I might still change these values as I go along but so far they seems to do the job pretty OK.

The Code

Remember how I said the code is the easiest part of the design? well I wasn’t joking.

int ON = 12;
int FB = 11;
float Actual, Last = 0, Error, Integral=0, Derivative, Output;
float setPOINT = (1.2*0.1)/0.00107; //Amp Calculated here
void setup() {
//setPOINT = ((setPOINT – 0.020)*0.1)/0.00107;
analogReference(INTERNAL); // set internal reference to 1.1 V
pinMode(ON,OUTPUT); // ON/OFF signal for LM2576
pinMode(FB, OUTPUT); //PWM for LM2576 Feedback
digitalWrite(ON, HIGH);
analogWrite(FB,62);
delay(500);
}

void loop()
{
digitalWrite(ON,LOW);
Actual = analogRead(A0);
Error = setPOINT – Actual;
Integral = Integral + Error;
Derivative = Last – Actual;
Output = -0.045*(Error) -0.0015*(Integral) -0.003*(Derivative)+ 62; //PID control equation (0.09, 0.006, 0.1//old loop values -0.045 proportional oscillation// +62 corresponds to 1.2 V this
analogWrite(FB, Output);// is what keep the LM2576-ADJ stable when only proportional gain is used Output = -0.0225*(Error) -0.0015*(Integral) -0.001*(Derivative)+ 62;
Last = Actual;
}

That’s it, you’ve been running away all your life from a demon that didn’t exist in the first place! the PID code consists just of these few lines and that makes life incredibly easy!

Closing Remarks & Performance Check

Here is a video demonstrating the controller trying to achieve the 1.2 Amp set point, notice how a disturbance is introduced into the system as I am touching the exposed leads of the feedback capacitors and as soon as I remove my finger the controller again quickly maintains the output current to the set point. Seems pretty solid so far with very less variation. To be honest I wasn’t really hopeful when I started this out, I was actually looking for digital potentiometer chips that I can program to get a fixed current output value out of my LM2576-ADJ but wasn’t able to find any in the market, implementing a real time controlling scheme like the PID was my second choice but in the end I am kind of glad it got down to this.

Here’s a more recent LCD recent version of the same basic circuit with an added LCD interface and a keypad to input the current set point without having to change the code every time, just makes things a lot more convenient.

 

 

Switching NiMh Battery Charger

Switching NiMh Battery Charger

Hope you guys are doing great.

Ever since I published my first blog post discussing the design and implementation of temperature gradient cut-off ATtiny24 smart charger for NiMh batteries I wasn’t fully satisfied with the power or the actual charging circuit, initially I decided to build the charger controller and the power circuit separately since I knew that I’d be making changes in the design as I go along.

For those of you who are lost at this point, here’s a link to my first post discussing the design of the my smart NiMh charger.

https://lonetechnologist.wordpress.com/2016/04/25/designing-a-delta-tempdelta-time-temperature-gradient-charge-termination-smart-charger-for-nimh-battery-pack/

Although I am fairly comfortable at this point with the control circuit but the power circuit has one obvious problem, it’s too bulky for my liking! the LM350 dissipates a lot of heat, I had to mount a fan on top of it to cool it off and since only recently I was beginning to think that I should get a case made for the project it just didn’t seem that the final version would look elegant owing exclusively to the big foot print.

I haven’t had any experience with using a switching regulator but anyone with basic electronics training would know that high current designs based around switching regulators are comparatively smaller in size to a regular linear regulator design and this comes due to the fact that switching regulators are efficient and hence waste less heat as compared to linear regulators and therefore require a much smaller heat sink and possibly no fan to remove the wasted heat. Secondly since we will be making a switching constant current charger/power circuit therefore it’s worth mentioning that in order to bias an LM350 as a constant current regulator for high currents approaching to 2 Amps you need big power resistors which in my case took most of the area on the perf-board but for a switching regulator we’ll be using a feedback technique that allows for usage of normal sized resistors saving up a lot of space in the process.

And yes for those of you who might argue probably the biggest reason an SMPS is lighter and smaller than a simple linear voltage supply is because high frequency ferrite core transformers are smaller and add a lot to the size reduction of the design, however in my case I have mentioned the aspects that have allowed me to make my circuit smaller.

Choosing a Switching Regulator

The obvious selection criteria for an LM350 replacement is to look for a regulator that can handle 3 Amps, is adjustable and can easy handle input voltages of around 35 volts (the more the better). After doing a little online search I found the LM2576-ADJ as a reasonable choice. The LM2576-ADJ is a buck regulator meaning you can have an output voltage of your choice which is lower than the input voltage.

LM2576-adj
The LM2576-Adjustable

Looking at the LM2576 you see it has two more pins than your usual linear regulators, the pin 5 is a normal TTL logic level ON and OFF signal that can enable or disable the chip at will while the fourth feedback pin might be new to you who haven’t worked with a switching regulator before, like me.

Essentially since a switching regulator regulates the internal oscillator’s duty cycle (PWM) in order to regulate its voltage output to a desired level therefore it needs to know what voltage is at the output pin, this is where the feedback pin comes into use.

For an explanation of how the DC-DC buck convertor works, check out Afrotechmods comprehensive video on the subject.

 

The Circuit Design

Fortunately Texas Instrument has a very well written literature (# snva557) on how a constant current charger power circuit can be designed using an LM2576 regulator and this is what I have based my design on.

snva557 charger
The original circuit as presented in Texas Instruments literature # snva557

The above is used for a 12 volt NiMh battery to be charged at a constant current of 2.2 Amps, I have modified the above circuit slightly in order to get selectable current levels of 700 mA and 1.8 Amp staying true to the specifications of the original LM350 based charging circuit.

The Op-Amp is a wonderful component as you’ll find out that just by selecting different feedback resistor values I have managed to get the required current output.

new
The Modified Circuit Design for 700 & 1800mA Current Outputs

Please ignore the crudity of the diagram, here just by adding two 12 volt relays (yes I can’t help using them!) I have managed to switch between 700 mA and 1.8 Amp, well in actual it’s around 1.73 Amps since my calculations were a bit off but it’s still good enough for me, the controller can select between the two current levels depending on what’s required for the charging process, also not shown in the above diagram I have added a red LED fed from 12 volts through a 1K ohm resistor as well and in case you are wondering I have only used the 0.1 ohms resistor instead of the 0.05 ohm because it was easily available.

The Code Upgrade

Well I was hoping the new power circuit will be fully compatible with the code that’s already on the ATtiny24 but unfortunately that is not the case, I had to do some minor adjustments in the code which will work with this power circuit.

void setup()
{
pinMode (3, OUTPUT); //Indication LED
pinMode (2, OUTPUT); //Relay control
pinMode (10, OUTPUT);//Thermistor control
pinMode (7, OUTPUT);//E/S LED
pinMode (9, OUTPUT); //High current mode ON
pinMode (4, OUTPUT); //Moderate current mode ON
analogReference(EXTERNAL);
delay(5000);
digitalWrite(3,HIGH);
digitalWrite(2,HIGH);//start charging
delay(2000);
if(analogRead(A6) >= 608) //if connected battery voltage equals or is greater than 16.7 volts, terminate charging with error to protect overcharge.
{
digitalWrite(2,LOW);
for(;;)
{
digitalWrite(3,HIGH);
delay(500);
digitalWrite(3,LOW);
delay(500);
}}
}
//int cycle = 0;
byte Count = 0;
void loop()
{
unsigned long Temp_C=0, Temp_N=0, x=0, y=0, TempN=0, TempC=0, b=0;
byte a=0, i = 0;
//int volts1, volts2;
//volts1 = analogRead(A6);
delay(1000);
if(analogRead(A6) >= 546)//When battery voltage is greater than or equal to 14.4 volts
{
digitalWrite(4, HIGH); //Turn OFF 700 mA mode
digitalWrite(9,HIGH);//Select 0.8C charging mode
}//digitalWrite(2,HIGH);//Start Charging
digitalWrite(10,HIGH);
//delay(5000);
delay(2000);
for(a=0;a<=5;a++){
Temp_C = analogRead(A1); //at 2.3V starts with 587
delay(1000);
if(Temp_C>=503)//Temp_C can be equal to 503000
{
x = 13975;
y = 9930680;
}
if(Temp_C<=502&&Temp_C>=386)
{
x = 11852;
y = 9186300;
}

  if(Temp_C<=385)//Temp_C can be equal to 385000
{
x = 9527;
y = 8144330;
}
Temp_C = Temp_C*10000; // 385*1000 = 385000
TempC = y-Temp_C; //(814433 – 385000)*10
TempC = TempC/x; //
b = b+TempC;
}
digitalWrite(10,LOW);
//b = b/6;
TempC = b/6;
a = 0;
b = 0;
if(analogRead(A6) >= 696) //when connected battery voltage at 18 volts (3.38 volts on the A6 pin) — edited on 17/4/2016 to 826 from 845, needs 3.30 volts on A6 now
{
digitalWrite(2,LOW);

for(;;)
{
digitalWrite(3,LOW);
}
//Count++;
}
while(i<=59)
{
delay(1000);
i++;
}
x=0;
y=0;
digitalWrite(10,HIGH);
delay(2000);
for(a=0;a<=5;a++){
Temp_N = analogRead(A1); //at 2.0V gets 503
delay(1000);
if(Temp_N>=503)
{
x = 13975;
y = 9930680;
}
if(Temp_N<=502&&Temp_N>=386)
{
x = 11852;
y = 9186300;
}
if(Temp_N<=385)
{x = 9527;
y = 8144330;}
if (Temp_N <= 365)//E/S when temperature is 45 degree or higher
{
digitalWrite(3,HIGH);
digitalWrite(7,HIGH);
digitalWrite(2, LOW);
for(;;){}}
Temp_N = Temp_N*10000;
TempN = y-Temp_N;
TempN = TempN/x;
b = b+TempN;
}
//digitalWrite(10,LOW);
TempN = b/6;
if(TempN > TempC)//Emergency cutoff charging
{
if(TempN-TempC >= 8)
{
digitalWrite(3, LOW); //Indicator LED
digitalWrite (7, HIGH); //E/S LED
digitalWrite(9, LOW);
//delay(2000);
digitalWrite(4,LOW);
delay(60000);
digitalWrite(2,LOW);//Relay control pin
for(;;){}
}}
Count++;
if(Count == 180) //Turn off charging after 3 hours regardless of termination conditions
{
digitalWrite(2,LOW);//Turn off charging
for(;;)
{
delay(500);
//digitalWrite(3,LOW);
digitalWrite(7,HIGH);
delay(500);
//digitalWrite(3,HIGH);
digitalWrite(7,LOW);
//delay(500);
}}
}

The Final Circuit on Perf-Board with Side by Side Size Comparisons

IMG_20160617_163814
The new switching charging circuit
IMG_20160617_163902
The LM2576 heat sinked with thermal grease
IMG_20160617_165122
The new charging circuit side by side with the old one based on the LM350, a definite size and performance advantage. Did I mention it looks a lot less uglier?

Finally here’s a short video of the complete charger circuit in action hooked up to the old controller board.

 

Final Words

All credit to the guys over at Texas Instruments for publishing such a smart and easily hackable design, well what basically started as a side project has turned out to be quite an interesting run so far, I am wondering if I can upgrade my controller circuit now, I already have an ATtiny24 but the ATmega328 isn’t that hard to accommodate on a similar sized board, I can try reducing some of the extra components, may be put in an LCD and a keypad to set battery voltage and charging current levels before charging starts and make it truly universal. Thanks for all your support and interest.

 

 

 

 

Current loop tester and pressure monitor for a 4-20mA (10 bar) analog sensor

Current loop tester and pressure monitor for a 4-20mA (10 bar) analog sensor

 

Hope you guys are doing great.

This post will discuss the design and implementation of a specialized milli-Amp meter and pressure monitor, the tester is intended to be hooked up like an amp-meter in series with a pressure sensor current loop in order to measure the milli-Amps flowing in the circuit and display the pressure in bars corresponding to the current output of the analog pressure sensor. This is designed specially to be used at a Heidelberg offset printing machine but the methods and techniques used in the design can offer help to a large number of students, professionals and hobbyists who are willing to achieve something similar.

For those of you who might be wondering, this is what a typical performance class Heidelberg Speedmaster XL 106 offset printing machine looks like.

XL106
an XL-106, 8 printing units with perfecting

some of these specific model machines require a pressure of around 7 bars to open up the compressed air inlet solenoid valve and then a stable pressure of around 6.5 bars to operate the machine at.

The pressure monitoring is done through an analog sensor with a current output of 4-20mA (two wire sensor configuration), the current is then fed directly to an analog value acquisition card which digitizes the mA’s current value for the CPU processor board. The sensor, solenoid safety valve and the pressure regulator is located at almost the far right end (beneath the feed table to be exact) in the above picture and in order to get a reading of that sensor’s current output for any given pressure at any time a technician is required to walk up to the opposite end of the machine and open up specialized service menus that show the sensor output.

The analog sensor or the current loop is fed through a 24VDC supply. The maximum load value for which the sensor can supply the specified current is given by the equation.

pressure sensor

Sensor load

This can vary from sensor to sensor depending on the manufacturing parameters. Working on this current loop offers the below challenges.

a) Quick visual pressure measurements

As mentioned, the sensor is installed at a good distance from the HMI which actually shows the sensor milli-Amps on the screen once software loads up fully. However by the time the software on the HMI (which is Windows based) loads up the machine had already gone through the pneumatic air valve actuation at 7 bar and the pressure has stabilized by the time the machine is ready to operate. Although there is a pressure gauge installed near the pressure regulator close to where the sensor is installed but due to their slow response its hard to get a quick and accurate reading. Secondly the pressure gauge is installed after the solenoid valve so one doesn’t get a pressure reading until the pressure at the sensor has reached 7 bar which would open up the valve and allow air to actually reach the gauge.

Since the pressure gauge  is inherently slow to response, therefore its difficult to draw a relation between the current output of the sensor and the pressure on the gauge in real-time troubleshooting.

b) Problem with analog input of the board is difficult to troubleshoot

Troubleshooting becomes a mess once there occurs a problem with the actual analog input of the electronic board itself, a faulty analog input results in wrong readings being transferred over to the machine computer which then resulted in unwanted malfunctions and error messages. The analog channel is of 25mA, means the ADC will saturate at 25mA, meaning any current value greater than 25 mA flowing into the analog input will be displayed as just 25 mA. As far as I know current can’t be digitized directly, it has to be converted into a voltage first which can then be converted into a digital value. I measured through simple experimentation that the input impedance of the analog input is around 100 ohms, so in order to troubleshoot if the analog input had gone bad, current going into the analog input and voltage across the input had to be measured, this is a rather tedious task and the measurements had to be repeated many times to make sure they were good enough to draw conclusions from.

Design Parameters to Counter these Issues

In addition to measuring current it was only logical to have an on-board microcontroller that could translate the real-time current value into the corresponding pressure and display  it on demand.

Since it was difficult to troubleshoot a faulty analog input on the electronic board therefore the measuring device should be designed with an input impedance that matches that of the actual analog value acquisition board so that the sensor can be disconnected from the analog input and connected directly across the measuring devices input to give a quick comparison of the milli-amps measured by the analog board on the machine and the measuring device.

The device had to be compact and easy to carry, should be able to power up from a range of voltage inputs depending on what’s available on site, any other functionality improvements will be an extra advantage.

The Actual Design

The circuit is centered around an ATtiny24 microcontroller, which quite frankly is a nice and powerful enough microcontroller for small tasks such as this one. For the display I am using three seven segments driven by the MC14511 BCD to seven segment latch/decoder. Since I am using Arduino IDE to program my ATtiny therefore the seven segment display was a logical choice since the lcd display code would have taken up a lot more code memory. The latch function of the MC14511 allows for usage of minimum number of controller pins in order to display numbers on three individual seven segment displays.

SAKtesternew
Final Circuit Diagram

since the tester will ultimately be connected in series with a 24 volt powered current loop so it was essential to build in some degree of protection in the tester to avoid damaging it in case (considering the worst case scenario) both the sensor and the analog input on the machine are shorted out, the port of the controller is protected using a 4.7 volt zener diode, a 10K ohm resistor is used as a current limiter for the analog input of the ATtiny24, a 100mA fuse is placed for further protection and in case a shorted current loop is tested it will blow out the fuse, instead of using a single 100 ohm test resistor I have used 30, 3000 ohm resistors in parallel, these are standard 0.25 watt resistors and combining them in parallel give me a wattage of over 7 watts, so even in a short circuited scenario where a maximum of 240 mA would be flowing through the 100 ohm test resistor the maximum power dissipated would be a little over 5.5 watts which won’t damage the 3000 ohm parallel resistor network, the 100 mA fuse is added to save the other protection components like the zener diode from the extra burden that a short-circuit would cause.

The LED is added to indicate if the pressure reading is above 9.99 bars in the system and is also used to as an indicator when the tester is made to operate in a special mode where it records the maximum and minimum values of pressure and milli-Amps.

The Code

The code as mentioned earlier is written using the Arduino IDE and is fairly simple and self explanatory, in order to convert the current readings into pressure, I have used a simple equation and have implemented it into the controller program.

I = 1.6*P + 4

Where I is the current in mA’s, P is the pressure in bars, it’s a simple linear relation which is in very close approximation of the relation I deduced taking pressure and current readings physically on the machine.

The seven segment displays are being updated one at a time, each three segments are being updated for new readings one after the other since I am using only four pin on the ATtiny24 to send out data to all the three seven segments. This is achieved by taking advantage of the latch functionality on the 14511 chip.

byte function, toggle = 0;
int peakValue = 0, minValue = 1023;
void setup()
{
pinMode(10,OUTPUT);
pinMode(9,OUTPUT); //Ardpin 13 – tinypin 11 D2 — D9
pinMode(8,OUTPUT); //Ardpin 12 – tinypin 10 D3 — D8
pinMode(7,OUTPUT); //Ardpin 11 – tinypin 9 D4 — D7
pinMode(6,OUTPUT); //Ardpin 10 – tinypin 8 D5 — D6
pinMode(5,OUTPUT); //Ardpin 9 – tinypin 7 D6 — D5
pinMode(4,OUTPUT); //Ardpin 8 – tinypin 6 D7 — D4
pinMode(3,OUTPUT); //Ardpin 7 – tinypin 5 D8 — D3
pinMode(2,INPUT); //Ardpin 6 – tinypin 3 D9 –D2
analogReference(EXTERNAL);
delay(500);
if(digitalRead(2) == HIGH)
{
function = 1;
}
}
void loop()
{
int currentValue;
long value;
byte segdis1, segdis2, segdis3;
if(function != 1)
{
currentValue = analogRead(A1);
value = currentValue;
delay(150);
}
if(function == 1)
{
currentValue = analogRead(A1);
delay(70);
if(currentValue > peakValue)
{
peakValue = currentValue;
}

if(peakValue >= 557)
{
if(currentValue < minValue)
{
minValue = currentValue;
}
}
if(toggle%2 == 0)
{
value = peakValue;
digitalWrite(10,HIGH);
}
if(toggle%2 != 0)
{
if(minValue == 1023)
{
if(peakValue < 1023)
{
value = 0000;
}
}
else
{
value = minValue;
}
digitalWrite(10,LOW);
}

}

value = value*2441;//800*2441 = 1952800
value = value/10000;//1952800/10000 = 195
if(digitalRead(2) == HIGH)
{
value = value – 40; //195-40 = 155
value = value*100; //155*100 = 15500
value = value/16;//155/16 = 968
if(value > 999)//maximum pressure condition
{
//segdis1 = 0;
//segdis2 = 0;
//segdis3 = 1;
digitalWrite(10,HIGH);//Maximum pressure fault LED indication
delay(20);
digitalWrite(10,LOW);
delay(20);
}

}
digitalWrite(4,HIGH);//4
digitalWrite(5,HIGH);//5
digitalWrite(3,HIGH);//3
byte k;
byte n = 9; //9
if(value >=0)
{
segdis1 = value%10; //remainder is stored e.g 20%10=0
value = value/10;
segdis2 = value%10;
value = value/10;
segdis3 = value;
}
else
{
segdis1 = 0;
segdis2 = 0;
segdis3 = 0;
}
for(k=0;k<=3;k++)
{
if(bitRead(segdis3,k)==1)
{
digitalWrite(n,HIGH);
}
if(bitRead(segdis3,k)==0)
{
digitalWrite(n,LOW);
}
n–;
}
digitalWrite(3,LOW);//3
// delay(50);
digitalWrite(3,HIGH);//3
n = 9;
//k=0;
for(k=0;k<=3;k++)
{
if(bitRead(segdis2,k)==1)
{
digitalWrite(n,HIGH);
}
if(bitRead(segdis2,k)==0)
{
digitalWrite(n,LOW);
}
n–;
}
// digitalWrite(8,HIGH);
digitalWrite(5,LOW);//5
// delay(50);

//digitalWrite(8,LOW);
digitalWrite(5,HIGH);
// delay(100);
//digitalWrite(8,HIGH);
n = 9;
//k=0;
for(k=0;k<=3;k++)
{
if(bitRead(segdis1,k)==1)
{
digitalWrite(n,HIGH);
}
if(bitRead(segdis1,k)==0)
{
digitalWrite(n,LOW);
}
n–;
}
digitalWrite(4,LOW);//4
digitalWrite(4,HIGH);

if(function == 1)
{
delay(1500);
toggle++;
}

}

The commented out text might not make much sense,since this was for my own personal reference, however the code should work without any issues if the ATtiny24 is programmed correctly.

Once again to save space and avoid floating point mathematics, I am multiplying my equations (by 10, 100, 1000 r whatever is required) to shift decimal places.

Features of the Tester

Here’s briefly what the tester is capable of doing.

1- Plug in the power and the tester is turned ON, it can measure the milli-Amps and show the corresponding pressure while the button is kept pressed.

2- Push the reset switch, keep the pressure/current switch pressed and release the reset button until the LED light’s up,the LED is now going to blink slowly at a rate of almost 2 seconds ON and 2 seconds OFF indicating that the tester has entered a maximum and minimum current and pressure recording mode, once the LED light’s up the maximum pressure measured will be displayed and when the LED turns OFF the minimum pressure measured will be shown on the segmented display. The minimum pressure monitoring only starts once the maximum pressure has gone past 6 bars since otherwise the minimum pressure would be recorded as zero every time, also the machine malfunctions only after when the minimum pressure has stayed below 6 bars for a few seconds so it’s only logical to start measuring the minimum pressure once the pressure is above 6 bars since any dips in pressure after that will be of interest since that can cause a malfunction during the production run.

The Finished Circuit of Perf-Board

I wanted the tester to be as small as possible so it can be easily carried out with my other testing gear, in order to achieve this I have implemented the design on two separate boards which can be combined creating a much smaller foot print.

IMG_20160604_223627
The display board, houses the seven segments, the BCD to segment decoder, the reset switch and the indicator LED
IMG_20160604_223729
Display board has male headers at the back through which it can be plugged onto the measuring and control board
IMG_20160604_223755
The measuring and control board, the left side shows the resistor network, the fuse and the current/pressure button, a single ATtiny24 sit at the center with female headers at either side on which the display board will be plugged on to.
IMG_20160604_223849
Soldering at the back of the measuring and control board
IMG_20160604_223925
A closer look at the resistor network, you can also see an LM7805 regulator through which the circuit will be powered (LM7805 is not explicitly mentioned in the schematic though)
IMG_20160605_163522
The board completely assembled

Here’s a link to a youtube video I have uploaded demonstrating the current and pressure measuring capabilities of the tester. The video shows a bench-top testing of the equipment giving an idea of how the instrument will perform once you are actually using it in the field.

 

Conclusion

I am having a protective case designed for this tester so I can carry it around easily without damaging it, I will update my post once the case is ready, if you found this post useful and would like to share your opinions please leave a comment, your support and interest matters a lot. Follow my blog and like my youtube channel if you’d like to support me.

Update 3rd July 2016: I had a case made for the tester, not the most elegant design but good enough for the job I guess, here are the dimensions and the final cased project,

The dimensions for the case
The dimensions for the case
IMG_20160703_123409
The final cased up project ready for field testing. Ignore my terrible hot gluing skills.