The Multiprotocol Radio Shield is an interconnection shield for Arduino, and was designed to connect two communication modules at the same time. This that means a lot of possibilities and applications can be made using the cooking-hacks modules. The Multiprotocol Radio Shield includes the SPI bus connections that allows the use of the RS-485, CAN Bus, LoRa modules and LoRaWAN, but also is compatible with the rest of the cooking-hacks modules as RFID, XBee or Bluetooth.
As an example in the pictures below we can see several examples of double radio integration: RS232 + Bluetooth (left), RS485 + RFID (center), Can Bus + 802.15.4 / ZigBee (right).
Let's summarize what we can do using this shield:
The Multiprotocol Radio Shield includes two sockets. In these two sockets can be connect any module that uses UART. As for using SPI modules, there are two possibilities. If SPI uses 3V3 voltage levels, you must connect it in the SOCKET1, and if it uses 5V levels, in SOCKET0.
Version 2 of the shield:
The Multiprotocol Radio Shield can be powered by the PC or by an external power supply. Some of the USB ports on computers are not able to give all the current the module needs to work, if your module have problems when it work, you can use an external power supply (12V - 2A) on the Arduino.
The Multiprotocol Radio Shield v2 counts with a C++ library that lets you manage the shield in a simple way. This library offers a simple-to-use open source system.
The Multiprotocol Radio Shield v2 includes a high level library functions for an easy manage. Before start using this functions you should download the library. The next zip includes all the files needed in a folder.
Download the Multiprotocol Radio Shield v2 Libraries for Arduino.
Libraries are often distributed as a ZIP file or folder. The name of the folder is the name of the library. Inside the folder will be the .cpp files, .h files and a examples folder.
To install the library, first quit the Arduino application. Then uncompress the ZIP file containing the library. For installing libraries, uncompress zip file. It should contain a folder called multiprotocolShield. Drag this folder into your libraries folder. Under Windows, it will likely be called "My Documents\Arduino\libraries". For Mac users, it will likely be called "Documents/Arduino/libraries". On Linux, it will be the "libraries" folder in your sketchbook.
The library won't work if you put the .cpp and .h files directly into the libraries folder or if they're tested in an extra folder. Restart the Arduino application. Make sure the new library appears in the Sketch->Import Library menu item of the software.
The main functions are listed here:
disableMUX(); //Disables the multiplexor ON(); //Switches ON the power supply of the SOCKET1 OFF(); //Switches OFF the power supply of the SOCKET1 setMUX(); //Configures the multiplexor in the SOCKET1 setCS(); //Enables the SPI of the SOCKET1 (5V Level) unsetCS(); //Disables the SPI of the SOCKET1
The Multiprotocol Radio Shield includes SPI bus connection in the two sockets, but the voltage levels of the sockets are not the same. The SOCKET0 of the Multiprotocol Radio Shield uses 5V voltage levels and the SOCKET1 uses 3V3 voltage levels.
These two sockets use different selection pins. The selection pin enables the communication with the module and must be configured previously as an OUTPUT. In the RS-485 and CAN Bus modules, this configuration is made in the library.
In this part of the tutorial we are going to connect two UART modules to see how to use the Multiprotocol Radio Shield multiplexer and how to combine two communication protocols. The modules used are the XBee 802.15.4 module and the RFID13.56 MHz module. We are going to connect the RFID module in the SOCKET0 and the XBee module in the SOCKET1. (In this case, doesn't matter where are connected).
We have divided the code in two parts. The first part reads the UID code of the RFID 13.56 MHz tag, and the second part, sends the UID trough the XBee 802.15.4 module.
In your gateway you should view the response of the module.
/* * Multiprotocol Radio Shield with RFID/NFC 13.56MHz * * Copyright (C) Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * a * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * Version: 1.1 * Design: David Gascón * Implementation: Ahmad Saad */ #include <multiprotocolShield.h> #include <Wire.h> #include <MCP23008.h> uint8_t dataRX[35];//Receive buffer. uint8_t dataTX[35];//Transmit buffer. uint8_t _UID[4]; // stores the UID (unique identifier) of a card. uint8_t blockData[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };//Data to write (16 bytes). uint8_t keyAccess[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} ;// stores the key or password. uint8_t address = 0x04;//Address to read. uint8_t ATQ[2];//Answer to request uint8_t state;//state of the process uint8_t aux[16];//Auxiliary buffer. void setup() { //Start serial port 115200 bps: Serial.begin(115200); delay(100); Serial.print("RFID/NFC @ 13.56 MHz module started"); delay(1000); socket0.ON(); // <------RFID SOCKET delay(100); socket0.setMUX(); // <------ Configure the MUX at MUX0 //! It is needed to launch a simple command to synchronize getFirmware(); configureSAM(); } void loop() { // Read the RFID TAG readTAG(); delay(1000); sendXBee(); delay(1000); } //********************************************************************** void sendXBee() { socket1.ON(); delay(100); socket1.setMUX(); // <------ Configure the MUX at MUX0 Serial.begin(9600); delay(1000); Serial.print( "The Card NUID : "); print(_UID , 4); Serial.print("\n"); Serial.print("Data read : "); print(aux , 16); Serial.print("\n"); delay(1000); Serial.begin(115200); delay(100); socket0.setMUX(); // <------ Configure the MUX at MUX0 } //********************************************************************** void readTAG() { socket0.setMUX(); // <------ Configure the MUX at MUX0 delay(100); Serial.print("\n"); Serial.println("Ready to read..."); ///////////////////////////////////////////////////////////// //Get the Card Identifier init(_UID, ATQ); Serial.print("\n"); Serial.print( "The Card NUID : "); print(_UID , 4); ///////////////////////////////////////////////////////////// //Authenticate a block with his keyAccess state = authenticate(_UID, address, keyAccess); Serial.print("\n"); if ( state == 0) { Serial.println("Authentication block OK"); } else { Serial.println("Authentication failed"); } ///////////////////////////////////////////////////////////// //Write blockData in a address, after authentication. if ( state == 0 ) { state = writeData(address, blockData); Serial.print("\n"); if ( state == 0) { Serial.println("Write block OK"); } else { Serial.println("Write failed"); } ///////////////////////////////////////////////////////////// //Read from address after authentication state = readData(address, aux); Serial.print("\n"); if (state == 0) { Serial.println("Read block OK"); } else { Serial.println("Read failed"); } Serial.print("Data read : "); print(aux , 16); Serial.print("\n"); } delay(2000); } //********************************************************************** //!The goal of this command is to detect as many targets (maximum MaxTg) // as possible in passive mode. uint8_t init(uint8_t *UID , uint8_t *ATQ) //! Request InListPassive { Serial.flush(); dataTX[0] = 0x04; // Length lengthCheckSum(dataTX); // Length Checksum dataTX[2] = 0xD4; dataTX[3] = 0x4A; // Code dataTX[4] = 0x01; //MaxTarget dataTX[5] = 0x00; //BaudRate = 106Kbps dataTX[6] = 0x00; // Clear check Sum position checkSum(dataTX); sendTX(dataTX , 7 , 23); for (int i = 17; i < (21) ; i++) { _UID[i - 17] = dataRX[i]; UID[i - 17] = _UID[i - 17]; } ATQ[0] = dataRX[13]; ATQ[1] = dataRX[14]; if ((dataRX[9] == 0xD5) & (dataRX[10] == 0x4B) & (dataRX[11] == 0x01)) { return 0; } else { return 1; } } //********************************************************************** //!A block must be authenticated before read and write operations uint8_t authenticate(uint8_t *UID, uint8_t blockAddress, uint8_t *keyAccess) { dataTX[0] = 0x0F; lengthCheckSum(dataTX); dataTX[2] = 0xD4; dataTX[3] = 0x40; // inDataEchange dataTX[4] = 0x01; //Number of targets dataTX[5] = 0x60; // Authentication code dataTX[6] = blockAddress; for (int i = 0; i < 6 ; i++) { dataTX[i + 7] = keyAccess[i]; } dataTX[13] = UID[0]; dataTX[14] = UID[1]; dataTX[15] = UID[2]; dataTX[16] = UID[3]; dataTX[17] = 0x00; checkSum(dataTX); sendTX(dataTX , 18 , 14); if ((dataRX[9] == 0xD5) & (dataRX[10] == 0x41) & (dataRX[11] == 0x00)) { return 0; } else { return 1; } } //********************************************************************** //!Write 16 bytes in address . uint8_t writeData(uint8_t address, uint8_t *blockData) //!Writing { Serial.print(" "); dataTX[0] = 0x15; lengthCheckSum(dataTX); // Length Checksum dataTX[2] = 0xD4; dataTX[3] = 0x40; //inDataEchange CODE dataTX[4] = 0x01; //Number of targets dataTX[5] = 0xA0; //Write Command dataTX[6] = address; //Address for (int i = 0; i < 16; i++) { dataTX[i + 7] = blockData[i]; } dataTX[23] = 0x00; checkSum(dataTX); sendTX(dataTX , 24 , 14); if ((dataRX[9] == 0xD5) & (dataRX[10] == 0x41) & (dataRX[11] == 0x00)) { return 0; } else { return 1; } } //********************************************************************** //!Read 16 bytes from address . uint8_t readData(uint8_t address, uint8_t *readData) //!Reading { Serial.print(" "); dataTX[0] = 0x05; lengthCheckSum(dataTX); // Length Checksum dataTX[2] = 0xD4; // Code dataTX[3] = 0x40; // Code dataTX[4] = 0x01; // Number of targets dataTX[5] = 0x30; //ReadCode dataTX[6] = address; //Read address dataTX[7] = 0x00; checkSum(dataTX); sendTX(dataTX , 8, 30); memset(readData, 0x00, 16); if ((dataRX[9] == 0xD5) & (dataRX[10] == 0x41) & (dataRX[11] == 0x00)) { for (int i = 12; i < 28; i++) { readData[i - 12] = dataRX[i]; } return 0; } else { return 1; } } //********************************************************************** //!The PN532 sends back the version of the embedded firmware. bool getFirmware(void) //! It is needed to launch a simple command to synchronize { Serial.print(" "); memset(dataTX, 0x00, 35); dataTX[0] = 0x02; // Length lengthCheckSum(dataTX); // Length Checksum dataTX[2] = 0xD4; // CODE dataTX[3] = 0x02; //TFI checkSum(dataTX); //0x2A; //Checksum sendTX(dataTX , 5 , 17); Serial.print("\n"); Serial.print("Your Firmware version is : "); for (int i = 11; i < (15) ; i++) { Serial.print(dataRX[i], HEX); Serial.print(" "); } Serial.print("\n"); } //********************************************************************** //!Print data stored in vectors . void print(uint8_t * _data, uint8_t length) { for (int i = 0; i < length ; i++) { Serial.print(_data[i], HEX); Serial.print(" "); } Serial.print("\n"); } //********************************************************************** //!This command is used to set internal parameters of the PN532, bool configureSAM(void)//! Configure the SAM { Serial.print(" "); dataTX[0] = 0x05; //Length lengthCheckSum(dataTX); // Length Checksum dataTX[2] = 0xD4; dataTX[3] = 0x14; dataTX[4] = 0x01; //Normal mode dataTX[5] = 0x14; // TimeOUT dataTX[6] = 0x00; // IRQ dataTX[7] = 0x00; // Clean checkSum position checkSum(dataTX); sendTX(dataTX , 8, 13); } //********************************************************************** //!Send data stored in dataTX void sendTX(uint8_t *dataTX, uint8_t length, uint8_t outLength) { Serial.print(char(0x00)); Serial.print(char(0x00)); Serial.print(char(0xFF)); for (int i = 0; i < length; i++) { Serial.print(char(dataTX[i])); } Serial.print(char(0x00)); getACK(); waitResponse(); // 1C - receive response getData(outLength); } //********************************************************************** //!Wait for ACK response and stores it in the dataRX buffer void getACK(void) { delay(5); waitResponse(); for (int i = 0; i < 5 ; i++) { dataRX[i] = Serial.read(); } } //********************************************************************** //!Wait the response of the module void waitResponse(void) { int val = 0xFF; int cont = 0x00; while (val != 0x00) { val = Serial.read(); delay(5); cont ++; } } //********************************************************************** //!Get data from the module void getData(uint8_t outLength) { for (int i = 5; i < outLength; i++) { dataRX[i] = Serial.read(); // read data from the module. } } //********************************************************************** //!Calculates the checksum and stores it in dataTX buffer void checkSum(uint8_t *dataTX) { for (int i = 0; i < dataTX[0] ; i++) { dataTX[dataTX[0] + 2] += dataTX[i + 2]; } byte(dataTX[dataTX[0] + 2] = - dataTX[dataTX[0] + 2]); } //********************************************************************** //!Calculates the length checksum and stores it in the buffer. uint8_t lengthCheckSum(uint8_t *dataTX) { dataTX[1] = byte(0x100 - dataTX[0]); }
The Multiprotocol Radio Shield has been designed to be used with the new industrial protocols modules. Some of these board uses SPI communication. The SPI port allows more speed communication and frees up the Arduino's UART for other purposes. In this part of the tutorial we are going to connect the RS-485 board (Modbus protocol) and send data wirelessly using XBee 805.15.4 modules.
This sketch shows how to send data through RS-485 standard. This standard defines the electrical characteristics of drivers and receivers for use in digital systems. It does not specify or recommend any communications protocol. For a complete communication protocol, please see the Modbus examples.
/* * Multiprotocol Radio Shield with RS-485 ModBus * * Copyright (C) Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * a * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * Version: 1.1 * Design: David Gascón * Implementation: Ahmad Saad */ // Include always this library when you are using the RS-485 functions #include <RS485.h.h> #include <multiprotocolShield.h.h> #include <Wire.h.h> #include <MCP23008.h.h> //Include the SPI library #include <SPI.h.h> // Create an instance RS485 myDevice = RS485(); void setup() { // Power on the USB for viewing data in the serial monitor Serial.begin(9600); delay(10); // Initializes the module and assigns the SPI if ( myDevice.begin() == 0) { Serial.println("RS-485 module started successfully"); } else { Serial.println("RS-485 did not initialize correctly"); } delay(100); // Configure the baud rate of the module myDevice.baudRateConfig(9600); // Configure the parity bit as disabled myDevice.parityBit(DISABLE); // Use one stop bit configuration myDevice.stopBitConfig(1); // Print hello message Serial.println("Hello this is RS-485 communication send data example."); delay(100); } void loop() { // Reading the analog input 1 int analog1 = analogRead(A1); //Reading the analog input 2 int analog2 = analogRead(A2); // Send data through RS-485 line myDevice.send("Data from analog1 input: "); myDevice.send(analog1); myDevice.send("\n"); myDevice.send("Data from analog2 input: "); myDevice.send(analog2); myDevice.send("\n"); delay(10); socket0.ON(); delay(100); socket0.setMUX(); delay(100); Serial.println(F("Data: 0 1 2 3 4 5 6 7 8 9 0 a b c d e f g h i j k l m n o p q r s t u v w x y z")); delay(100); }
If you are interested in Internet of Things (IoT) or M2M projects check our open source sensor platform Waspmote which counts with more than 100 sensors available to use 'off the shelf', a complete API with hundreds of ready to use codes and a low consumption mode of just 0.7µA to ensure years of battery life.
Know more at:
Get the Starter Kits at: