IO22D08 control and library


[pre][color=#202124]Has anyone used ID22D08? I need help. I need an example and a library.
I don't know how to control relays and 7-segment displays by multiplexing.[/color]


Sorry I could not find any information on the ID22D08 to see what it is. The theory behind the multiplexing technique is relatively simple. It is done by using a multi element X/Y matrix. This link shows it being done with a PIC microcontroller, and a good explanation of how it works. Here is another link that shows it being done with an Arduino. There is a lot more information available on the WEB. Try using this as your search argument: multiplexing 7 segment display arduino

The device is perhaps IO22D08 which is designed to be driven by a Pro-mini. Here's a link to some info that may help.
IO22C04 pro mini delay relay demo - YouTube (video)
IO22D08 8ch DC 12V Pro mini Relay Shield Module PLC Timer Board | eBay

  • which has some technical detail at the bottom of the page. It recommends to use the provided sketch (for Pro-mini) as the starting point and build your own code.

Frankly speaking, my point is that 2 HC595 are connected to this display, but in such a way that I do not know how to bite it. The first one is connected to the segments C, F, DP, A, D, E and !!! common cathode of the first digit. The second HC595 : Fourth digit cathode, third digit cathode, second digit cathode and segment B and C.
Yes, I would deal with it quickly if the first HC595 was responsible only for the cathodes, and the second HC595 for the segments only . After all, it is obvious that the display must be multiplexed. I would like an example or an idea.

I bought an ID22D08 too and I'm a bit disappointed.

I bought it to use the photocouped inputs and this part seems to work as expected.

What I discovered about the shift registers on the board is:

the first 74595 drives a ULN2803 and then the 8 relays. The other two 595 are chained to the first. So one has to ShiftOut 3 bytes: the first 2 control the display and the third the relays.

arduino pin A3 drives 595 serial clock
arduino pin A2 drives 595 latch
arduino pin A1 drives 595 /OE
arduino pin 13 drives 595 data

Until now I'm not able to drive the display properly and succeded partly in driving the relays:

  digitalWrite(OE, LOW);
  digitalWrite(latchPin, LOW);
  digitalWrite(clockPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, whatever);
  shiftOut(dataPin, clockPin, MSBFIRST, whatever);
  shiftOut(dataPin, clockPin, MSBFIRST, relay_status);
  digitalWrite(latchPin, HIGH);

there isn't a perfect corrispondence between relay_status bits and the relays in the way one can expect: I found that MSB turns on relay1, LSB turns on relay7 and so on.

Were you able to get the card to work or not? Let's join forces?


Please post a description of exactly what you have linked to

Its a "RAR" file on ONEDRIVE but clearly the OP has not read any of the sticky posts.


Could you take a few moments to Learn How To Use The Forum.

Other general help and troubleshooting advice can be found here.
It will help you get the best out of the forum in the future.

It’s a RAR file containing…

IO22D08 8 Channel Pro mini PLC Board\8ch_Pro_Mini_delay_relay(Schematic).pdf
IO22D08 8 Channel Pro mini PLC Board\IO22C04 pro mini delay relay demo.wmv
IO22D08 8 Channel Pro mini PLC Board\IO22D08 8ch Pro mini PLC Instructions.docx
IO22D08 8 Channel Pro mini PLC Board\Remark.txt
IO22D08 8 Channel Pro mini PLC Board\FlexiTimer2\FlexiTimer2.cpp
IO22D08 8 Channel Pro mini PLC Board\FlexiTimer2\FlexiTimer2.h
IO22D08 8 Channel Pro mini PLC Board\FlexiTimer2\keywords.txt
IO22D08 8 Channel Pro mini PLC Board\FlexiTimer2\examples\FlashLed\FlashLed.pde
IO22D08 8 Channel Pro mini PLC Board_8ch_delay_relay_8ch_delay_relay.ino

8ch_Pro_Mini_delay_relay(Schematic).pdf is an Adobe Acrobat document containing a schematic.

IO22C04 pro mini delay relay demo.wmv is a video demonstrating a relay / LED board with an Arduino.

IO22D08 8ch Pro mini PLC Instructions.docx is a Microsoft Word document containing “IO22D08 8ch Pro mini PLC Instructions”.

Remark.txt contains “Put folder “FlexiTimer2” into “arduino\libraries””.

_8ch_delay_relay.ino is a fairly simple 250 line sketch that appears to exercise the “IO22D08 8ch Pro mini PLC”.

The stuff in the FlexTimer2 folder are an Arduino library. It appears to be a wrapper over timer 2 or timer 4 depending on the AVR processor.

I assume the post is meant to address this from the original post...

I need an example and a library.

It appears grm-rj hit the mark.


This is a link to the program (sketch) for the device IO22D08.

You're welcome!

It's my simple program for it:

I just came to this board. beside the shift registers for the display it's really nice. I didn't like the external timer library to trigger the shift registers, therefore I made a version without external dependencies. The display works fine - like the OEM sketch without flicker.

My version can be found here:

and a short video:

Couldn’t post an attachment as a new user. This base code works a treat for me and allows you to write control code in main(). I’m not an expert but it may help someone out?

// IO22D08 PLC Board by Nick Mellor - Last update 04/01/2020

// IO22D08 Hardware Pin Assignments
// A1 = 595_OE, A2 = Latch, A3 = Clock
// 2 = I1, 3 = I2, 4 = I3, 5 = I4, 6 = I5, A0 = I6, 12 = I7, 11 = I8
// 7 = K1, 8 = K2, 9 = K3, 10 = K4, 13 = Onboard LED

//Shift register 1 drives relays but not in a logical order!

// Bit 1 = Ch. 7
// Bit 2 = Ch. 6
// Bit 3 = Ch. 5
// Bit 4 = Ch. 4
// Bit 5 = Ch. 3
// Bit 6 = Ch. 2
// Bit 7 = Ch. 1
// Bit 8 = Ch. 8

//Shift register 2 pins (again, not logical!)

// Bit 1 = Unused?
// Bit 2 = Unused?
// Bit 3 = Digit 1 select
// Bit 4 = segment b
// Bit 5 = segment g
// Bit 6 = Digit 2 select
// Bit 7 = Digit 3 select
// Bit 8 = Unused?

//Shift register 3 pins (again, not logical!)

// Bit 1 = segment c
// Bit 2 = segment f
// Bit 3 = Unused?
// Bit 4 = segment a
// Bit 5 = segment d
// Bit 6 = Digit 4 select
// Bit 7 = segment e
// Bit 8 = Unused?

#include <FlexiTimer2.h>

int latch = A2; // Shift register latch

int clock = A3; // Shift register data clock

int data = 13; // Shift register data out

// K1-K4 Onboard pushbuttons
const int K1 = 7; // Shutdown
const int K2 = 8; // Start
const int K3 = 9; // Fill
const int K4 = 10; // Drain

// Field digital inputs
const int INPUT1 = 2; // Unassigned
const int INPUT2 = 3; // Unassigned
const int INPUT3 = 4; // Unassigned
const int INPUT4 = 5; // Unassigned
const int INPUT5 = 6; // Unassigned
const int INPUT6 = A0; // Unassigned
const int INPUT7 = 12; // Unassigned
const int INPUT8 = 11; // Unassigned

// T outputs - Driven by shift register outputs via function updateShiftRegister(); just set RX to 0 or 1!
bool R1 = 0; // Unassigned
bool R2 = 0; // Unassigned
bool R3 = 0; // Unassigned
bool R4 = 0; // Unassigned
bool R5 = 0; // Unassigned
bool R6 = 0; // Unassigned
bool R7 = 0; // Unassigned
bool R8 = 0; // Unassigned

// Timers - These are timer data arrays. They are used by function timer. 16 timers can be configured within the program. This is expandable.
int T_Current[16];
int T_Setpoint[16];
int T_Start[16];

// digit select masks from right to left. Value is logically OR’d with segment data to turn on digit select outputs
const byte colDig[4] =
B00000100, // digit 1
B00100000, // digit 2
B01000000, // digit 3
B00100000, // digit 4

//Because the segment data and digit select outputs are not logically laid out (register outputs mix segment data and digit select outputs!) the 2 byte values below are required for each digit and are sent to shift registers 2 and 3. Crazy!

const byte shift2[16] = //seven segment digits in bits and digit select lines set to 0

const byte shift3[16] = //seven segment digits in bits and digit select lines set to 0

byte shift2_buf[4]={0xff, 0xff, 0xff, 0xff}; //Buffer to place segment/select data byte 1
byte shift3_buf[4]={0xff, 0xff, 0xff, 0xff}; //Buffer to place segment/select data byte 2

byte relay_stat;
int seg;
int digit;
int watchdog = 10;
int state=0;

void setup() {

Serial.begin(57600); // For debugging code only

// SPI for shift register
pinMode(latch, OUTPUT);
pinMode(clock, OUTPUT);
pinMode(data, OUTPUT);
// Set K1-K4 as INPUT
pinMode(K1, INPUT);
pinMode(K2, INPUT);
pinMode(K3, INPUT);
pinMode(K4, INPUT);
pinMode(INPUT1, INPUT);
pinMode(INPUT2, INPUT);
pinMode(INPUT3, INPUT);
pinMode(INPUT4, INPUT);
pinMode(INPUT5, INPUT);
pinMode(INPUT6, INPUT);
pinMode(INPUT7, INPUT);
pinMode(INPUT8, INPUT);

FlexiTimer2::set(3, 1.0/1000, updateShiftRegister); //Calls updateShiftRegister() every 3 milliseconds!

digitalWrite(INPUT1, HIGH);
digitalWrite(INPUT2, HIGH);
digitalWrite(INPUT3, HIGH);
digitalWrite(INPUT4, HIGH);
digitalWrite(INPUT5, HIGH);
digitalWrite(INPUT6, HIGH);
digitalWrite(INPUT7, HIGH);
digitalWrite(INPUT8, HIGH);

digitalWrite(K1, HIGH);
digitalWrite(K2, HIGH);
digitalWrite(K3, HIGH);
digitalWrite(K4, HIGH);

T_Start[0] = millis(); //initialise T0 start time (Spinning digit update interval)
T_Setpoint[0] = 166;
T_Start[1] = millis(); //initialise T1 start time (
T_Setpoint[1] = 1000;


// Function to write data to shift registers (drives 7 segment displays AND relays)
// There are 3 shift registers i series. 1st drives relays, 2nd drives segment data and digit 4 select, 3rd drives segment data and digit 1, 2 and 3 select
void updateShiftRegister()


if(digit<4) //Loop through each segment


digitalWrite(clock, LOW); //Set clock bit low
digitalWrite(latch, LOW); //Set latch bit low

if (digit==3) { 
shiftOut(data, clock, LSBFIRST, shift3_buf[digit]); // Write 7 segment data
shiftOut(data, clock, LSBFIRST, shift2_buf[digit]|colDig[digit]); // Write 7 segment data and select digit 4 via OR mask 

else { // else digit 0 to 2
shiftOut(data, clock, LSBFIRST, shift3_buf[digit]|colDig[digit]); // Write 7 segment data and select digit 1, 2 or 3 via OR mask 
shiftOut(data, clock, LSBFIRST, shift2_buf[digit]); // Write 7 segment data

//Update relay bit states


shiftOut(data, clock, LSBFIRST, relay_stat); //RELAYS

digitalWrite(latch, HIGH); //Set latch bit high

digit ++; // Next segment


 else digit=0;


// Function to write selected digit data to buffer, just pass the segment position and data array data position to this function
void update_buffers(int pos,int num)

// Function to update segments 0-3 with a (3 digit) integer number if required (digit 4 is used to indicate code is running by “spinning”)
void dig_update(int value)
update_buffers(2,value/100); // Calculate 100’s
update_buffers(1,(value%100)/10); //Modulo of 100’s division / 10 = 10’s
update_buffers(0,(value%100)%10); //Modulo of 100’s division then Modulo of 10’s = units

bool timer(int timer_id) //Non-blocking timer object
T_Current[timer_id] = millis();

if (T_Current[timer_id] - T_Start[timer_id] >= T_Setpoint[timer_id]) //test whether the period has elapsed
return 1;
else {
return 0;

void loop() //MAIN PROGRAM


//Watchdog display timer

//Watchdog spins digit 4 to indicate code is running
if (timer(0)>0) {
if(watchdog<15) {watchdog++;}
else {watchdog=10;}

//Increment digit 1 - 7 segment display every 1 secong - demo
if (timer(1)>0) {

if(state<999) {state++;}
else {state=0;}

dig_update(state); // Call this fuction to update 7 segment display with value “state”


// This is where to out the control program logic. Here I am just turning a couple of relays on and off

if (digitalRead(K1)==LOW)

if (digitalRead(K2)==LOW)

if (digitalRead(K3)==LOW)

if (digitalRead(K4)==LOW)