Category Archives: Electronics

Electronics

C2000 Solar MPPT tutorial Pt/1

 

This series of four posts will cover a project build for a C2000 Solar MPPT Tutorial.  The Maximum Power Point Tracker (MPPT) circuit is based around an interleaved synchronous buck circuit topology.  The microcontroller used is the Texas Instruments (TI) C2000 family, the C2000 Launchpad is used which has a TMS320F28027 chip on-board.  Considerable research was carried out on this project, as there was no prior knowledge of the C2000, all the relevant peripherals were tested separately and then brought together and tweaked for the final code.  TI provides all the documentation required, which can be found here and for this tutorial the ADC, ePWM and the F2802x Peripheral Driver Library Users’ Guide were referenced.

The C2000 solar MPPT tutorial can also be used as a guide if designing a circuit for other microcontrollers such as Arduino, as the electronic principles and some of the code is transferable to any platform.

The image below shows the final prototype MPPT PCB with the C2000 Launchpad secured on top via the header connections.

C2000 Solar MPPT Tutorial final prototype PCB

The video below shows the system set-up, allowing the Perturb and Observe algorithm to be tuned.  There is also a second video demonstrating the algorithm tracking the maximum power point of the solar panel, this can be found on my YouTube account and will be embedded in the final tutorial.

In this part a basic overview of the hardware design will be covered, further tutorial parts will cover the following areas in greater detail:

  • Buck circuit calculation, a look at MOSFET efficiency, current and voltage sampling and circuit design and layout
  • Software approach including phase shifted PWM, ADC sampling and the Perturb and Observe algorithm
  • Final set-up, testing and tuning

Maximum Power Point Tracking

Maximum power point tracking is employed, to ensure the maximum power is extracted from a solar panel.  In order to understand this further we first need to look at the power curve characteristics of a solar panel, the image below shows a Suntech STP230-20Wd (230W panel) power curve.

C2000 Solar MPPT Tutorial solar panel power curve

The maximum power point (MPP) of a solar panel lies at the knee of the current and voltage curve.  Reading the datasheet on the Suntech panel tells us that Vmp (voltage at maximum power point) is 29.8V and Imp (current at maximum power point) is 7.72A, locating the intersection point of these two values, it can be seen that the MPP is at the knee of the curve. The graph also illustrates that the voltage variation is much less compared to the current only with differing irradiance, however the current varies linearly with solar intensity.  Temperature also affects the power output from a panel, current increases slightly with an increase in temperature, whereas voltage decreases with an increase in temperature.  As the voltage is affected by temperature more than the current, voltage calculations need to be considered when large string arrays are used, to ensure the system meets the requirements of the inverter used.

The panel has an internal resistance which changes dynamically with differing irradiance levels.  So if a static load is connected directly to a panel and its resistance is higher or lower than the panels internal resistance at MPP, then the power drawn from the panel will be less than the maximum available.  Taking a simple example under bright midday sun, say we connected the Suntech STP230-20Wd directly to a 12V lead acid battery, the panel voltage would be dragged down near to the load voltage of the battery as the batteries resistance is lower than the panels.  With a quick calculation the panel is now outputting 12V and 7.72A, therefore 93W, this equates to a loss of 137W or 60%. Obviously this is an extreme example, but even using a 24V battery would still equate to a 20% loss, which is far from efficient.

This is where MPPT comes into play.  MPPT circuits can be based on various switch mode power supply (SMPS) topologies, they generally have a fixed frequency but varying duty cycle.  The duty cycle is controlled via an algorithm so as to track the changing MPP, the output power is determined by the efficiency of the circuit and usually closely matches the incoming power within 3-10% (typical losses).  The output voltage and current will not necessarily be fixed under changing irradiance conditions depending on the system employed, so further circuitry maybe required or a more elaborate algorithm.

System Overview

The image below shows an overview of the final system

C2000 Solar MPPT Tutorial Prototype System Diagram

The solar panel in the diagram will be represented in real life by a 10W panel purchased from Ebay, this has a Vmp of 17.2V and an Imp of 580mA.  Four ADC inputs and 2 PWM outputs will be used on the C2000.  The input voltage and current and output voltage and current will both be monitored, so the input and output power can be determined.  A pair of half bridge driver integrated circuits (IC) will be used to drive the four N-Channel MOSFETs. There is also an auxiliary supply, this was used to power a 12V linear regulator which powered the half bridge drivers.  The 12V regulator could also be powered directly from the panel, which was used in testing under bright sun conditions.

 

The chosen SMPS topology will be based on a synchronous buck converter circuit, there will be two of these in parallel forming an interleaved design.  Using an interleaved approach is over kill for the 10W panel prototype, but it gives the system scalability for future iterations.  The synchronous buck design was chosen as it offers a higher efficiency, these design choices will become clear as the tutorial progresses.

Interleaved Synchronous Buck Converter

The buck converter circuit will be over viewed as this forms a large part of the system design, this will naturally lead into the advantages of the synchronous and interleaved design chosen.  A boost circuit could quite easily be implemented in place of buck design, but in this case the target output voltage was 12V.

A buck converter is basically a small DC to DC converter.  The main principle at work in a buck converter, is the tendency for an inductor to resist changes in current.  A buck converter output voltage will always be lower or the same as the input voltage.  A simplified schematic of a buck converter can be seen in the below image.

C2000 Solar MPPT Tutorial buck converter circuit

A buck converter relies on a switch to change or reduce the current flowing through the inductor, the switch usually takes the form of a MOSFET (Q).

  1. When the MOSFETs gate is saturated effectively closing the switch, current flows through the inductor (L) in a clockwise direction into the load (R) and also charging the output capacitor (C).  At this point the voltage on the cathode of the diode is positive, therefore the diode (D) is blocking any flow of current and is said to be reverse biased.  The Instantaneous current flow into the load from Vin is slow, as energy is stored in the inductor as it’s magnetic field increases.  So during the on phase of the MOSFET, energy is loaded into the inductor.
  2. When the MOSFET is switched off, the voltage across the inductor is reversed.  The inductors magnetic field begins to collapse, this collapse releases the stored energy allowing current to flow from the inductor into the load.  The diode now has a negative voltage on the cathode so becomes forward biased.  Therefore the inductors discharge current flows in a clockwise direction through the load and back through the diode. Once the inductors energy has fallen below a certain threshold, the load voltage falls and the capacitor becomes the main source of current, ensuring the load is still supplied until the next switching cycle begins.  To ensure Continuous Conduction Mode (CCM) the inductor must not be fully discharged before the MOSFET is switch on again, and the cycle repeats.

Now that the basic concept of a buck converter has been explained the synchronous design can be covered.  The synchronous design simply replaces the diode with a second MOSFET, this eliminates the losses incurred by the forward voltage drop across the diode, thus making the circuit more efficient.  This is slightly more complex to implement, as the second mosfet switching needs to be carefully timed with the switching of the first mosfet.  It is essential to ensure that both are never on at the same time, or the current will have a direct path to ground, effectively causing a short circuit.  The MOSFET switching is effectively 180 degrees out of phase, with a short delay period between each transition referred to as a Dead-Band.  A dead-band is usually a common feature of most half bridge drivers, the C2000 also allows for the dead-band to be programmed in and tuned, so in reality with modern microcontrollers this is quite simple to implement.

The interleaved design simply takes two synchronous buck circuits and places them in parallel, the main components MOSFETs and inductor are individual to each circuit, but they share a common input and output as well as the same input and output capacitors.  Using an interleaved design reduces the current ripple by half, as each interleaved phase shares the total current.  The shared current allows smaller inductors and capacitors to be used, which can also reduce system size and cost.  Additionally this systems PWM frequency was chosen to be 15kHz as it reduces the switching losses in the MOSFETs, but increases the current ripple and also the inductor size.  By using the interleaved approach it then helps to negate these factors.  These trade-offs will be covered in more detail in the hardware section of this tutorial, where MOSFET losses will be covered.

10W Solar Panel

As mentioned previously the solar panel was purchased from Ebay for around £20.  It’s a polycrystalline panel, which is encased in an aluminium frame and comes with 2 large croc clip leads and a small diode box.  The panel seems pretty good quality and appears to be weather proofed, the diode box is not sealed very well but as it sits under the panel I don’t believe there would be any issues.  Have enclosed 2 shots of the panel, and I can probably dig out the links to the company if anyone is interested.

C2000 Solar MPPT Tutorial 10W panel front

C2000 Solar MPPT Tutorial 10W panel back

System Schematic

C2000 Solar MPPT Tutorial hardware schematic

The next part of this tutorial will go more in-depth into the circuit calculations and schematic design.

I take great care when writing all the tutorials and articles, ensuring all the code is fully tested to avoid issues for my readers.  All this takes time and a great deal of work, so please support the site by using the Adfly links etc.  If you have found this useful or have any problems implementing, please feel free to leave a comment and I will do my best to help.

Power Factor Correction PFC Tutorial

In this Power Factor Correction PFC tutorial, a basic PFC circuit and the calculations used to design the circuit will be demonstrated.

A PFC circuit is required as the power factor in a system can be degraded.  One of these reasons is due to reactive power, the other is due to harmonics generated by the load device.  This tutorial will not cover harmonics, that will be covered in a later project build where an active PFC is designed and built around a Texas Instruments C2000 microprocessor.

Reactive power is a quantity normally only defined in alternating current (AC) systems, a countries national grid consists of an AC system.  Most AC systems consist of a sinusoidal wave with a frequency of 50 or 60Hz, the voltage and the current will both fluctuate at this frequency, but not necessarily at the same time.  The power being transmitted will fluctuate around an average value, assuming the voltage and current waveforms are in phase, then this value is known as the ‘real’ or ‘true’ power.  For a domestic household the real or true power over time, is measured by the electricity meter as kilowatt hours (kWh).

If the average value is zero then the voltage and current would be completely out of phase and the power being transmitted is said to be reactive power.  The unit for reactive power is the VAR, which stands for Volt Ampere Reactive.  Depending by how much the voltage and current sinusoids are out of phase, determines the amount of reactive power verses real power, and the resultant power factor.  There is also one other element to consider, this is known as the ‘apparent’ power.  Apparent power is the power that appears to be flowing to the load.  The equations below will help clarify the relationship between these terms, real or true power is denoted by P, reactive power by Q and apparent by S.

Power Factor Correction PFC tutorialReactive power in a system is caused when the load device in a system stores power, this power then flows back towards the primary power source.

The inductive and capacitive loads affect on the current wave form is known as the Displacement Power Factor.  The harmonic distortion caused by switching elements, is known as the Total Harmonic Distortion or THD.  Both the Displacement Power Factor and the THD are used to calculate the overall power factor.  In the following example a simplified model is over viewed where the THD is assumed to be zero.

Basic PFC Circuit

The video below demonstrates a basic AC circuit, under 3 conditions;

  1. The circuits first condition is with a purely resistive load, and the voltage and current waveforms can be observed to be in phase.
  2. The next condition an inductive load is switched in parallel with the resistive load, the current sine wave can be observed to become out of phase with the voltage.
  3. The third and final condition is to place a capacitor in parallel with the inductor and resistor, this brings the current sine wave back in phase with the voltage.

For the basic resistor circuit it is fairly straight forward to calculate the power in the circuit.

Power Factor Correction PFC tutorial

The image below shows the circuit again, the yellow trace is the current and blue trace is the voltage.  The peak to peak and rms values for the traces can be seen to the right of the oscilloscope screen, bearing in mind that the current transformer is set to 1mV/mA, the values can be seen to almost mirror the calculations above.

Power Factor Correction PFC tutorial

To calculate the power when the inductor has been added, requires the inductor reactance to be calculated, which then allows the total impedance of the circuit to be determined. Complex numbers will be used to determine the inductor reactance and the total circuit impedance.

Power Factor Correction PFC tutorial

Using the basic parallel calculation in rectangular form, the impedance can be calculated and then the new circuit current.

Power Factor Correction PFC tutorial

As with the previous calculation for the resistive load, the inductor calculation can be compared with the image below showing the oscilloscope trace and values.

Power Factor Correction PFC tutorial

From this the circuits displacement power factor can also be determined, using the resultant phase shift of the current due to the new inductive load.

Power Factor Correction PFC tutorialWith the power factor calculated, it is now possible to determine the real power, apparent power and reactive power.

Power Factor Correction PFC tutorial

The final part of this tutorial involves calculating the value of the power factor correction capacitor.  It can be seen from the video this brings the current waveform back in phase with the voltage waveform.  The capacitor achieves this by cancelling the inductors reactance out, this makes the load appear purely resistive.  The calculation for this is as follows.

Power Factor Correction PFC tutorial

Furthermore by using the resonance formulae, it can be seen that the inductor and capacitor are in resonance.

Power Factor Correction PFC tutorial

The power factor is now effectively 1 as there is no phase difference between the voltage and current waveforms.  It can be shown that the same real power is still being delivered to the load.

Power Factor Correction PFC tutorial

As with the previous calculations the image below can be seen to match the equation.

Power Factor Correction PFC tutorial

Further reading on power factor can also be found here.

I take great care when writing all the tutorials and articles, ensuring all the code is fully tested to avoid issues for my readers.  All this takes time and a great deal of work, so please support the site by using the Adfly links etc.  If you have found this useful or have any problems implementing, please feel free to leave a comment and I will do my best to help.

PID Tutorial C code Example Pt/2

In this PID tutorial C code example Pt/2, the basic concept of a Boost PID controller will be explored.  All the PID controller C code is stepped through, as well as some basic concepts for testing and tuning the controller.  The final C code example can be downloaded via the link at the end of the article.

Hardware Overview

The image below shows a rough blocked out diagram of the boost circuit and feedback loop.

PID Tutorial C code Example using a Stellaris LM3S6965

As can be seen it’s a fairly simple design, with the output voltage being monitored and fed back to the LM3S6965.

A schematic for the boost converter can be seen below, this circuit was originally made to test a variable voltage boost converter.  The original design would use a 5V input which would then be boosted to either 9V, 12V or 15V, this was controlled via a state machine running on the Stellaris LM3S6965.

PID Tutorial C code Example using a Stellaris LM3S6965

The drive circuit for the mosfet uses 2 transistors in a totem pole configuration, and a 3rd transistor is to ensure a small current is sourced from the LM3S6965.  The main boost circuit itself consists of L1, Q1, D1 and C3.  The sampled output voltage via the potential divider is first passed through an operational amplifier U1A, configured as a non inverting amplifier which provides a gain of 2.2.  The operational amplifier U1B acts as a unity gain buffer, it’s input is connected to 3 resistors R7, R8 and R9.  These 3 resistors provide the offset voltage of 770mV and U1B ensures there is a high impedance input.  The output of U1B feeds the offset voltage to R4 and then to the negative input on U1A (effectively offsetting ground).  The boost converter was originally set-up to measure voltages between 4V and 19V.  So the operational amplifier arrangement with offset, ensures the sampled voltage range uses almost the full range of the ADC.  For the PID testing the output voltage will be regulated to 9V, which is equal to 353 on the ADC which is also the set point value.

Software

The software used was written after reading various sources on PID.  It has been designed so it is easy to understand, as it uses local and global variables.  A more efficient way would be to use a typedef structure or typedef struct in C.

So firstly we have our constants and global variables.

In the first part of this tutorial the proportional (Kp), integral (Ki) and derivative (Kd) constant values were mentioned.  These are the values which provide the tuning for the PID control system.  The next constant is the set point, this was observed as the read ADC value, when 9V was present on the output.  The 9V was measured and adjusted using a multimeter with a fixed load on the output, the duty cycle had a fixed value which was then increased until 9 volts was reached.  The first 2 global variables are used to store the accumulated and historic error values required for integration and differentiation.  The global variable PWM_Temp is initially given a value, then this is used to store the old duty cycle value, which is then used in the new duty cycle calculation.

The next set of variables are all local to the PID function called PWM_Duty_Change(), all the code that follows will be inside this function, until the closing brace of the function is stated and mentioned.  Additionally the entire code which was used on the LM3S6965 can be downloaded (bottom of the page), so it can be seen how and when the function was called.

The first 2 local variables are called iMax and iMin, these are used to prevent integral windup.  More will explained on integral windup further in the tutorial, but for now we will just run through the variables.  The next 4 variables have already briefly been touched upon in part 1 of this tutorial, these are Err_Value, P_Term, I_Term and D_Term.  Then we are left with new_ADC_value which is simply the latest sampled value form the ADC, and finally PWM_Duty which will be the new PWM duty cycle value passed to the timer module.

The read ADC code does not need much explanation, other than a function was created to read the ADC and return the value as an integer.  If you are using this code on another microcontroller, you simply need to construct an ADC read function, then insert instead of the read_ADC().

Going back to part 1 of this tutorial it was shown that the error value can be obtained, by simply taking the newest error value away from the set point, that’s all this line performs.

To obtain the proportional term the Kp constant is multiplied by the error value.

The accumulated error value is used in integration to calculate the average error, so first the current error value must be added to the accumulated value, and that’s what this line performs.

The if and else if statements are used to cap the accumulated integral term, by simply setting upper and lower thresholds.

The integral term is then calculated by multiplying the Ki constant with the accumulated integral value.

The first line of this code snippet calculates the derivative term.  To understand how the code works the second line needs to be run through quickly, this basically assigns the newest ADC value to the d_temp global variable.  So the d_Temp variable effectively stores the historic error value, therefore allowing the derivative to be calculated.  Now looking at the first line again, the newest ADC value is taken away from the historic value, the difference between the 2 would allow the rate of change to be calculated (assuming the time between the readings is a known quantity). Then this value is multiplied by the derivative constant and assigned to the derivative term.

Now that we have all the PID terms calculated, they can be used to change the PWM duty cycle.  This next piece of code adds all the PID terms together, then they are subtracted from the PWM_Temp variable (PWM_Temp usage is shown shortly as it comes towards the end of the function).  This value is then assigned to the PWM_Duty variable.  The way the PID terms are used here is specific to this program, firstly the sum of the PID terms is subtracted, this is due to the final electronic circuit used.  What’s important here is the PID terms are summed, then they need to be used in such away as to construct a valid PWM duty cycle or other chosen control method.

The if and else if statements are used to prevent the duty cycle from going too high or too low, in this case this simply prevents the output voltage from going too high or too low.  If say you were using a half bridge driver integrated circuit, these usually state a maximum duty cycle of say 99%, if this is exceeded the voltage doubler cannot function correctly, so having limits can be a good protection system.

This line is again limited to this specific application, it simply calls the function adjust_PWM(), which has the new PID calculated duty cycle value, as a parameter.

The final statement in the function before the closing brace, assigns the current PWM duty cycle value to the PWM_Temp global variable.

Integral windup can occur if the integral term accumulates a significant error, during the rise time to the set point.  This would cause the output to overshoot the set point, with potentially disastrous results, it can also cause additional lag in the system.  The integral windup prevention used in this example, places a cap on the maximum and minimum value the integrated error can be.  This effectively sets a safe working value and is considered good working practice in any PID system.  The values used for integral windup as with the PID constant gain values are specific to this system, these would need to be determined and tuned to your system.

Step Response

The intention was to also explore the well documented Ziegler-Nichols approach, however time constraints for the project did not allow this method to be fully explored.  Some basic concepts of how to carry out a step response test will be shown, as I am sure it will prove useful.

The systems step response shows how the system responds to a sudden change, electronic circuits switch quickly, so an oscilloscope was the best piece of equipment for the job.  The boost converter was set up with a fixed load, a fixed PWM duty cycle and no feedback , therefore in an open loop configuration.  Then some additional test code was added, initiating these 2 extra functions when a button was pressed on the LM3S6965 development board :

  1. A free GPIO pin would be taken from low to high
  2. The PWM duty cycle would decrease by 10% effectively increasing the output voltage

The free GPIO pin would be connected to channel 2 on the oscilloscope, and in this way can be used as a trigger to start a capture event.  Channel 1 on the oscilloscope would be connected to the output of the boost converter, thereby capturing the step response as the output voltage rises.  The image below is a photograph of the captured step response on the oscilloscope.

PID Tutorial C code Example using a Stellaris LM3S6965

The GPIO pin was polled before the PWM duty cycle was updated, however this happens so quickly, it is difficult to distinguish this.  The lower square wave type step is the GPIO pin on channel 2, and the top curved step response is the output from the boost converter.  It can be seen to overshoot it’s settling level at the beginning then oscillate for a time before settling down, this oscilloscopes accuracy wasn’t the best, using a longer time base did not show any extra detail on the oscillations.

If the step response was of a first order, a calculation based on the reaction curve could be performed.  However the step response from the boost circuit is of a second order, and has an under-damped nature.  In order to explore this calculation further, requires another tutorial altogether, however further reading on this can be found here.

The step response of a similar system under the control of a PID controller can also be viewed.  This can be achieved by using a similar set up, the external pin is used again to trigger an oscilloscope capture.  That same GPIO pin is also used to switch a mosfet, which places an additional load in parallel with the output of the boost converter.  The PID algorithm will then regulate the output voltage to ensure it meets the set point with the new load, and the step response can then be captured.

Testing and Tuning

The system was set up and a basic tuning approach was used, the image below shows the system on the test bench.

PID Tutorial C code Example using a Stellaris LM3S6965

The image shows the following pieces of equipment:

  • Hewlett Packard multimeter connected to the output, monitoring the output voltage
  • Bench power supply, supplying 5V to the circuit
  • Oscilloscope, used to monitor the PWM duty cycle
  • 0-100Ω bench potentiometer
  • Boost converter PCB, LM3S6965 development board and a laptop to tweak the code

With everything connected the PID algorithm was set up, but with only the proportional part in operation.  The set point was set to 353 as mentioned previously, which produced close to 9V give or take 10-15mV.  The load was fixed and set to 100Ω.  Initially the proportional gain constant Kp was set very low around 0.001, this was too low so it was increased over a few steps until 0.01.  At this point the output voltage was observed to be approximately 7.5V, and the duty cycle waveform was observed to have a small amount of jitter, as the duty cycle fluctuated +/- 0.5%.  The Kp value was again increased, until the output voltage read approximately 8V, the duty cycle was again observed and found to be fluctuating by a greater amount, by approximately +/-5%.  The increase in jitter on the PWM duty cycle can be equated to greater oscillations on the output voltage, the multimeter was not suitable for observing these.  It would have been possible to see them on the oscilloscope but this probably would have involved a stop capture then restart method, therefore to make the process quicker the PWM duty cycle was considered ‘good enough’.

At this point the Kp value was backed off, to the previous level of 0.01 so the output voltage was at 7.5V.  This point can be considered close to the offset level mentioned in part 1 of this tutorial, and for ease of reading the image showing the offset level can again be seen below. This image also illustrates again how too larger Kp value can introduce instability in the output.

PID Tutorial C code Example using a Stellaris LM3S6965

Now with this level reached, the integral part of the algorithm was introduced.  All the hardware was untouched, just a simple modification to the algorithm was made.  The initial value chosen for Ki was 0.01.  This was then loaded on to the LM3S6965 and the output voltage on the multimeter was immediately observed to read 9.02V, +/-10mV.  The oscilloscope was also observed to have minor jitter as before of only a few half percent.  The integral value was not tweaked any further, but in most cases tuning the Kp and Ki values would take a greater time and under a wide range of conditions.

With the PI controller working on a basic level, the next test was to see how it performed under different load conditions.  First the bench potentiometer was left at 100Ω and the input current and output voltage were noted, the wiper was then moved to the middle (approximately 50Ω) and again the output voltage and input current were noted.  At 100Ω the output voltage was 9.02V with a current of 180mA, at 50Ω the output voltage was 8.99V with a current of 500mA, both output voltages still showed minor voltage variations in the +/-10mV range.

The next step was to move the potentiometer wiper rapidly between the 100Ω and 50Ω position, then observe the output voltage and duty cycle (not the most scientific test, but goes some way to demonstrating the system).  With this test being performed the duty cycle was observed to rapidly increase and decrease, too quick to observe anything further and a step response would be the best method to use here.  The output voltage was observed to have a minor variations, fluctuating +/-15-20mV

After this test, the derivative constant was introduced and tweaked to find the best settings. The Kd constant was not observed to have a huge affect on the system, unless increased dramatically which produced instability.  This set up is not ideal for testing the derivative term and a more detailed and longer term approach would be best.

The basic test performed seemed to conclude the PI controller was working as per the research carried out.  The system used here updates at a very fast rate, therefore observing the step response at this point would be best practice.  As this system has no critical importance other than to explore PID, it simply wasn’t necessary to tune it to a high degree of accuracy.  I have a number of projects in the works however, which touch on this subject again and I intend to post them when I have time.

Example Code

The link below contains the zip file with the complete C code and an external functions folder, there is a small advert page first via Adfly, which can be skipped and just takes a few seconds, but helps me to pay towards the hosting of the website.

PID LM3S6965 C code

I take great care when writing all the tutorials and articles, ensuring all the code is fully tested to avoid issues for my readers.  All this takes time and a great deal of work, so please support the site by using the Adfly links etc.  If you have found this useful or have any problems implementing, please feel free to leave a comment and I will do my best to help.

PID Tutorial C code Example Pt/1

In this PID tutorial C code example Pt/1, the basic concept of a PID controller will be explored. The full example code is implemented on a Stellaris LM3S6965 microcontroller, and is used to control a simple boost converter circuit, regulating the voltage with a change in load resistance. The boost circuit is not covered in-depth in this tutorial, but the fundamentals of a boost circuit are covered.

In this first part the basic concepts of a control system will be explored, as well as the PID controller.  The second parts covers the code implementation in the C language on the Stellaris LM3S6965, all the code is stepped through and can be downloaded at the end of the second part.

Basic Control System Concepts

To understand how PID controllers are used, it is important to first understand some basic control system principles.  The image below illustrates the 2 basic types of control system.

PID Tutorial C code Example using a Stellaris LM3S6965

The open loop system can clearly be seen to have no feedback, therefore if the load changes on the motor, the motor speed will change.  The control unit cannot command the driver to increase or decrease the power to the motor, as it has no knowledge of the speed change induced in the motor, by the change in load.

The closed loop system however has feedback from the motor.  So if the motors speed were to decrease due to an increase in load, the control unit could command the driver to increase the power to the motor, keeping a constant speed.  Common direct current motor control is achieved via PWM, and simply increasing or decreasing the duty cycle will increase or decrease the motor speed.

On/Off Controller

Using the above closed control loop as an example, the basic operation can be broken down. The feedback signal will often go through some signal conditioning circuitry, before being fed to the control unit.  The control unit will have some reference set point or threshold levels, that it is aiming to keep the motor speed at or between.  If a reference set point is used the new feedback signal could be used to generate an error value in the following way

Error_Value = Set_Point – New_Feedback_Value

We will come back to the Error_Value shortly as this is used in the PID controller, but first lets look at a more simplistic approach using the threshold level.

If threshold levels are used, lets say to keep the motor speed between 1200-1300rpm, the feedback signal could be directly used as a comparison.  Therefore if the feedback signal is 1320rpm the control unit needs to decrease the motor speed.  If we now said the control unit was a microcontroller, and the driver was a simple amplifier.  The microcontroller could reduce the duty cycle of the PWM, this in turn would then slow the motor down.  If we consider the motor to have a very quick response to changes in PWM drive, and the load on the motor to alter subtle over time, then there are 2 important factors to consider.  (1) The speed at which the PWM duty cycle is updated by the microcontroller, and (2) how large a change is made to the duty cycle on each update i.e. 1%, 5% etc.  This control system is often known as an on/off controller, the 2 factors can be tuned to suit the individual control system.  An example of on/off controller which is slightly more complex than this example, as it has other parameters is a Perturb and Observe algorithm used in a solar MPPT for photovoltaics.  The image below shows how an on/off controller usually oscillates around the set output level.

PID Tutorial C code Example using a Stellaris LM3S6965

On/off control systems typically oscillate around the desired output level, as they overshoot and undershoot the desired value.  The threshold level example used has no fixed setpoint so even if the motor speed stayed within these bounds, its speed would still oscillate to some degree.  The size of these oscillations is dependant on the PWM step size and the control loop speed.  If the system is very dynamic and changing at a fast rate, then a compromise between these 2 factors needs to be reached, to ensure good tracking performance.  When the desired reference value is reached, the size of the oscillations will be dependant on the PWM step size.

PID Controller

PID stands for Proportional, Integral and Derivative.  PID controllers have been used since the 1890s, and were originally developed by Elmer Sperry for an automatic ship steering system.  A PID control system uses 3 gain constants, which are multiplied with the Error_Value.  The proportional value gain constant is referred to as Kp, the integral value gain constant as Ki and the derivative value gain constant as Kd.   The results of these multiplications produces 3 further values, for this tutorial these are referred to as the P_term, I_term and D_term.

As previously mentioned the Error_Value can be obtained from simply taking the New_Feedback_Value away from the Set_Point.  In a PID controller the error value can simply be multiplied with the Kp constant, but for the Ki and Kd constants a different approach is required.  In order to calculate the I_term and D_term historic error values are required.  The I_term is using integration which gives the average error value over time, and the D_term is using differentiation which gives the rate of change of the error value over time.  Once all the PID terms are calculated, these new values are then summed together and used in the final control output.

The P, I and D terms have different affects on the final system performance, and need to be tuned to the individual control system.  The ultimate aim for any control system is to respond as quickly as possible, without excessive overshoot and oscillations around the set point.  The system response ideally needs to reach a settled state as quickly as possible, the settled state is very subjective and dependant on the application.  A block diagram of a PID control system can be seen below.

PID Tutorial C code Example using a Stellaris LM3S6965

The proportional term (P_term) provides an output value which is proportional to the current error value.  The Kp constant value determines how large the gain response will be to the current error value.  A high proportional gain constant will induce a large change in the output, often overshooting the set point level.  If the gain is too high the system can become unstable and excessive oscillations can occur.  Another affect of a high Kp constant is faster response time, vice versa a low Kp constant will result in a slower response time.  When a low Kp constant is used, there will still be oscillations and some overshoot of the set point depending on the level, however these will not be as aggressive.

A low Kp value will also settle in an offset position slightly below the set point level, this offset position can be used when tuning a PID system.  The image below illustrates the step response waveforms of a system with high and low Kp gain constants, on a hypothetical control system.

PID Tutorial C code Example using a Stellaris LM3S6965

 

The integral term (I_term) is used to bring long term precision to the control loop.  It is proportional to both the magnitude and duration of the error.  Using Integration allows for the average error to be calculated, as the sum of the instantaneous error over time provides an accumulated offset.  The accumulated error is then multiplied by the Ki gain constant, allowing the offset which should have been corrected previously, to be added to the controller output.  This then accelerates the controller output response towards the set point, eliminating the offset found when just using a proportional control value.

As with the the Kp gain constant the Ki constant, needs to be tuned.  If the Ki value is too high the system will have a faster response time, but it will also be likely to overshoot the set point, inducing further unwanted oscillations before finally settling.  An ideal Ki value produces a response time that is fast enough for the application, with little or no overshoot and a quick settling time.  The image below illustrates the step response waveforms with a tuned Kp value already set, then a few Ki gain constants are applied on a hypothetical control system.

PID Tutorial C code Example using a Stellaris LM3S6965

 

The derivative term (D_term) is the least used of the three terms, most controllers are based on PI control algorithms.  Introducing the Kd term is generally used in specific control systems, these are usually where overshooting the set point can cause dangerous results. Differentiation is used to determine the rate of change, by using the instantaneous error value and the previous error value, so a rate of change can be determined.  The derivative term can be used to predict system behaviour, improving settling time.

PID Control Loop Tuning

As can be seen the constant gain values Kp, Ki and Kd all affect the control system in different ways, therefore careful tuning of these values is an essential part of an effective PID controller.  Tuning a PID system is a difficult problem, there are only 3 parameters but finding a balance often takes some time depending on the complexity of the system.  Some systems have auto tuning features, but in some situations to have the best performance from a system, it is often recommended to manually tune.

A well known tuning method is called Ziegler-Nichols, developed by John G. Ziegler and Nathaniel B. Nichols.  This relies on the Ki and Kd gain constants first being set to zero.  The the Kp constant is adjusted until it reaches the ultimate gain, which is classified by the output from the control loop oscillating at a constant amplitude.  Then the ultimate gain value and oscillation period are used to calculate the Ki and Kd constants.  More about the Zieglar-Nichols method can be found here.

There are other methods and simply searching on Google will yield many results.

The C code, set-up and tuning of the boost converter will be covered in part 2 of this tutorial.

I take great care when writing all the tutorials and articles, ensuring all the code is fully tested to avoid issues for my readers.  All this takes time and a great deal of work, so please support the site by using the Adfly links etc.  If you have found this useful or have any problems implementing, please feel free to leave a comment and I will do my best to help.

Stellaris ADS1118 Tutorial

Stellaris ADS1118 tutorial will show how a Stellaris LM3S6965 is interfaced with a ADS1118 16 bit ADC using the SPI bus.

The ADS1118 was chosen as it can be used to interface thermocouples, in this example only the temperature data from the on-die temperature sensor will be read. The thermocouple interfacing will be covered at a later date.  The datasheet for the ADS1118 can be downloaded form here.

ADS1118 Package

The ADC was sourced in ADS1118IDGST package, then a symbol, package and device was constructed in EagleCAD.  Once this was completed a small PCB was milled out, which can be seen below.

Stellaris ADS1118 Tutorial C Code

 

 

 

 

 

The SMD decoupling capacitor was placed as close to the IC as possible (milling machine restrictions) to reduce noise, additionally the bottom layer was used as a ground plane.  This PCB layout uses male jumper pins, therefore allowing the ADS1118 to be plugged in and used with other test boards.  For testing a small piece of veroboard was used with a few discrete components, and some female headers so the ADS1118 PCB could be plugged in. This was then connected directly to the Stellaris evaluation board, using the 3.3V line as the main supply for the ADC.  The finished test board can be seen in the below image.

Stellaris ADS1118 Tutorial LM3S6965

The ADS1118 uses the Serial Peripheral Interface (SPI) to send and receive data from a microcontroller, the Stellaris will be the master and the ADS1118 the slave.  To ensure the SPI (known as SSI on the Stellaris) connections were correct, the the datasheet for the ADS1118 was read thoroughly, this was also necessary to familiarise oneself with ADS1118 control registers and SPI mode of operation.  This is not a tutorial on SPI so there are some assumptions made, that you the reader knows some basics regarding the SPI protocol.  Some useful links for SPI reference can be found here and here

The image below shows the ADS1118IDGST pinout, for this example pins 1 to 3 and 8 to 10 were used.

Stellaris ADS1118 Tutorial LM3S6965

 

 

 

 

 

These were connecting to the Stellaris as follows:

ADS1118 SCLK —– Stellaris SSICLK

ADS1118 CS —– Stellaris SFSS

ADS1118 DIN —– Stellaris SSITX (MOSI)

ADS1118 DOUT —– Stellaris SSITX (MISO)

*These pins on the Stellaris are generally used for interfacing with the on board OLED display, in this example the OLED is not used.  There is a second SPI peripheral on the LM3S6965 evaluation board.

ADS1118 SPI Operation

From the ADC datasheet we can find some useful information regarding the transmission cycle, and what information we need to send the ADS1118 to configure the control registers.  The ADS1118 has 2 modes of operation: 32 bit data transmission cycle and a shorter 16 bit data transmission cycle, the former also allows the SS line to be tied to Gnd. The image below shows the 16 bit data transmission cycle, which is the method used in the code for this tutorial.

Stellaris ADS1118 Tutorial LM3S6965

The SS line is controlled by the master, when this goes low the the master sends a 16 bit word to the ADS1118 on the MOSI line, this word contains the control register configuration settings.  As the SPI interface allows data to be transmitted and received simultaneously, the ADS1118 sends a 16 bit word back on the MISO line.  The master then takes the SS line high, and another 16 bit word transfer can take place as soon as this is taken low again.

The control register settings for the ADS1118 are used to configure various parameters i.e. Temperature Sensor Mode, Pull-Up resistors, Programmable Gain Amplifier Configuration etc.  A full list of these parameters can be found on pages 21 and 22 of the datasheet.  For this example we will be configuring the ADS1118 to function in a basic temperature sensing mode, using the internal temperature sensor.  To configure the control register in this way the 16 bit word looks like this in binary 00000000 00010010 or 0x12 in hexadecimal.  Bit 4 is set to 1 which places the device in Temperature Sensor Mode.  Bit 1 and 2 have a fixed setting if the control register data is classed as ‘Valid data’, this is 01 anything other than this will mean the 16 bit word is invalid, and it will therefore not be written to the control register.

Information regarding the clock polarity (CPOL) and the clock phase (CPHA) can be found in Figure 1 on page 6 of the datasheet.

C Code

Now the code used in this project is loosely based on some Stellaris example code, which is bundled with Stellarisware, however this code is not in the examples for the LM3S6965 board.  As with previous posts I will list some of the code in the post, and the complete C file can be downloaded at the end of the post.

All the SSI setup code has been bundled into one function called Setup_SSI()

First of all the clock is setup which is part of any hardware setup and required not just for the SSI.  Next the SSI0 module is enabled, followed by GPIO port A being enabled which the SSI0 module uses.

After the port is enabled the next function configures the pin muxing feature for port A, which relates to the pin_map.h header file in the Stellarisware.  Not all stellaris devices support pin muxing, so check the datasheet for your device.  The GPIO pins are then configured to be used by the SSI module using the function GPIOPinTypeSSI(), this takes 2 parameters, the port base address and then the individual pins on that port.

Then SSIConfigSetExpClk() is used to configure the SSIO peripheral, with 6 parameters:

The first parameter specifies the module base address, SSI0 is used here.  The second parameter specifies the rate of the clock supplied to the SSI, system clock is used in this case.  The third parameter specifies the SPI mode used (there are 4 variations), in this case Mode 1 is used.  The forth parameter specifies if the Stellaris will function as a master or a slave device.  The fifth parameter specifies the clock rate, in this case the system clock is divided by 8 so 1MHz, and finally the sixth specifies the number of bits transferred per frame, 16 bits are used in the example.

As mentioned the SPI protocol has 4 transfer modes, this is dependent on the clock polarity (CPOL) and the clock phase (CPHA).  The links provided earlier in this post will prove useful in understanding the mode of choice, as well as reading the datasheet for the slave device to ascertain which mode of operation it uses.

The final function call is to enable the SSI0 module.

Now that the SSI0 module has been setup, the functions to send and receive data can be used.  In order to store the data to be sent and received, the code example uses an unsigned long array for the transmitted and received data.  Also a further unsigned long is used as a counter variable making the process easier, if further data words were being sent.  This format is overkill for this example, as only one 16 bit word is required to be transmitted and received.  However in this example two 16 bit words will be sent, one containing the correct control register data, and another with invalid control register data.  The number of data arrays is determined by a #define NUM_SSI_DATA 2.

Inside the main function contained within a while loop, the first function is called as follows

This functions gets the received data from the receive FIFO of the SSI0 module (the first parameter), and places the data into the location specified by the second parameter, which is a pointer to the storage location.  If there is no data the function returns zero.

After this the data arrays for transmit and receive are initialized, here the values previously discussed for the control register are loaded.

Next a for loop is used to control the flow of data being transmitted to the slave.

The SSIDataPut() function call takes 2 parameters, the base address of the SSI module and the data to be transmitted over the SSI interface.  This function uses a blocking send function, it places data into the transmit FIFO of the SSI module.  If there is no space available in the transmit FIFO, it waits until there is space before returning.  This then ensures all the data is sent.

The SSIBusy() function simply ensures that the program waits while the SSI0 module is busy. Lastly the SS line is taken high to indicate the end of the 16 bit word transfer.

The next piece of code uses another for loop to control the flow of data being received from the slave.

The SSIDataGet() function call takes 2 parameters, the base address of the SSI module and the data to be received over the SSI interface.  This function uses a blocking get function, it will wait until there is data in the receive FIFO of the SSI module.  The data is then placed into the function location specified by the second parameter pointer address.  If there is no data the function waits until data is received before returning.

The SSIBusy() function is used again here as with the previous for loop.

Before we look at the rest of the code, which is used to calculate the temperature data from the ADS1118, lets firstly look at the SPI timing diagram produced by the code.

Stellaris ADS1118 Tutorial LM3S6965

The timing diagram was captured with a USB logic analyzer, which also has a function to decode the SPI bus protocol.  As can be seen in the waveform the SS line drops low to allow data to be sent, and remains low while data in being trasnmitted and receieved.  The serial clock starts shortly after the SS line drops low, and data is transmitted from master to slave on the MOSI line, and from slave to master on the MISO line.  The SS line can be seen to go high between each 16 bit word transfer.

The decoded data shown at the top, is the same as displayed on the MOSI and MISO lines below, it just saves counting the 0’s and 1’s and then calculating the hexadecimal value. From this it is easy to see the transmitted data values match, the values placed in the transmit FIFO by the code.  Also it can be seen that the second invalid control register data just instigates a transmit and receive sequence.  The data coming back from the slave are temperature values, which don’t mean a great deal in their present form, so some additional code is required to interpret and calculate the current temperature.

We know the temperature data is being sent in a 16 bit word, reading the datasheet especially the chapter titled ‘Temperature Sensor’ provides all the necessary information. Only the upper most 14 bits are valid temperature data, so the last 2 LSB can be discarded. The data is also sent in 2’s compliment format, this example does not go into negative values for the temperature, but this is good to know dependent on the temperature range being measured. Also the datasheet provides a temperature constant of 0.03125 degrees C, which equals 1 bit of the 14 bit number, so a simple multiplication is required.

3 variables are used to calculate the temperature sensor reading.

Firstly the raw 16 bit word is assigned to the unsigned int Raw_Value.  Looking back at the SPI timing diagram this value would be 0x0BF8 or 0000101111111000 in binary. We are however only interested in the 14 MSB, shown in bold.

This value is turned from a 16 bit word to a 14 bit word by shifting to the right by 2 places. After the binary value has been shifted it reads 00001011111110 or 766 in decimal.

The next step is to multiply the 14 bit raw value with the temperature constant for the ADS1118 temperature sensor.  Therefore 766 multiplied by 0.03125 equals 23.9375 degrees C.

Using Code Composer Studio v5.5 the next screen shot shows the data captured in the debug mode.  A breakpoint was set and adjusted to simply update the view, therefore the variables could be seen to change in real time.  The Raw_Value 767 is 3068 divided by 4 which is basically the operation the right shift is performs.

Stellaris ADS1118 Tutorial LM3S6965

Example Code

The link below contains the zip file with the complete C code, there is a small advert page first via Adfly, which can be skipped and just takes a few seconds, but helps me to pay towards the hosting of the website.

Stellaris ADS1118 SPI C code

I take great care when writing all the tutorials and articles, ensuring all the code is fully tested to avoid issues for my readers.  All this takes time and a great deal of work, so please support the site by using the Adfly links etc.  If you have found this useful or have any problems implementing, please feel free to leave a comment and I will do my best to help.

MSP430 State Machine Project Pt/2

In part 2 of this MSP430 state machine project, I will overview the state machine logic, as well as covering the C programming code.

State Machine

MSP430 State Machine Project C Code

The state machine diagram above illustrates the logic behind the state machines operation. The machine can only be in one state at a time, this is known as the current state. Changes from one state to another are brought about by an event, this brings about a transition into a new state or alters a parameter in the current state.

As can be seen from the diagram there are 5 states.  There are 8 events listed in top right of the image, 2 of these events (E_INC and E_DEC) do not trigger a state transition but alter a parameter in the states they are associated with.

The lines and arrows between each of the states shows the direction that a state can transition to i.e. in the diagram above we can see that the OFFSTATE cannot make a transition to the AUTOMATIC STATE.  Therefore the state diagram gives us a structure to follow, that can be hard coded into the C programming code ensuring the logical flow of the state machine is followed.

States

OFFSTATE – This is simply a state to indicate the system is off

ONSTATE – This is simply a state to indicate the system is on

BRIGHTNESS ADJ STATE – Allows the brightness of an LED to be increased and decreased

PRESETS MODE STATE – Allows the user to scroll through 3 preset LED brightness values

AUTOMATIC STATE – The brightness of the LED will be dependant on the brightness of the ambient light falling on the LDR

Events

E_OFF – This brings about a transition into the OFFSTATE

E_ON – This brings about a transition into the ONSTATE

E_BRIADJ – This brings about a transition into the BRIGHTNESS ADJ STATE

E_PRESET – This brings about a transition into the PRESETS MODE STATE

E_AUTO – This brings about a transition into the AUTOMATIC STATE

E_INC – Allows the user to increase the brightness or change the preset levels, depending on which state the system is currently in

E_DEC – Allows the user to decrease the brightness or change the preset levels depending on which state the system is currently in

E_TIMEOUT – This brings about a transition into the ONSTATE and is a 15 second timeout

MSP430 State Machine C Code

In this section of the tutorial I will give a brief overview of the main parts of the code.  All of the code was written in either Eclipse or Texas Instruments Code Composer Studio v5.3 or above.

Variables

There are 2 types of enum value enum states and enum events, the enum states are prefixed with an ‘S’ and the enum events are prefixed with an ‘E’, this ensures that they are easily readable when coding.

There are also 10 global variables which is not ideal and global variables should be avoided when ever possible, at the time of writing this code I was not aware of a better solution and this method sufficed.

Most of these are self explanatory so I will cover the ones I believe are most relevant:

sysTick –  This uses the system timer to generate a timed pulse which is used like a system heart beat to bring control and order to the state machine and the user button polling.

ScrRefresh – As the LCD was interfaced with minimum pins, any feedback from the LCD to indicated it is busy was not possibly.  The LCD operates at a much slower frequency to the microcontroller.

briadjSys, presetSys and autoSys – The last 3 global variables are used as flags to determine the current state, they are toggled every time a transition is made from or to states S_BRIADJ, S_PRESET and S_AUTO.  Specific functions are run depending on the toggled values outside the StateM function, but within the infinite while loop.  These variables are necessary as the functions will then run even when the state changes to S_ON, which can be transitioned to after 15 seconds if the TimeOut function is called.

Functions

CheckButtons – This function contains if else statements, which are executed and return an event depending on which user button was pressed.  There is also some addtional checks using C operators to determine what state the state machine is in.  The CheckButtons function returns a value to the StateM function.  *Update*  This code is still valid but I have improved on a function to check the GPIO pins on the MSP430, by using switch case statements.  This is all covered in a new two part article on switch debouncing, located here.

StateM – The StateM function contains the main frame work for the state machine.  It uses switch case statements to determine which state the current state can make a transition to, when an event is passed to it.

The logic in this function defines how the state machine will operate.  Looking back to the state machine diagram it can be seen that the OFFSTATE can only make a transition into the ONSTATE.  Now looking at the first case in the code below, it can be seen that the only state S_OFF can move to is S_ON, which is brought about by the E_ON event.  The rest of the switch case code follows the same logical process and can be directly compared with the state diagram.

Right at the end of the StateM function are 2 if statements, these are used to run external functions called OnEnter, OnExit and Do.  These functions can be used to action any code when a transitions occurs between 2 states, or if the same state is selected.

counter – This function sets up and initialises the Timer 0 on the MSP430, the code is well commented so does not need a great deal of explanation.  When the timer has counted to the predefined value, an interrupt is generated, this is then used to set the sysTick variable to 1, the sysTick variable is then zeroed every time the StateM function is executed, which allows the user buttons to be polled.  There is also some additional counter timing functions carried out here for the TimeOut function.

TimeOut – The TimeOut function simply runs if a counter reaches a certain value, which is roughly 15 seconds.  The counter for this function is reset every time the user presses a button.  looking back at the CheckButtons function right at the top can be seen the logic for the E_TIMEOUT event.

setup_HW – This function contains the code used to stop the watchdog timer, set up the system clock, set up the ADC and finally some GPIO port settings.

automatic – This function is used to take the ADC value read from the LDR input.  It divides the value by 9, so it can be broken down into 10 values the user can then adjust the brightness on a scale of 1 to 10.

automatic_lcd – This function is used to update the LCD with the raw value being read directly from the ADC input, an external itoa function is used to convert the integer into a char string so it can be displayed correctly on the LCD.  The ScrRefresh variable is used to ensure the LCD is not updated too quickly, which would otherwise cause corruption of the LCD information.

main – The main function obviously contains the programming code and is essential to any C program, this is the last function I will over with a code excerpt as it ties together the functions previously discussed.

There are some hardware set up functions run at the start of main.  Then there is an infinite while loop, a characteristic of any embedded system.  The first if statement ensures the sysTick variable is equal to 1, and then if this is true the next if statement ensures a user button has been pressed.

The StateM function is, which calls the CheckButtons function, which then returns an event to the StateM function.  Once the StateM function is complete, the sysTick and LongDelay variables are both reset to 0.

The last 3 if statements ensure that the LED’s are controlled continuously even when the state machine is not running, the three variables being used as flags are all reset upon entering the S_OFF state.

Finally the TimeOut function is called and counter checked.

OnEnter – This function is called at the end of the StateM function, and is passed the next state value as an integer. Using a switch case statement the OnEnter function then runs any code specified for that new state upon entering.

Do – This function is also called at the end of the StateM function, and is passed the current state (which now has the same value as the next state) value as an integer. Using a switch case statement the Do function then runs any code specified for the current state to run.

bri_adj – Function is called by the Do function when in S_BRIADJ state, it displays information on the LCD depending on the brightness value, which is determined by the increase and decrease user buttons.

preset_modes – This is very similar to bri_adj function except it is called when in the S_PRESET state.

soft_PWM – Function loads a software PWM based on switch case statements, which determine the brightness of the output LED’s.

preset_level – Almost the same as the soft_PWM function, but fewer cases.

Complete State Machine C Code

The link below contains the zip file with the full state machine C code covered in this second  tutorial, there is a small advert page first via Adfly, which can be skipped and just takes a few seconds, but helps me to pay towards the hosting of the website.

MSP430 State Machine C Code

I take great care when writing all the tutorials and articles, ensuring all the code is fully tested to avoid issues for my readers.  All this takes time and a great deal of work, so please support the site by using the Adfly links etc.  If you have found this useful or have any problems implementing, please feel free to leave a comment and I will do my best to help.

MSP430 State Machine Project Pt/1

MSP430 state machine project tutorial demonstrates a simple state machine, with a human interface consisting of 4 buttons, an LCD and some interfacing electronics.

A video demonstrating the state machine code can be seen below.

This project write up uses a state machine based in the C language, the state machine model is based on some code discussed in a three part state machine tutorial I have already written.  The first part of this tutorial can be found here and all the state machine tutorial parts can be found in the C Programming category of this website.

The project itself is a good learning tool as it not only suing the concept of a state machine, but also incorporates the ADC and Timer on the MSP430 Launchpad.

The Initial Concept

The project was undertaken as part of a course and was designed to teach the basic concept of a state machine, as well as designing a human interface with control switches and and LCD.

As a proof of concept the idea of system would be to control the brightness of 2 lights, one via a manual adjust, which would have preset values for brightness, and the other would be adjusted automatically dependant on the ambient light.  The lights in this case would be LED’s not ideal but serve the purpose for the demonstration, their brightness would be adjusted via PWM (Pulse Width Modulation).  An LDR (Light Dependant Resistor) would be used to detect the ambient light, and interfaced to the ADC (Analog to Digital Converter) on MSP430.  There would also be a 16×2 LCD interfaced in parallel mode to the MSP430 launchpad.  A basic block diagram of the system can be seen below.

MSP430 State Machine Project Tutorial C Code

Hardware

I will start by over viewing the connections to the MSP430.  The MSP430G2231 was originally used but as the project went on, memory became an issue as did the number of available GPIO ports, so the MSP430G2432 was an obvious choice as the memory is extended from 2kb to 8kb and an extra 6 GPIO.  The image below illustrates the pinout configuration for the launchpad.

MSP430 State Machine Project Tutorial C Code

16×2 LCD

As can be seen in the pinout configuration the LCD uses 6 pins, the pins for the LCD are based around an external tutorial which includes all the necessary C code.  This tutorial can be found by following this link.

This is a 16*2 dot matrix character display, using the Hitachi HD44780U controller. This controller has been around for many years, which means there is a wealth of information. There are several websites with API’s aiding in the interfacing of the LCD to a MSP430, along with the one previously mentioned.
The LCD uses an 8 bit parallel interface, but fortunately can also be used in 4 bit mode which still requires 6 pins.
It was also necessary to provide the LCD with a 5V supply and a potentiometer to adjust the contrast on the display, this was a very simple circuit and was constructed on a piece of vero board.

The C code for the LCD has been placed into a library in the final state machine code, all the code can be downloaded as a zip file at the end of this article.

Tack Switch Board

The tack switch boarded consisted of 3 tack switches and some debounce components constructed on a piece of vero board.  When a switch is depressed, the connected GPIO pin on the launchpad will be pulled low.  The 4th button used was S2 on the launchpad board, this served as an on/off button.  An image of the tack switch circuit and also the finished vero board can be seen below.

MSP430 State Machine Project Tutorial C Code

MSP430 State Machine Project Tutorial C Code

LDR and Interface Circuit

The LDR are non linear devices which makes them less than ideal for detecting small changes in light and then interfacing to the ADC of a microcontroller.  They are found in many devices, a common use is in garden solar lights that switch on when a preset lux level is reached, in this case the LDR is being used as a simple switch.  For the purpose of this project the output from the LDR would need to be converted to suit ADC on MSP430 launchpad.  The ADC has an input range from 0V to 3V.  The circuit was first simulated in OrCad, it incorporates 3 opamps and 2 adjustable potentiometers so fine adjustments can be made depending on the ambient light conditions.  There was also a small amount of linearisation added to the LDR as a result of this circuit design.  The final interface circuit schematic can be seen below.

MSP430 State Machine Project Tutorial C Code

LDR Circuit final construction on vero board can be seen in the next image.

MSP430 State Machine Project Tutorial C Code

LED Demo Board

The LED board is a very simply construction, using a pair of transistors acting as switches to drive the LED’s.  The circuit schematic and final board construction can be seen in the following 2 images.

MSP430 State Machine Project Tutorial C Code

 

MSP430 State Machine Project Tutorial C Code

So the final system looks like this, a bit ‘Heath Robinson’ but proof of concept remember!

MSP430 State Machine Project Tutorial C Code

I had intended this to be a one page article but the images have extended it more than I anticipated, so in part 2 I will cover the state machine structure and C programming code.

I take great care when writing all the tutorials and articles, ensuring all the code is fully tested to avoid issues for my readers.  All this takes time and a great deal of work, so please support the site by using the Adfly links etc.  If you have found this useful or have any problems implementing, please feel free to leave a comment and I will do my best to help.