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()
#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

Métodos
MétodoDescripción
//Codigo en Maestro
#include <Wire.h>
//Esclavo en direccion 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. oneWIRE

El bus oneWIRE 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.

Cada dispositivo oneWIRE 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)

#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 i; 
   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 (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