Julian on October 14th, 2013
// Wiring:
//A0 - Pot
//A1 - Volts (solar)
//A2 - Volts (battery)
//A4 - Amps (solar)
//A5 - Amps (battery)

//D3 - PWM out to DCOI
//D8 -LCD_RST (1)
//D9 - LCD_CE (2)
//D10 - LCD_DC (3)
//D11 - LCD_DIN (4)
//D12 - LCD_CLK (5)
//-----LCD_VCC (6)
//---LCD_LIGHT (7)
//-----LCD_GND (8)

#define LCD_C     LOW
#define LCD_D     HIGH

#define PIN_RESET 8
#define PIN_SCE   9
#define PIN_DC    10
#define PIN_SDIN  11
#define PIN_SCLK  12

//#include <stdlib.h>;
#include "header.h";
#include <PWM.h>
int32_t frequency = 15000; //frequency (in Hz)

int sensorValue = 0;
float panelVolts = 0;
float batteryVolts = 0;
float lastPanelVolts = 0;
float lastBatteryVolts = 0;
float panelAmps = 0;
float lastPanelAmps = 0;
float batteryAmps = 0;
float lastBatteryAmps = 0;
float efficiency = 0;
float siemens = 0;
float panelWatts = 0;
float lastPanelWatts = 0;
float batteryWatts = 0;
float maxwatts = 0;
int barwatts = 0;
float Voc = 0;
float Isc = 0;
char tmp[25];
//boolean gotVoc = false;
//boolean gotIsc = false;
boolean highWatts = false;
int chartX = 0;
int chartY = 0;
//int bin = 0;
boolean mpptOn = false;
const boolean initialise = true;

void LcdInitialise(void)
  pinMode(PIN_SCE, OUTPUT);
  pinMode(PIN_DC, OUTPUT);
  pinMode(PIN_SDIN, OUTPUT);
  pinMode(PIN_SCLK, OUTPUT);
  digitalWrite(PIN_RESET, LOW);
  digitalWrite(PIN_RESET, HIGH);
  LcdWrite(LCD_C, 0x21 );  // LCD Extended Commands.
  LcdWrite(LCD_C, 0xBC );  // Set LCD Vop (Contrast). 
  LcdWrite(LCD_C, 0x04 );  // Set Temp coefficent. //0x04
  LcdWrite(LCD_C, 0x14 );  // LCD bias mode 1:48. //0x13
  LcdWrite(LCD_C, 0x0C );  // LCD in normal mode.
  LcdWrite(LCD_C, 0x20 );
  LcdWrite(LCD_C, 0x0C );

void LcdClear()
  for (int i=0; i<504; i++) LcdWrite(LCD_D, 0x00);

void LcdWrite(byte dc, byte data)
  digitalWrite(PIN_DC, dc);
  digitalWrite(PIN_SCE, LOW);
  shiftOut(PIN_SDIN, PIN_SCLK, MSBFIRST, data);
  digitalWrite(PIN_SCE, HIGH);

void LcdString(char *characters, int x, int y)
  LcdWrite(LCD_C, 0x80 | x);  // Column.
  LcdWrite(LCD_C, 0x40 | y);  // Row.
  while (*characters) LcdCharacter(*characters++);

void LcdCharacter(char character)
  for (int index = 0; index < 5; index++) LcdWrite(LCD_D, ASCII[character - 0x20][index]);
  LcdWrite(LCD_D, 0x00);

void LcdXY(int x, int y)
  LcdWrite(LCD_C, 0x80 | x);  // Column.
  LcdWrite(LCD_C, 0x40 | y);  // Row.

void LcdPlot (int x, int y)
//  static int lastX;
//  static int lastY;
  LcdXY(x,5-(y/8)); //set display address for plot
  int bin=128;
  for (int q=0; q<y%8; q++) bin=bin/2; //calculate pixel position in byte
  LcdWrite(LCD_D, bin); //plot pixel
  float slope=float(47-y)/float(83-x);
  for (int j=x+2; j<84; j++) {
    float dy=slope*float(j-x);
    int k=y+round(dy);
    LcdXY(j,5-(k/8)); //set display address for plot
    int bin=128;
    for (int q=0; q<k%8; q++) bin=bin/2; //calculate pixel position in byte
    LcdWrite(LCD_D, bin); //plot pixel
//  lastX = x;
//  lastY = y;

void perturb(boolean init=false)
  static byte pulseWidth = 0;
  static boolean trackDirection = false; //counts down / pwm increases
//  static int loopCounter = 0;
  if (init) {
    pulseWidth = 255;
    trackDirection = false;
  else {
    if (!trackDirection) {
      if (pulseWidth != 0) {pulseWidth--;} else {trackDirection = true;}
    else {
      if (pulseWidth != 255) {pulseWidth++;} else {trackDirection = false;}
  pwmWrite(3, pulseWidth); //write perturbed PWM value to PWM hardware
  if ((panelWatts - lastPanelWatts) < -0.1) trackDirection = !trackDirection;

void setup()
  bool success = SetPinFrequencySafe(3, frequency);
  if(success) {
    pinMode(13, OUTPUT);
    digitalWrite(13, HIGH);    


void loop()
  panelVolts = analogRead(A1) * 47.0 / 1023; //get the volts
  panelVolts = (panelVolts + lastPanelVolts) / 2; //average the volts
  lastPanelVolts = panelVolts;
  LcdString(dtostrf(panelVolts,5,2,&tmp[0]),0,3); //display the volts
  panelAmps = (514 - analogRead(A4)) * 27.03 / 1023; //get the panelAmps
  panelAmps = (panelAmps + lastPanelAmps) / 2; //average the panelAmps
  lastPanelAmps = panelAmps;
  if (panelAmps < 0) panelAmps = 0; //don't let the panelAmps go below zero
  LcdString(dtostrf(panelAmps,5,2,&tmp[1]),0,4); //display the panelAmps
  panelWatts = panelVolts * panelAmps; //calculate the watts
  LcdString(dtostrf(panelWatts,4,1,&tmp[2]),40,4); //display the panel watts

  sensorValue = analogRead(A0);
  if (sensorValue > 1020) {
//    pwmWrite(3, sensorValue / 4);
    if (mpptOn) {
    else {
      mpptOn = true;
      perturb(initialise); //initialise the perturb algorithm
      LcdString("A",35,0); //display an A for auto
  else {
    if (!mpptOn) {
      pwmWrite(3, sensorValue / 4);
    else {
      mpptOn = false;
      LcdString("M",35,0); //display an M for manual
  lastPanelWatts = panelWatts;
  batteryVolts = analogRead(A2) * 25.0 / 1023; //get the battery volts
  batteryVolts = (batteryVolts + lastBatteryVolts) / 2; //average the volts
  lastBatteryVolts = batteryVolts;
  LcdString(dtostrf(batteryVolts,5,2,&tmp[0]),0,2); //display the battery volts
  batteryAmps = (514 - analogRead(A5)) * 27.03 / 1023; //get the panelAmps
  batteryAmps = (batteryAmps + lastBatteryAmps) / 2; //average the panelAmps
  lastBatteryAmps = batteryAmps;
  if (batteryAmps < 0) batteryAmps = 0; //don't let the batteryAmps go below zero
//  LcdString(dtostrf(batteryAmps,5,2,&tmp[1]),0,4); //display the panelAmps
//  if (volts > 1) {
//    siemens = panelAmps / volts; //calculate the conductance
//    LcdString(dtostrf(siemens,5,2,&tmp[2]),0,2); //display the siemens
//  }
  batteryWatts = batteryVolts * batteryAmps; //calculate the battery watts

  efficiency = batteryWatts / panelWatts * 100;
  LcdString(dtostrf(efficiency,3,0,&tmp[2]),0,1); //display the efficiency
  maxwatts = max(maxwatts, panelWatts); //calculate the max watts
  LcdString(dtostrf(maxwatts,4,1,&tmp[3]),40,3); //display the max watts
  if (panelWatts > 27) highWatts = true; //go to 83Watt bargraph
    if (!highWatts) {
      barwatts = round(panelWatts * 3);
      for(int k=0; k<84; k++)
        if (k >= barwatts) LcdWrite (LCD_D, 0x00);
        else if (k % 30 == 0) LcdWrite (LCD_D, 0xf0);
        else if (k % 15 == 0) LcdWrite (LCD_D, 0xe0);
        else LcdWrite (LCD_D, 0xc0);
    else {
      barwatts = round(panelWatts);
      for(int k=0; k<84; k++)
        if (k >= barwatts) LcdWrite (LCD_D, 0x00);
        else if (k % 10 == 0) LcdWrite (LCD_D, 0xf0);
        else if (k % 5 == 0) LcdWrite (LCD_D, 0xe0);
        else LcdWrite (LCD_D, 0xc0);
  Voc = max(Voc, panelVolts); 
  Isc = max(Isc, panelAmps);
  chartX = min(panelVolts/Voc*84, 83);
  chartY = min(panelAmps/Isc*48, 47);

  if (chartX > 41 & chartY > 23) { //if in upper right quadrant
    LcdPlot (chartX, chartY);

Julian on June 25th, 2013

Malembo Micro GridThere’s an incredibly exciting project going on in the village of Malembo in Uganda. Solar panels are being used to generate electricity which is being distributed to local businesses and individuals to provide light, and power to charge phones. Two PWM5 Solar Charge Controllers are keeping the battery charged.

Read the full story at Julian and Lydia’s blog:


Julian on June 2nd, 2013

Boats and RVsThe PWM5 Solar Charge Controller is ideally suited for use in recreational vehicles such as boats, caravans and motorhomes. Ultra-low power consumption, 100% waterproofing and flexible multi-controller configurations are three of the benefits. Let’s look at each in turn.

  • The controller draws just 1 milliamp from the battery it’s protecting, so it can be left connected permanently. The PWM5 is completely tolerant of other charge sources, so it won’t mind if the vehicle’s alternator starts up, or if you connect a mains powered battery charger. The solar panel can be left permanently connected too, because the anti-backfeed diode (lump in the yellow wire) stops current flowing back into the solar panel.
  • The PWM5 is 100% waterproof, so it can be used in wet environments (even completely submerged). Keep connections dry however, wrap them in tape or better still adhesive-lined heatshrink sleeving.
  • If your vehicle has two (or more) batteries, you can use two (or more) PWM5 controllers to keep them all optimally charged. Using one controller per battery, you can parallel the controllers on the solar panel side (yellow/black wires) enabling a single solar panel (up to 100W) to charge all your batteries, even if they’re on separate circuits.
Julian on April 25th, 2013

MailRoyal Mail provide a reliable (and reasonably fast) overseas small packet airmail service. But it costs!

Prices have increased again recently, to £3.50 for 80g to USA/Australia. At the tail end of 2011, it was just £2.07 –  Similarly, prices to Europe have increased from £1.49 to £2.70

Unfortunately therefore, I’m having to increase prices to international and European destinations. However, the good news is that UK inland postage prices have risen less dramatically, so I’ve been able to keep the PWM5 at the original £17.99 price for UK purchases.

Julian on April 15th, 2013

Light bulbSome solar charge controllers include a load disconnect function. In most cases it just switches off the load when the battery voltage drops below a pre-determined level. Sure it provides the ultimate fail safe against a flat battery, but it’s a crude device.

Imagine the scenario: you’re in the shed late at night – it’s a pretty creepy place at the best of times. Then, without warning, the lights go out. Scary!

I think the load disconnect function should be part of a more sophisticated device, separate from the charge controller.

Here’s my spec for the ultimate load control device.

An intelligent controller with multiple event-driven switch on and switch off triggers. An LCD lists all the triggers which can be ticked or unticked. An audible warning can be enabled to precede any switching event. Warning can be 5 minute and or 1-minute (non-urgent/urgent)

On triggers:

  • PIR sensor – lights come on when you enter the room
  • Dusk sensor – lights come on when it starts to get dark
  • Clock trigger – lights come on at a pre-settable time
  • Battery voltage trigger – load switched on when battery voltage reaches a pre-settable level
  • Manual – press button to switch on load

Off triggers

  • Dawn sensor – lights go off when it starts to get light
  • Clock trigger – lights go off at a pre-settable time
  • Duration trigger – lights go off after a pre-settable delay
  • Battery voltage trigger – load switched off when battery voltage reaches a pre-settable level
  • Manual – press button to switch off load

The Arduino is the perfect platform on which to build such a device, and it wouldn’t be particularly difficult. Let’s do it.

Note: above image is ironic

Julian on April 11th, 2013

Here is the transcript of a recent email exchange I had with one of my customers:

PWM5 was working perfectly until I disconnected battery bank (boat).
Cannot get LED working again even though controller part seems fine. Have reconnected and waited 2+ seconds before disconnecting battery again and reconnecting. No LED. Please help.
Many thanks


Hi John
This can happen when there’s power coming from the solar panel. Cover the solar panel and try disconnecting the battery again. Or wait until dark and disconnect the battery. The LED function will be restored.


Dear Julian,
Fixed – works fine now.
I am able to readily monitor battery voltage as the boat is so equipped. Unlike the Chinese made controller supplied with the solar panel at 3 times the cost of your device which allowed the batteries to sit at 15V, causing my monitor to display an alarm, your device does exactly what is it supposed to.
Thanks for your prompt reply and excellent product.
Julian on April 8th, 2013

Blue LEDThis is a story of unintended consequences.

When I designed the PWM5, I thought it would be a useful feature to be able to switch off the flashing blue LED. And a few people have agreed that it does come in handy. But not for the reason I had in mind!

The blue LED is quite bright, which makes it easy to see in daylight. But at night, on a boat or in a caravan, it can be a bit of a distraction particularly if you’re trying to get to sleep. So the ability to switch it off can be useful.

My original intention was to let eco-geeks who are obsessed with power saving measures (I’m really describing myself here) to shave a little more off the power consumption of the controller. In fact it almost halves the consumption from 1mA to about 650 microamps. But I now question whether this was really necessary. At 1mA it would take 50,000 hours for the controller to fully discharge a 50Ah battery. And that’s about 5½ years!

So I don’t use it. I leave the LED turned on. I like to see the blue flashes. It lets me read the battery voltage from quite a distance, particularly at night.

But it’s worse than that…

I don’t mind admitting that about a dozen controllers have been returned to me, almost without exception because the LED had stopped working. And indeed one of them did have a faulty LED. It was intermittent, sometimes working sometimes not. OK my bad! A dodgy LED slipped through the net, which is surprising as the LED is tested 3 separate times during assembly. LEDs are really easy to test.

All the other controllers worked fine.

New controllers were sent out and I apologise to those of you that had to suffer the inconvenience of waiting for a replacement when there was actually nothing wrong with the first one. For me, it’s not been a major problem. I now have a little stash of controllers with which to conduct experiments and make YouTube videos.

Getting the LED working again should be simple. Disconnect the battery cables (red/black) and re-connect. But there’s a twist. Power from the solar panel can keep the controller running. It’s a side-effect of the PWM process.

So. What to do?

I’ve added a little troubleshooting section to the user guide. And it goes like this…


Problem: The LED has stopped working and disconnecting the battery hasn’t fixed it.

Solution: This can happen when there’s power coming from the solar panel. Cover the solar panel and try disconnecting the battery again. Or wait until dark and disconnect the battery. The LED function will be restored.


Julian on April 5th, 2013

PWM5I keep coming back to the idea of an MPPT Solar Charge Controller. It would be the maximum power point tracking version of the PWM5. But there’s an idea buzzing around inside my head which I have to research before I can begin the design process.

It’s the thought that there might be a coincidence between the maximum power point of the solar panel and maximum battery voltage. If this is the case, the difficult task of measuring solar panel power wouldn’t be necessary. Instead the controller would simply look for maximum battery voltage.

It seems logical to me that squeezing more power from the solar panel would result in a higher voltage on the terminals of the battery. Finding the maximum power point of the solar panel results in both greater voltage and greater current. The DC/DC converter turns that extra panel voltage into extra charging current into the battery. So that’s 2 lots of extra current, surely. And the higher the charge current, the higher the battery terminal voltage.

But logic and theory and supposition are no substitute for hard proof, so an experiment is called for.

I need to put a DC/DC converter between the solar panel and the battery and tweak the pulse width to obtain maximum power from the panel. So I need to measure both panel voltage and the current flow and multiply them together to get panel Watts. A voltmeter is also needed on the battery. It would be very useful if both the Wattmeter and the Voltmeter had analogue bargraphs to make visual identification of the maxima easier to achieve.

It struck me that the Arduino would be the ideal platform on which to develop this piece of test equipment. A 16×2 LCD could display panel Watts, battery Volts together with the desirable analogue bargraphs. Various compatible sensors are available to measure voltage and current. Then it’s just a case of building a DC/DC converter with variable input voltage. That’s a bit trickier.

Julian on March 11th, 2013

Renault TwizyI’m sorry, but I’m not a fan of rechargeable electric cars.

The car buying public simply won’t embrace electric vehicles until they can re-fuel them in under 5 minutes – the same amount of time it takes to re-fuel a petrol or diesel motor.

There is a system that replaces the entire battery pack using robot lifting gear, but it’s hugely expensive and retailers won’t want to pay for it.

The answer seems incredibly simple and it’s the motor manufacturers that should be implementing it.  Electric cars should have multiple replaceable batteries, each light enough to be lifted out of the vehicle with one hand. Perhaps the size and shape of a small fire extinguisher, a small car may have 8 and a large car 48.

The driver would be able to re-fuel her vehicle by lifting the hood/bonnet, pulling out all the batteries showing a red light and putting them into spare slots in a charge wall. Fully charged batteries from the charge wall (showing a green light) would be transferred to the vehicle. Pay at the kiosk and go. Five minutes, perhaps a little longer for larger vehicles.

Retailers could replace one petrol pump at a time with a charge wall, as and when demand (and funding) permitted. And vehicle owners could have a compact charger at home that would recharge one or two batteries overnight – a cost saving measure but not essential, it wouldn’t matter if you forgot to do it. People without off-road parking (plenty of them in London) can’t recharge at home as it stands – you can’t drape mains cables across the sidewalk/pavement. Portable batteries solve that problem.

Re-charging stations make no sense. Can you imagine the land area that would be needed to accommodate hundreds of vehicles, all waiting several hours for a recharge? And who’d be dumb enough to wait that long anyway? No-one.