Today we’ll expand Arduino’s digital resources thanks to an I2C bus equipped shield and we’ll allow the management of the board via a bluetooth connection RN-42 through an Android systems.
All Arduino boards feature a number of digital I/Os. For the simplest projects, such resources are usually more than sufficient, but in those where they you need several control lines, “standard” I/Os can be less than enough, because some pins are shared with internal resources while others are dedicated to external shields.
In these cases, a possible solution is to switch to more powerful Arduinos (for example, the Mega, which has more I/Os than the classic Duemilanove or Uno) or use special expansion shield. In this article, we present one shield that allows you to add I/Os that can be handled very simply via an I²C bus data channel. The shield is basically what we call “I/O expander”. I²C bus management is provided by MCP23017 integrated circuit manufactured by Microchip.
The bus is made of three wires: one is the (common) ground while the other two are SCL (a clock that marks the communication) and SDA (Bi-directional serial data). In the I²C-Bus protocol the beginning of each communication session comes from a Master unit (Slaves can only reply to the Master), which sends 8 bytes commands, one of which contains the address of the Slave which is directed to. Since the address is made by one byte, the I²C-Bus could theoretically support 128 devices but you can only use 112, since 16 addresses are reserved. The identification of the individual slave units is usually done by setting the appropriate combination logic on the lines for which each integrated is provided: these lines are usually three allowing 8 combinations.
In our case, the ability to define the destination of the I²C-Bus commands allows us to connect several I²C I/O Expander board at the same time by stacking them one on top of the other. Each expansion board has 8 relay outputs and as many digital inputs, the I²C address of the MCP23017 chip can be selected from eight possible, so you can mount eight shield, until a total of 64 relay outputs and 64 digital inputs .
On top of this smart system we decided to add Bluetooth control, in order to manage it from a smartphone. To be super cool, we added our Bluetooth RN-42 shield, and we developed a special app for Android that allows you to view the status of all digital resources and send commands to activate outputs.
Being the overall system modular (you can add and remove Expander shields at will) it lends itself to different end-user applications. Both the Arduino firmware and the App will adapt: the firmware is indeed able to detect how many (and which) Expander shields are present while the App receives such information from Arduino and consequently adapt its own graphical user interface.
The App has a special configuration page that makes possible to set text labels to be used for the description of the I / O resources, thus adapting to your particular hardware configuration. Finally, there is a bluetooth setup page where you can set your name and pin code to be matched to the RN-42 shield.
Wiring Diagram of the I2C I/O Expander Shield
The circuit diagram of a single expansion shield has been developed around the U1 component, namely Microchip’s MCP23017. Find more info in the previous post.
Outputs end on U2, the ULN2803, specially designed to drive inductive loads such as relay coils (in fact, has several transistor stages with protection diodes of the base-collector junction).
Inputs (B port) are connected to appropriate circuit sections which carry the digital inputs. Each input has a protection diode, a pull-up resistor, and an LED that indicates the status. When the input is logically low (to ground) the corresponding LED is lit, and the I/O Expander shows that the input is “0”, whereas, when the input is high, the LED is off and the I/O Expander indicate that the input is “1”.
MCP23017 management happens though the I²C Bus protocol and by reading and writing specific registers. The SDA and SCL lines are available on pins 13 and 12, which, as you see in the wiring diagram, are taken to the corresponding pins of the Arduino board. As the MCP23017 has the ability to generate an interrupt when at least one pin programmed as input changes state, we used this function to handle inputs from the Arduino in interrupt mode instead of polling (thus being faster and without burdening the I²C bus). The interrupt allows you to initiate a connection, with the the Arduino operating as the Master unit. Clearly, as we’ll see later, the software must be specially crafted to take advantage of this feature.
Thanks to a jumper we left the possibility of bringing the MCP23017 interrupt pin (INTB, 19) as input on 2 different Arduino pins (D2 or D4) to fit as much as possible to the actual use.
MCP23017’s I2C address is selected via SW1 dip-switch: 3 dips are present therefore it is possible to connect up to 8 different shield without interfering with each of them.
Finally, there is a power supply section composed by the regulator U3 (integrated L78L05) which transforms the input voltage Vin to 5 volts needed to operate the entire circuit. Through the JP5V bridge you can choose to bypass the regulator but directly use the 5V supplied by the Arduino board.
The I2C I/O Expander Shield Arduino Library
We developed an ad hoc Arduino software library that provides all the routines needed for the detection of connected shields and I /O management.
The communication with the MCP23017 is based on the I2C Bus, so the library uses “Wire.h”. A function called “begin(int i2cAddress)” is available to initialize the single shield identified by an I2C address. Furthermore you have a “init()” to properly program the internal registers of the chip according to your needs and finally the “pinMode (int pin, int mode)” is to indicate whether the individual pins of I/O are inputs or outputs.
Besides the initialization functions, particularly interesting instructions are the “digitalRead (int pin)”, “digitalWrite (int pin, int val)”, “digitalWordRead ()” and “digitalWordWrite (word w)”, which respectively allow you to read the state of a single input pin, write a single output pin, read the status of all input pins (8 in our case), and finally write the status of all output pins (always 8).
As mentioned above, the management of the input is done via an interrupt, therefore this is a special function “pinDisableINT (int pin)” that allows you to set (or not to set) the pin as a single interrupt generator (in certain applications it may be useful to have the option not set all the input pins as interrupt generators but do it selectively)
The Arduino RN-42 Shield and library
The shield that makes the bluetooth connection possible is based on the Roving Networks RN-42, module. You can find the complete description of this module in a previous post here on this blog.
The Arduino firmware
Having previously defined the software library for the management of I/O Expander and Bluetooth shields, creating Arduino software is easier and straightforward.
Arduino’s CPU is responsible for managing both the I2C communication with the inputs and outputs (read/write logic state configuration) and the serial communication with the RN-42 (new connections or disconnections requests and data transmission protocol).
The Android Software
The Software developed for Android smartphones (“ShieldIOControl”) allows you to connect and remotely manage the system: you can check the current status of all digital inputs, realize the state of the outputs (ON or OFF) and change the value to suit your needs. The display of different measured shield is managed by pages and you can “browse” through the different pages thanks to two buttons.
Graphical labels that identify the various I/O and their status descriptions can be configured by software and saved so that they are restored to the subsequent executions. We point out, however, that these settings are stored in the smartphone and not in the PCB (it would take too many bytes of EEPROM), so if you use 2 or more smartphones for the management of electronics, you must run the configuration on both ends.
At start-up, after an initial presentation screen, the app starts scanning and detecting all bluetooth devices present within the coverage area. In the list that appears all systems already paired and the new detected are shown. By clicking on the single board label (“BTIOControl” in our example), you select it and require to start the connection. A button to request a new execution of the scan and update the list s also available.
At this point if it is the first time that the device is detected, you are asked to enter the PIN code (“1234” by default; Screenshot_2_Articolo image). Later you switch to the main screen of the program: starting from the top you see the number of shield shown, the status of the 8 relay outputs and 8 digital inputs. Next to the label that identifies the shield are two buttons to switch to the previous and next shield.
For each output the following convention is used: on the extreme left is the text label that identifies the resource, then it is indicates the current status (always via text label) and then right-most button can be used to change the current status. Whether the output is on or off the text label is updated (ON or OFF in our example) and the button is enabled.
For each digital input is instead present only a single text label showing the current status: ON in our example in the case in which the digital input is high; OFF otherwise.
Coming back to outputs, to request the change of the current state you simply click on the appropriate button: at this point the selected command is sent to the card and, upon completion, the graphical user interface is updated.
During normal operation, a refresh timer helps the app to cyclically connect to the board, read the current status and update the graphical interface of all the shields.
By choosing Android’s “menu” button, the configuration menu pops up consisting of two buttons: “BT Config” allows to select the configuration of the bluetooth boad and “Text Config” allows to configure the text labels.
In the first configuration page there are 2 configuration sections “System Name” and “PIN code”: each section has a text field to edit and a button to confirm the configuration.
On the second configuration page, you can setup eight text labels, descriptive of each output; two more to identify the state of the outputs, and finally an additional two labels are matched to the two-state inputs. On the right, a button helps reset al the default configurations, while on the left a “OK” button confirms the entered values.
Mounting on the Arduino Uno
In case you want to implement the project presented today using an Arduino Uno (the simplest but also the more widespread version) we highlight that Arduino Uno early versions used the A4 and A5 pins for the I2C bus (SDA and SCL signal). Starting from Rev. 3 2 pins have been added just for the communication channel but the designers also left, however, pins A4 and A5 connected to the bus.
As we saw in the post Arduino’s CPU communicates with the I/O Expander shield by using the I2C bus while the RN-42 module of the bluetooth shield has some GPIO; 3 of these are brought towards Arduino (in particular the GPIO9 refers to pin A4).
We can easily understand that this would generate an incompatibility on pin A4 (which would be connected to both the I2C bus to the MCP23017 and the GPIO9 of the RN-42): this problem would affects the proper functioning of the board, indeed, at the startup of the same, the I2C bus would be blocked and therefore the software would not run correctly.
The solution to this problem is, when stacking the shields, to add the Bluetooth shield as the last on (above all also to avoid communication interference), and, on this shield, leaving the pin that corresponds to Arduino A4 floating (meaning not plugged into the corresponding female strip; refer to the mounting plane for an image that is explanatory of the final result you should aim for).
In this way the Arduino One is able to communicate with the MCP23017 via I2C bus and with the bluetooth RN-42 via the serial port (clearly the GPIO9 may not be used or, at least, connected with Arduino).
I think you are a genuis. The idea in your post is quite helpful and lights me. I have been puzzled for a long time in my new project.