Como configurar a comunicação I2C para o Arduino

cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br


Neste tutorial, discutiremos o que é o protocolo I2C e como ele funciona. Também construiremos um projeto que usa a comunicação I2C para trocar dados entre duas placas Arduino Uno.

Anúncio PCBWay

O que é o I2C?

I2C é um acrônimo para Circuito Inter-Integrado. É um protocolo de comunicação serial de baixa velocidade, adequado para distâncias curtas. Se seus sinais de comunicação precisarem percorrer uma distância substancial, este protocolo não é recomendado. Um exemplo de uma rede I2C simples é mostrado abaixo.

Arduino-I2C-Tutorial-amostra-I2C-rede
Figura 1: Exemplo de rede I2C

Como você pode ver no diagrama, a vantagem de usar o I2C é que você só precisa de dois fios para se comunicar com vários dispositivos. Toda a comunicação passa pelos dois fios para / de dispositivos mestre / escravo. Isso é muito útil ao executar projetos do Arduino. Usando apenas dois fios, o Arduino pode se comunicar com muitos dispositivos no I2C.

A rede I2C

Uma rede I2C consiste em mestre e escravo dispositivos conectados por um ônibus.

A rede I2C pode ter vários dispositivos principais e dispositivos escravos. Todos os dispositivos escravos têm um endereço para identificação na rede. Esse endereço possibilita que um dispositivo mestre envie dados para um dispositivo escravo específico no barramento. Os dispositivos mestres podem enviar e receber dados. Os dispositivos escravos respondem ao que um dispositivo mestre envia. Ao enviar dados no barramento, apenas um dispositivo pode enviar dados por vez.

o ônibus no I2C são simplesmente dois fios que interconectam todos os dispositivos I2C na rede. Os fios são designados como SDA e SCL, respectivamente. A linha SDA conecta os pinos SDA de todos os dispositivos e é para onde os dados são enviados. A linha SCL conecta os pinos SCL de todos os dispositivos e é aqui que o sinal do relógio é enviado para o tempo de comunicação adequado. Os resistores pull-up são necessários para manter as duas linhas no estado HIGH. Deve-se tomar o máximo cuidado e observar ao conectar diferentes dispositivos I2C. Alguns dispositivos I2C operam em um nível lógico diferente. Verifique a folha de dados de cada dispositivo para isso. Se os resistores pull-up estiverem conectados a + 5V, todos os dispositivos devem ser compatíveis para trabalhar com o nível lógico de + 5V.

Para uma leitura mais aprofundada sobre o I2C, acesse https://www.circuitbasics.com/basics-of-the-i2c-communication-protocol/

Fazendo o Arduino falar da maneira I2C

Nosso projeto será sobre duas placas do Arduino Uno se comunicando através do I2C para alterar a taxa de intermitência do LED da outra. Um Arduino atuará como Mestre e o outro Arduino atuará como Escravo.

Arduino UNO I2C

Os Arduinos têm pinos dedicados para I2C. Além disso, esses pinos possuem resistores de pull-up, conforme exigido pelo protocolo I2C.

Para placas UNO Arduino, esses são pinos A4 / A5 como SDA / SCL, respectivamente. Para a versão R3, há outro local para o I2C próximo ao soquete USB da placa. Veja a figura 2.

Arduino-UNO-I2C-pinos-R3
Figura 2: Localização dos pinos do Arduino I2C

Componentes de hardware

  • Placa Arduino Uno – 2 unid.
  • Potenciômetro (10Kohm) – 2 unid.
  • Jumper wires

Diagrama de ligação

Depois de reunir todos os componentes necessários, chegou a hora de montar o projeto. Vejo Figura 3 para o diagrama de conexão. Como você deve ter notado, não temos resistores pull-up nas linhas SDA e SCL. Os resistores pull-up já estão embutidos no Arduino UNO.

Conexão do Arduino-I2C-Tutorial
Figura 3: Diagrama de conexão

Esboço para o dispositivo mestre do Arduino

Como temos duas placas Arduino em nossa rede I2C, temos dois conjuntos de esboços. Não há muita diferença entre os dois esboços, como você verá mais adiante. A função dos dispositivos mestre e escravo é ler o valor de uma entrada do potenciômetro, transmutar o valor e enviá-lo para o dispositivo escravo via I2C.

Leia Também  Como lidar com "gengivas negras" do tabagismo [Plus, 9 Other Causes]

Agora, inicie o seu software IDE favorito do Arduino e crie um novo esboço.

Código básico para o nosso projeto

A parte básica do nosso código para os dispositivos mestre e escravo é o que eu chamo de piscar código lógico. Este é o código que piscará o LED embutido das placas Arduino. Para fazer isso, adicionaremos o seguinte código:

  • Adicionar variáveis ​​globais byte i2c_rcv,int time_start, stat_LED e byte value_pot no topo do nosso esboço.
  • Inicialize valores das variáveis ​​globais dentro setup()
  • Inicialize o pino 13 do Arduino Uno como pino de saída dentro setup() usando pinMode()
  • Adicione o código lógico intermitente dentro loop()
// Arduino I2C Tutorial
// MASTER sketch

byte i2c_rcv;               // data received from I2C bus
unsigned long time_start;   // start time in mSec
int stat_LED;               // status of LED: 1 = ON, 0 = OFF
byte value_pot;             // potentiometer position

void setup()
{
	// initialize global variables
	i2c_rcv = 255;
	time_start = millis();
	stat_LED = 0;
	
	pinMode(13, OUTPUT);    // set pin 13 mode to output
}

void loop()
{
	// blink logic code
	if((millis() - time_start) > (1000 * (float)(i2c_rcv/255))) {
		stat_LED = !stat_LED;
		time_start = millis();
	}
	digitalWrite(13, stat_LED);
}

Wire Library

Para usar a interface I2C embutida no Arduino, usaremos o Biblioteca de fios. Essa biblioteca é padrão com o IDE do Arduino. Como em outras bibliotecas do Arduino, a Wire Library possui funções I2C prontas para facilitar a codificação para nós. Para usar as funções da Biblioteca de Fios, precisamos adicioná-lo primeiro ao nosso esboço. Em nosso esboço, adicione a seguinte linha na parte superior: #include

// Arduino I2C Tutorial
// MASTER sketch

#include 

byte i2c_rcv;               // data received from I2C bus
unsigned long time_start;   // start time in mSec
int stat_LED;               // status of LED: 1 = ON, 0 = OFF
byte value_pot;             // potentiometer position

void setup()
{
	// initialize global variables
	i2c_rcv = 255;
	time_start = millis();
	stat_LED = 0;
	
	pinMode(13, OUTPUT);    // set pin 13 mode to output
}

void loop()
{
	// blink logic code
	if((millis() - time_start) > (1000 * (float)(i2c_rcv/255))) {
		stat_LED = !stat_LED;
		time_start = millis();
	}
	digitalWrite(13, stat_LED);
}

Depois de adicionar a biblioteca em nosso esboço, agora podemos usar as funções internas da biblioteca. A primeira coisa a fazer é conectar o dispositivo no barramento I2C. A sintaxe para isso é Wire.begin(address). o endereço é opcional para dispositivos principais. Portanto, para o esboço do Arduino destinado ao dispositivo mestre, adicionamos o código Wire.begin(); dentro setup().

cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br
// Arduino I2C Tutorial
// MASTER sketch

#include 

byte i2c_rcv;               // data received from I2C bus
unsigned long time_start;   // start time in mSec
int stat_LED;               // status of LED: 1 = ON, 0 = OFF
byte value_pot;             // potentiometer position

void setup()
{
	Wire.begin(); // join I2C bus as Master
	
	// initialize global variables
	i2c_rcv = 255;
	time_start = millis();
	stat_LED = 0;
	
	pinMode(13, OUTPUT);    // set pin 13 mode to output
}

void loop()
{
	// blink logic code
	if((millis() - time_start) > (1000 * (float)(i2c_rcv/255))) {
		stat_LED = !stat_LED;
		time_start = millis();
	}
	digitalWrite(13, stat_LED);
}

Agora, passamos ao código para o loop(). Nosso código fará com que o Arduino leia o valor do potenciômetro conectado ao pino A0 e salve o valor na variável value_pot.

// Arduino I2C Tutorial
// MASTER sketch

#include 

byte i2c_rcv;               // data received from I2C bus
unsigned long time_start;   // start time in mSec
int stat_LED;               // status of LED: 1 = ON, 0 = OFF
byte value_pot;             // potentiometer position

void setup()
{
	Wire.begin(); // join I2C bus as Master
	
	// initialize global variables
	i2c_rcv = 255;
	time_start = millis();
	stat_LED = 0;
	
	pinMode(13, OUTPUT);    // set pin 13 mode to output
}

void loop()
{
	// read potentiometer position
	value_pot = analogRead(A0);   // read analog value at pin A0 (potentiometer voltage)

	// blink logic code
	if((millis() - time_start) > (1000 * (float)(i2c_rcv/255))) {
		stat_LED = !stat_LED;
		time_start = millis();
	}
	digitalWrite(13, stat_LED);
}

Enviando dados

Depois de salvar o valor do pino A0 para a variável value_pot, agora estamos prontos para enviar o valor por I2C. O envio de dados pelo I2C envolve o uso de três funções que são Wire.beginTransmission(), Wire.write() e Wire.endTransmission().

Wire.beginTransmission ()

Iniciamos um comando de envio informando primeiro os dispositivos no barramento que enviaremos dados. Para fazer isso, chamamos a função Wire.beginTransmission(address). o address é o endereço do dispositivo escravo pretendido que receberá os dados. Essa função faz duas coisas:

  • Ele informa ao barramento que estaremos enviando dados.
  • Informa o destinatário pretendido dos dados para estar pronto para receber.
Wire.write ()

E então estaremos enviando o valor da variável value_to_send usando a função Wire.write(value).

Wire.endTransmission ()

Após o envio dos dados, precisamos liberar a rede para permitir que outros dispositivos enviem dados ou para que um dispositivo escravo responda (no caso de solicitações de dados). Isso é feito usando a função Wire.endTransmission().

// Arduino I2C Tutorial
// MASTER sketch

#include 

byte i2c_rcv;               // data received from I2C bus
unsigned long time_start;   // start time in mSec
int stat_LED;               // status of LED: 1 = ON, 0 = OFF
byte value_pot;             // potentiometer position

void setup()
{
	Wire.begin(); // join I2C bus as Master
	
	// initialize global variables
	i2c_rcv = 255;
	time_start = millis();
	stat_LED = 0;
	
	pinMode(13, OUTPUT);    // set pin 13 mode to output
}

void loop()
{
	// read potentiometer position
	value_pot = analogRead(A0);   // read analog value at pin A0 (potentiometer voltage)

	// send potentiometer position to Slave device 0x08
	Wire.beginTransmission(0x08); // informs the bus that we will be sending data to slave device 8 (0x08)
	Wire.write(value_pot);        // send value_pot
	Wire.endTransmission();       // informs the bus and the slave device that we have finished sending data
	
	// blink logic code
	if((millis() - time_start) > (1000 * (float)(i2c_rcv/255))) {
		stat_LED = !stat_LED;
		time_start = millis();
	}
	digitalWrite(13, stat_LED);
}

Nosso dispositivo mestre também precisa obter a posição do potenciômetro no dispositivo escravo. Fazemos isso usando Wire.requestFrom(), Wire.available() e Wire.read().

Wire.requestFrom ()

A sintaxe completa para solicitar dados de um dispositivo escravo é Wire.requestFrom(address, quantity). o address é o endereço do dispositivo escravo de que precisamos para obter dados e quantity é o número de bytes que precisamos. Para o nosso projeto, o endereço do dispositivo escravo é 0x08 e precisamos de um byte.

Dentro de loop(), adicionamos a linha de código Wire.requestFrom(0x08, 1); solicitar do escravo 0x08 um byte de dados.

Depois de emitir o comando Wire.requestFrom(0x08, 1), deve ser seguido por um comando de leitura para obter a resposta do barramento I2C.

Write.available ()

Primeiro, verificamos se há dados disponíveis no barramento. Fazemos isso usando a função Write.available() dentro de um condicional IF()declaração. A função Write.available() retorna o número de bytes aguardando para serem lidos.

Wire.read ();

Para disponibilizar os dados, usamos a função Wire.read() e salve o valor de retorno na variável i2c_rcv. Cada chamada para a função Wire.read() obtém apenas um byte de dados do barramento I2C.

O código abaixo mostra como as três funções são implementadas em nosso esboço.

// Arduino I2C Tutorial
// MASTER sketch

#include 

byte i2c_rcv;               // data received from I2C bus
unsigned long time_start;   // start time in mSec
int stat_LED;               // status of LED: 1 = ON, 0 = OFF
byte value_pot;             // potentiometer position

void setup()
{
	Wire.begin(); // join I2C bus as Master
	
	// initialize global variables
	i2c_rcv = 255;
	time_start = millis();
	stat_LED = 0;
	
	pinMode(13, OUTPUT);    // set pin 13 mode to output
}

void loop()
{
	// read potentiometer position
	value_pot = analogRead(A0);   // read analog value at pin A0 (potentiometer voltage)

	// send potentiometer position to Slave device 0x08
	Wire.beginTransmission(0x08); // informs the bus that we will be sending data to slave device 8 (0x08)
	Wire.write(value_pot);        // send value_pot
	Wire.endTransmission();       // informs the bus and the slave device that we have finished sending data

	Wire.requestFrom(0x08, 1);    // request potentiometer position from slave 0x08
	if(Wire.available()) {	      // read response from slave 0x08
		i2c_rcv = Wire.read();
	}
	
	// blink logic code
	if((millis() - time_start) > (1000 * (float)(i2c_rcv/255))) {
		stat_LED = !stat_LED;
		time_start = millis();
	}
	digitalWrite(13, stat_LED);
}

Finalmente, concluímos o esboço do nosso dispositivo mestre do Arduino. Salve o esboço como arduino_I2C_master.ino

Esboço para dispositivo escravo do Arduino

Para o esboço do Arduino Slave, abra um novo arquivo no Arduino IDE e adicione o código básico mencionado neste tutorial.

Nosso esboço acima é destinado ao dispositivo mestre do Arduino. Para o dispositivo escravo, há uma pequena diferença na codificação da comunicação I2C. A primeira diferença está no Wire.begin(address). Para dispositivos escravos, o address é um requisito. Para o nosso projeto, o endereço do dispositivo escravo será 0x08. Pode ser qualquer endereço que você desejar, mas verifique se ele é único na rede I2C. Alguns dispositivos escravos I2C também têm seus endereços definidos, portanto, verifique sempre suas respectivas folhas de dados.

Nós ingressaremos na rede I2C como um dispositivo escravo adicionando o código Wire.begin(0x08);dentro setup().

// Arduino I2C Tutorial
// SLAVE sketch

#include 

byte i2c_rcv;               // data received from I2C bus
unsigned long time_start;   // start time in mSec
int stat_LED;               // status of LED: 1 = ON, 0 = OFF
byte value_pot;             // potentiometer position

void setup()
{
	Wire.begin(0x08);           // join I2C bus as Slave with address 0x08
	
	// initialize global variables
	i2c_rcv = 255;
	time_start = millis();
	stat_LED = 0;
	
	pinMode(13, OUTPUT);        // set pin 13 mode to output
}

void loop()
{
	// send potentiometer position
	value_pot = analogRead(A0); // read analog value at pin A0 (potentiometer voltage)
	
	// blink logic code
        if((millis() - time_start) > (1000 * (float)(i2c_rcv/255))) {
		stat_LED = !stat_LED;
		time_start = millis();
	}
	digitalWrite(13, stat_LED);
}

Manipuladores de Eventos

A próxima tarefa é adicionar manipuladores de eventos ao nosso código para gerenciar dados recebidos de outros dispositivos na rede I2C. Manipuladores de eventos são trechos de código que gerencia eventos que nosso dispositivo provavelmente encontrará durante a execução.

Wire.onReceive ()

No setup() parte do nosso esboço, adicionaremos a função Wire.onReceive(handler) para registrar uma função (a manipulador) que gerenciará os dados recebidos. Vamos chamar nossa função de manipulador como dataRcv(). Observe que o nome da função pode ser o que quisermos. Em nosso código, adicionaremos a linha Wire.onReceive(dataRcv); no setup(). Além disso, no final do nosso esboço, criaremos o código para a função manipuladora. É inicializado como void dataRcv(int numBytes). O parâmetro int numBytes contém o número de bytes de dados recebidos.

Wire.onRequest ()

O próximo manipulador de eventos que usaremos é Wire.onRequest(handler). Esta função é usada em dispositivos escravos e funciona de maneira semelhante à Wire.onReceive(). A única diferença é que ele lida com eventos de solicitações de dados. Os pedidos de dados são provenientes de dispositivos principais. Abaixo explica como usá-lo em nosso código.

No setup(), adicionamos o código Wire.onRequest(dataRqst);. E no final do nosso esboço, adicionamos a função void dataRqst(). Por favor note que Wire.onRequest() manipuladores não aceitam nenhum parâmetro. A função dataRqst() contém apenas Wire.write(). Nós não precisamos Wire.beginTransmission() e Wire.endTransmission(). Isso ocorre porque a Biblioteca de Fios já lida com as respostas dos dispositivos escravos.

E aqui está o código para o dispositivo escravo do Arduino, salve-o como arduino_I2C_slave.ino

// Arduino I2C Tutorial
// SLAVE sketch

#include 

byte i2c_rcv;               // data received from I2C bus
unsigned long time_start;   // start time in mSec
int stat_LED;               // status of LED: 1 = ON, 0 = OFF
byte value_pot;             // potentiometer position

void setup()
{
	Wire.begin(0x08);           // join I2C bus as Slave with address 0x08
	
	// event handler initializations
	Wire.onReceive(dataRcv);    // register an event handler for received data
	Wire.onRequest(dataRqst);   // register an event handler for data requests
	
	// initialize global variables
	i2c_rcv = 255;
	time_start = millis();
	stat_LED = 0;
	
	pinMode(13, OUTPUT);        // set pin 13 mode to output
}

void loop()
{

	value_pot = analogRead(A0); // read analog value at pin A0 (potentiometer voltage)
	
	// blink logic code
        if((millis() - time_start) > (1000 * (float)(i2c_rcv/255))) {
		stat_LED = !stat_LED;
		time_start = millis();
	}
	digitalWrite(13, stat_LED);
}

//received data handler function
void dataRcv(int numBytes)
{
	while(Wire.available()) {	// read all bytes received
		i2c_rcv = Wire.read();
	}
}

// requests data handler function
void dataRqst()
{
	Wire.write(value_pot); // send potentiometer position
}

Testando nosso projeto de comunicação Arduino I2C

Aí vem a parte mais emocionante: ligar e testar!

Usando o Arduino IDE, faça o download do arduino_I2C_master.ino para uma das placas do Arduino Uno. Depois de baixar o esboço no quadro, conecte o outro quadro e faça o download do arquivo arduino_I2C_slave.ino. E nós terminamos!

Operação

  • Ajuste o potenciômetro no dispositivo mestre para controlar a taxa de piscada do LED do dispositivo escravo.
  • Ajuste o potenciômetro no dispositivo escravo para controlar a taxa de piscada do LED do dispositivo mestre.

Nosso código toma a posição do potenciômetro do mestre e o envia para o dispositivo escravo por I2C. O dispositivo escravo usa o valor recebido para ajustar o tempo de atraso do piscar do LED. O mesmo acontece com a posição do potenciômetro do escravo.

cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br