Convert legacy control panel into LCD alarm and warning system with Arduino.

In the old days, We used to have electronic controllers or PLCs to send the warnings or alarms on the panel by turning combination of  light indicators  on or off. To understand these signals we have to refer their operation manuals to interpret these messages. For example if they have three indicators on the panel which has Light A(LA), Light B(LB) and Light C(LC),  it will be 2^3 =8 combinations of warning/alarms. To make it easy to understand , they provide us a troubleshooting table to tell operators or technicians to trace the problem.

LA=0, LB=0, LC=0 -> ” Machine OK” ,

LA=1,LB=0, LC=0 -> ” Motor Overload” ,

LA=1, LB=1 ,LC=0 -> “Motor Overtemperature”,

etc, etc

(0 =OFF, 1 =ON) .

I am sure such devices or control panels still exists and still be produced today. Sometimes it is not easy to troubleshoot the problem because of missing manuals or any other reasons. For this purpose we will design and  build Alarm messaging system using Arduino to retrofit old panels and to convert  light bulb/LED  indicators into a LCD display. Here is the example. Let says that we had an old PLC that control the following system (pic1). The ladder diagram showed here  just to demonstrate how to manipulate 3 coil or relay outputs. Of course we can build more than 3 outputs when we need it.



The ladder diagram looks like this :



Basically, this program tell us to open the  valve 5 seconds  before turning the centrifugal pump on. When we press “Xstart” button,  it will open the valve. The Ylight1 will turn on after  valve open limit switch (XLSopen)  become true. Ylight2 shows the pump is running meanwhile Ylight3 indicate that there is low pressure(XLowPressure) on discharge line.The normal operation should give us Ylight1=1, Ylight2=1 and Ylight3=0. This means valve is fully opened, motor is running and we got normal pressure. Since we can make 8 combinations from these lights, We can convert these states  into meaningful messages with Arduino. There is two options to use Arduino for this purpose. The first one is just for converting the state of indicators into messages. Secondly it can be utilized as both PLC and warning/alarm messages. We will use the later for this example.

Things we need to build this Project:

  1. Arduino Board.
  2. Arduino IDE.
  3. LCD display (serial or I2C) with Arduino Library.
  4. LDMicro.
  5. PHP script to build  Arduino Library header (optional).

Any Arduino board can be used for this project. All I/O will be configured using Arduino header. Download LDmicro from this site :  

The beauty of this LDmicro is that we can compile the ladder diagram into ANSI- C code and from this cpp format we can build the library for Arduino IDE.

For PHP script to generate a header we can get it from here :   

Please remember to run php script, we need to install PHP program  in our computer. For PHP for windows  download the program here :

Now Lets modify the ladder diagram from pic1.


When we look at new ladder diagram, there are some changes and  some rungs additions which have accumulator instruction (Acc ) inserted to them. These four extra rungs actually to convert binary status into decimal, Binary Coded Decimal (BCD). From three coil status, we can generate 8 messages.

Save this ladder diagram as ladder.ld ( we can choose any name for this file). Next step is to choose a microprocessor. On “Setting”->”Microcontrollers” , choose ANSI-C code. Then  go to “Compile” ->”Compile as… ” and save it as ladder.cpp. Click OK and it will shows :


Don’t worry about this warning. Like it said on pop-up window, this is not complete program so we have to build header by itself.  C/C++ programming skills is not really needed. Just use this cpp together with header we are going to build to create a library to be used in Arduino IDE.

Now It is time to build a header(Ladder.h) The header below built using ladder-gen.php ( see  previous link above to download it). Follow instruction there how to run and to build a header for Arduino. We can see that all I/O pins fo Arduino  can be configured here.

  1.  #ifndef LADDER_H
  2.     #define LADDER_H
  3.     #if ARDUINO >= 100
  4.     #include "Arduino.h"
  5.     #else
  6.     #include "WProgram.h"
  7.     #endif
  8.     #define BOOL boolean
  9.     #define SWORD int
  10.     #define EXTERN_EVERYTHING
  11.     #define NO_PROTOTYPES
  12.     EXTERN INT U_i_arduino;
  13.     void PlcCycle(void);
  14.     /* Configure digital I/O according to LD (call this in setup()). */
  15.     inline void PlcSetup()
  16.     {
  17.     pinMode(11, INPUT);
  18.     pinMode(12, INPUT);
  19.     pinMode(5, OUTPUT);
  20.     pinMode(9, INPUT);
  21.     pinMode(6, OUTPUT);
  22.     pinMode(10, INPUT);
  23.     }
  24.     /* Individual pins (this code is used in ladder.cpp) */
  25.     inline extern BOOL Read_U_b_XSTART(void)
  26.     {
  27.     return digitalRead(11);
  28.     }
  29.     inline extern BOOL Read_U_b_XSTOP(void)
  30.     {
  31.     return digitalRead(12);
  32.     }
  33.     inline BOOL Read_U_b_YValve(void)
  34.     {
  35.     return digitalRead(5);
  36.     }
  37.     inline void Write_U_b_YValve(BOOL v)
  38.     {
  39.     digitalWrite(5, v);
  40.     }
  41.     inline extern BOOL Read_U_b_XLSopen(void)
  42.     {
  43.     return digitalRead(9);
  44.     }
  45.     inline extern BOOL Read_U_b_XOverload(void)
  46.     {
  47.     // TODO
  48.     }
  49.     inline BOOL Read_U_b_Ymotor(void)
  50.     {
  51.     return digitalRead(6);
  52.     }
  53.     inline void Write_U_b_Ymotor(BOOL v)
  54.     {
  55.     digitalWrite(6, v);
  56.     }
  57.     inline extern BOOL Read_U_b_XLowPressure(void)
  58.     {
  59.     return digitalRead(10);
  60.     }
  61. #endif


To write an Arduino sketch, the first step is to create a new folder. Name it as “Ladder” and put both ladder.cpp and ladder.h inside this folder. Copy or move it into Dir://Path/to/Arduino/libraries.

It ‘s time to write an interesting sketch in Arduino IDE.

  1. #define _Digole_Serial_UART_
  2. #include "DigoleSerial.h"
  3. DigoleSerialDisp mydisp(&Serial1, 9600);
  4. #include "ladder.h"
  5. /* Plc cycle interval, set this according to LDmicro settings. (micro sec.) */
  6. #define PLC_INTERVAL 10000
  7. #define LCDCol 16
  8. #define LCDRow 2
  9. int ptr;
  10. const char a[] = "Arduino PLC";
  11. void setup()
  12. {
  14.   mydisp.begin(); 
  15.     mydisp.clearScreen();
  16.     mydisp.disableCursor(); //disable cursor, enable cursore use: enableCursor();
  17.   //  mydisp.drawStr(4, 0, "Testing");
  18.     mydisp.setPrintPos(2, 0);
  19.     mydisp.print(a); // display a char array
  20.   //  resetpos();
  21.    {
  23.   PlcSetup();
  24. }
  25. }
  26. void loop()
  27. {
  28.     if (IsPlcInterval())
  29.     {
  30.         PlcCycle();
  31.     switch (U_i_alarm) {
  32.   case 0:
  33.    mydisp.drawStr(4, 1, "Valve closed");
  34.   break;
  35.   case 1:
  36.   mydisp.drawStr(4, 1, "Valve opened   ");
  37.   break;
  38.   case 2:
  39.   mydisp.drawStr(4, 1, "Check if valve is OK ?   ");
  40.   break;
  41.   case 3:
  42.   mydisp.drawStr(4, 1, "Pump and Valve OK   ");
  43.  break; 
  44.  case 4:
  45.   mydisp.drawStr(4, 1, "Low Pressure , Valve and Pump off   ");
  46.   break;
  47.   case 5:
  48.   mydisp.drawStr(4, 1, "Low pressure , check Pump!   ");
  49.  break; 
  50.   case 6:
  51.   mydisp.drawStr(4, 1, "Low pressure , check Valve!    ");
  52.  break; 
  53.  case 7:
  54.   mydisp.drawStr(4, 1, "Low pressure , check the line/leak   ");
  55.  break;     
  56.  }
  57.     }
  58. }
  59. /* Plc Cycle timing function. */
  60. boolean IsPlcInterval()
  61. {
  62.     static unsigned long last_run;
  64.     if (micros() - last_run >= PLC_INTERVAL)
  65.     {
  66.         last_run = micros();
  67.         return true;
  68.     }
  69.     return false;
  70. }


In the example above we use Digole serial LCD to display the messages. The good thing about  LDmicro is that it much easier to create ladder program  and then modify in the future with no change or few change in Arduino sketch itself. As long we have same numbers of I/O pins we don’t need generate a new header, what we need is  just to compile a new ladder (  newladder.ld)  and to save it as  newladder. cpp then to copy it to an arduino library folder.

Press Ctrl+C to copy the following code.