I have developed a lot of IoT prototypes so far, then I have observed that most of my IoT projects require a communication protocol for wired sensor networking, satisfiying the requirements below:
- low power consumption and lower voltage (5V or 3.3V)
- bus topology (daisy-chain) rather than hub and spoke (star)
- two-wire or one-wire
- cheap (<$10 per node on average) and open
- small software footprint
There are a lot of such technologies for in-vehicle network (CAN/LIN), buidling management (BACnet) or factory automation (PROFINET), but none of them satisfies all the requirements above.
This is a project to develop a networking protocol and building blocks for local wired sensor network.
The network is composed of multiple nodes(blocks) and one scheduler.
-----+---------------------+---------------------------+-------- I2C bus
| | |
+------|-----+ +------|-----+ +------|-----+
| [node] | | [node] | | [node] |
| | | | | | | | | ( )
| [sensor] | | [sensor] | | +------------[IoT GW(*1)]---( Cloud )
+------------+ +------------+ . . . +------------+ ( )
block block scheduler
(slave) (slave) (master)
(*1) I use Node-RED (on RasPi or PC) and Android as IoT gateways.
Note: I am going to support CAN bus as well.
All the blocks developed in this project support Plug&Play protocol that runs on UART.
USB hub
+---+
[block A]--UART/USB--| |
[block B]--UART/USB--| |--USB--[IoT GW]
[block C]--UART/USB--| |
+---+
hub&spoke topology
It also runs on I2C.
<- - - - - I2C backplane - - - - ->
[block A]---[block B]---[block C]---[Scheduler]--UART/USB--[IoT GW]
bus topology (daisy-chain)
I use PIC16F1829/PIC16F1825 that satisfies the requirements of this project.
Clock speed:
- 4MHz typical
- 32MHz (8MHz w/ PLL) for high sampling rate
The base board below is a common hardware part of node:
One I2C master and three I2C slaves are connected with each other via backplane bus on the back of base board
A similar construct to the above, but all the boards are connected with each other in a daisy-chain manner:
I use Microchip's MPLAB-X IDE. I also use MPLAB Code Configurator (MCC) to automatically generate code for EUSART, I2C(master/slave), ADC, Timer etc. I modify the generated I2C slave code to support Plug&Play protocol.
Plug&play protocol specification
Some blocks operates in pubsub mode -- how it works.
All nodes need to import this protocol library:
I2C slaves also require I2C-slave-specific code -- I modified MCC-generated I2C slave code (i2c1.c) to support the protocol on I2C slave side. See this modifed code: i2c1.c.
The following is an example of main routine:
void main(void)
{
// Protocol initialization
PROTOCOL_Initialize(DEVICE_ID, NULL, NULL, NULL, inv_handler, 250);
// avoid using SYSTEM_Initialize() automatically generated by MCC,
// because I2C1_Initialize() must be last in the initialization order
PIN_MANAGER_Initialize();
OSCILLATOR_Initialize();
WDT_Initialize();
ADC_Initialize();
TMR0_Initialize();
EUSART_Initialize();
I2C1_Initialize();
// Enable interrupt
INTERRUPT_GlobalInterruptEnable();
INTERRUPT_PeripheralInterruptEnable();
// Infinite loop
PROTOCOL_Loop();
}
In this project, PIC16F1829 MCU is used for general-purpose blocks such as a scheduler or LCD controller.
- 5V: Scheduler (BACKPLANE-MASTER)
- 5V: Character LCD actuator block (AQM1602XA-RN-GBW)
- 5V: Acceleration sensor block (KXR94-2050)
- 5V: Speed sensor block (A1324LUA-T)
- 5V: Temperature and humidity sensor block (HDC1000)
- 5V: Position detector block
In this project, PIC16F1825 MCU is used for purpose-specific blocks such as a position detector having multiple analog ports.
A typical usage of the position detector is to detect a position of a moving object such as a doll on a catwalk miniature (not a belt conveyer).
Example of its usage
#WHO
$:WHO:MULTI_A1324LUA_T
#MAP
$:MAP:21,22
#RSC
$:RSC:0,0,0,0|0,0,0,0|0,0,0,0|0,0,0,0|0,0,0,0|0,0,0,0|0,0,0,0
#POS:0
#WSC:21
#POS:1
#WSC:22
#RSC
$:RSC:21,22,0,0|0,0,0,0|0,0,0,0|0,0,0,0|0,0,0,0|0,0,0,0|0,0,0,0
#I2C:21
#WHO
$:WHO:21
#SET:15
#I2C:22
#SET:9
#I2C:1
#STA
%21:UINT8_T:0,1,0,0
%21:UINT8_T:0,0,0,0
%21:UINT8_T:0,0,0,1
%21:UINT8_T:0,0,0,0
%21:UINT8_T:0,0,0,1
%21:UINT8_T:0,0,0,0
%21:UINT8_T:0,1,0,0
%21:UINT8_T:0,0,0,0
%21:UINT8_T:1,0,0,0
%21:UINT8_T:0,0,0,0
%21:UINT8_T:0,1,0,0
%21:UINT8_T:0,0,0,0
%21:UINT8_T:0,0,0,1
%21:UINT8_T:0,0,0,0
%21:UINT8_T:0,0,1,0
%21:UINT8_T:0,0,0,0
%22:UINT8_T:0,0,0,1
%22:UINT8_T:0,0,0,0
%22:UINT8_T:1,0,0,0
%22:UINT8_T:0,0,0,0
Write I2C slave address on the blocks. For exmaple, if the address is 16 in decimal, then:
#WDA:16
#RDA
$:RDA:16
#WHO
$:WHO:BACKPLANE-MASTER
#SCN
#MAP
$:MAP:16,17,19
$:RSC:0,0,0,0|0,0,0,0|0,0,0,0|0,0,0,0|0,0,0,0|17,0,0,0|0,0,0,0
#POS:12
#WSC:19
#RSC
$:RSC:0,0,0,0|0,0,0,0|0,0,0,0|19,0,0,0|0,0,0,0|17,0,0,0|0,0,0,0
#STA
%17:UINT16_T:0
%19:FLOAT:-0.07,-0.08,0.94
%19:FLOAT:-0.05,-0.06,0.94
%19:FLOAT:-0.07,-0.06,0.94
%19:FLOAT:-0.06,-0.07,0.93
%19:FLOAT:-0.07,-0.08,0.94
%19:FLOAT:-0.05,-0.09,0.94
%19:FLOAT:-0.06,-0.09,0.94
%19:FLOAT:-0.05,-0.08,0.93
%19:FLOAT:-0.07,-0.08,0.93
%19:FLOAT:-0.06,-0.07,0.94
%19:FLOAT:-0.07,-0.07,0.94
%19:FLOAT:-0.06,-0.07,0.93
%19:FLOAT:-0.07,-0.08,0.93
:
#I2C:16
$:WHO:16
#CLR
#LED:ON
#LED:OFF
#STR:Hello World!
#NWL
#STR:Guten Tag!
#I2C:1
:
#STP
*:STP:ACK
Use the CLI to control the scheduler or stream sensor data to the cloud.
- Python: pySerial
- Node.js: serialport
- Java/Android: D2XX driver
In some projects, I used telephone line (6P4C) with RJ11 moduler plug/jack, as I2C bus. I used this tool to make wires among nodes: Crimper for RJ11. Telephone line makes physical wirling very easy.
6P4C telephone line is suitable for I2C with power line: SDA, SCL, 5V, GND.