Buses de comunicación

1. SPI

El bus Serial Peripheral Interface SPI es una tecnología de comunicación en serie síncrona full duplex, que usa cuatro cables y una arquitectura maestro/esclavo. Un dispositivo maestro puede comunicarse en dúplex completo con varios esclavos usando una señal de SS (Slave Select) específica para cada esclavo. La comunicación es adecuada para distancias cortas. Usa 4 pines.

Pines SPI
NombresDescripciónArduino UNO + NANOArduino MEGALeodardo y DUE
MISO o SDIMaster-In Slave-Out o Serial Data In1151ICSP-1
MOSI o SDOMaster-Out Slave-In o Serial Data Out1250ICSP-4
CLK o SCKClock o Serial Clock1352ICSP-3
SS o CS o CESalave Select o Chip Select o Chip Enable10534, 10 y 52

SS (Slave Select): es una linea exclusiva para cada esclavo. Desde el maestro se usa este pin para habilitar y deshabilitar esclavo específico. Cuando el pin SS de esclavo está LOW, se comunica con el maestro. Cuando esta HIGH, ignora al maestro. Esto le permite tener múltiples esclavos en el bus SPI compartiendo las mismas líneas comunes: MISO, MOSI y CLK.

Bus SPI

Es importante que interconecte (junte) todos los GND del maestro y sus exclavos.

SPI tiene un reloj maestro y datos sincrónicos de maestro a esclavo y viceversa. Un total de 3 cables más Vcc, GND y selección de chip opcional. Los datos se transfieren simultáneamente dentro y fuera, típicamente 8 bits a la vez. Los datos pueden ser MSB-first o LSB-first, dependiendo del dispositivo esclavo SPI conectado.

El bus SPI tiene una arquitectura de tipo maestro-esclavo. El dispositivo maestro puede iniciar la comunicación con uno o varios dispositivos esclavos y enviar o recibir datos de ellos. Los esclavos no pueden iniciar la comunicación, ni intercambiar datos entre ellos directamente. El maestro mantiene en estado HIGH en todas las líneas SS. Cuando el maestro quiere establecer comunicación con un esclavo pone a LOW esa línea SS, lo que indica al esclavo que debe iniciar la comunicación.

SPI es una interfaz interna, prácticamente usada entre chips en la misma PCB. SPI es bueno para cosas incrustadas, ya que es solo un registro de desplazamiento y no mucho más, esto permite comunicaciones realmente rápidas (10 Mbps no es poco común incluso en pequeños uP de 8 bits y más de 50 Mbps en muchos chips de 32 bits). Los datos se cargan en un registro de desplazamiento y se envían bit por bit en cada ciclo de reloj. En el otro extremo, se realiza la acción inversa.

Ventajas alta velocidad de transmisión (hasta 8 MHz), full duple, puede enviar secuencias de bits de cualquier tamaño, sin dividir y sin interrupciones.

Desventajas requiere 3 cables (MISO+MOSI+CLK) + 1 por esclavo (SS), máximo 30 cm, la longitud de mensaje tiene que ser conocido por ambos lados y no hay acuse de recepción.

Debes usar la librería SPI.h

SPI.beginTransaction(SPISettings (1400000, MSBFIRST, SPI_MODE0));
Métodos
MétodoDescripción
begin()Inicia el bus SPI
beginTransaction()
transfer()Envía un byte
attachInterrupt()Activa la interrupción para recibir datos
setBitOrder()LSBFIRST/MSBFIRST
setDataMode()SPI_MODEx, x=0, 1, 2, 3.
setClockDivider()SPI_CLOCK_DIVx, x=2, 4, 8, 16, 32, 64, 128.
endTransaction()
end()Finaliza en bus SPI
#include <SPI.h>
byte SS = 10; //Slave Select
byte MOSI = 11; //Master Out
byte MISO = 12; //Master in
byte SCK = 13; //Clock

void setup(){
	pinMode(SS, OUTPUT);
	pinMode(MOSI, OUTPUT);
	pinMode(MISO, INPUT);
	pinMode(SCK, OUTPUT);
}

void loop(){
	digitalWrite(SS, HIGH);
    //Put SCK, MOSI, SS pins into output mode
    //also put SCK, MOSI into LOW state, and SS into HIGH state.
    //Then put SPI hardware into Master mode and turn SPI on
	SPI.begin();

	delay(5000);

	char c;
  
	// enable Slave Select
	digitalWrite(SS, LOW);
  
	// send test string
	for (const char * p = "Fab" ; c = *p; p++){
		SPI.transfer(c);
	}

	// disable Slave Select
	digitalWrite(SS, HIGH);

	//turn SPI hardware off
	SPI.end();
 
	while (1);
}

Consulta el articulo del australiano Nick Gammon para mas informacion. Como comunicar dos Arduinos por bus SPI y tambien jecrespo.

2. I2C

El bus Inter Integrated Circuit o I2C es un bus de comunicación en serie síncrono que usa dos cables que proporciona comunicación entre dos chips. Introducido en 1982 por Philips Semiconductor. El I2C puede funcionar a diferentes velocidades: estandar=100 Kbps, full speed=400 Kbps, fast mode=1 Mbps y High speed=3.4 Mbps. Se usa para conectar también diferentes placas con la simplicidad de cablear solo dos cables, llamados SDA (línea de datos), SCK (línea de reloj). Puede admitir hasta 128 dispositivos esclavos porque maneja direcciones de 7 bits.

En este tipo de comunicación cada dispositivo tiene una dirección única en el rango de 8~119 y cada dispositivo puede funcionar como Master o Slave.

Pines I2C
NombresDescripciónArduino UNO + NANOArduino MEGA
SDALinea de datosA420
SCKLinea de relojA521

En Arduino UNO ambos pines requieren un Pull-Up (4K7) y también se requiere conectar GND para completar el circuito. Por ejemplo si quieres conectar 2 o mas Arduinos UNO debes unir todos los pines A4 con una 4K7 a +5V y cuando un Arduino quiera transmitir la pone en LOW. La transmisión se inicia poniendo SDA en LOW y dejando SCL en HIGH. Luego viene la dirección de 7 bits del esclavo (empezando por el bit mas significativo). Por ejemplo 42 (0x2A o 0101010). Luego se envía el bit de lectura/escritura: un LOW para escribir (Maestro a esclavo) o HIGH para leer (esclavo a maestro). Luego el maestro espera al esclavo a que tire la linea SDA a LOW (que significa ACK o reconocido y listo). Si no existe un esclavo con esa dirección SDA se mantiene HIGH lo que significa NAK. Luego se tramite el byte de datos. Nuevamente el maestro tira SDA a LOW y ya se puede transmitir otro dato. Finalmente el esclavo libera SDA indicando que termino.

Bus I2C

Es importante que interconecte (junte) todos los GND del maestro y sus esclavos.

I2C es una interfaz interna de chip a chip en serie que está más cerca de una UART de baja velocidad en términos de complejidad y conteo de pines. No es full duplex ni tiene control de errores, pero si hay ACK.

Debes usar la librería Wire.h, I2Cdevlib.h o I2C.h.

Métodos
MétodoDescripción
begin()Inicializa el bus
beginTransmission(dirección)Comienza la transmisión
available()Detecta si hay datos pendientes de ser leídos
read()Recibe byte
write()Envia byte
onReceive()Funcion callback al recibir dato
onRequest()Funcion callback al solicitar dato
endTransmission()Finaliza la transmisión
//Codigo en Maestro
#include <Wire.h>
//Esclavo en dirección 42
const byte SLAVE_ADDRESS = 42;
const byte LED = 13;

void setup (){
	Wire.begin();
	pinMode(LED, OUTPUT);     
}

void loop (){
	for (byte x = 2; x <= 7; x++){  
		Wire.beginTransmission(SLAVE_ADDRESS);
		Wire.write(x);
		if (Wire.endTransmission() == 0){
			digitalWrite(LED, HIGH); 
		}else{
			digitalWrite(LED, LOW); 
		}
		delay(200);
    }
}

//Codigo en Esclavo
#include <Wire.h>
const byte MY_ADDRESS = 42;

void setup(){
	Wire.begin(MY_ADDRESS);
	for (byte i = 2; i <= 7; i++){
		pinMode(i, OUTPUT);
	}
	Wire.onReceive(receiveEvent);
}

//Interrupcion de llegan datos
void receiveEvent (int howMany){
	for (int i = 0; i < howMany; i++){
		byte c = Wire.read();
		if (digitalRead(c) == LOW){
			digitalWrite(c, HIGH);
		}else{
			digitalWrite (c, LOW);
		}
	}
}
void loop(){
  ...
}

Consulta el articulo del autraliano Nick Gammon para mas información.

3. 1-Wire

El bus 1-Wire es un protocolo patentado por Maxim Integrated que es gratuito. En una bus de 1 cable también llamado "MicroLan", para comunicar un único dispositivo maestro con uno o más esclavos vía una sola línea de datos, a una velocidad de 15.4 Kbps, que incluso se puede usar para alimentar a los esclavos, llamado modo parásito.

Bus 1-Wire

Cada dispositivo 1-Wire contiene una dirección en ROM de 64 bits única, que consta de un código de familia de 8 bits, un número de serie de 48 bits y un CRC de 8 bits. El CRC se usa para verificar la integridad de los datos. Por ejemplo, para un sensor de temperatura DS18S20, el código de familia es 0x10, un sensor DS18B20 su código de familia es 0x28 y para un sensor DS1822 su código de familia es 0x22.

Es importante que interconecte (junte) todos los GND del maestro y sus esclavos.

Antes de enviar un comando el maestro selecciona un esclavo usando su ROM único, el esclavo responde si se le encuentra. El maestro también puede hacer un llamado a todos los esclavos con el comando "omitir ROM" (0xCC)

Comienza una nueva busqueda.
Métodos 1-Wire
MétodoDescripción
select(direccion)
search(direccion)Busca el siguiente dispositivo. La direccion es una matriz de 8 bytes. Verdadero si la encuentra.
reset_search()
read()
read_bit()Lee un byte
write(num)Escribe un byte.
write_bit(num,1)Escribe un byte y deja alimentacion al bus.
skip()Omite la seleccion del dispositico. Solo funciona con un dispoisitivo.
depower()
crc8(direccion, long)Calcula una verificacion CRC en una matriz de datos
crc16()
chck_crc16()
reset()Resetea el bus. Por lo general antes de una comunicacion

Debes usar la librería OneWire.h

#include <OneWire.h> 
OneWire miOneWire(pin);
#include <OneWire.h> 

//Termometro DS18S20
OneWire ds(10);  //Termometro en el pin 10 

void setup(void) { 
   //inicia el puerto serie
   Serial.begin(9600); 
} 

void loop(void) {
   byte present=0; 
   bytes data[12]; 
   byte addr[8]; 

   ds.reset_search( ); 
   if (!ds.search(addr)) {
      Serial.print("No más direcciones.\ n"); 
      ds.reset_search( ); 
      return; 
   }
   Serial.print("R =") ; 
   for (byte i=0; i<8; i++) {
      Serial.print(addr[ i ], HEX); 
      Serial.print(""); 
   } 

   if (OneWire::crc8(addr, 7) != addr[7]) {
      Serial.print("CRC no es válido !!!\n"); 
      return;
   } 

   if (addr[0] == 0x10) {
      Serial.print("El dispositivo es un dispositivo de familia DS18S20.\n"); 
   }else if (addr[0] == 0x28) {
      Serial.print("El dispositivo es un dispositivo de familia DS18B20.\n") ; 
   }else{
      Serial.print ("Familia de dispositivos no reconocida: 0x"); 
      Serial.println(addr[0], HEX ); 
      return; 
   }

   ds.reset(); 
   ds.select(addr); 
   ds.write(0x44,1); //iniciar la conversión, con el parásito encendido

   delay(1000);     //Quizas 750 ms es suficiente, tal vez no.
   //podríamos hacer un ds.depower() aquí, pero el reinicio se encargará de eso. 

   preset = ds.reset( ); 
   ds.select(addr);    
   ds.write(0xBE);      // Leer el Scratchpad

   Serial.print("P ="); 
   Serial.print(preset, HEX); 
   Serial.print(""); 
   for (i=0; i<9; i++) {      //necesitamos 9 bytes
      data[i] = ds.read();
      Serial.print(data[i], HEX); 
      Serial.print(""); 
   }
   Serial.print("CRC ="); 
   Serial.print(OneWire::crc8(data,8), HEX); 
   Serial.println( ); 
}

Algunos componentes que usas ente tipo de comunicación son: el termómetro DS1822, DS18S20 y DS2438.

Debes usar la librería oneWire.h

4. CAN

El Controller Area Network es un protocolo de comunicaciones desarrollado por la firma alemana Robert Bosch GmbH, basado en una topología bus para la transmisión de mensajes en entornos distribuidos. Además ofrece una solución a la gestión de la comunicación entre múltiples CPUs. Proporciona los siguientes beneficios:

5. RS-485

También conocido como EIA-485 es un estándar de comunicación en bus de la capa física del modelo OSI. Está definido como un sistema de bus diferencial multipunto, es ideal para transmitir a altas velocidades sobre largas distancias (10 Mbps hasta 12 m y 100 kbps en 1200 m) y a través de canales ruidosos, ya que el par trenzado reduce los ruidos que se inducen en la línea de transmisión. El medio físico de transmisión es un par trenzado, que admite 32, 128 o 256 estaciones en 1 solo par, con una longitud máxima de 1200 m operando entre 300~19200 bit/s y la comunicación semiduplex (half-duplex) dependiendo del consumo de cada driver. La transmisión diferencial permite alcanzar mayor distancia con una notable inmunidad al ruido, siempre que el bus de comunicación conserve las características de bus balanceado dando la posibilidad de una configuración multipunto.