Expanding digital IO ports on a microcontroller – Part 2

In Part 1 of this article, I bumped into some “problems” and promised myself I would rewrite the program using nothing but the Wire library.

For starters, if I want to be perfectly honest, I don’t believe there’s a problem with the library itself. Here’s why:

PCF8574 port expander at power ON

This is a screenshot of the part datasheet from NXP. It clearly states: At power on, all the ports are HIGH! It cannot be clearer than that, but gain – I failed to read the documentation carefully!

After realizing that, I went along with this circuit modification/simulation (again using my friend’s instance of Proteus…):

schematic_v3_runtime

The two notable modifications from the original version is the addition of a HEX inverter (in the form of a 74HCT04) after the output PCF8574 device and the Darlington array (in the form of a ULN2803) at the output stage. With the first one, I no longer notice the “blink effect” at power up, and with the second IC, I get slightly greater output current at each port i.e. 500mA max (from the ULN2803) divided by 8 – which results in little over than 60mA per output.

The rest of the circuit I believe is fairly clear.

I then proceeded with drawing the circuit in EasyEDA and making a PCB design of it so that I can send it to a PCB fab house and quickly realized that creating a prototype with a perfboard with a footprint that of an Arduino UNO and with THT components, would be challenging to say the least. So I decided to wait for my boards from JLCPCB, which as some of you may know, integrates well with EasyEDA.

Schematic_IO-Port-Expander-PCF8574_UNO-Shield_20190819160020

Schematic_IO-Port-Expander-Companion-Shield_TEST-Shield_20190819160114

Here are the links from the projects on my EasyEDA account:

The source code is – as always – on my BitBucket repo.

The source code is pretty self explanatory. I setup the device at 0x21 and declare all of its port pins as inputs:

 

byte init_byte = 1;

for(int i = 0; i < 9; i++)
{
	Wire.beginTransmission(INPUT_DEV_ADDR);
	Wire.write(init_byte);
	Wire.endTransmission();
	init_byte <<= 1;
}

And this is very important: as you see in the snippet above, by setting each port pin HIGH – one at a time! Otherwise it won’t work.

Then a I read the state of the inputs and update the outputs accordingly and lastly in the setup() function, I declare the interrupt service routine to be executed each time there’s a change on digital pin 2 of the UNO. The ISR does nothing but updating a flag (trigger_on) and signalizing that ‘something has changed on pin 2’.

Inside the loop() function, I read the sate of the inputs ONLY when the trigger flag is updated, again – update the state of the outputs accordingly and finally reset the trigger flag.

And now I wait for these to arrive and assemble them:

Port Expander boards