--- title: Networking and Communications description: Autors: FLU --- ###### tags: `FabAcademy` `FLU` `Future Learning Unit` `Fab Lab Barcelona` `MDEF` [TOC] # Day 1: Networking and communication ## Overview - Wired communication - Intro - Asynchronous communication - RX/TX - V-USB - Synchronous communication - I2C - SPI - OTA communication - Bluetooth - NRF24 high rf 2.4ghz - HC-12 low rf 400mhz - Wifi - Wifi openfrecuency - Selection criteria [Neil's class](http://academy.cba.mit.edu/classes/networking_communications/index.html) ## Wired communication :::warning This introduction is a quick reminder of the contents seen in [the electronics basics page](http://fab.academany.org/2019/labs/barcelona/local/clubs/electroclub/electronics2/). ::: There are quite a few wired protocols in which microcontrollers can talk to one another. Before digging into them, it is important to understand the differences between their characteristics. **Serial vs. Parallel** **Parallel interfaces** transfer multiple bits at the same time. They usually require buses of data - transmitting across eight, sixteen, or more wires. This means that waves of data can be sent, with high speeds, but with a lot of wires. ![](https://cdn.sparkfun.com/r/700-700/assets/c/a/c/3/a/50e1cca6ce395fbc27000000.png) _Image source: Sparkfun_ :::info "Have you seen this?" Many printers use parallel communication before the advent of serial communication! ![](https://upload.wikimedia.org/wikipedia/commons/thumb/f/f4/Mini-Centronics_36_pin_with_Micro-Centronics_36_pin.jpg/440px-Mini-Centronics_36_pin_with_Micro-Centronics_36_pin.jpg) ::: **Serial interfaces** stream their data with a reference signal, one single bit at a time. These interfaces can operate on as little as one wire, usually never more than four: ![](https://cdn.sparkfun.com/r/700-700/assets/e/5/4/2/a/50e1ccf1ce395f962b000000.png) _Image source: Sparkfun_ **Synchronous vs. Asynchronous** "Asynchronous" (not synchronous) means that data is transferred without support from an external clock signal. This transmission method is perfect for minimizing the required wires and I/O pins, but it does mean we need to put some extra effort into reliably transferring and receiving data. ![](https://i.imgur.com/mpK1muw.png) _Image source: Sparkfun_ "Synchronous" data interface always pairs its data line(s) with a clock signal, so all devices on a synchronous bus share a common clock. This makes for a more straightforward, often faster transfer, but it also requires at least one extra wire between communicating devices. ![](https://i.imgur.com/AWi49fR.png) _Image source: Sparkfun_ :::info Serial communication: [Learn more](https://learn.sparkfun.com/tutorials/serial-communication/all) ::: In this section, we will focus on **serial communication**, making distinction between *synchronous* and *asynchronous*. ### Asynchronous communication We use the asynchronous communication when data can be sent without timing constraints as well as _oftenly_ less speed, with the benefit of using one less wire, one less port on each side. The most well known asynchronous communication protocol is the RX/TX or simply Serial protocol (because it's the most important). #### RX/TX By RX/TX we know the most common way of serial communication. It requires only two wires, appart from a common ground: ![](https://cdn.sparkfun.com/r/700-700/assets/2/5/c/4/5/50e1ce8bce395fb62b000000.png) Data is sent asynchronously, so it means that both ends of the communication need to agree on some topics, being the speed the most important one (known as baud rate). We also have to agree on how long the data strings are. Generally, they are grouped by _bytes_, with some extras, like parity bits or and synchronisation bits (start and stop). Usually, an asynchronous serial communication frame consists of a START bit (1 bit) followed by a data byte (8 bits) and then a STOP bit (1 bit), which forms a 10-bit frame as shown in the figure below. The frame can also consist of 2 STOP bits instead of a single bit, and there can also be a PARITY bit after the STOP bit. ![](https://www.electronicwings.com/public/images/user_images/images/Raspberry%20Pi/RaspberryPi_UART/1_PIC18F4550_USART_Frame_Structure.png) :::info If you want to learn much more, you can visit [this tutorial](https://learn.sparkfun.com/tutorials/serial-communication/all) ::: **UART** UART stands for _Universal Asynchronous Receiver/Transmitter_ and is the piece of hardware in charge of managing the data. Microcontrollers might have one, many or none UARTs: ![](https://i.imgur.com/TBTOzT2.png) Sometimes it's also present in a hybrid way, as **UsART**, which implements both, synchronous and asynchronous communication. :::info Chips without UART still can implementing by bit-banging (using pins to send the data as voltage levels very quickly). The [SoftwareSerial](http://arduino.cc/en/Reference/SoftwareSerial) is for example used in this case. ::: **Libraries for Arduino** - [Serial](https://www.arduino.cc/reference/en/language/functions/communication/serial/) The most basic example of all time: ```arduino #include <Arduino.h> void setup() { Serial.begin(9600); // OR, in some boards like the arduino Zero: SerialUSB.begin(115200); while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only } } void loop(){ Serial.println("Hello Fabacademy"); } ``` - [SoftwareSerial](http://arduino.cc/en/Reference/SoftwareSerial) Example using both, serial and software serial, when we only have one hardware serial comm: ```arduino #include <SoftwareSerial.h> SoftwareSerial BT1(10, 11); // RX | TX void setup() { pinMode(8, OUTPUT); // Al poner en HIGH forzaremos el modo AT pinMode(9, OUTPUT); // cuando se alimente de aqui digitalWrite(9, HIGH); delay (500) ; // Espera antes de encender el modulo Serial.begin(9600); Serial.println("Levantando el modulo HC-06"); digitalWrite (8, HIGH); //Enciende el modulo Serial.println("Esperando comandos AT:"); BT1.begin(38400); } void loop() { if (BT1.available()) Serial.write(BT1.read()); if (Serial.available()) BT1.write(Serial.read()); } ``` **Libraries for Python** - [pyserial](https://pythonhosted.org/pyserial/) ```python import serial PORT = '/dev/cu.usbmodem1421' BAUDRATE = 115200 ser = serial.Serial(PORT, BAUDRATE) print ser.readline().replace("\r\n", "") ser.write('Hello') ``` #### V-USB [V-USB](https://www.obdev.at/products/vusb/index.html) is a library that allows to add USB connectivity to ATtiny microcontrollers (it was previously named tinyUSB). :::warning **USB 1.1** V-USB will create an USB 1.1 compliant low-speed device. ::: USB is comprised of 4 lines: Vcc, GND, D+ and D-. It is a [differential pair circuit](https://en.wikipedia.org/wiki/Differential_signaling) in which, **roughly**, the difference between D+ and D- is the actual signal we want to transmit. ![](https://www.electroschematics.com/wp-content/uploads/2010/01/usb-pinout.jpg) The **data lines require 3.3V**, and for that reason we need to limit the voltage coming from many USB ports (computers, chargers, etc). Some ways to do this: - Using an LDO in the Vcc - Using zener diodes in the D+, D- :::info **Great tutorials available h Find a quite nice tutorial for the hardware [here](https://codeandlife.com/2012/01/22/avr-attiny-usb-tutorial-part-1/) And the actual implementation of V-USB [here](https://codeandlife.com/2012/01/29/avr-attiny-usb-tutorial-part-3/) ::: ### Synchronous communication When timing and speed are are important, and it's worth having more wires, we will use _synchronous communication_. This means that we will have a clock line that stablishes the rate at which data is transferred. Most common inter-chip communication is implemented like this. ::: danger **Very important** I2C and SPI seen here are seen at a descriptive level. When facing a new design, sensor usage, etc. try to find already existing libraries from people like _Adafruit_, _Sparkfun_, _Arduino_ and others. Unless the set up is **super** simple, the implementation is not straight forward in many cases and it's better to follow a more *copy approach*. ::: #### I2C The Inter-integrated Circuit (I2C) Protocol is a protocol intended to allow multiple slave digital integrated circuits (chips) to communicate with one or more master chips. It is only meant for short distance communications within a single device. I2C is a convenient way of setting up communication because: - It allows for several masters - It allows for several slaves - The number of wires does not change It allows for several masters to be in the same system and for only the masters to be able to drive the data line high. This means that no slave will be able to lock the line in case other slave or master is talking: ![](https://i.imgur.com/FVIXFQW.png) Image Source: _NXP semiconductors_ So, I2C bus consists of two signals (apart from VCC and GND): SCL and SDA. SCL is the clock signal, and SDA is the data signal. Each device is recognized by an **unique address** (whether it is a microcontroller, LCD driver, memory or keyboard interface) and can operate as either a **transmitter or receiver**, depending on the function of the device. In addition to transmitters and receivers, devices can also be considered as masters or slaves when performing data transfers. A master is the device which initiates a data transfer on the bus and **generates the clock signals to permit that transfer**. At that time, any device addressed is considered a slave. :::info Check [this AAN](https://www.nxp.com/docs/en/user-guide/UM10204.pdf) by NXP semiconductors to learn much more about I2C. ::: :::warning **Remember the pull-ups!** The data lines need to be driven high when they are not used, and for that they need pull-up resistors. Values for the pull up resistors could be around 5kΩ. ::: The actual protocol works with messages broken up into two types of frame: an address frame, where the master indicates the slave to which the message is being sent, and one or more data frames, which are 8-bit data messages passed from master to slave or vice versa. Data is placed on the SDA line after SCL goes low, and is sampled after the SCL line goes high. ![](https://cdn.sparkfun.com/r/600-600/assets/6/4/7/1/e/51ae0000ce395f645d000000.png) Image Source: _Sparkfun_ :::info **Grove connector from Seeed** Grove, by Seeed, uses this connector as a way to interface with several protocols. This is how it looks for the I2C one: ![](https://i.imgur.com/0xZ9LJ9.png) ::: **Libraries for Arduino** - [Wire](https://www.arduino.cc/en/Reference/Wire) :::info **Examples explained** The following examples are copied from [here](https://www.arduino.cc/en/Tutorial/MasterWriter) and [here](https://www.arduino.cc/en/Tutorial/MasterReader). ::: **Example 1 Master as receiver: requesting information** Receiver: ```arduino #include <Wire.h> void setup() { Wire.begin(); // join i2c bus (address optional for master) Serial.begin(9600); // start serial for output } void loop() { Wire.requestFrom(8, 6); // request 6 bytes from slave device #8 while (Wire.available()) { // slave may send less than requested char c = Wire.read(); // receive a byte as character Serial.print(c); // print the character } delay(500); } ``` Sender: ```arduino #include <Wire.h> void setup() { Wire.begin(8); // join i2c bus with address #8 Wire.onRequest(requestEvent); // register event } void loop() { delay(100); } // function that executes whenever data is requested by master // this function is registered as an event, see setup() void requestEvent() { Wire.write("hello "); // respond with message of 6 bytes // as expected by master } ``` **Example 2 Master as sender: sending information** Sender: ```arduino #include <Wire.h> void setup() { Wire.begin(); // join i2c bus (address optional for master) } byte x = 0; void loop() { Wire.beginTransmission(8); // transmit to device #8 Wire.write("x is "); // sends five bytes Wire.write(x); // sends one byte Wire.endTransmission(); // stop transmitting x++; delay(500); } ``` Receiver: ```arduino #include <Wire.h> void setup() { Wire.begin(8); // join i2c bus with address #8 Wire.onReceive(receiveEvent); // register event Serial.begin(9600); // start serial for output } void loop() { delay(100); } // function that executes whenever data is received from master // this function is registered as an event, see setup() void receiveEvent(int howMany) { while (1 < Wire.available()) { // loop through all but the last char c = Wire.read(); // receive byte as a character Serial.print(c); // print the character } int x = Wire.read(); // receive byte as an integer Serial.println(x); // print the integer } ``` - [TinyWireS](https://github.com/rambo/TinyWire/tree/master/TinyWireS) Example (for an analog pressure sensor that sends data via I2C): ```arduino #include <Arduino.h> #include <TinyWireS.h> #include <avr/sleep.h> #include <avr/wdt.h> // Set I2C Slave address #define I2C_SLAVE_ADDRESS 0x13 #ifndef TWI_RX_BUFFER_SIZE #define TWI_RX_BUFFER_SIZE ( 16 ) #endif // Sensor and Indicator Led Pins #define SENSOR 1 // Measurement #define MAX_TICK 50 unsigned int tick = 0; //Smoothing Factor #define LPF_FACTOR 0.5 volatile byte reg_position = 0; const byte reg_size = sizeof(i2c_regs); unsigned long lastReadout = 0; // I2C Stuff volatile uint8_t i2c_regs[] = { 0, //older 8 0 //younger 8 }; void requestEvent() { TinyWireS.send(i2c_regs[reg_position]); reg_position++; if (reg_position >= reg_size) { reg_position = 0; } } void setup() { analogReference(EXTERNAL); // Setup I2C TinyWireS.begin(I2C_SLAVE_ADDRESS); TinyWireS.onRequest(requestEvent); // set clock divider to /1 CLKPR = (1 << CLKPCE); CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0); } void loop() { unsigned long currentMillis = millis(); // On tick value 0, do measurements if (abs(currentMillis - lastReadout) > MAX_TICK) { // Read the values int sensorReading = analogRead(SENSOR); // Treat them float Vs = 0; float pressure = 0; Vs = ((float) sensorReading + 0.5 ) / 1024.0 * 5.0; pressure = (Vs*687.8/Va - 18.77); // in kPa i2c_regs[0] = pressure >> 8 & 0xFF; i2c_regs[1] = pressure & 0xFF; // Update the last readout lastReadout = currentMillis; } } ``` **Libraries for Python** - [sm.BUS](http://wiki.erazor-zone.de/wiki:linux:python:smbus:doc) **Example 1, master as receiver** ```python import smbus import time bus = smbus.SMBus(1) # Indicates /dev/i2c-1 DEVICE_ADDRESS = 0x13 packet_size = 4 def ReadSensor(_address): i = 0 _value = 0 while (i < packet_size): _measure = bus.read_i2c_block_data(_address, 0, 1) _value |= _measure[0] << (8*(packet_size-(1+i))) i+=1 return _value while True: result = ReadSensor(DEVICE_ADDRESS) print result time.sleep(1) ``` **Example 2, master as sender** ```python import smbus bus = smbus.SMBus(1) # 0 = /dev/i2c-0 (port I2C0), 1 = /dev/i2c-1 (port I2C1) DEVICE_ADDRESS = 0x15 #7 bit address (will be left shifted to add the read write bit) DEVICE_REG_MODE1 = 0x00 DEVICE_REG_LEDOUT0 = 0x1d #Write a single register bus.write_byte_data(DEVICE_ADDRESS, DEVICE_REG_MODE1, 0x80) #Write an array of registers ledout_values = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff] bus.write_i2c_block_data(DEVICE_ADDRESS, DEVICE_REG_LEDOUT0, ledout_values) ``` ::: info **WiringPi** If you are using a Raspberry Pi, you can use [WiringPi](https://projects.drogon.net/raspberry-pi/wiringpi/i2c-library/) (C++), instead of sm.BUS (Python). ::: ::: info **More references** sm.BUS in python is not greatly documented with examples, but here you can find [some reference](https://raspberry-projects.com/pi/programming-in-python/i2c-programming-in-python/using-the-i2c-interface-2) ::: #### SPI Serial Peripheral Interface (SPI) is a synchronous serial protocol, used for short-distance communication, primarily in embedded systems. ![](https://i.imgur.com/083jT4a.png) _Image Credit: SparkFun_ It uses a master-slave architecture with a single master. The master device originates the frame for reading and writing. Multiple slave-devices are supported through selection with individual slave select (SS) lines. All these pins are explained in the SPI [tutorial](https://learn.sparkfun.com/tutorials/serial-peripheral-interface-spi) above. To summarize: - In SPI, only one side generates the clock signal (usually called CLK or SCK for **S**erial **C**loc**K**). The side that generates the clock is called the “master”, and the other side is called the “slave”. There is always only one master (which is almost always your microcontroller), but there can be multiple slaves. - When data is sent from the master to a slave, it’s sent on a data line called MOSI, for “Master Out / Slave In”. If the slave needs to send a response back to the master, the master will continue to generate a prearranged number of clock cycles, and the slave will put the data onto a third data line called MISO, for “Master In / Slave Out”. - To select the Slave, we use the SS line, by dropping it, telling the particular slave to go active ![](https://cdn.sparkfun.com/assets/f/f/e/5/8/52ddb2dbce395fae408b4568.png) _Image Credit: SparkFun_ We can summarize all this in the following image, but note we will be using a different Serial Communication on the PC side: ![](https://i.imgur.com/1ohG4RJ.png) _Image Credit: ATMEL_ SPI is used by many programmers to flash the microcontroller's code onto the flash memory, mainly because it's fast, really fast. In many cases is the only protocol available, and in some other cases it's much faster than I2C. :::info **Read the datasheet** For example, for the ATtiny, the **Section 19.5** explains all the necessary instructions for the Serial Programming. Below, the needed connections are summarized: |Symbol |Pins |I/O |Description | |:----: |:---: |:--: |:----------------| | MOSI | PA6 | I | Serial Data In | | MISO | PA5 | O | Serial Data Out | | SCK | PA4 | I | Serial Clock | ::: A master can communicate with multiple slaves (however only one at a time). It does this by asserting SS for one slave and de-asserting it for all the others. The slave which has SS asserted (usually this means LOW) configures its MISO pin as an output so that slave, and that slave alone, can respond to the master. The other slaves ignore any incoming clock pulses if SS is not asserted. Thus you need one additional signal for each slave. :::info - Check the [Serial Peripheral Interface - SPI](https://learn.sparkfun.com/tutorials/serial-peripheral-interface-spi), to understand why it's important to use **Synchronous** Serial communication. - Another great page by [gammon](www.gammon.com.au/spi). Probably the best of the best that you'll ever see ::: **Libraries for arduino** - [SPI](https://www.arduino.cc/en/Reference/SPI) _Example, arduino as master, sending_: ```arduino #include <SPI.h> void setup (void) { digitalWrite(SS, HIGH); // ensure SS stays high SPI.begin (); } // end of setup void loop (void) { byte c; // enable Slave Select digitalWrite(SS, LOW); // SS is pin 10 // send test string for (const char * p = "Fab" ; c = *p; p++) SPI.transfer (c); // disable Slave Select digitalWrite(SS, HIGH); delay (100); } // end of loop ``` :::info **Looking to implement SPI?** Check the first response on [this thread](https://arduino.stackexchange.com/questions/16348/how-do-you-use-spi-on-an-arduino) ::: ## OTA communication ![](http://sevenhorizons.pbworks.com/f/1438017529/frequency-spectrum.png) ![](https://www.rfpage.com/wp-content/uploads/2016/07/RF-spectrum-range.jpg) RANGE VS POWER ![](https://modernsurvivalblog.com/wp-content/uploads/2011/03/radiation-inverse-square-law.jpg) [Range on geography](http://www.exeterars.co.uk/hamnet-meshnet/HilltopStablesToG7NBU_partA.png) ### HC08-Communication Bluetooth communication ![](https://i2.wp.com/m.eet.com/media/1111248/wireless_audio_distribution_fig1t.jpg) Both classic Bluetooth and low-energy Bluetooth apply the Adaptive Frequency Hopping (AFH) feature that detects interference from. For example, a WLAN device 802.11 b, g, n that transmits nearby, if such interference is detected, the channel is automatically placed in the blacklist. In order to handle the temporary interference, an implemented scheme retries the channels of the blacklist and if the interference has ceased the channel can be used. AFH prevents Bluetooth from interfering with other nearby wireless technologies. - *The hardware that makes up the Bluetooth device is made up of two parts:* - a radio device, responsible for modulating and transmitting the signal. - a digital controller, consisting of a CPU, a digital signal processor (DSP - Digital Signal Processor) called Link Controller (or Link Controller) and interfaces with the host device.* **The LC or Link Controller** is responsible for the processing of the baseband and the handling of the ARQ and FEC protocols of the physical layer; In addition, it handles both asynchronous and synchronous transfer functions, audio coding and data encryption. Low-energy Bluetooth, also referred to as Bluetooth LE, Bluetooth ULP (Ultra Low Power) and Bluetooth Smart, is a new digital radio (wireless) interoperable technology for small devices developed by Bluetooth. ![](https://i0.wp.com/www.prometec.net/wp-content/uploads/2014/11/BT-masterslave.jpg) **Master-Slaves** BlueTooth devices can act as Masters or as Slaves. The difference is that a BlueTooth Slave can only connect to a master and nobody else, instead a BlueTooth master, can connect to several Slaves or allow them to connect and receive and request information from all of them, arbitrating information transfers (up to a maximum of 7 Slaves). -Wiring ![](https://ardudron.files.wordpress.com/2016/04/arduino_ble_hc08.jpg?w=1088) ![](https://http2.mlstatic.com/bluetooth-hc-08-hc08-40-ble-arduino-control-inalambrico-D_NQ_NP_664225-MCO25395542038_022017-F.jpg) AT COMMANDS FOR CONFIGURATION AT+VERSION, Firmware version AT+NAMEXXX,Program the name we want to present when someone looks for us AT+BAUDX, Set the communication speed between the module and the console according to the following table: 1 configure 1200bps 2 configure 2400bps 3 configure 4800bps 4 configure 9600bps (Default) 5 configure 19200bps 6 configure 38400bps 7 configure 57600bps 8 configure 115200bps AT+PINXXXX, set the personal identification number, which will be required to establish the link AT+ROLE It informs us if it is configured as Master 1, or as slave 0. AT+ROLE1 Configure the module in master mode AT+ROLE0 Configure the module in slave mode :::info Some commands need to be send with a "?" string at the end of the command to make it work. ::: **For The Master Module (The other one that will be controlling the link.)** 1. Connect to the FTDI to the computer and the bluetooth to the ftdi, select the port connection on the arduino IDE 2. You may type AT+CMODE=1 (master mode), and press enter. This will connect to all bluetooth modules within range, but it will only connect to one master module. 4. Now, type AT+ADDR, and press enter. You should get an address like "587A62500108", or something similar. Write this down, you will need it later.This is the mac address of the master module. **For The Slave Module (The other one that will be listening to the link.)** 1. Connect to the FTDI to the computer and the bluetooth to the ftdi, select the port connection on the arduino IDE 2. You may type AT+CMODE=1 (master mode), and press enter. This will connect to all bluetooth modules within range, but it will only connect to one master module. 3. You may type AT+CMODE=0 ( slave mode), and press enter. This will connect to all bluetooth modules within range, but it will only connect to one master module. 4. Now, type AT+BIND="MAC ADDRESS OF THE MASTER" obviously with your respective address to the slave. Note the commas instead of colons given by the slave module.(in case your mac address has comas) **What should happen?** The modules should auto link when plugged in if not check for setting up the same setting in both devices and check the MacAddress **Example-1** ```arduino #include <SoftwareSerial.h> SoftwareSerial BT1(10, 11); // RX | TX void setup() { pinMode(8, OUTPUT); // Al poner en HIGH forzaremos el modo AT pinMode(9, OUTPUT); // cuando se alimente de aqui digitalWrite(9, HIGH); delay (500) ; // Espera antes de encender el modulo Serial.begin(9600); Serial.println("Levantando el modulo HC-06"); digitalWrite (8, HIGH); //Enciende el modulo Serial.println("Esperando comandos AT:"); BT1.begin(38400); } void loop() { if (BT1.available()) Serial.write(BT1.read()); if (Serial.available()) BT1.write(Serial.read()); } ``` **Example-2** ```arduino #include <SoftwareSerial.h> SoftwareSerial EEBlue(10, 11); // RX | TX void setup() { Serial.begin(9600); EEBlue.begin(38400); //Baud Rate for command Mode. Serial.println("Enter AT commands!"); } void loop() { // Feed any data from bluetooth to Terminal. if (EEBlue.available()) Serial.write(EEBlue.read()); // Feed all data from termial to bluetooth if (Serial.available()) EEBlue.write(Serial.read()); } ``` **Example 3 - Python** ```python from Adafruit_SHT31 import * import serial import time sensor = SHT31(address = 0x44) #sensor = SHT31(address = 0x45) ser = serial.Serial( port='/dev/ttyS0', baudrate = 9600, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS, timeout=1 ) def readSHT(): try: return sensor.read_temperature(), sensor.read_humidity() except: return None, None if __name__ == "__main__": try: while True: temp, humidity = readSHT() time.sleep(1) print 'Temp = {0:0.3f} deg C'.format(temp) print 'Humidity = {0:0.2f} %'.format(humidity) try: ser.write('T:') ser.write(str(temp)) ser.write(',') ser.write('H.') ser.write(str(humidity)) ser.write('\n') except: print ('Serial problem') pass except KeyboardInterrupt: raise SystemExit ``` ### NRF24-Communication **Caution working voltaje of : 3 ~ 3.6V Max** The NRF24L01 integrates an RF transceiver (transmitter + receiver) at a frequency between 2.4GHz to 2.5GHz, a free band for free use. The transmission speed is configurable between 250 Kbps, 1Mbps, and 2 Mbps and allows simultaneous connection with up to 6 devices. The NRF24L01 also incorporates the necessary logic to make communication robust, such as correcting errors and forwarding data if necessary, freeing the processor of this task. The control of the module is done through the SPI bus, so it is easy to control it from a processor such as Arduino. The band of frequency is of 2400 to 2525 MHz, being able to choose between 125 channels spaced at the rate of 1MHz. It is recommended to use the frequencies from 2501 to 2525 MHz to avoid interference with Wi-Fi networks. But before starting with the example, you have to know that the NRF24L01 module is a transceiver and not a receiver transmitter. A receiving transmitting equipment can send radio messages and receive them simultaneously because both circuits, although very similar, are isolated from each other and can be operated independently. - Wiring ![](https://www.luisllamas.es/wp-content/uploads/2016/12/arduino-NRF24L01-2.4ghz-conexion.png) ![](https://www.luisllamas.es/wp-content/uploads/2016/12/arduino-NRF24L01-2.4ghz-esquema.png) The first thing you have to do is download the latest version of the RF24 library and import it into your Arduino IDE, for this in the menu bar go to Sketch> Import Library> Add Library The following example shows the sending of a text string from an Arduino sender to an Arduino receiver, which upon receiving the text shows it by serial port. **Sender Code** :::success ```c++ #include <nRF24L01.h> #include <RF24.h> #include <RF24_config.h> #include <SPI.h> const int pinCE = 9; const int pinCSN = 10; RF24 radio(pinCE, pinCSN); // Single radio pipe address for the 2 nodes to communicate. const uint64_t pipe = 0xE8E8F0F0E1LL; char data[16]="Hola mundo" ; void setup(void) { radio.begin(); radio.openWritingPipe(pipe); } void loop(void) { radio.write(data, sizeof data); delay(1000); } ``` ::: **Receiver** :::success ```c++ #include <nRF24L01.h> #include <RF24.h> #include <RF24_config.h> #include <SPI.h> const int pinCE = 9; const int pinCSN = 10; RF24 radio(pinCE, pinCSN); // Single radio pipe address for the 2 nodes to communicate. const uint64_t pipe = 0xE8E8F0F0E1LL; char data[16]; void setup(void) { Serial.begin(9600); radio.begin(); radio.openReadingPipe(1,pipe); radio.startListening(); } void loop(void) { if (radio.available()) { int done = radio.read(data, sizeof data); Serial.println(data); } } ``` ::: :::info **More tutorials** - [Tutorial 1](https://www.luisllamas.es/comunicacion-inalambrica-a-2-4ghz-con-arduino-y-nrf24l01/) - [Tutorial 2](https://naylampmechatronics.com/blog/16_Tutorial-b%C3%A1sico-NRF24L01-con-Arduino.html) - [Tutorial Duplex](https://www.prometec.net/duplex-nrf2401/) - [Networking](https://howtomechatronics.com/tutorials/arduino/how-to-build-an-arduino-wireless-network-with-multiple-nrf24l01-modules/) ::: ### HC12-Communication The HC-12 is a half-duplex wireless serial communication module with 100 channels in the 433.4-473.0 MHz range that is capable of transmitting up to 1 km. The HC-12 is a half-duplex 20 dBm (100 mW) transmitter paired with a receiver that has -117 dBm (2×10-15 W) sensitivity at 5000 bps. Paired with an external antenna, these transceivers are capable of communicating up to and possibly slightly beyond 1 km in the open and are more than adequate for providing coverage throughout a typical house. - Setup & Configuration [AT Serial Commands](https://quadmeup.com/hc-12-433mhz-wireless-serial-communication-module-configuration/) - Wiring ![](https://howtomechatronics.com/wp-content/uploads/2017/07/Arduino-and-HC-12-Circuit-Schematic.png) ![](https://robotedu.my/image/robotedu/image/data/all_product_images/product-1166/arduino-hc12-433-si4463-wireless-serial-module-remote-1000m-robotedu-1801-11-robotedu%409.jpg) **Pro´s** - Control and communication over Serial. Able to use simple software serial protocols. - A receiving transmitting equipment can send radio messages and receive them simultaneously because both circuits, although very similar, are isolated from each other and can be operated independently. **Con´s** - Not able to resolve lost package data - Usually expensive setup :::info **More and more** - [More examples](https://howtomechatronics.com/tutorials/arduino/arduino-and-hc-12-long-range-wireless-communication-module/) - [Example](https://www.allaboutcircuits.com/projects/understanding-and-implementing-the-hc-12-wireless-transceiver-module/) ::: **Example Code Send-Receive** :::success ```c++ /* HC12 Send/Receive Example Program 1 By Mark J. Hughes Connect HC12 "RXD" pin to Arduino Digital Pin 4 Connect HC12 "TXD" pin to Arduino Digital Pin 5 Connect HC12 "Set" pin to Arduino Digital Pin 6 Transceivers must be at least several meters apart to work. */ #include <SoftwareSerial.h> const byte HC12RxdPin = 4; // Recieve Pin on HC12 const byte HC12TxdPin = 5; // Transmit Pin on HC12 SoftwareSerial HC12(HC12TxdPin,HC12RxdPin); // Create Software Serial Port void setup() { Serial.begin(9600); // Open serial port to computer HC12.begin(9600); // Open serial port to HC12 } void loop() { if(HC12.available()){ // If Arduino's HC12 rx buffer has data Serial.write(HC12.read()); // Send the data to the computer } if(Serial.available()){ // If Arduino's computer rx buffer has data HC12.write(Serial.read()); // Send that data to serial } } ``` ::: ### Antennas * Radiation pattern ![](https://i.imgur.com/R1Kxurv.png) ![](https://www.4-wheeling-in-western-australia.com/images/antenna3-6-9dB.jpg) Antenna based on the frecuency ![](http://eduardochamorro.github.io/beansreels/workshops/beandrone/spw58-2_1359095259352.jpg) [Video of wavelenght penetration comparison](https://www.youtube.com/watch?v=LltDtKs2sQ4) #### Monopole Monopole antenna is the simplest form of antenna, which is basically just a piece of un-shielded wire. It’s very common in radio receivers because they are cheap and easy to repair. However they are not as effective as Dipole antennas. ![](https://oscarliang.com/ctt/uploads/2017/05/monopole-antenna-mono-pole-fpv-vtx-vrx-rx-tx.jpg) **Calculation of wire length for antenna** If the antenna is a quarter wave monopole antenna, then its length should be a quarter of the signal wavelength. Length (m) = c / frequency / 4 The more precise wire length is, the better signal you should get ideally. If you are using Coaxial Cable, it doesn’t matter how long the cable is with shielding, all that matter is the exposed wire (the part that is without the shielding). Alternatively if you are using a wire like copper wire, just cut it to the calculated length and you have a monopole antenna :) ![](https://oscarliang.com/ctt/uploads/2015/02/dipole-antenna-fpv-video-transmitter-length-5-8ghz.jpg) #### Dipole antenna Dipole antennas has a simple design. It’s basically just a monopole antenna with a ground sleeve at under the active element. The ground sleeve can supposedly boost the performance considerably ![](https://oscarliang.com/ctt/uploads/2015/02/dipole-antenna-inside-fpv-video-transmitter-5-8ghz.jpg) #### Half Wave dipole antenna A half-wave dipole antenna consists of two quarter-wavelength conductors placed end to end for a total length of approximately L = λ/2 ![](http://electronics-diy.com/schematics/537/dipole.jpg) #### Patch antenna Patch antennas are also directional, and can be found in linear and circular polarization. They generally have less directionality than Helical, and smaller foot-print. ![](http://www.mcv-microwave.com/images/large/patch-antenna.jpg) ### WiFi Before moving into the specifics of the code, it is important to know **who is who**. _From the ESP8266WiFi library docs_: devices that connect to Wi-Fi network are called stations (**STA**). Connection to Wi-Fi is provided by an access point (**AP**), that acts as a hub for one or more stations. The access point on the other end is connected to a **wired network**. An access point is usually integrated with a router to provide access from Wi-Fi network to the internet. Each access point is recognized by a **SSID (Service Set IDentifier)**, that essentially is the name of network you select when connecting a device (station) to the Wi-Fi. In the case of the ESP8266, or ESP32, they can work as: 1. **Station**: station (STA) mode is used to get ESP module connected to a Wi-Fi network established by an access point. ![](https://i.imgur.com/oqbVBnz.png) 2. **Soft-AP**: An access point (AP) is a device that provides access to Wi-Fi network to other devices (stations) and connects them further to a wired network. ESP8266 can provide similar functionality except it does not have interface to a wired network. Such mode of operation is called soft access point (soft-AP) ![](https://i.imgur.com/TKMRdin.png) 3. **Both station and soft-AP**: Another handy application of soft-AP mode is to set up mesh networks. ESP can operate in both soft-AP and Station mode so it can act as a node of a mesh network. ![](https://i.imgur.com/HVO5CfA.png) 4. **Client**: in this mode, the module can access services provided by servers in order to send, receive and process data. In this case, we can request a site from a server, and do something with it. ![](https://i.imgur.com/faX0G1g.png) 5. **Server**: in this mode, the module can provide functionality to other devices, or simply serve a website: ![](https://i.imgur.com/XefrDDd.png) **Libraries** - [Basic Arduino WiFi Library](https://www.arduino.cc/en/Reference/WiFi) - [ESP8266 WiFi library](https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/readme.html) - [ESP32 Wifi library (*use with caution*)](https://github.com/espressif/arduino-esp32/tree/master/libraries/WiFi) **Examples** - [Station](https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/station-examples.html) - [Client](https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/client-examples.html) - [Server](https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/server-examples.html) - [Soft-AP](https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/soft-access-point-examples.html) :::danger **Need security?** You can use [TLS/SSL](https://en.wikipedia.org/wiki/Transport_Layer_Security) extensions to protect your data from being sniffed! ::: ### WIFIBROADCAST [Wifibroadcast](https://github.com/rodizio1/EZ-WifiBroadcast/wiki) is a project aimed at the live transmission of HD video (and other) data using wifi radios. One prominent use case is to transmit camera images. In contrast to a normal wifi connection wifibroadcast tries to mimic the advantageous properties of an analog link (like graceful signal degradation, unidirectional data flow, no association between devices). ![](https://befinitiv.files.wordpress.com/2015/04/dataflow.png) Wifibroadcast puts the wifi cards into monitor mode. This mode allows to send and receive arbitrary packets without association. Additionally, it is also possible to receive erroneous frames (where the checksum does not match). This way a true unidirectional connection is established which mimics the advantageous properties of an analog link. # Day 2: Hands on communication :::success **Objetivo** 4 equipos, que cada uno que construyan una estación receptora ::: **Sender Nodes** 1. Raspberry Pi with: - SHT31 sensor via I2C - HC12 antenna via Serial 2. Arduino with: - NRF24 via SPI - ?? Sensor 3. Arduino with: - - ?? Sensor ## Raspberry Pi References - [Pinout 1](https://pinout.xyz/#) - [Pinout 2](https://elinux.org/RPi_Low-level_peripherals) - [UART on a Pi](https://www.raspberrypi.org/documentation/configuration/uart.md) - [Using UART in Raspberry Pi](https://www.electronicwings.com/raspberry-pi/raspberry-pi-uart-communication-using-python-and-c) - [NRF24L01 on a Pi directly via SPI](https://www.raspberrypi.org/forums/viewtopic.php?p=908161) - [Another one](https://www.riyas.org/2014/08/raspberry-pi-as-nrf24l01-base-station-internet-connected-wireless.html)