Comunicação SPI entre dois Arduinos Uno (SPI em ambos os lados)

Comunicação SPI (Serial Peripheral Interface), protocolo síncrono serial, entre dois Arduinos Uno.

Referências para consultar:

* https://www.arduino.cc/en/reference/SPI

* https://learn.sparkfun.com/tutorials/serial-peripheral-interface-sp...

* https://arduino.stackexchange.com/questions/16348/how-do-you-use-sp...

Explicando este experimento:

* Neste experimento são necessários 2 Arduinos, um para master e outro para slave.

* O Arduino master enviará automaticamente e seguidamente, a cada 5 segundos, duas sequências de caracteres...

* A primeira sequência de caracteres é composta de um caracter 'a' seguido dos números 10, 17, 33 e 42, da seguinte forma:

*   1. o slave recebe o primeiro byte do master, o caracter 'a' e espera pelo próximo byte do master. O caracter 'a' sinaliza para o slave adicionar 10 aos números que receber a seguir

*   2. o slave receber o segundo byte, o número 10, e então adiciona 10 ao número 10 recebido, resultando 20, e espera

*   3. o slave recebe o terceiro byte do master, o número 17, somando 10 a ele, e aproveita esta conexão para enviar, ao mesmo tempo (comunicação full duplex) em que recebe, o resultado da operação de adição anterior, o númro 20

*   4. o slave recebe o quarto byte do master, o número 33, somando 10 a ele, e aproveita esta conexão para enviar, ao mesmo tempo (comunicação full duplex) em que recebe, o resultado da operação de adição anterior, o número 27

*   5. o slave recebe o quinto byte do master, o número 42, somando 10 a ele, e aproveita esta conexão para enviar, ao mesmo tempo (comunicação full duplex) em que recebe, o resultado da operação de adição anterior, o número 43

*   6. o master não tem mais números a enviar para o slave mas o slave tem uma resposta a enviar para o master, o número 52, resultado da adição de 10 + 42

*   7. então o master, para não ficar sem esse resultado, envia um caracter qualquer para o slave e o slave aproveita esta conexão para enviar o número 52 para o master, finalizando a sequencia numérica enviada pelo master

* A segunda sequência de caracteres é composta de um caracter 's' seguido dos mesmos números 10, 17, 33 e 42, porém o 's' sinaliza para o slave agora fazer a subtração de 10 nestes números na mesma sequencia anterior

Pinagem entre os dois Arduinos Uno:

* Master   <==>   Slave

* D10 (SS)           D10 (SS)

* D11 (MOSI)        D11 (MOSI)

* D12 (MISO)        D12 (MISO)

* D13 (SCK)         D13 (SCK)

* 5V                    Vin

* GND                 GND

Código (sketch) para o Arduino master:

* Neste sketch (master) usaremos a biblioteca <SPI.h>

-------------------------------------------------------------------------------------------------------------------------------------------------

#include <SPI.h>

SPISettings settings(4000000, MSBFIRST, SPI_MODE0); // define velocidade desta conexão SPI em

                                                                                   // 4MHz (16MHz do Uno / 4 = 4MHz, default)

void setup(){
  Serial.begin (9600);
  Serial.println();

  digitalWrite(SS, HIGH);         // desabilitar comunicação com o slave. Garantir que o pino SS do

                                             // master não inicie habilitando a comunicação com o slave (SS em

                                             //estado ALTO = desconectado)
  SPI.begin();
}

byte charInOut(const byte charOut){ // rotina para transferir 1 byte do master para o slave
  byte charIn = SPI.transfer(charOut); // transfer 1 byte para o slave e, ao mesmo tempo, recebe 1

                                            // byte do slave armazenando-o em 'a'
  delayMicroseconds(20);       // pausa por 0,000.02 segundos ou 20 microsegundos
  return charIn;
}

void loop(){
  byte a, b, c, d;

  digitalWrite(SS, LOW);                   // habilitar comunicação SPI com o slave
  SPI.beginTransaction(settings);       // inicializar a conexão SPI usando o SPIsettings definido
  charInOut('a');                                // enviar o caracter 'a' para o slave. Neste sketch o caracter 'a'

                                                      // sinaliza para o slave fazer uma operação de adição
  charInOut(10);                               // enviar o número 10 para o slave e, ao mesmo tempo, não

                                                      // receber o que quer que seja do slave
  a = charInOut(17);                          // enviar o número 17 para o slave e, ao mesmo tempo, receber

                                                      // o dado enviado do slave armazenando-o na variável "a"
  b = charInOut(33);                         // enviar o número 33 para o slave e, ao mesmo tempo, receber

                                                      // o dado enviado do slave armazenando-o na variável "b"
  c = charInOut(42);                         // enviar o número 42 para o slave e, ao mesmo tempo, receber

                                                     // o dado enviado do slave armazenando-o na variável "c"
  d = charInOut(0);                          // enviar o número 0 (ou qualquer outro caracter) para o slave e,

                                                     // ao mesmo tempo, receber o dado enviado do slave 

                                                     // armazenando-o na variável "d". Esta operação só existe para

                                                     // receber dado do slave
  SPI.endTransaction();                   // finalizar a conexão SPI
  digitalWrite(SS, HIGH);                 // desabilitar comunicação SPI com slave

  Serial.print("O números são 10, 17, 33 e 42. Adicionando 10: ");
  Serial.print(a, DEC);
  Serial.print(", ");
  Serial.print(b, DEC);
  Serial.print(", ");
  Serial.print(c, DEC);
  Serial.print(", ");
  Serial.print(d, DEC);

  digitalWrite(SS, LOW);                  // habilitar comunicação SPI com o slave
  SPI.beginTransaction(settings);      // inicializar a conexão SPI usando o SPIsettings definido
  charInOut('s');                               // enviar o caracter 's' para o slave. Neste sketch o caracter 's'

                                                     // sinaliza para o slave fazer uma operação de subtração
  charInOut(10);                               // enviar o número 10 para o slave e, ao mesmo tempo, não

                                                     // receber o que quer que seja do slave
  a = charInOut(17);                         // enviar o número 17 para o slave e, ao mesmo tempo, receber o

                                                     // dado enviado do slave armazenando-o na variável "a"
  b = charInOut(33);                         // enviar o número 33 para o slave e, ao mesmo tempo, receber o

                                                     // dado enviado do slave armazenando-o na variável "b"
  c = charInOut(42);                         // enviar o número 42 para o slave e, ao mesmo tempo, receber o

                                                     // dado enviado do slave armazenando-o na variável "c"
  d = charInOut(0);                          // enviar o número 0 (ou qualquer outro caracter) para o slave e,

                                                     // ao mesmo tempo, receber o dado enviado do slave

                                                     // armazenando-o na variável "d". Esta operação só existe para

                                                     // receber dado do slave
  SPI.endTransaction();                    // finalizar a conexão SPI
  digitalWrite(SS, HIGH);                 // desabilitar comunicação SPI com slave

  Serial.print(". Subtraindo 10: ");
  Serial.print(a, DEC);
  Serial.print(", ");
  Serial.print(b, DEC);
  Serial.print(", ");
  Serial.print(c, DEC);
  Serial.print(", ");
  Serial.println(d, DEC);

  Serial.println();
  delay (5000); // esperar 5 segundos para fazer isso tudo novamente
}

-------------------------------------------------------------------------------------------------------------------------------------------------

Código (sketch) para o Arduino slave:

* Neste sketch não usaremos a biblioteca <SPI.h> mas trabalharemos diretamente com os registradores SPI

-------------------------------------------------------------------------------------------------------------------------------------------------

volatile byte command = 'x';                 // Para ter certeza que dados de variáveis globais sejam

                                                         // passados entre as ISRs e o programa principal, use definir

                                                         // a variável como "volatile"

void setup(){
  pinMode(MISO, OUTPUT);                 // pino MISO deste slave é definido como de output

  SPCR |= _BV(SPE);                         // Habilitar a comunicação SPI neste slave atribuindo 1 ao bit

                                                         // SPE do registrador SPCR do SPI do Arduino, ou seja,

                                                         // habilitar SPI neste slave
  SPCR |= _BV(SPIE);                         // Habilitar a interrupção SPI atribuindo 1 ao bit SPIE do

                                                         // registrador SPCR do   SPI do Arduino
}

ISR(SPI_STC_vect){                            // Interrupt Service Routine (ISR), SPI_STC_vect, esta

                                                         // interrupção será executada enquanto estiver recebendo

                                                         // dados do master, ou seja, a interrupt do pino SS em estado

                                                         // BAIXO
  byte c = SPDR;                                // lê o registrador "de troca" SPDR que contém o dado (o byte)

                                                         // enviado pelo master, armazenado-o na variável 'c'
  switch (command){
    case 'x':                                         // se 'command' = 0, ou seja, se não tem uma ação de adição

                                                         // ou subtração
      command = c;                              // atribui à variável 'command' o caracter recebido na variável 'c'
      SPDR = 0;                                   // escreve o número 0 no registrador SPDR, enviando-o ao

                                                         // master
      break;
    case 'a':                                         // se 'command' = 'a' (de adição)
      SPDR = c + 10;                           // soma 10 ao número armazenado em 'c' escrevendo o

                                                         // resultado no registrador SPDR, enviando-o ao master
      break;
    case 's':                                         // se 'command' = 's' (de subtração)
      SPDR = c - 10;                             // subtrai 10 ao número armazenado em 'c' escrevendo o 

                                                         // resultado no registrador SPDR, enviando-o ao master
       break;
  }
}

void loop(){                                         // permanecerá dentro do void loop() enquanto a interrupção

                                                         // ISR(SPI_STC_vect) estiver em estado ALTO, ou seja, com a

                                                         // SPI inativa
  if (digitalRead (SS) == HIGH)             // se a interrupção estiver em estado ALTO, ou seja, se SPI

                                                         // inativa (não estiver recebendo dados do master)
    command = 'x';
}

-------------------------------------------------------------------------------------------------------------------------------------------------

Exibições: 1741

Responder esta

Respostas a este tópico

Analisando a comunicação SPI com o Saleae Logic16 Analyzer:

Análise do gráfico, especificamente para a rotina destes sketchs:

* verificar que a linha SPI-Enable habilita a comunicação entre master e slave colocando-se em estado BAIXO.

* só então, e inicialmente, o master (Channel 3 - MOSI) envia um caracter para o slave (possivelmente o caracter 'a', ou 's') e, ao mesmo tempo, o slave (Channel 4 - MISO) envia um byte ao master (neste momento, conforme o sketch do slave, não há transmissão de dados para o master).

* no segundo momento, o master envia o número '10' mas o slave ainda não tem nada a enviar ao master

* no terceiro momento o master envia o número '17' e, ao mesmo tempo, o slave agora envia o número '20' (a adição de 10 + 10, conforme manda o sketch do slave) ao master.

* segue assim para os demais números do sketch (que não são demonstrados neste gráfico) até findar a execução dos sketch's, quando SPI-Enable desabilita a comunicação entre master e slave colocando-se em estado ALTO.

Conclusão: observa-se então ser a comunicação SPI full duplex.

RSS

© 2024   Criado por Marcelo Rodrigues.   Ativado por

Badges  |  Relatar um incidente  |  Termos de serviço