Skip to Content

Comunicación SPI maestro-esclavo y ejemplo de lectura SPI de Arduino

Comunicación SPI maestro-esclavo y ejemplo de lectura SPI de Arduino

Este artículo le dará toda la información necesaria sobre el protocolo de comunicación de la interfaz de periféricos en serie (SPI) del microcontrolador AVR utilizado en la placa Arduino UNO y Arduino Mega.

He incluido una especificación detallada, un diagrama de pines y un código para la comunicación SPI entre dos placas Arduino. También he incluido el ejemplo de lectura SPI de Arduino con el lector RFID-RC522.

Después de este artículo, aprenderás a utilizar el protocolo SPI y a leer/escribir datos a través del protocolo SPI.

Suministros

Componentes de hardware

Arduino UNO Rev3× 1Amazon
Cable USB tipo A/B× 1Amazon
Arduino Mega 2560 Rev3× 1Amazon

Software

Arduino IDEArduino IDE

Makerguides.com participa en el Programa de Asociados de Amazon Services LLC, un programa de publicidad de afiliados diseñado para proporcionar un medio para que los sitios ganen honorarios de publicidad mediante la publicidad y los enlaces a productos en Amazon.com.

Protocolo básico de comunicación SPI

Motorola fundó la interfaz SPI (Serial Peripheral Interface) en 1970. SPI es un protocolo de comunicación serie síncrona y full-duplex.

Esto significa que los datos pueden ser transferidos en ambas direcciones al mismo tiempo. También puede configurarse para el modo semidúplex.

¿Qué es el SPI?

SPI es un protocolo de comunicación serie síncrono para transferir los datos con el flanco ascendente o descendente del impulso de reloj entre dos microcontroladores o entre el microcontrolador y los dispositivos periféricos SPI.

El dispositivo SPI puede ser configurado como Maestro o Esclavo, y sólo el Maestro puede generar pulsos de reloj e iniciar la comunicación.

Sin embargo, una vez iniciada la comunicación, tanto el maestro como el esclavo pueden transmitir los datos simultáneamente. También se conoce como protocolo de cuatro hilos.

La comunicación SPI utiliza cuatro cables MISO, MOSI, CLK y CS/SS. Un SPI puede tener sólo un maestro y puede tener múltiples esclavos.

Un maestro suele ser un microcontrolador, y los esclavos pueden ser un microcontrolador o cualquier periférico como sensores, ADC, DAC, LCD, RTC, etc.

Interfaz maestro-esclavo SPI

Interfaz maestro-esclavo SPI

El protocolo SPI contiene cuatro líneas MISO, MOSI, SCK y CS/SS.

MOSI (Master Out Slave In) - Utilizando el pin MOSI el Maestro envía datos al Esclavo.

MISO (Master In Slave Out) - Usando MISO el Esclavo puede enviar datos al Maestro.SCK (Serial Clock) - El Maestro genera la señal de reloj, y proporciona la sincronización entre el Maestro y el Esclavo.

CS (Chip Select) - Usando CS o Slave Select (SS), el Maestro puede seleccionar el Esclavo. Se trata de un pin activo-bajo, por lo que es necesario ponerlo bajo para seleccionar el dispositivo esclavo.

Maestro SPI con múltiples esclavos

Maestro SPI con múltiples esclavos

El protocolo SPI permite tener varios dispositivos SPI compartiendo las mismas líneas MOSI, MISO y CLK del Maestro.

Como se puede observar en el diagrama anterior, hay tres esclavos en los que el MOSI, MISO, SCK se conectan comúnmente al Maestro, y el CS de cada esclavo se conectan por separado a los pines CS individuales del maestro.

¿El Arduino Uno tiene SPI?

Sí, la placa Arduino Uno viene con un microcontrolador AVR ATMEGA328p, y tiene una interfaz SPI en la placa.

Por lo tanto, para utilizar SPI en Arduino Uno y establecer diferentes modos y velocidades, es necesario aprender sobre el registro SPI en AVR MCUs.

¿Qué son los registros SPI en el AVR?

La serie AVR utiliza tres registros para configurar la comunicación SPI que son el Registro de Control SPI (SPCR), el Registro de Estado SPI (SPSR) y el Registro de Datos SPI (SPDR).

Registro de control SPI (SPCR)

El valor por defecto del registro SPCR es 0x00.

Registro de control SPI (SPCR)

El bit 7 es SPIE, bit de habilitación de interrupción SPI. Puede habilitar la interrupción SPI poniendo el bit a nivel alto y deshabilitarla poniendo el bit a nivel bajo.

El bit 6 es SPE, SPI Enable bit. Es necesario poner este bit en alto para habilitar el SPI.

El bit 5 es DORD, bit de orden de datos. Si el bit está activado, entonces se transmite primero el LSB. Si el bit está despejado, entonces se transmite primero el MSB.

El bit 4 es MSTR, bit de selección maestro/esclavo. Se ajusta para el modo Maestro y se borra el bit para el modo Esclavo.

El bit 3 es CPOL, bit de selección de la polaridad del reloj. Si está activado, los relojes comienzan desde la lógica uno, y si está desactivado, el reloj comienza desde la lógica cero.

El bit 2 es CPHA, bit de selección de fase de reloj. Los bits de polaridad de reloj (CPOL) y fase de reloj (CPHA) definen cómo se transfieren los datos en serie entre el maestro y el esclavo.

Si el bit está activado, la muestra de datos está en el flanco de reloj posterior, y si está desactivado, la muestra de datos está en el flanco de reloj anterior.

CPOLCPHAEl borde de ataqueBorde de fuga
00Muestra (en aumento)Configuración (caída)
01Configuración (en aumento)Muestra (caída)
10Muestra (caída)Configuración (en aumento)
11Configuración (caída)Muestra (en aumento)

Los bits 1:0 son bits de selección de frecuencia de reloj SPI SPR1-SPR0. La siguiente tabla muestra la configuración de los bits de selección de frecuencia de reloj SCK.

SPI2XSPR1SPR0Frecuencia del reloj
000Fosc/4
001Fosc/16
010Fosc/64
011Fosc/128
100Fosc/2
101Fosc/8
110Fosc/32
111Fosc/64

Registro de estado SPI (SPSR)

Registro de estado SPI (SPSR)

Bit 7 - SPIF: Bit de bandera de interrupción SPI.

Cuando la transferencia de datos en serie se completa, esta bandera se pone en marcha.

También se establece cuando el pin SS es conducido a nivel bajo en el modo maestro.

Bit 6 - WCOL: Bit de bandera de colisión de escritura. Este bit se establece cuando se producen escrituras en el registro de datos SPI durante la transferencia de datos anterior.

Bit 5:1 - Bits reservados. Estos bits están reservados y siempre se leen como cero.

Bit 0 - SPI2X: Bit de doble velocidad SPI. Si la velocidad SPI (frecuencia SCK) se duplica cuando se establece este bit.

Registro de datos SPI (SPDR)

Registro de datos SPI (SPDR)

El Registro de Datos SPI es un registro de lectura/escritura. Se utiliza para la transferencia de datos entre el archivo de registro y el registro de desplazamiento SPI.

La escritura en el registro inicia la transmisión de datos.

La lectura del registro hace que se lea el búfer de recepción del registro de desplazamiento.

¿Qué es el SPI en Arduino?

Supongamos que utilizas Arduino Uno o Arduino Mega y quieres transferir datos en serie entre dos dispositivos SPI.

En ese caso, esta parte del artículo te ayudará a empezar con SPI en el framework de Arduino.

¿Qué son los pines SPI en Arduino Uno?

Arduino Uno tiene una interfaz de comunicación SPI. Pin 10 (CS/SS), 11 (MOSI), 12 (MISO) y 13 (SCK).

Función SPIPin en Arduino
MOSI11 o ICSP-4
MISO12 o ICSP-1
SCK13 o ICSP-3
CS10
SPI Pins of Arduino Uno
SPI Pins of Arduino Uno

¿Dónde está la biblioteca SPI de Arduino?

There is a readily available library for SPI communication in the Arduino framework. To use the SPI library, you need to include #include <SPI.h> in your code.

Para utilizar la biblioteca SPI, hay que tener en cuenta los siguientes puntos.

  • Habilitar la comunicación SPI
  • Seleccione el modo como Maestro o Esclavo
  • ¿Quiere enviar primero el bit más significativo (MSB) o el bit menos significativo (LSB)?
  • Establecer el tiempo de inactividad del reloj como alto o bajo
  • Fijar la muestra en el flanco descendente o ascendente de los pulsos de reloj
  • Velocidad de la comunicación SPI

¿Cuál es la velocidad máxima de SPI?

Puede ajustar la velocidad de SPI configurando los parámetros en SPISettings. La velocidad de SPI dependerá de la velocidad del chip.

Por ejemplo, si utilizas un chip a 16 MHz, entonces utiliza 16000000 en SPISettings.

¿Cómo puedo conectar dos Arduinos con SPI?

En esta sección, aprenderás sobre la interconexión de dos placas Arduino Uno, Arduino Uno y Arduino Mega, para la comunicación SPI.

Asegúrese de que la tierra de dos placas es común.

Interfaz de dos placas Arduino Uno para SPI

Pin SPIArduino Uno-1Arduino Uno-2
CS/SS1010
MOSI1111
MISO1212
SCK1313
Interfaz de dos placas Arduino Uno para SPI
Interfaz de dos placas Arduino Uno para SPI

Interfaz de la placa Arduino Uno y la placa Arduino Mega para SPI

Pin SPIArduino UNOArduino Mega
CS/SS1053
MOSI1151
MISO1250
SCK1352
Interfaz de la placa Arduino Uno y la placa Arduino Mega para SPI
Comunicación SPI maestro-esclavo y ejemplo de lectura SPI de Arduino

¿Cómo se escribe un código SPI?

Para escribir un código para la comunicación SPI entre dos placas Arduino, en primer lugar, es necesario establecer una placa como maestro y otra como esclavo.

A continuación se muestran los códigos para configurar Arduino Uno o Mega como maestro y esclavo.

Código Arduino para el modo maestro

# include "SPI.h"

char str[ ]="Hello Slave, I'm Arduino Family\n";

void setup() {
  Serial.begin(115200); // set baud rate to 115200 for usart
  SPI.begin();
  SPI.setClockDivider(SPI_CLOCK_DIV8); //divide the clock by 8
  Serial.println("Hello I'm SPI Mega_Master");
} 

void loop (void) {
  digitalWrite(SS, LOW); // enable Slave Select
  // send test string
  for(int i=0; i< sizeof(str); i++) 
    SPI.transfer(str[i]);
  digitalWrite(SS, HIGH); // disable Slave Select
  delay(2000);
}

Cómo funciona el código para el Modo Maestro

En primer lugar, es necesario incluir un archivo de cabecera para utilizar la biblioteca SPI.

# include "SPI.h"

La función SPI.begin() se basa en el bus SPI estableciendo SCK, MOSI y CS como salida, tirando de SCK y MOSI a bajo, y de SS a alto para las placas Arduino.

Por defecto, el código funciona en modo maestro.

La función SPI.setClockDivider(divider) sirve para establecer el divisor del reloj SPI en relación con el reloj del sistema. Los divisores disponibles son 2, 4, 8, 16, 32, 64 o 128.

La configuración por defecto es SPI_CLOCK_DIV4, que establece el reloj SPI a un cuarto de la frecuencia del reloj del sistema (5 Mhz para las placas a 20 MHz).

Ahora, en el bucle vacío, necesitas poner el pin CS/SS como bajo para seleccionar el dispositivo esclavo, luego puedes transferir los datos usando SPI.transfer, y finalmente, al final, poner el pin CS/SS como alto para desactivar la conexión esclava.

digitalWrite(SS, LOW); // enable Slave Select
 // send test string
 for(int i=0; i< sizeof(str); i++) 
    SPI.transfer(str[i]);
 digitalWrite(SS, HIGH); // disable Slave Select
 delay(2000);

Código Arduino para el modo esclavo

#include "SPI.h"

char str[50];
volatile byte i;
volatile bool pin;

void setup()
 {
  Serial.begin (115200);    // set baud rate to 115200 for usart
  Serial.println("Hello I'm SPI UNO_SLAVE");
  pinMode(MISO, OUTPUT);   // have to send on Master in so it set as output
  SPCR |= _BV(SPE);        // turn on SPI in slave mode
  i = 0; // buffer empty
  pin = false;
  SPI.attachInterrupt();     // turn on interrupt
}

void loop(){
  static int count;
  if (pin)
  {
    pin = false;   //reset the pin
    if(count++< 5){
    Serial.print(count);
    Serial.print(" : ");

    Serial.println(str); //print the array on serial monitor
    if(count==5)
    {
      delay(1000);
      Serial.println("The end data");
    }
    delay(1000);
    i= 0; //reset button to zero
  }
}

// Interrupt function
ISR(SPI_STC_vect) 
{
  char c = SPDR;        // read byte from SPI Data Register
  if (i < sizeof(str)) {
    str [i++] = c; // save data in the next index in the array buff
    if ( (c == '\r') || (c == '\n') || (c=='\0') ) //check for the end of the word
      pin = true;
  }
}

Cómo funciona el código para el modo esclavo

Para utilizar la placa Arduino como dispositivo esclavo, es necesario establecer el pin MISO como salida y activar el modo esclavo. Además, es necesario adjuntar una interrupción para poder manejar los datos recibidos por el Maestro.

pinMode(MISO, OUTPUT); // hay que enviar en Master in para que se establezca como salida

SPCR |= _BV(SPE); // activar SPI en modo esclavo

SPI.attachInterrupt(); // activar la interrupción

Siempre que se genere una interrupción debido a los datos del dispositivo maestro, en Slave, el puntero saltará a ISR con la dirección de SPI_STC_vect, y copiará los datos de SPDR a la variable c y finalmente de c al array de str.

ISR(SPI_STC_vect) 
{
  char c = SPDR;        // read byte from SPI Data Register
  if (i < sizeof(str)) {
    str [i++] = c; // save data in the next index in the array buff
    if ( (c == '\r') || (c == '\n') || (c=='\0') ) //check for the end of the word
      pin = true;
  }
}

Por último, en el bucle vacío, los datos recibidos se imprimen en el terminal serie.

A continuación se muestra la salida del monitor en serie para los dispositivos maestros y esclavos. 

Salida del dispositivo maestro:

Salida del dispositivo maestro

Salida del dispositivo esclavo:

Salida del dispositivo esclavo

Cómo utilizar el módulo RFID-RC522 (lector RFID) con el Arduino UNO

Ahora, le proporcionaré el código y el diagrama de interconexión de RFID (identificación por radiofrecuencia) con Arduino Uno.

La RFID es un sistema de transferencia de datos a corta distancia. Utilizaré el lector RFID RC522 y las etiquetas pasivas.

Interfaz del módulo RFID-RC522 con Arduino Uno

Interfaz del módulo RFID-RC522 con Arduino Uno
Módulo RFID-RC522Arduino Uno
SDADigital 10
SCKDigital 13
MOSIDigital 11
MISODigital 12
IRQNo conectado
GNDGND
RSTDigital 9
3.3V3.3V
Módulo RFID-RC522 con Arduino Uno

Código Arduino para RFID-RC522

Necesita instalar la librería RFID en su Arduino IDE. Vaya a Herramientas > Gestionar Bibliotecas.

En el cuadro de búsqueda, escriba "mfrc" e instale la biblioteca MFRC522 SPI.

Biblioteca RFID en su IDE de Arduino
#include "SPI.h"
#include "MFRC522.h"

#define chipS 10
#define RESET 9
MFRC522 mfrc522(chipS, RESET);        // Create MFRC522 instance.

void setup() 
{
  Serial.begin(115200);   // Initiate a serial communication
  SPI.begin();            // Initiate  SPI bus
  mfrc522.PCD_Init();     // Initiate MFRC522
  Serial.println("Scan  your card to the RFID Reader...");
  Serial.println();  
}

void loop() 
{
  if ( ! mfrc522.PICC_IsNewCardPresent())          //  Look for new card
  {
    return;
  }
  if ( ! mfrc522.PICC_ReadCardSerial())           //  Select one of the cards
  {
    return;
  }
  Serial.print("UID tag :");             // Show UID on serial monitor

  String content= "";
  byte letter;
  for (byte i = 0; i < mfrc522.uid.size; i++) 
  {
     Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
     Serial.print(mfrc522.uid.uidByte[i], HEX);
     content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
     content.concat(String(mfrc522.uid.uidByte[i], HEX));
  }
  Serial.println();
  Serial.print("Reader MSG : ");
  content.toLowerCase();
  if ((content.substring(1) == "4c cd d2 22")  )  //change here the UID of the card/cards
  {
    Serial.println("Valid member access");
    Serial.println();
     delay(2000);
   }
 else   {
    Serial.print("Warning !!!!");
    Serial.print(" : ");
    Serial.println("Invalid member access");
    delay(2000);
 } 
}

Salida de monitor en serie:

Salida de monitorización en serie

Conclusión

En este artículo, he mostrado cómo configurar la comunicación SPI entre dos placas Arduino y el ejemplo de lectura SPI para RFID con la placa Arduino Uno.

Espero que este artículo le haya resultado informativo. Si es así, ¡compártalo con un amigo al que le guste la electrónica y hacer cosas!

Si tienes alguna pregunta o sugerencia, o si crees que faltan cosas en este tutorial, deja un comentario a continuación.

Tenga en cuenta que los comentarios son retenidos por la moderación para evitar el spam.

Daniel

Domingo 17 de julio de 2022

Creo que los valores de los bits de la configuración del reloj son incorrectos.

LZ

Domingo 27 de marzo de 2022

"tienen que enviar en el Maestro en lo que establece como salida" Przecież dzieje się odwrotnie w tym kodzie - to master wysyła a slave odczytuje. Jak można takie nonsensy przepuszczać.