O popular protocolo I2C permite que duas ou mais placas Arduino se comuniquem. Descubra como conectá-los e codificá-los.
Embora um único Arduino possa realizar muitas tarefas, alguns projetos podem exigir o uso de mais de uma placa para lidar com diferentes funcionalidades. Portanto, para permitir a transferência de dados entre os dois microcontroladores, um protocolo de comunicação como CAN, SPI, I2C ou UART deve ser configurado.
Neste guia, abordaremos o básico de como o I2C funciona, as conexões de hardware e a implementação de software necessária para configurar duas placas Arduino como dispositivos I2C mestre e escravo.
O que é I2C?
Inter-Integrated Circuit (I2C) é um protocolo de comunicação amplamente utilizado em sistemas embarcados e microcontroladores para permitir a transferência de dados entre dispositivos eletrônicos. Ao contrário do SPI (Serial Peripheral Interface), o I2C permite conectar mais de um dispositivo mestre a um barramento com um ou vários dispositivos escravos. Foi usado pela primeira vez pela Philips e também é conhecido como protocolo de comunicação Two Wire Interface (TWI).
Como funciona a comunicação I2C?
O I2C usa duas linhas bidirecionais: Serial Data (SDA) e Serial Clock (SCL) para transferir dados e sincronizar a comunicação entre os dispositivos. Cada dispositivo conectado ao barramento I2C possui um endereço único que o identifica durante a comunicação. O protocolo I2C permite que vários dispositivos compartilhem o mesmo barramento, e cada dispositivo pode atuar como mestre ou escravo.
A comunicação é iniciada pelo dispositivo mestre e o endereçamento incorreto dos dispositivos escravos pode causar erros na transferência. Confira nosso guia detalhado sobre como funcionam as comunicações seriais UART, SPI e I2C para lhe dar algum contexto.
Uma grande vantagem da comunicação I2C digna de nota é a flexibilidade que ela oferece quando se trata de gerenciamento de energia. Dispositivos que operam em diferentes níveis de tensão ainda podem se comunicar de forma eficaz com a ajuda de conversores de tensão. Isso significa que os dispositivos operando em 3,3 V precisam de conversores de tensão para se conectar a um barramento I2C de 5 V.
A Biblioteca de Fios
A biblioteca Wire é uma biblioteca integrada do Arduino que fornece funções para se comunicar por I2C. Ele usa dois pinos - SDA e SCL - na placa Arduino para comunicação I2C.
Pinos I2C no Arduino Uno:
Pinos Arduino Nano I2C:
Para usar a biblioteca, você deve incluir o fio.h arquivo de cabeçalho no início do esboço do Arduino.
#incluir
A biblioteca Wire fornece funções para iniciar a comunicação com um dispositivo I2C, enviar dados e receber dados. Algumas funções importantes que você deve saber incluem:
- Wire.begin(): usado para entrar no barramento I2C e iniciar a comunicação.
- Wire.beginTransmission(): usado para especificar o endereço do escravo e iniciar uma transmissão.
- Wire.write(): usado para enviar dados para o dispositivo I2C.
- Wire.endTransmission(): usado para encerrar a transmissão e verificar se há erros.
- Wire.requestFrom(): usado para solicitar dados do dispositivo I2C.
- Fio.disponível(): usado para verificar se os dados estão disponíveis para leitura do dispositivo I2C.
- Wire.read(): usado para ler dados do dispositivo I2C.
Use o Wire.beginTransmission() função para definir o endereço do sensor, que é inserido como um argumento. Por exemplo, se o endereço do sensor for 0x68, você usaria:
Arame.startTransmission(0x68);
Configuração de Hardware Arduino I2C
Para conectar duas placas Arduino usando I2C, você precisará dos seguintes componentes de hardware:
- Duas placas Arduino (mestre e escravo)
- Protoboard
- Fios de jumper
- Dois resistores pull-up de 4,7kΩ
Conecte o SDA e SCL pinos de ambas as placas Arduino a uma breadboard. Conecte os resistores pull-up entre os SDA e SCL pinos e o 5V power rail na breadboard. Por fim, conecte as duas breadboards usando fios de jumper.
Circuito Arduino Uno
Circuito Arduino Nano
Configurando as placas Arduino como dispositivos mestre e escravo I2C
Use o Wire.requestFrom() função para especificar o endereço do dispositivo escravo com o qual queremos nos comunicar. Então use o Wire.read() função para obter dados do dispositivo escravo.
Código do dispositivo mestre:
#incluir
vazioconfigurar(){
Arame.começar(); // junta-se ao barramento i2c
Serial.começar(9600); // inicia serial para saída
}
vazioreceber dados(){
int endereço = 8;
int bytesToRead = 6;
Arame.requestFrom(endereço, bytesToRead);
enquanto (Arame.disponível()) {
Caracteres dados = Arame.ler();
Serial.imprimir(dados);
}
atraso(500);
}
vaziolaço(){
receberDados();
}
O Wire.onReceive() A função é usada para especificar o que fazer quando o escravo recebe dados do dispositivo mestre. No código acima, o Fio.disponível() função verifica se os dados estão disponíveis, e o Wire.read() função lê os dados enviados pelo dispositivo mestre.
Código do dispositivo escravo:
#incluir
vazioconfigurar(){
Arame.começar(8); // junta o barramento I2C com endereço 8
Arame.ao receber(receberEvento); // chama receiveEvent quando os dados são recebidos
}
vaziolaço(){
atraso(100);
}
vazioreceberEvento(int bytes){
Arame.escrever("olá "); // responde com mensagem de 6 bytes conforme esperado pelo mestre
}
Enviando e recebendo dados usando I2C
Neste exemplo, vamos ler a temperatura de um sensor de temperatura DHT11 interfaceado com o Arduino escravo e imprimi-lo no monitor serial do Arduino mestre.
Vamos modificar o código que escrevemos anteriormente para incluir a medição de temperatura que enviaremos para a placa mestre pelo barramento I2C. A placa mestre pode então ler o valor que enviamos e exibi-lo no monitor serial.
Código do dispositivo mestre:
#incluir
vazioconfigurar(){
Arame.começar();
Serial.começar(9600);
Serial.println("Mestre inicializado!");
}
vaziolaço(){
Arame.requestFrom(8, 1); // Solicita dados de temperatura do escravo
se (Arame.disponível()) {
byte temperatura = Arame.ler(); // Lê os dados de temperatura do escravo
Serial.imprimir("Temperatura: ");
Serial.imprimir(temperatura);
Serial.println("°C");
}
atraso(2000); // Espera 2 segundos antes de solicitar temperatura novamente
}
Código do dispositivo escravo:
#incluir
#incluir#definir DHCPIN4 // Pino conectado ao sensor DHT
#definir DHTTYPE DHT11 // Tipo de sensor DHT
DHT dht(DHTPIN, DHTTYPE);
byte temperatura;vazioconfigurar(){
Arame.começar(8); // O endereço do escravo é 8
Arame.onRequest(pedidoEvento);
dht.começar();
}vaziolaço(){
atraso(2000); // Espera 2 segundos para o DHT estabilizar
temperatura = dht.lerTemperatura(); // Lê a temperatura do sensor DHT
}
vaziorequestEvent(){
Arame.escrever(temperatura); // Envia dados de temperatura para o mestre
}
Você pode personalizar este código para se adequar a quaisquer sensores que você possa ter em seu projeto, ou até mesmo exibir os valores do sensor em um módulo de exibição para faça seu próprio termômetro e medidor de umidade.
Endereçamento Escravo com I2C no Arduino
Para ler os valores dos componentes adicionados a um barramento I2C em tal projeto, é importante que você inclua o endereço escravo correto ao codificar. Felizmente, o Arduino oferece uma biblioteca de scanner que simplifica o processo de identificação de escravos endereços, eliminando a necessidade de vasculhar extensas folhas de dados do sensor e confusão on-line documentação.
Use o código a seguir para identificar o endereço de qualquer dispositivo escravo presente no barramento I2C.
#incluir
// Inclui a biblioteca Wire para comunicação I2C vazioconfigurar(){
Arame.começar(); // Inicializa a comunicação I2C
Serial.começar(9600); // Inicializa a comunicação serial com baud rate de 9600
enquanto (!Serial); // Aguarda o estabelecimento da conexão serial
Serial.println("\nLeitor I2C"); // Imprime uma mensagem indicando o início da varredura I2C
}vaziolaço(){
byte erro, endereço; // Declara variáveis para armazenar erros e endereços de dispositivos
int nDispositivos; // Declara uma variável para armazenar o número de dispositivos encontradosSerial.println("Digitalizando..."); // Imprime uma mensagem indicando o início da varredura I2C
nDispositivos = 0; // Define o número de dispositivos encontrados para 0
para (endereço = 1; endereço < 127; endereço++) { // Itera sobre todos os endereços I2C possíveis
Arame.startTransmission(endereço); // Inicia uma transmissão para o endereço atual
erro = Arame.endTransmission(); // Termina a transmissão e armazena quaisquer errosse (erro == 0) { // Se nenhum erro foi encontrado
Serial.imprimir("Dispositivo I2C encontrado no endereço 0x"); // Imprime uma mensagem indicando que um dispositivo foi encontrado
se (endereço < 16) Serial.imprimir("0"); // Se o endereço for menor que 16, adicione um 0 à esquerda para fins de formatação
Serial.imprimir(endereço, HEX); // Imprime o endereço em formato hexadecimal
Serial.println(" !"); // Imprime uma mensagem indicando que um dispositivo foi encontrado
nDispositivos++; // Incrementa o número de dispositivos encontrados
}
outrose (erro == 4) { // Se um erro foi encontrado
Serial.imprimir("Erro desconhecido no endereço 0x"); // Imprime uma mensagem indicando que um erro foi encontrado
se (endereço < 16) Serial.imprimir("0"); // Se o endereço for menor que 16, adicione um 0 à esquerda para fins de formatação
Serial.println(endereço, HEX); // Imprime o endereço em formato hexadecimal
}
}
se (nDispositivos == 0) { // Se nenhum dispositivo foi encontrado
Serial.println("Nenhum dispositivo I2C encontrado\n"); // Imprime uma mensagem indicando que nenhum dispositivo foi encontrado
}
outro { // Se os dispositivos foram encontrados
Serial.println("concluído\n"); // Imprime uma mensagem indicando o fim da varredura I2C
}
atraso(5000); // Atrasa 5 segundos antes de iniciar a próxima varredura
}
Expanda seu projeto hoje
A interface de duas placas Arduino usando o protocolo de comunicação I2C oferece uma maneira flexível e eficiente de realizar tarefas complexas que não podem ser realizadas por uma única placa. Com a ajuda da biblioteca Wire, a comunicação entre as duas placas usando I2C é facilitada, permitindo que você adicione mais componentes ao seu projeto.