The I2C IO Card for ESP-12E I2C Base Card is another expander card for the ESP-12E I2C Base Card Project. This PCB is an address-selectable I2C module with two relays and six (6) GPIO pins, all driven from a single PCF8574 running at 3v. The relays are optically isolated, and generous mains isolation cutouts were provided to reduce the possibility of mains voltage tracking. A jumper to enable/disable the i2c pullup-resistors is also provided on the PCB.
The relays are powered from a single LDO regulator, accepting 12v DC from the 2x20pin female header on the bottom of the card. 3.3v and ground should also be applied to the card at the 2x20pin header.
It is worth mentioning that this circuit does not contain level converting circuitry and that the i2c bus thus runs at 3.3v to be compatible with ESP chips.
It is possible to use the card with other processors if the appropriate level converters are used on the i2c bus.
The Schematic
Manufacturing the PCB
Over the past eight years, PCBWay has continuously upgraded their MANUFACTURING plants and equipment to meet higher quality requirements, and now THEY also provide OEM services to build your products from ideas to mass production and access to the market.
The PCB for this project has been manufactured at PCBWay. Please consider supporting them if you would like your own copy of this PCB, or if you have any PCB of your own that you need to have manufactured.
If you would like to have PCBWAY manufacture one of your own, designs, or even this particular PCB, you need to do the following… 1) Click on this link 2) Create an account if you have not already got one of your own. If you use the link above, you will also instantly receive a $5 USD coupon, which you can use on your first or any other order later. (Disclaimer: I will earn a small referral fee from PCBWay. This referral fee will not affect the cost of your order, nor will you pay any part thereof.) 3) Once you have gone to their website, and created an account, or login with your existing account,
4) Click on PCB Instant Quote
5) If you do not have any very special requirements for your PCB, click on Quick-order PCB
6) Click on Add Gerber File, and select your Gerber file(s) from your computer. Most of your PCB details will now be automatically selected, leaving you to only select the solder mask and silk-screen colour, as well as to remove the order number or not. You can of course fine-tune everything exactly as you want as well.
7) You can also select whether you want an SMD stencil, or have the board assembled after manufacturing. Please note that the assembly service, as well as the cost of your components, ARE NOT included in the initial quoted price. ( The quote will update depending on what options you select ).
8) When you are happy with the options that you have selected, you can click on the Save to Cart Button. From here on, you can go to the top of the screen, click on Cart, make any payment(s) or use any coupons that you have in your account.
Then just sit back and wait for your new PCB to be delivered to your door via the shipping company that you have selected during checkout.
In this, part 3 of the “Giving new Life to an Old Toy Car” series, we will be adding some flashing lights to the toy car project. This will ultimately serve two purposes, with the most obvious being to give some life and excitement to the project ( as the final user will be a young boy of 7, the visual aspect is important). The second purpose is more obscured, and mostly only useable to programmers and coders, or those that will debug the project… The flashing lights will function as status indicators, at startup, as well as during the normal operation of the toy. Obviously, the diagnostic nature should be well obscured so as to not distract from the visual aspects.
A short test of the display unit, disguised as a “police-style” flasher unit
The flasher unit is made up of an extremely simple circuit, with only a PCF8574 IO expander, bypass capacitors, some LED lights, and current limiting resistors.
The bottom layer of the flasher unit, shows the Io expander, bypass capacitors, and current limiting resistors.The top layer is designed to be as clean as possible, with only LEDs and some labeling
Schematic
Schematic
The schematic is straightforward, with no surprises, consisting only of a few components, like the PCB8574, bypass capacitors, current limiting resistors, and of course the LEDs. It is also important to remember that I plan to use this entire robot car to teach a young boy to program microprocessors. I believe that visual is best, thus, all the lights 🙂
Coding
As this is still a project in quite a lot of development stages, I will not publish my exact code at this moment. You can however look forward to the future conclusion post, which will contain all my code at that stage. For now, however, we need to keep in mind that the PCF8574 is an I2C port expander, with an 8-bit IO port.
It is thus possible to do something simple like the below:
#include <Wire.h>
void setup() {
wire.begin();
wire.beginTransmission(0x20);
wire.write(0b11111111); // All LEDS off
// our circuit is sinking current into the io expander
wire.endTransmission();
delay(1000); // delay for illustration purposes, production code will use
// non blocking code
wire.beginTransmission(0x20);
wire.write(0b10100101); // All blue LED on
// our circuit is sinking current into the io expander
wire.endTransmission();
delay(1000);
}
void loop() {
}
Obviously, this is just a very quick example and is meant to just test functionality. Your own application will ultimately determine the exact code that you would need.
Manufacturing the PCB
The PCB for this project is currently on its way from China, after having been manufactured at PCBWay. Please consider supporting them if you would like your own copy of this PCB, or if you have any PCB of your own that you need to be manufactured.
If you would like to have PCBWAY manufacture one of your own, designs, or even this particular PCB, you need to do the following… 1) Click on this link 2) Create an account if you have not already got one of your own. If you use the link above, you will also instantly receive a $5USD coupon, which you can use on your first or any other order later. (Disclaimer: I will earn a small referral fee from PCBWay. This referral fee will not affect the cost of your order, nor will you pay any part thereof.) 3) Once you have gone to their website, and created an account, or login with your existing account,
4) Click on PCB Instant Quote
5) If you do not have any very special requirements for your PCB, click on Quick-order PCB
6) Click on Add Gerber File, and select your Gerber file(s) from your computer. Most of your PCB details will now be automatically selected, leaving you to only select the solder mask and silk-screen colour, as well as to remove the order number or not. You can of course fine-tune everything exactly as you want as well.
7) You can also select whether you want an SMD stencil, or have the board assembled after manufacturing. Please note that the assembly service, as well as the cost of your components, ARE NOT included in the initial quoted price. ( The quote will update depending on what options you select ).
8) When you are happy with the options that you have selected, you can click on the Save to Cart Button. From here on, you can go to the top of the screen, click on Cart, make any payment(s) or use any coupons that you have in your account.
Then just sit back and wait for your new PCB to be delivered to your door via the shipping company that you have selected during checkout.
I2C port extenders or expanders are extremely useful devices, and I use quite a lot of them in my projects. My go-to device is definitely the PCF8574, mainly because it is sort of “breadboard friendly”. The MCP23017, with the existing breakouts available locally, are not. I have thus decided to design my own version of a breadboard friendly MCP23017 breakout board.
The Breakout Module PCB and its features
A breadboard friendly MCP23017 breakout board – Fronta breadboard friendly MCP23017 breakout board – Back
While this was definitely one of my easier projects, It still took a bit of time to get it just right and add some essential components and features directly onto the PCB.
The main features of this breakout: – DIP12 Layout – with all pins broken out, address pins to jumper headers… – Proper decoupling capacitors, as close as possible to the MCP23017 chip. I had to make use of the back layer of the PCB to do this, not exactly ideal, but with proper power and ground planes, and nice thick tracks, I believe they will be just fine.
– Address selector jumpers – The breakouts that are available locally, do not have these. – Breadboard friendly layout – 33.020mm x 20.320mm [board size], with 15.240mm vertical spacing between the rows of pins, ensures that you can easily fit it onto your breadboard, while still having space to add jumper wires to the pins. Horizontal pin spacing is standard 2.45mm.
The Schematic
The schematic is plain and simple. A few points to note though: – The address selection header, as well as the io pin headers are not shown on the schematic. – I2C pullup resistors are set at 1k but can be replaced with more suitable values as required in your circuit
The PCB for this project is currently on its way from China, after having been manufactured at PCBWay. Please consider supporting them if you would like your own copy of this PCB, or if you have any PCB of your own that you need to be manufactured.
If you would like to have PCBWAY manufacture one of your own, designs, or even this particular PCB, you need to do the following… 1) Click on this link 2) Create an account if you have not already got one of your own. If you use the link above, you will also instantly receive a $5USD coupon, which you can use on your first or any other order later. (Disclaimer: I will earn a small referral fee from PCBWay. This referral fee will not affect the cost of your order, nor will you pay any part thereof.) 3) Once you have gone to their website, and created an account, or login with your existing account,
4) Click on PCB Instant Quote
5) If you do not have any very special requirements for your PCB, click on Quick-order PCB
6) Click on Add Gerber File, and select your Gerber file(s) from your computer. Most of your PCB details will now be automatically selected, leaving you to only select the solder mask and silk-screen colour, as well as to remove the order number or not. You can of course fine-tune everything exactly as you want as well.
7) You can also select whether you want an SMD stencil, or have the board assembled after manufacturing. Please note that the assembly service, as well as the cost of your components, ARE NOT included in the initial quoted price. ( The quote will update depending on what options you select ).
8) When you are happy with the options that you have selected, you can click on the Save to Cart Button. From here on, you can go to the top of the screen, click on Cart, make any payment(s) or use any coupons that you have in your account.
Then just sit back and wait for your new PCB to be delivered to your door via the shipping company that you have selected during checkout.
Sometimes we need extra Inputs or Outputs on a device, or for use with a project. To implement it properly we also need a lot of additional electronic components to properly isolate these inputs and outputs, with the signals they switch, from our own project, because, let us be real, electronics and electrical devices in the real world do not all work with Arduino or ESP32/ESP8266 save voltages ( 5v and 3.3v ).
I will also tell you about a very special deal to get PCBs of your own made for only one (1) USD ( Including shipping with DHL )! No, I am not joking, and I am not crazy either… More on that later in the post…
It is thus extremely important to have a module that can effectively interface with inputs of 5.5v up to 32v DC ( optically Isolated up to 3000v ), and relay outputs, also optically isolated at 3000v. ( Note that the optical isolation voltage does not mean you can input that voltage level into the chip! It means that it can isolate the electronics on the safe side of the isolator from a voltage spike of up to that voltage!).
I also love using I2C, as it allows me to add modules onto an existing data bus while using only 2 GPIO lines on the MCU!
The module I am presenting to you today was designed to be operated from 5v DC. That includes the I2C data lines (SDA and SCL). If you need to interface to a 3.3v microprocessor, like an ESP32 or ESP8266, or even the new RP2040 or an STM32, you need to use a logic level converter.
The PCB uses the popular PCF8574 8 channel IO expander, which is extremely easy to use, and where you can connect up to 8 devices in a chain ( 16 if you use the PCF8574AT variant as well.. Meaning eight of each variant) This surely adds up to quite a lot of IO lines at a cost of only 2 GPIO on your MCU!
The Circuit diagram is below, and I will discuss each part briefly.
Schematic – Page 1
This is the Galvanic Isolated Input schematic. Each input operates at a voltage of 5.5v to 32v DC. Complete Galvanic Isolation between the Module and the remote input is in effect. Please note that you have to supply a remote ground from the device that provides the input. DO NOT connect the PCB Module ground to an isolated ground pin. This may still work but renders the galvanic Isolation for that input completely useless.
Relay Driver Schematic
This is the Relay driver schematic. Each relay output is driven through an optocoupler, as well as a transistor. Although this arrangement does not provide complete galvanic Isolation of the relay coil, it does protect your MCU from any voltage spikes caused by back-emf when the relay is de-energised. The Relay contacts themselves, being magnetically actuated by the coil, are in themselves Galvanically Isolated from the rest of the PCB.
I2C Control Schematic
Finally, we have the I2C IO Expander schematic, with a 5v LDO regulator, capable of providing up to 600mA of current to the PCB. The PCF8574 Chip’s address is selectable with DipSwitch SW1 so that you can use multiple PCBs at the same time if you should choose to do so. The only note on that is that you should not connect the 5v lines of each individual PCB together. You should also only connect the GND and SDA, SCL lines back to the MCU.
Raw PCB Layout
Earlier on in the post, I promised to tell you about a very special deal…
Well, here it is, as well as some details about the sponsor of this very exciting deal…
PCBPartner.com is owned and operated by Kinji Group, which was established in 1997. We have over 20 years of experience in PCB manufacturing, PCB design, component manufacturing and distribution, PCB assembly and PCB cam software development.
While Kinji Group has 3 PCB factories in China, we have also developed strategic partnerships with more than 15 other factories around Asia. We, therefore, have a large group of specialists in PCB manufacturing, quality control, technical support and part sourcing to support your innovative ideas and products.
Our over 500 employees are spread across 8 branches in Mainland China (Shenzhen, Dongguan, Shanghai, Wuxi, Chengdu, Xiamen), Hong Kong SAR, and Taiwan. And we’re still growing!
We’re confident once you try us out, we’ll become your PCB Partner. And if not? Well, you’ll have scored some free PCB! So why not take us for a spin, you’ve got nothing to lose.
We, MakerIoT2020.com, have decided to give it a go and send this particular PCB to PCBPartner.com for manufacturing. So far, while we are still waiting to receive the PCB, ( Weekends happen 🙂 ), We are very happy with the ease of use of the online ordering system provided.
We would also like to point out that this special order will only be available until the end of March 2022, as well as that there are a few conditions:
Promotion ends March 31st 2022 Each new customer can enjoy free PCB on their first order This promotion applies to 1-2 layers of FR4 PCB, up to 100x100mm, 10pcs, with Green Solder Mask 4 layer of FR4 PCB, up to 50x50mm, 10pcs, with Green Solder Mask 1 layer Aluminum PCB, up to 100x100mm, 10pcs This PCB promotion cannot be used with other discounts or other promotional activities
For a full list of conditions, and countries that may participate in this offer, please click on the link here
Let us have a look at the entire ordering process..
Once you click on the PCBPartner.com link, you will be taken to their website, where you should sign up, which is free and easy… We used our Google.com account details and were ready to order in seconds…
FR4 PBC Quote Form – Before uploading your Gerber Files
Enter the specific details for the manufacturing of your PCB, and upload your Gerber files.
After uploading your Gerber Files.
Continue selecting options for your PCB order… Make sure to select DHL shipping, to take advantage of the special 1USD option, and click on the ADD to Cart Button…
Quote added to your shopping cart.
You will now get a message that your enquiry has been submitted successfully.
Click on the “Under review” button, to see your quote status… In my case, it took about 5 minutes for the review to pass, and be able to checkout and pay for the order…
PCB order under review
Once the review has passed, you will see a pending payment,
Payment Pending
You may now click on the “Proceed to Payment” option
Add your shipping address, and choose your payment option.
At this moment in time, only two payment options are supported, Paypal ( as well as Debit and Credit cards) and Direct Bank Transfer. I believe more options will be made available in future.. Checkout with Paypal
In my case, I chose Paypal and paid by Debit card.
Enter your card detailsAfter Payment.
After payment was made successfully, you can also check on the status of your order…
Review your order status
You can also review your order at any stage before or after payment, as well as get progress reports of the manufacturing process.
PCB Order Status.
In conclusion, I would like to say that it was quite easy to order and make payment. The Website is easy to use, and everything is clear and easy to understand. The PCB was well manufactured and seems to be quite good quality
In a previous post, I have shown you how to use the MCP23017 16 Port I2C I/O Port extender with the standard Wire library, as supplied with the Arduino IDE. In this post, I will have a quick look at using Adafruit’s library for this IC. I believe that this library brings a lot of ease-of-use to the part, making it possible to obscure some of the complexity of I2C.
I do however prefer to use the native Wire library myself, as it is slightly faster.
When using single pin operations such as pinMode(pinId, dir) or digitalRead(pinId) or digitalWrite(pinId, val) then the pins are addressed using the ID’s below. For example, for set the mode of GPB0 then use pinMode(8, …).
Physical Pin #
Pin Name
Pin ID
21
GPA0
0
22
GPA1
1
23
GPA2
2
24
GPA3
3
25
GPA4
4
26
GPA5
5
27
GPA6
6
28
GPA7
7
1
GPB0
8
2
GPB1
9
3
GPB2
10
4
GPB3
11
5
GPB4
12
6
GPB5
13
7
GPB6
14
8
GPB7
15
Some examples, directly from the library, all code belongs to Adafruit, and was not written by me.
1. A Button Example
#include <Wire.h>
#include "Adafruit_MCP23017.h"
// Basic pin reading and pullup test for the MCP23017 I/O expander
// public domain!
// Connect pin #12 of the expander to Analog 5 (i2c clock)
// Connect pin #13 of the expander to Analog 4 (i2c data)
// Connect pins #15, 16 and 17 of the expander to ground (address selection)
// Connect pin #9 of the expander to 5V (power)
// Connect pin #10 of the expander to ground (common ground)
// Connect pin #18 through a ~10kohm resistor to 5V (reset pin, active low)
// Input #0 is on pin 21 so connect a button or switch from there to ground
Adafruit_MCP23017 mcp;
void setup() {
mcp.begin(); // use default address 0
mcp.pinMode(0, INPUT);
mcp.pullUp(0, HIGH); // turn on a 100K pullup internally
pinMode(13, OUTPUT); // use the p13 LED as debugging
}
void loop() {
// The LED will 'echo' the button
digitalWrite(13, mcp.digitalRead(0));
}
2. An Interrupt Example
// Install the LowPower library for optional sleeping support.
// See loop() function comments for details on usage.
//#include <LowPower.h>
#include <Wire.h>
#include <Adafruit_MCP23017.h>
Adafruit_MCP23017 mcp;
byte ledPin=13;
// Interrupts from the MCP will be handled by this PIN
byte arduinoIntPin=3;
// ... and this interrupt vector
byte arduinoInterrupt=1;
volatile boolean awakenByInterrupt = false;
// Two pins at the MCP (Ports A/B where some buttons have been setup.)
// Buttons connect the pin to grond, and pins are pulled up.
byte mcpPinA=7;
byte mcpPinB=15;
void setup(){
Serial.begin(9600);
Serial.println("MCP23007 Interrupt Test");
pinMode(arduinoIntPin,INPUT);
mcp.begin(); // use default address 0
// We mirror INTA and INTB, so that only one line is required between MCP and Arduino for int reporting
// The INTA/B will not be Floating
// INTs will be signaled with a LOW
mcp.setupInterrupts(true,false,LOW);
// configuration for a button on port A
// interrupt will triger when the pin is taken to ground by a pushbutton
mcp.pinMode(mcpPinA, INPUT);
mcp.pullUp(mcpPinA, HIGH); // turn on a 100K pullup internally
mcp.setupInterruptPin(mcpPinA,FALLING);
// similar, but on port B.
mcp.pinMode(mcpPinB, INPUT);
mcp.pullUp(mcpPinB, HIGH); // turn on a 100K pullup internall
mcp.setupInterruptPin(mcpPinB,FALLING);
// We will setup a pin for flashing from the int routine
pinMode(ledPin, OUTPUT); // use the p13 LED as debugging
}
// The int handler will just signal that the int has happen
// we will do the work from the main loop.
void intCallBack(){
awakenByInterrupt=true;
}
void handleInterrupt(){
// Get more information from the MCP from the INT
uint8_t pin=mcp.getLastInterruptPin();
uint8_t val=mcp.getLastInterruptPinValue();
// We will flash the led 1 or 2 times depending on the PIN that triggered the Interrupt
// 3 and 4 flases are supposed to be impossible conditions... just for debugging.
uint8_t flashes=4;
if(pin==mcpPinA) flashes=1;
if(pin==mcpPinB) flashes=2;
if(val!=LOW) flashes=3;
// simulate some output associated to this
for(int i=0;i<flashes;i++){
delay(100);
digitalWrite(ledPin,HIGH);
delay(100);
digitalWrite(ledPin,LOW);
}
// we have to wait for the interrupt condition to finish
// otherwise we might go to sleep with an ongoing condition and never wake up again.
// as, an action is required to clear the INT flag, and allow it to trigger again.
// see datasheet for datails.
while( ! (mcp.digitalRead(mcpPinB) && mcp.digitalRead(mcpPinA) ));
// and clean queued INT signal
cleanInterrupts();
}
// handy for interrupts triggered by buttons
// normally signal a few due to bouncing issues
void cleanInterrupts(){
EIFR=0x01;
awakenByInterrupt=false;
}
/**
* main routine: sleep the arduino, and wake up on Interrups.
* the LowPower library, or similar is required for sleeping, but sleep is simulated here.
* It is actually posible to get the MCP to draw only 1uA while in standby as the datasheet claims,
* however there is no stadndby mode. Its all down to seting up each pin in a way that current does not flow.
* and you can wait for interrupts while waiting.
*/
void loop(){
// enable interrupts before going to sleep/wait
// And we setup a callback for the arduino INT handler.
attachInterrupt(arduinoInterrupt,intCallBack,FALLING);
// Simulate a deep sleep
while(!awakenByInterrupt);
// Or sleep the arduino, this lib is great, if you have it.
//LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF);
// disable interrupts while handling them.
detachInterrupt(arduinoInterrupt);
if(awakenByInterrupt) handleInterrupt();
}
I hope that this shows you another way of using this versatile IC,
In a future post, I will show you how to do interrupts, using the native Wire library, as well as point out a few things about why interrrupts sometimes does not seem to be working, as well as a workaround for that.
Today I will show you another useful IO Expander chip, The MCP23017. This chip, although similar to the PCF8475, which I have already covered in a previous article, has many additional features that may make it a very attractive solution when you need some more extra GPIO pins for a big project…
Features
Let us look at some of the features of this chip
16-Bit Remote Bidirectional I/O Port:
I/O pins default to input • High-Speed I2C Interface (MCP23017):
100 kHz
400 kHz
1.7 MHz • High-Speed SPI Interface (MCP23S17):
10 MHz (maximum) • Three Hardware Address Pins to Allow Up to Eight Devices On the Bus • Configurable Interrupt Output Pins:
Configurable as active-high, active-low or open-drain • INTA and INTB Can Be Configured to Operate Independently or Together • Configurable Interrupt Source:
Interrupt-on-change from configured register defaults or pin changes • Polarity Inversion Register to Configure the Polarity of the Input Port Data • External Reset Input • Low Standby Current: 1 µA (max.) • Operating Voltage:
1.8V to 5.5V @ -40°C to +85°C
2.7V to 5.5V @ -40°C to +85°C
4.5V to 5.5V @ -40°C to +125°C
MCP23017 Pinout Diagram
The sixteen I/O ports are separated into two ‘ports’ – A (on the right) and B (on the left. Pin 9 connects to 5V, 10 to GND, 11 isn’t used, 12 is the I2C bus clock line (Arduino Uno/Duemilanove analogue pin 5, Mega pin 21), and 13 is the I2C bus data line (Arduino Uno/Duemailnove analogue pin 4, Mega pin 20).
External pull-up resistors should be used on the I2C bus – in our examples we use 4.7k ohm values. Pin 14 is unused, and we won’t be looking at interrupts, so ignore pins 19 and 20. Pin 18 is the reset pin, which is normally high – therefore you ground it to reset the IC. So connect it to 5V!
Finally we have the three hardware address pins 15~17. These are used to determine the I2C bus address for the chip. If you connect them all to GND, the address is 0x20. If you have other devices with that address or need to use multiple MCP23017s, see figure 1-2 in the datasheet.
You can alter the address by connecting a combination of pins 15~17 to 5V (1) or GND (0). For example, if you connect 15~17 all to 5V, the control byte becomes 0100111 in binary, or 0x27 in hexadecimal.
It is also available on a convenient breakout PCB, for about $USD0.80 from AliExpress
MCP23017 on Breakout PCB – Back
MCP23017 on Breakout PCB – Front
Please Note: THIS BREAKOUT PCB IS NOT SUITED FOR USE ON A BREADBOARD. YOU WILL SHORT OUT VCC AND GROUND AS WELL AS ALL THE IO PINS IF YOU TRY TO USE IT ON A BREADBOARD.
As you can see, the pins are however very clearly labelled, and thus easy to use. I have also purposely soldered my header pins “the wrong way round” to prevent using it on a breadboard, as this will short out Vcc to Ground!
Having interrupt outputs is one of the most important features of the MCP23017, since the microcontroller does not have to continuously poll the device to detect an input change. Instead an interrupt service routine can be used to react quickly to an input change such a key press…
To make life even easier each GPIO input pin can be configured with an internal pullup (~100k) and that means you won’t have to wire up external pull up resistors for keyboard input. You can also mix and match inputs and outputs the same as any standard microcontroller 8 bit port.
Addressing
The 23017 has three input pins to allow you to set a different address for each attached MCP23017.
The above corresponds to a hardware address for the three lines A0, A1, A2 corresponding to the input pin values at the IC. You must set the value of these hardware inputs as 0V or (high) volts and not leave them floating otherwise they will get random values from electrical noise and the chip will do nothing!
The four left most bits are fixed a 0100 (specified by a consortium who doles out address ranges to manufacturers).
So the MCP23017 I2C address range is 32 decimal to 37 decimal or 0x20 to 0x27 for the MCP23017.
Please note: The addresses are the same as those for the PCF8475. You must thus be careful if you use these two devices on the same i2c bus!
MCP23017 Non interrupt registers
IODIR I/O direction register
For controlling I/O direction of each pin, register IODIR (A/B) lets you set the pin to an output when a zero is written and to an input when a ‘1’ is written to the register bit. This is the same scheme for most microcontrollers – the key is to remember that zero (‘0’) equates to the ‘O’ in Output.
GPPU Pullup register
Setting a bit high sets the pullup active for the corresponding I/O pin.
OLAT Output Latch register
This is exactly the same as the I/O port in 18F series PIC chips where you can read back the “desired” output of a port pin whether or not the actual state of that pin is reached. i.e. consider a strong current LED attached to the pin – it is easily possible to pull down the output voltage at the pin to below the logic threshold i.e. you would read back a zero if reading from the pin itself when in fact it should be a one. Reading the OLAT register bit returns a ‘one’ as you would expect from a software engineering point of view.
IPOL pin inversion register
The IPOL(A/B) register allows you to selectively invert any input pin. This reduces the glue logic needed to interface other devices to the MCP23017 since you won’t need to add inverter logic chips to get the correct signal polarity into the MCP23017.
It is also very handy for getting the signals the right way up e.g. it is common to use a pull up resistor for an input so when a user presses an input key the voltage input is zero, so in software you have to remember to test for zero.
Using the MCP23017 you could invert that input and test for a 1 (in my mind a key press is more equivalent to an on state i.e. a ‘1’) however I use pullups all the time (and uCs in general use internal pullups when enabled) so have to put up with a zero as ‘pressed’. Using this device would allow you to correct this easily.Note: The reason that active low signals are used everywhere is a historical one: TTL (Transistor Transistor Logic) devices draw more power in the active low state due to the internal circuitry, and it was important to reduce unnecessary power consumption – therefore signals that are inactive most of the time e.g. a chip select signal – were defined to be high. With CMOS devices either state causes the same power usage so it now does not matter – however active low is used because everyone uses it now and used it in the past.
SEQOP polling mode : register bit : (Within IOCON register)
If you have a design that has critical interrupt code e.g. for performing a timing critical measurement you may not want non critical inputs to generate an interrupt i.e. you reserve the interrupt for the most important input data.
In this case, it may make more sense to allow polling of some of the device inputs. To facilitate this “Byte mode” is provided. In this mode, you can read the same set of GPIOs using clocks but not needling to provide other control information. i.e. it stays on the same set of GPIO bits, and you can continuously read it without the register-address updating itself. In non-byte mode, you either have to set the address you read from (A or B bank) as control input data.
Now to examine how to use the IC in our sketches.
As you should know by now most I2C devices have several registers that can be addressed. Each address holds one byte of data that determines various options. So before using we need to set whether each port is an input or an output. First, we’ll examine setting them as outputs. So to set port A to outputs, we use:
Wire.beginTransmission(0x20);
Wire.write(0x00); // IODIRA register
Wire.write(0x00); // set all of port A to outputs
Wire.endTransmission();
Then to set port B to outputs, we use:
Wire.beginTransmission(0x20);
Wire.write(0x01); // IODIRB register
Wire.write(0x00); // set all of port B to outputs
Wire.endTransmission();
So now we are in void loop() or a function of your own creation and want to control some output pins. To control port A, we use:
Wire.beginTransmission(0x20);
Wire.write(0x12); // address port A
Wire.write(??); // value to send
Wire.endTransmission();
To control port B, we use:
Wire.beginTransmission(0x20);
Wire.write(0x13); // address port B
Wire.write(??); // value to send
Wire.endTransmission();
… replacing ?? with the binary or equivalent hexadecimal or decimal value to send to the register.
To calculate the required number, consider each I/O pin from 7 to 0 matches one bit of a binary number – 1 for on, 0 for off. So you can insert a binary number representing the status of each output pin. Or if binary does your head in, convert it to hexadecimal. Or a decimal number.
So for example, you want pins 7 and 1 on. In binary that would be 10000010, in hexadecimal that is 0x82, or 130 decimal. (Using decimals is convenient if you want to display values from an incrementing value or function result).
For example, we want port A to be 11001100 and port B to be 10001000 – so we send the following (note we converted the binary values to decimal):
Wire.beginTransmission(0x20);
Wire.write(0x12); // address port A
Wire.write(204); // value to send
Wire.endTransmission();
Wire.beginTransmission(0x20);
Wire.write(0x13); // address port B
Wire.write(136); // value to send
Wire.endTransmission();
A complete Example
// pins 15~17 to GND, I2C bus address is 0x20
#include "Wire.h"
void setup()
{
Wire.begin(); // wake up I2C bus
// set I/O pins to outputs
Wire.beginTransmission(0x20);
Wire.write(0x00); // IODIRA register
Wire.write(0x00); // set all of port A to outputs
Wire.endTransmission();
Wire.beginTransmission(0x20);
Wire.write(0x01); // IODIRB register
Wire.write(0x00); // set all of port B to outputs
Wire.endTransmission();
}
void binaryCount()
{
for (byte a=0; a<256; a++)
{
Wire.beginTransmission(0x20);
Wire.write(0x12); // GPIOA
Wire.write(a); // port A
Wire.endTransmission();
Wire.beginTransmission(0x20);
Wire.write(0x13); // GPIOB
Wire.write(a); // port B
Wire.endTransmission();
}
}
void loop()
{
binaryCount();
delay(500);
}
Using the pins as inputs
Although that may have seemed like a simple demonstration, it was created show how the outputs can be used. So now you know how to control the I/O pins set as outputs. Note that you can’t source more than 25 mA of current from each pin, so if switching higher current loads use a transistor and an external power supply and so on.
Now let’s turn the tables and work on using the I/O pins as digital inputs. The MCP23017 I/O pins default to input mode, so we just need to initiate the I2C bus. Then in the void loop() or other function all we do is set the address of the register to read and receive one byte of data.
// pins 15~17 to GND, I2C bus address is 0x20
#include "Wire.h"
byte inputs=0;
void setup()
{
Serial.begin(9600);
Wire.begin(); // wake up I2C bus
}
void loop()
{
Wire.beginTransmission(0x20);
Wire.write(0x13); // set MCP23017 memory pointer to GPIOB address
Wire.endTransmission();
Wire.requestFrom(0x20, 1); // request one byte of data from MCP20317
inputs=Wire.read(); // store the incoming byte into "inputs"
if (inputs>0) // if a button was pressed
{
Serial.println(inputs, BIN); // display the contents of the GPIOB register in binary
delay(200); // for debounce
}
}
Other Libraries
You can also download and install the MCP23017 Library from Adafruit for the Arduino IDE. This library will make using this chip even easier… I will discuss this library in another post
Using a matrix keypad is a very easy way to add multiple control buttons to a project, be it to enter a password, or to control different devices. These keypads do unfortunately have some serious flaws (in my view anyway)
1) They are usually of extremely low quality ( especially some of the membrane types from China). This means they dont last very long. 2) A typical 4×4 Matrix keypad will require 8 of your precious IO pins for itself.
These two flaws can however easily be solved, if we use a bit of technology, and are willing to to a bit of simple circuit construction by ourselves.
What does this mean ? Most of us makers will inevitably have a piece of proto-board or strip-board lying around, as well as a few momentary push-button switches. These can easily be used to make out own, much more reliable keypad. Let us look at the circuit
Circuit diagram for a 4×4 Matrix Keypad
As we can see, to build a 4×4 matrix keypad, we will need 16 momentary switches. These are connected together as shown above. You can then interface it with your favourite micro-controller to read the key(s) pressed…
This definitely solves the first of my problems, but we still need 8 pins to control this keypad… or do we? No, we don’t, we need only 2 pins. That is to say if we use one of those PCF8574 I2C IO port expander modules. They are much more reliable, as well as quite cheap as well. all depending on where you buy them from, and how long you are willing to wait for shipping 🙂
Let us see how to connect the keypad to the I2C Module
a 4×4 Membrane Matrix Keypad with PCF8574 I2C port expander moduleConnecting the two together, note that we do not connect the INT pinConnect Power (VCC, GND and I2C lines Connect to Arduino or your preferred microcontroller. We have used Arduino Uno, Note that you can also connect the I2C to A4 (SDA) and A5(SCL) if you prefer.
Now, we need to install some libraries
The first one is the actual Keypad library, you can download it from the link below
#include <Key.h>
#include <Keypad.h>
#include <Keypad_I2C.h>
#define I2CADDR 0x26 // Set the Address of the PCF8574
const byte ROWS = 4; // Set the number of Rows
const byte COLS = 4; // Set the number of Columns
// Set the Key at Use (4x4)
char keys [ROWS] [COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
// define active Pin (4x4)
byte rowPins [ROWS] = {0, 1, 2, 3}; // Connect to Keyboard Row Pin
byte colPins [COLS] = {4, 5, 6, 7}; // Connect to Pin column of keypad.
// makeKeymap (keys): Define Keymap
// rowPins:Set Pin to Keyboard Row
// colPins: Set Pin Column of Keypad
// ROWS: Set Number of Rows.
// COLS: Set the number of Columns
// I2CADDR: Set the Address for i2C
// PCF8574: Set the number IC
Keypad_I2C keypad (makeKeymap (keys), rowPins, colPins, ROWS, COLS, I2CADDR, PCF8574);
void setup () {
Wire .begin (); // Call the connection Wire
keypad.begin (makeKeymap (keys)); // Call the connection
Serial.begin (9600);
}
void loop () {
char key = keypad.getKey (); // Create a variable named key of type char to hold the characters pressed
if (key) {// if the key variable contains
Serial.println (key); // output characters from Serial Monitor
}
}
Upload this to your Arduino device and enjoy. This sketch can also be adapted for 1×4, and 4×3 keypads, and with a little modification, will also work perfectly on ESP32 or ESP8266 as well…
Today I will continue my series on I2C by showing you how to use multiple devices on the I2C bus. This will be an extremely short post, as it builds on skills that we have already covered.
All of these devices will be controlled from Arduino Uno, using the following libraries
LiquidCrystal_I2C.h to control the LCD screen, Wire.h and PCF8574.h to control the I2C IO extenders and Adafruit_GFX, Adafruit_SSD1306.h and SPI.h to control the SSD1306 128×32 OLED display.
With DuPont wires and breadboards being the reliable things they are, I decided that, after initial testing, I will not show you how to do button inputs on the PCF8574 at this stage. The amount of stray capacitance floating around on the breadboards, and small momentary push-button switches, made for a very impressive but unreliable mess of wires, with no real learning value to it 😉 Maybe some more on that later when I do a decent real-world example using these technologies 🙂
As the total distance between the devices is relatively short, it was not necessary to use pull-up resistors on the I2C bus in my setup. I suspect that that is due to the fact that they may already be included on some of my devices.
The circuit is quite straight forward.
Connect all SDA pins on the I2C devices together serially, and connect that to the Arduino SDA pin ( That is usually A4)
Connect all SCL pins on the I2C devices together serially, and connect that to the Arduino SCL pin ( That is usually A5)
A note: On my Uno clone, there is an additional I2C breakout at the top of the device, near the USB adapter. I chose to use that as well as A4 and A5, as the bus hung itself up when connected to the breadboard. Your mileage may vary on this one 🙂
Connect all 5v (Vcc) lines to 5v on the Arduino, and all Ground (GND) lines to GND on the Arduino.
Now connect 4 LEDs, through a suitable resistor ( 640 ohms up to 1k ohm ) to pin P0 and P1 on both of the PCF8574 IO extenders. Also, connect the other leg of the LED to ground.
I have powered my Uno from an external 5v power supply, as I did not want to pull too much current from the regulator on the actual Uno clone.
That should complete your hardware setup. Double check all your connections, and then load the i2c scanner sketch in the Arduino IDE, you may find it under the examples for the Wire.h library.
Power up the circuit, and upload the sketch to the Uno. Open the Serial Monitor.
You should see 4 I2C devices being detected. Note their addresses. If you dont see 4 devices, check your wiring and addresses. You may have a device with a conflicting address or a bad connection. If you used the breadboard to connect the bus, chances are very good that you will not see all the devices.
Good, if all of that is working, copy paste the following code into a new Arduino IDE window. I will explain the code in the section below:
/*
Multiple devices on the I2C bus
Maker and Iot Ideas, MakerIoT2020
*/
// Include the libraries that we will need
#include <SPI.h> // needed for OLED display.
#include <PCF8574.h> // PCF8574
#include <Wire.h> // Generic I2C library
#include <Adafruit_GFX.h> // for OLED display
#include <Adafruit_SSD1306.h> // for OLED display
#include <LiquidCrystal_I2C.h> // For I2C LCD display
// we need to define the size of the OLED screen
#define OLED_WIDTH 128
#define OLED_HEIGHT 32
// mine does not have an onboard reset pin. If yours do, specify the
// pin that it is connected to on the Arduino here. To use the
// Arduino reset pin, specify -1 as below
#define OLED_RESET -1
// Define the OLED display, width,hight protocol and reset pin
Adafruit_SSD1306 oled(OLED_WIDTH,OLED_HEIGHT, &Wire, OLED_RESET);
// Define the I2C LCD screen address and pin configuration
LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7,3,POSITIVE);
// Define the PCF8574 devices ( you can have up to 8 on a bus )
// but in this case, my LCD uses address 0x27, so I will have a
// conflicting address if I were to use 8 of them together with the
// LCD
PCF8574 Remote_1(0x20);
PCF8574 Remote_2(0x21);
// Note the I2C addresses. You can obtain them from the i2c_scanner
void setup() {
// serial debugging if needed
Serial.begin(115200);
// Start OLED Display Init
if (!oled.begin(SSD1306_SWITCHCAPVCC,0x3C)) { // Init the OLED
Serial.println(F("OLED INIT FAILED"));
for(;;); // Dont proceed ... loop forever
}
oled.display();
delay(2000); // This delay is required to give display time to
// initialise properly
oled.clearDisplay();
oled.setTextSize(0);
oled.setTextColor(SSD1306_WHITE);
oled.setCursor(0,0);
oled.println("TEST SCREEN");
oled.display();
delay(2000);
oled.clearDisplay();
oled.setCursor(1,0);
oled.println("OLED SCREEN ON");
oled.display();
// Start the LCD
lcd.begin(16,2);
// Set the initial state of the pins on the PCF8574 devices
// I found that the PCF8574 library sometimes does funny things
// This is also an example of how to use native i2c to set the
// status of the pins
Wire.begin();
Wire.beginTransmission(0x20); // device 1
Wire.write(0x00); // all ports off
Wire.endTransmission();
Wire.begin();
Wire.beginTransmission(0x21); // device 2
Wire.write(0x00); // all ports off
Wire.endTransmission();
// Set pinModes for PCF8574 devices
// Note that there are two of them
Remote_1.pinMode(P0,OUTPUT);
Remote_1.pinMode(P1,OUTPUT);
Remote_2.pinMode(P0,OUTPUT);
Remote_2.pinMode(P1,OUTPUT);
// Start both IO extenders
Remote_1.begin();
Remote_2.begin();
// and set ports to low on both
// you may find that if you ommit this step, they come up in an
// unstable state.
Remote_1.digitalWrite(P0,LOW);
Remote_1.digitalWrite(P1,LOW);
Remote_2.digitalWrite(P0,LOW);
Remote_2.digitalWrite(P1,LOW);
}
void loop() {
// Draw a character map on the OLED display.
// This function is borrowed from the Adafruit library
testdrawchar();
// Write to the IO extenders
Remote_1.digitalWrite(P0,HIGH);
Remote_1.digitalWrite(P1,LOW);
Remote_2.digitalWrite(P0,HIGH);
Remote_2.digitalWrite(P1,LOW);
// Display their status on the LCD
lcd.setCursor(0,0);
lcd.print(" R1 P0=1 P1=0");
lcd.setCursor(0,1);
lcd.print(" R2 P0=1 P1=0");
delay(500);
// Change status
Remote_1.digitalWrite(P1,HIGH);
Remote_1.digitalWrite(P0,LOW);
Remote_2.digitalWrite(P1,HIGH);
Remote_2.digitalWrite(P0,LOW);
// Update LCD
lcd.setCursor(0,0);
lcd.print(" R1 P0=0 P1=1");
lcd.setCursor(0,1);
lcd.print(" R2 P0=0 P1=1");
delay(500);
// Do some graphics on the OLED display
// Function borrowed from Adafruit
testdrawrect();
oled.clearDisplay();
delay(500);
// repeat indefinitely
}
void testdrawrect(void) {
oled.clearDisplay();
for(int16_t i=0; i<oled.height()/2; i+=2) {
oled.drawRect(i, i, oled.width()-2*i, oled.height()-2*i, SSD1306_WHITE);
oled.display(); // Update screen with each newly-drawn rectangle
delay(1);
}
delay(500);
}
void testdrawchar(void) {
oled.clearDisplay();
oled.setTextSize(1); // Normal 1:1 pixel scale
oled.setTextColor(SSD1306_WHITE); // Draw white text
oled.setCursor(0, 0); // Start at top-left corner
oled.cp437(true); // Use full 256 char 'Code Page 437' font
// Not all the characters will fit on the display. This is normal.
// Library will draw what it can and the rest will be clipped.
for(int16_t i=0; i<256; i++) {
if(i == '\n') oled.write(' ');
else oled.write(i);
}
oled.display();
delay(500);
}
This concludes a quick and dirty show and tell… I hope that it will stimulate questions and ideas for a lot of people.
In the first part of this series, I showed you how to extend the available output pins on your microprocessor by using a SIPO (Serial In, Parallel Out) Shift Register. These work great to extend your outputs, but they do tend to involve a bit of extra work and organisation in your code. They are also a bit slower than the normal GPIO pins, because data has to be serially shifted into them, and then latched out onto the parallel port.
I have also mentioned that there are I2C devices available that can make this much easier… In today’s article, I will show you how to use one of these I2C devices, the PCF8574.
These little modules have some quite impressive features, for one, allowing you to cascade up to 8 of them together, giving you a quite impressive 64 GPIO ports ! I am also happy to tell you, that if you can find the PCF8574A variant, as well, you can increase the total amount of ports to 128! ( If you chain 8x PCF8574 as well as 8x PCF8574A together) This is possible because the I2C addresses of the two series of chips are different. Thus allowing us to add a total of 16 of them to the I2C bus.
It must however be said that you should calculate your bus resistance very carefully if you plan on doing that. For most of us, I do not believe we will need that much GPIO on a single microprocessor!
Enough introduction, let us start by looking closely at the chip, as well as the modules that you can purchase for around 1 USD each…
A word of caution, there is also another version of these available, which is specifically designed to be used with LCD screens. You should thus be careful when you buy a premade module, that you choose the io-extender version, and not the LCD controller version.
PCF8574 I2C IO Extender module – Front ViewPCF8574 I2C IO Extender – Back View
As we can see, the GPIO ports are clearly labeled, from P0 to P7, with the INT (Interrupt Pin) on the very right.
As I have said before, you can cascade up to 8 of these onto the I2C bus. This is done by setting the I2C address of the module. This is done by setting the jumpers as seen in the picture below.
Address Jumpers on the PCF8574 I2C IO Extender Module
The Address can be set by using the following table to lookup the address and set the jumpers accordingly.
A2
A1
A0
I2C Device Address
0
0
0
0x20
0
0
1
0x21
0
1
0
0x22
0
1
1
0x23
1
0
0
0x24
1
0
1
0x25
1
1
0
0x26
1
1
1
0x27
Available I2C Addresses for PCF8574 selected by setting the jumpers
Connecting the device is very easy. You only have to supply 5v and Ground, as well as connect it to the SCL and SDA Pins on your microprocessor. For Arduino Uno / Nano that is A4 (SDA) and A5 (SCL)
As far as the coding is concerned, you have two options. You can either use the built-in Wire library, or you can download a special library. Both works equally well, but I do believe that the built-in Wire library might be a little bit faster.
Another point to make is that there are a lot of “fake” modules on the market these days. These modules work, but some of them have extremely weak current sourcing abilities. ( I recently bought a pair online, and they are unable to properly light an LED even without a current limiting resistor. I fixed that issue by driving the LED through a small BJT transistor, like the 2n2222a.
You should also take note that the ports will start up in a weak HIGH state when the module is powered up. This should be taken into consideration when designing your circuit to drive external devices through the outputs. In other words, you should take precautions to prevent the devices from switching on before the microprocessor takes control of the module.
Let us start to look at the coding that you will need to do to use this device. I will start with the built-in wire Library that is included with the Arduino IDE.
#include <Wire.h> // Wire.h provide access to I2C functions
void setup() { Wire.begin(); // Start I2C }
void loop() {
Wire.beginTransmission(0x20); // Our device is on Address 0x20 Wire.write(0x0F); // This is equal to 0b00001111, meaning it will switch ports P0 to P3 High Wire.endTransmission(); delay(1000); Wire.beginTransmission(0x20); Wire.write(0xF0); // This is equal to 0b11110000, meaning it will switch ports P4 to P7 High Wire.endTransmission(); delay(1000); }
The code above will alternate between switching 4 ports high and low every one second. You can observe this by connecting 8 LEDs through 330ohm resistors to ports P0 through P7
Reading the status of a port (meaning that you configured it as an input) can be done using the following code
#include<Wire.h>
void setup() { Serial.begin(9600); Wire.begin(); Wire.beginTransmission(0x20); Wire.write(0x00); //LED1 is OFF Wire.endTransmission(); }
void loop() { Wire.requestFrom(0x20, 4); // Read the state of P4 byte x = Wire.read(); if (bitRead(x, 4) == LOW) { Wire.beginTransmission(0x20); Wire.write(0x01); //LED1 is ON Wire.endTransmission(); } else { Wire.beginTransmission(0x20); Wire.write(0x00); //LED1 is OFF Wire.endTransmission(); } delay(1000); }
This code assumes that you have connected a LED throught a resistor to P0, and that you have connected a pullup resistor of 10k to P4, with a pushbutton to GROUND.
The LED should switch on when you press the switch, and go off again once you release it.
If you want to use the special library, you can download it below:
There will come a time that you will run out of available input or output pins on your Arduino/ESP32 or STM32 device. Today, I will show you one way to work around this problem and how to add additional input and/or outputs to your device.
There are many ways to do this, the easiest of them being adding some sort of i2c chip (the Waveshare PCF8574 IO Expansion Board is a good example).
This particular device can be cascaded to provide up to 64 IO ports on the i2c bus.
At Maker and IoT Ideas, we would however like to show you electronics that you can build yourself, or stuff that have not already been made up into some kind of commercial project.
So, keeping this DIY attitude going, I will teach you how to use a shift register today.
Before we do that, we have to look at what a shift register is, and how they work…
A shift register, at its basic level, is actually just a series of D Type Flip-Flops.
D Type Flip Flop
These flip flops are connected together to give this
Parallel in, Serial out Shift Register
There are three basic types of Shift Register – Serial In, Serial Out (SISO) – Serial In, Parallel Out (SIPO) and – Parallel In, Serial Out (PISO)
We can see that they these type of shift registers are mainly used to convert between an serial and parallel data interface.
Serial In, Serial Out ( SISO)
This is the easiest configuration for a shift register. It is basically just a row of flip flops, with the output of the first, connected to the input of the next… and so on. This type of shift register is mainly used to introduce a delay into the data stream. This means that for a 8 bit SISO Shift register, the first data will only appear at the output after 8 clock cycles !
Serial In, Parallel Out (SIPO)
This kind of Shift Register has the same configuration as the SISO type, but it differs in that there is output after every flip-flop. That makes this type of shift register a good choice to use to extend the outputs on a microcontroller like Arduino or ESP32. The downside of using a shift register as a parallel output device is that the outputs will be slightly slower than if you used the native outputs on the microcontroller.
Parallel In, Serial Out (PISO)
A Parallel In, Serial out shift register can be used to read inputs from buttons or other digital devices. These inputs are then serially shifted into a serial pin on the microcontroller to be processed. It is also slightly slower than if you used the native inputs on the microcontroller.
Universal Shift register
You are also able to use a universal shift register. These chips can be used as both inputs and outputs. They are however only available in a 4 bit configuration.
Example using Arduino with 74HC595n SIPO Shift Register
We will look at an example to connect the 74HC5959N to Arduino to drive eight (8) LEDs. This example can be adapted to drive other loads as well by using a small BJT transistor and current limiting resistor instead of the LED
74hc595n Pin Number
Description and Connection
Q0…Q7 (15,1,2,3,4,5,6,7)
Parallel outputs of the shift register to write up to 8 signals with only 3 pins on your Arduino or ESP32 microcontroller
GND (8)
Connect to the ground on the microcontroller
VCC (16)
Connect to 3.3V or 5V on the microcontroller
DS (14)
Serial data input has to be connected to the microcontroller (in this example D4)
OE (13)
Output enable input do we not need and connected to ground
STCP (Latch) (12)
Storage register clock input has to be connected to the microcontroller (in this example D5)
SHCP (11)
Shift register clock input has to be connected to the microcontroller (in this example D6)
MR (10)
Master reset connected to VCC because is active with LOW and we do not want to reset the register
Q7S (9)
Serial data output not needed and therefore not connected
Connections for 74HC595n to Arduino
The operation of the 74hc595n SIPO Shift Register can easily be explained in three steps:
The latch (STCP pin) is pulled LOW because the data is only stored in the register on a LOW to HIGH transition of this pin.
Data is shifted out to the register with the data pin (DS) and with a LOW to HIGH transition of the clock signal (SHCP).
The latch (STCP pin) is pulled HIGH to save the data in the register.
Make the following connections to your Arduino and Breadboard ( we will use Arduino Nano today, but you can use the same pins and code for Arduino Uno )
Breadboard Layout for 74HC595 Shift Register as Output Extender with Arduino NanoSchematic Diagram for using 74HC595 Shift Register as Output Extender with Arduino Nano
Double-check all your connections, and then you can start the coding. The code will be much easier than you may think, as there is already a builtin function in the Arduino C language that we will use to shift the data out to the register.
// Define the Control Pins for the register int latch-Pin = 5; int clock-Pin = 7; int data-Pin = 6;
In this example, we output a HIGH to each led in turn, shifting from 0 to 7.
I hope that this will make sense to everybody, and be useful. Questions and comments are welcome. Next time, we will look as using a PISO Shift register to extend the inputs on you Arduino/ESP32/STM32