Como usar a comunicação SPI no microcontrolador STM32

Tempo de leitura: 7 minutes

Neste tutorial, substituiremos uma placa Arduino pela placa Blue Pill que é Stm32f103c8t6 e nos comunicaremos com a placa Arduino usando o barramento SPI.

Neste exemplo STM32 SPI, usaremos Arduino UNO como escravo e STM32F103C8 como mestre com dois monitores LCD 16X2 conectados um ao outro separadamente. Dois potenciômetros também são conectados com STM32 (PA0) e Arduino (A0) para determinar os valores de envio (0 a 255) do mestre para o escravo e do escravo para o mestre variando o potenciômetro.

 

SPI em STM32F103C8

Comparando o barramento SPI no Arduino e a placa STM32F103C8 Blue Pill, o STM32 possui 2 barramentos SPI enquanto o Arduino Uno possui um barramento SPI. O Arduino Uno possui o microcontrolador ATMEGA328 e o STM32F103C8 possui o ARM Cortex-M3, o que o torna mais rápido que a placa Arudino.

Pinos SPI STM32F103C8

SPI Line1Pino em STM32F103C8
MOSI1PA7 ou PB5
MISO1PA6 ou PB4
SCK1PA5 ou PB3
SS1PA4 ou PA15
SPI Line2
MOSI2PB15
MISO2PB14
SCK2PB13
SS2PB12

 

Pinos SPI no Arduino

SPI LinePino no Arduino
MOSI 11 ou ICSP-4
MISO12 ou ICSP-1
SCK13 ou ICSP-3
SS10

Componentes necessários

STM32F103C8
Arduino
LCD 16×2 – 2
Potenciômetro de 10k – 4
ProtoBoard
Fios de conexão

 

Diagrama de circuito e conexões

 

A tabela abaixo mostra os pinos conectados para comunicação STM32 SPI com o Arduino.

SPI Pino STM32F103C8Arduino
MOSIPA711
MISOPA612
SCKPA513
SS1PA410

A tabela abaixo mostra os pinos conectados para Dois LCD (16×2) com STM32F103C8 e Arduino separadamente.

LCD pinoSTM32F103C8Arduino
VSSGNDGND
VDD+5V+5V
V0Para o Pino do centro do potenciômetro para contraste do LCDPara o Pino do centro do potenciômetro para contraste do LCD
RSPB02
RWGNDGND
EPB13
D4PB104
D5PB115
D6PC136
D7PC147
A+5V+5V
KGNDGND

Importante:

Não se esqueça de conectar o Arduino GND e o STM32F103C8 GND juntos.

 

Programação STM32 SPI

A programação é semelhante ao código do Arduino. A mesma biblioteca <SPI.h> é usada na programação STM32F103C8. Pode ser programado usando a porta USB sem usar o programador FTDI, para aprender mais sobre a programação STM32 com Arduino IDE siga o link.

Neste exemplo STM32 SPI, usaremos Arduino UNO como escravo e STM32F103C8 como mestre com dois monitores LCD 16X2 conectados um ao outro separadamente. Dois potenciômetros também são conectados com STM32 (PA0) e Arduino (A0) para determinar os valores de envio (0 a 255) do mestre para o escravo e do escravo para o mestre variando o potenciômetro.

A entrada analógica é feita no pino PA0 do STM32F10C8 (0 a 3,3 V) girando o potenciômetro. Em seguida, esse valor de entrada é convertido em valor analógico para digital (0 a 4096) e esse valor digital é posteriormente mapeado para (0 a 255), pois podemos enviar apenas dados de 8 bits (bytes) por meio da comunicação SPI de uma vez.

Da mesma forma, no lado escravo, pegamos o valor da entrada analógica no pino A0 do Arduino de (0 a 5V) usando o potenciômetro. E novamente este valor de entrada é convertido em valor analógico para digital (0 a 1023) e este valor digital é posteriormente mapeado para (0 a 255)

Este tutorial tem dois programas, um para o STM32 mestre e outro para o Arduino escravo. Programas completos para ambos os lados são fornecidos no final deste projeto.

 

Explicação de programação Master STM32 SPI

1. Em primeiro lugar, precisamos incluir a biblioteca SPI para usar as funções de comunicação SPI e a biblioteca LCD para usar as funções LCD. Defina também os pinos de LCD para LCD 16×2. Saiba mais sobre a interface do LCD com o STM32 aqui.

#include<SPI.h>    
#include<LiquidCrystal.h> 
const int rs = PB0, en = PB1, d4 = PB10 , d5 = PB11 , d6 = PC13, d7 = PC14;  
LiquidCrystal lcd(rs,en,d4,d5,d6,d7);

2. No void setup()

  • Inicie a comunicação serial na taxa Baud 9600.
Serial.begin(9600);
  • Em seguida, comece a comunicação SPI
SPI.begin();
  • Em seguida, defina o divisor de relógio para comunicação SPI. Eu configurei o divisor 16.
SPI.setClockDivider(SPI_CLOCK_DIV16)
  • Em seguida, defina o pino SS para ALTO, pois não iniciamos nenhuma transferência para o arduino escravo.
digitalWrite(SS,HIGH);

3. No void loop()

  • Antes de enviar qualquer valor para o escravo, precisamos BAIXAR o valor de seleção do escravo para iniciar a transferência do mestre para o escravo.
digitalWrite(SS, LOW);
  • Em seguida, leia o valor analógico do POT STM32F10C8 mestre conectado ao pino PA0.
int pot = analogRead(PA0);

Em seguida, converta esse valor em termos de um byte (0 a 255).

byte MasterSend = map(pot,0,4096,0,255);
  • Aí vem a etapa importante, na instrução a seguir enviamos o valor convertido do POT armazenado na variável Mastersend para o Arduino escravo, e também recebemos o valor do Arduino escravo e o armazenamos na variável mastereceive.
Mastereceive = SPI.transfer(Mastersend);
  • Em seguida, exiba os valores recebidos do arduino escravo com um atraso de 500 microssegundos e, em seguida, receba e exiba continuamente os valores.
Serial.println("Slave Arduino para Master STM32");                               
Serial.println(MasterReceive  lcd.setCursor(0,0);                                                         
 lcd.print("Master: STM32");
 lcd.setCursor(0,1);                                                   
 lcd.print("SalveVal:");                                                         
 lcd.print(MasterReceive  delay(500);
 digitalWrite(SS, HIGH);

Nota: Usamos serial.println() para visualizar o resultado no Serial Motor do Arduino IDE.

 

Explicação de programação SPI do Slave Arduino

1. Da mesma forma que o mestre, em primeiro lugar, precisamos incluir a biblioteca SPI para usar as funções de comunicação I2C e a biblioteca LCD para usar as funções LCD. Defina também os pinos de LCD para LCD 16×2.

#include<SPI.h>  
#include<LiquidCrystal.h> 
 LiquidCrystal lcd(2, 3, 4, 5, 6, 7);    // Definir os pinos do módulo LCD (RS, EN, D4, D5, D6, D7)

2. No void setup()

  • Iniciamos a comunicação serial na taxa Baud 9600.
Serial.begin(9600);
  • A instrução abaixo define MISO como OUTPUT (tem que enviar dados para Master IN). Assim, os dados são enviados via MISO do Slave Arduino.
pinMode(MISO,OUTPUT);
  • Agora ligue o SPI no modo escravo usando o registro de controle do SPI
SPCR |= _BV(SPE);
  • Em seguida, ligue a interrupção para comunicação SPI. Se um dado for recebido do mestre, a rotina de serviço de interrupção é chamada e o valor recebido é obtido do SPDR (Registro de dados SPI)
SPI.attachInterrupt();
  • O valor do master é retirado do SPDR e armazenado na variável Slavereceived. Isso ocorre na seguinte função de rotina de interrupção.
ISR (SPI_STC_vect)
{
  Slavereceived = SPDR;                  
  received = true;                       
}

3. Próximo em void loop ()

  • Leia o valor analógico do Slave Arduino POT conectado ao pino A0.
int pot = analogRead(A0);
  • Converta esse valor em termos de um byte de 0 a 255.
Slavesend = map(pot,0,1023,0,255);
  • O próximo passo importante é enviar o valor convertido para o Master STM32F10C8, então coloque o valor no registrador SPDR. O registro SPDR é usado para enviar e receber valores.
SPDR = Slavesend;
  • Em seguida, exiba o valor recebido (SlaveReceive) do Master STM32F103C8 no LCD com um atraso de 500 microssegundos e, em seguida, receba e exiba continuamente esse valor.
lcd.setCursor(0,0);                     
lcd.print("Slave: Arduino");
lcd.setCursor(0,1);                                                    
lcd.print("MasterVal:");   
Serial.println("Master STM32 para Slave Arduino");  
Serial.println(SlaveReceived);                  
lcd.print(SlaveReceived);                       
delay(500);

Girando o potenciômetro de um lado, você pode ver os valores variáveis no LCD do outro lado:

Portanto, é assim que a comunicação SPI ocorre no STM32. Agora você pode conectar qualquer sensor SPI com a placa STM32.

Código

Master STM32 SPI

//Código mestre SPI para STM32F103C8
//Comunicação SPI entre STM32 e Arduino

#include<SPI.h>                                                               // Incluindo biblioteca para usar a comunicação SPI

#define SS PA4                                                              

#include<LiquidCrystal.h>                                                     // Incluindo biblioteca de display LCD

const int rs = PB0, en = PB1, d4 = PB10 , d5 = PB11 , d6 = PC13, d7 = PC14;   // Declarando nomes e números de pinos de LCD

LiquidCrystal lcd(rs,en,d4,d5,d6,d7);                                         // Configurando lcd e seus parâmetros

void setup (void)

{
  lcd.begin(16,2);                                                            // Configurando lcd como modo 16x2
  lcd.setCursor(0,0);                                                         // Setting cursor at first row and first column
  lcd.print("Cap Sistema");                                                   // Coloque Cap Sistema no LCD
  delay(3000);                                                                // Delays por 3 segundos
  lcd.clear();                                                                // Limpa o LCD
  
  Serial.begin(9600);                                                         // Inicia a comunicação serial na taxa Baud 9600
  pinMode(SS,OUTPUT);                                                         // Coloca SS como saída
  SPI.begin();                                                                // Começa a comunicação SPI
  SPI.setClockDivider(SPI_CLOCK_DIV16);                                       // Define o relógio para comunicação SPI em 16 (72/16 = 4,5 MHz)
  digitalWrite(SS,HIGH);                                                      // Configurando Slave Select como HIGH (portanto, o mestre não se conecta ao escravo)
}

void loop(void)
{ 
  
  byte MasterSend,MasterReceive;
  
  int pot = analogRead(PA0);                                                   // Analógico lê o valor do potenciômetro de entrada no pino PA0
  
  MasterSend = map(pot,0,4096,0,255);                                          // Used to convert pot value in terms of 0 to 255 from 0 to 4096
  
  digitalWrite(SS, LOW);                                                       // Inicia a comunicação com o Slave conectado ao mestre
  
  MasterReceive=SPI.transfer(MasterSend);                                      // Envia o valor do mastersend para o escravo também recebe o valor do escravo
  Serial.println("Slave Arduino para Master STM32");                           // Usado no Monitor Serial
  Serial.println(MasterReceive);                                               // Coloca valor recebido no monitor serial
  lcd.setCursor(0,0);                                                          
  lcd.print("Master: STM32");
  lcd.setCursor(0,1);                                                    
  lcd.print("SalveVal:");                                                         
  lcd.print(MasterReceive);                                                    // Coloca o valor recebido do arduino escravo 
  delay(500);
  digitalWrite(SS, HIGH);                                                      // Novamente torna a linha SS ALTA para que não se comunique com o Slave
  lcd.clear();

}

 

Slave Arduino SPI

Slave Arduino SPI

//Código SPI Slave para Arduino
//Comunicação SPI entre STM32F103C8 e Arduino


#include<SPI.h>                           // Incluindo biblioteca para usar a comunicação SPI
#include<LiquidCrystal.h>                 // Incluindo biblioteca de display LCD
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);      // Defina os pinos do módulo LCD (RS, EN, D4, D5, D6, D7)
volatile boolean received;
volatile byte SlaveReceived,Slavesend;
void setup()

{ 
  lcd.begin(16,2);                        // Inicializar display LCD
  lcd.setCursor(0,0);                     // Define o cursor na primeira linha do display
  lcd.print("Cap Sistema");               // Imprime Cap Sistema no LCD 
  delay(3000);                            // Delay por 3 secondos
  lcd.clear();                            // Limpa o LCD
  
  Serial.begin(9600);                     // Inicia a comunicação serial na taxa Baud 9600
  
  pinMode(MISO,OUTPUT);                   // Define MISO como OUTPUT (tem que enviar dados para Master IN (STM32F103C8)
 
  SPCR |= _BV(SPE);                       // Ligue o SPI no modo Slave
  received = false;
  SPI.attachInterrupt();                  // A interrupção ON está definida para comunicação SPI
}

ISR (SPI_STC_vect)                        // Função de rotina de entrada 
{
  SlaveReceived = SPDR;                   // O valor recebido do mestre STM32F103C8 é armazenado na variável slavereceived
  received = true;                        // Conjuntos recebidos como verdadeiros
}

void loop()
{ 
  int pot = analogRead(A0);               // Analógico lê o valor do potenciômetro de entrada do pino analógico A0
  Slavesend = map(pot,0,1023,0,255);      // Converte o valor do potenciômetro (0-1023) em (0-255) para enviar ao mestre stm32
                              
  SPDR = Slavesend;                       // Envia o valor salvesend para o mestre STM32F103C8 via SPDR
  lcd.setCursor(0,0);                     
  lcd.print("Slave: Arduino");
  lcd.setCursor(0,1);                                                     
  lcd.print("MasterVal:");    
  Serial.println("Master STM32 para Slave Arduino");   
  Serial.println(SlaveReceived);                   // Coloca o valor recebido do Mestre STM32F103C8 no Monitor Serial                         
  lcd.print(SlaveReceived);                        // Coloca o valor recebido do Mestre STM32F103C8 no display LCD
  delay(500);
  lcd.clear();
}

 

 

Conclusão

Neste artigo, mostrei como usar a Transferencias de dados SPI entre o Arduino e o STM32. Espero que você tenha achado útil e informativo. Se sim, compartilhe com um amigo que também gosta de eletrônica e de fazer coisas!

Eu adoraria saber quais projetos você planeja construir (ou já construiu) com esses tipo de transferencia usando os dois tipos. Se você tiver alguma dúvida, sugestão ou se achar que falta algo neste tutorial, por favor, deixe um comentário abaixo.