Introdução
I2C comunicações tornaram-se de facto o método de comunicação entre microcontroladores, microcomputadores e uma variedade de circuitos integrados e sensores. Ele existe desde 1982 e foi originalmente desenvolvido para uso em receptores de televisão.
embora tenhamos usado muitos sensores e exibições de I2C em artigos anteriores, na verdade não vimos como o I2C funciona e como ele pode ser usado para se comunicar entre microcontroladores.
hoje vamos corrigir isso e aprender mais sobre I2C. também vamos ver como ele pode ser usado para trocar informações entre dois Arduinos e como ele pode ser usado para permitir que um Arduino para controlar outro.
Este será o primeiro de quatro artigos sobre I2C. Nos próximos artigos iremos ver como podemos construir o nosso próprio I2C dispositivos, como interface de um Raspberry Pi e um Arduino usando I2C e como fazer algumas avançada I2C configurações, incluindo o uso de vários mestres em um barramento I2C.vamos começar!
I2C Communications
I2C is a serial protocol used on a low-speed 2-wire interface. Foi originalmente desenvolvido por Phillips em 1982 para permitir que circuitos integrados dentro de receptores de televisão se comunicassem uns com os outros.
Os tempos mudaram, Phillips é agora NXP e I2C tornou-se um padrão de comunicação que é suportado por praticamente todos os principais fabricantes de semicondutores.
I2C é uma abreviatura para”circuito Inter-integrado”. Também é chamado ” IIC “ou”I squared C”.
Uses and Limitations
I2C is used with microcontrollers like the Arduino and with microcomputers like the Raspberry Pi. Muitos displays e sensores interface para seu controlador host usando I2C.
I2C tem várias limitações no entanto. Não é particularmente rápido, embora para a maioria de suas utilizações pretendidas é bastante rápido o suficiente.
I2C só pode ser usado em distâncias curtas, afinal de contas, ele foi originalmente concebido para se comunicar entre circuitos integrados na mesma placa de circuitos impressos. A distância máxima de transmissão confiável diminui à medida que a velocidade aumenta, na velocidade mais lenta (100 Kbaud ou uma taxa de relógio de 100 KHz) a distância máxima é de cerca de um metro.
velocidades I2C
o barramento I2C original tinha uma velocidade máxima de 100 KHz. As aplicações mais comuns ainda usam esta velocidade, pois é bastante suficiente para transferir dados de sensores e para exibições simples.
I2C e tem alguns modos de velocidade mais elevados. Nem todos os dispositivos I2C suportam estes modos:
- Modo Rápido – este tem uma velocidade máxima de relógio de 400 KHz.
- Modo de alta Velocidade – máxima frequência de relógio fo 3.4 MHz
- Ultra Modo Rápido – Máxima frequência de clock de 5 MHz
Em um barramento I2C é o mestre que determina a velocidade do relógio.
como o I2C funciona
um barramento I2C tem dois sinais, juntamente com uma conexão de energia e solo.
As duas linhas de sinal são as seguintes:
- SDA – esta é a linha de dados bidireccional.
- SCL – este é o sinal do relógio.
Existem duas resistências de tracção ligadas a cada linha de sinal, que puxam o barramento até à tensão de alimentação quando está inactivo.Note que a tensão de alimentação não é padrão, pode ser de 3,3 ou 5 volts. Também pode ser uma menor voltagem para algumas implementações I2C de alta velocidade.
Esta diferença nas tensões de alimentação pode causar problemas quando você está interagindo com dispositivos I2C que usam diferentes níveis lógicos. Vamos discutir isso mais em um artigo futuro quando eu lhe mostrar como interface um Raspberry Pi (3.3-volt logic) with an Arduino Uno (5-volt logic).
Existem dois tipos de dispositivos que podem ser conectados aos mestres de ônibus e escravos I2C.
O dispositivo principal controla o barramento e fornece o sinal do relógio. Pede dados dos escravos individualmente. Pode haver mais de um dispositivo mestre no ônibus, mas apenas um pode ser o mestre ativo a qualquer momento.
os dispositivos principais não têm um endereço atribuído a eles.
dispositivos escravos têm um endereço, e este endereço precisa ser único no ônibus. Eles usam um esquema de endereçamento de 7 bits, então até 128 escravos podem estar em um ônibus I2C. Na vida real esta grande coleção de dispositivos nunca é usado, é raro ver mais de uma dúzia de dispositivos I2C em um ônibus.
um novo esquema de endereçamento de 10 bits foi implementado, é backward-compatível com o método de endereçamento de 7 bits existente.
dispositivos comerciais I2C são alocados endereço I2C pela NXP, que mantém as especificações do barramento. Embora o I2C tenha sido de código aberto desde 2006, há uma taxa cobrada para obter um endereço escravo do NXP. Não é exigida qualquer taxa para os dispositivos principais ou para os dispositivos que não se destinam à fabricação comercial.
alguns dispositivos I2C recebem vários endereços, geralmente variâncias nos bits de endereços inferiores. Estes dispositivos podem ser configurados manualmente para diferentes endereços, permitindo que vários dispositivos do mesmo tipo sejam usados em um único barramento I2C.
outros derivados I2C
Existem outros barramentos que foram derivados do barramento I2C, e que são em muitos aspectos compatíveis com I2C.
- TWI – a Interface de fio duplo é virtualmente idêntica ao barramento I2C. Este é realmente o ônibus que o Arduino usa, TWI foi desenvolvido quando o ônibus I2C não era de código aberto e Atmel não queria arriscar uma violação de nome comercial. A única grande diferença entre TWI e I2C é que o TWI não suporta uma técnica avançada chamada “clock stretching”.
- SMBus is another I2C equivalent bus, developed by Intel. Como o TWI, ele suporta a maioria dos recursos do I2C.
num artigo futuro, explicarei como os dados do barramento I2C estão estruturados. Mas agora temos algumas informações básicas do I2C, o suficiente para começar a experimentar.
Arduino Wire Library
The Arduino has a built-in library for working with I2C called The Wire Library. Torna muito fácil comunicar – se no autocarro I2C, e pode configurar o Arduino para se tornar um mestre ou um escravo.
The Wire library has several useful functions for working with I2C.
- begin() – isto inicia a biblioteca e configura o Arduino como mestre ou escravo.
- request from() – esta função é usada pelo mestre para solicitar dados de um escravo.
- beginTransmission() – esta função é usada pelo mestre para enviar dados a um escravo especificado.
- endTransmission() – Esta função é usada pelo mestre para terminar uma transmissão começou com o beginTransmission função.
- write() – usado tanto pelo mestre como pelo escravo para enviar dados no barramento I2C.
- disponível() – usado tanto pelo mestre como pelo escravo para determinar o número de bytes nos dados que estão a receber.
- read() – lê um byte de dados do barramento I2C.
- SetClock() – usado pelo mestre para definir uma frequência de clock específica.
- onReceive() – Usado pelo escravo para especificar uma função que é chamada quando os dados são recebidos do mestre.
- onRequest() – usado pelo escravo para especificar uma função que é chamada quando o mestre pediu dados.
usaremos algumas destas funções em nossos esboços.
Arduino I2C conexões
as conexões SDA e SCL para I2C são diferentes entre os modelos Arduino. As experiências que estou prestes a mostrar-lhe foram feitas usando dois Arduino Unos, mas você pode usar outros modelos do Arduino desde que você mude os pinos de acordo.preparei um gráfico para o ajudar a perceber. Inclui algumas placas de Arduino comuns, bem como alguns dos chips discretos. Os pinouts para a lista chips I (ATTiny e ATmega328P) são com o pacote DIP, não os de superfície-montagem.
Arduino Board or Chip | SDA | SCL |
Uno | A4 | A5 |
Mega2560 | 20 | 21 |
Nano | A4 | A5 |
Pro Mini | A4 | A5 |
Leonardo | 2 | 3 |
Due (has two I2C) | 20 + SDA1 | 20 + SCL1 |
ATTiny85 & ATTiny45 | 5 | 7 |
ATmega328P | 27 | 28 |
Alguns Arduino Uno clones têm separado SDA e SCL pinos e você pode usá-los em vez de dois pinos analógicos, se você desejar. Eles estão ligados internamente ao mesmo lugar.
Note que o Arduino Due realmente tem duas portas I2C.
também, esteja ciente de que existem alguns diagramas de Conexão incorretos na internet para o Pro Mini. Usar os dois pinos analógicos A4 e A5, como mostrado na tabela acima.
I2C entre 2 Arduino’s
para o nosso primeiro experimento vamos hoo dois Arduinos juntos e trocar dados entre eles. Um Arduino será o mestre, o outro será o escravo.
estou usando dois Arduino Unos, mas você pode substituir outros Arduino’s se você não tem dois Unos. Use o gráfico anterior para as ligações.
ligar 2 Arduino’s
Aqui está como eu conectei os meus dois Arduino Unos juntos:
é uma ligação bastante simples, essencialmente você apenas amarra o chão e os dois pinos I2C juntos.
uma coisa a estar ciente é que o meu diagrama não mostra o uso de resistências pull-up, eu descobri que tudo parecia funcionar corretamente sem eles. No entanto, você pode querer incluí-los, especialmente se você experimentar erros ou operação intermitente.para ligar algumas resistências, um par de resistências de 10k às linhas SDA e SCL. Anexar a outra extremidade à saída de 5 volts em um dos Arduino’s.
Master Demo Sketch
Aqui está o sketch que será usado no Arduino que você designou como sendo o mestre.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
/*
I2C Mestre de Demonstração
i2c-mestre-demo.ino
Demonstrate use of I2C bus
Master sends character and gets reply from Slave
DroneBot Workshop 2019
https://dronebotworkshop.com
*/
// Include Arduino Wire library for I2C
#include <Wire.h>
// Define Slave I2C Address
#define SLAVE_ADDR 9
// Define Slave answer size
#define ANSWERSIZE 5
void setup() {
// Initialize I2C communications as Master
Wire.begin();
/ / Setup serial monitor
Serial.begin (9600);
Serial.println (“I2C Master Demonstration”);
}
Void loop () {
delay(50);
Serial.println (“Write data to slave”);
// Write a charatre to the Slave
Wire.beginTransmission (SLAVE_ADDR);
Wire.write (0);
Wire.endTransmission ();
Serial.println (“Receive data”);
// Read response from Slave
// Read back 5 characters
Wire.pedido de (SLAVE_ADDR, ANSWERSIZE);
/ /Add characters to string
String response=””;
while (Wire.disponível ()) {
char B = fio.read ();
resposta + = b;
}
// Print to Serial Monitor
Serial.println (response);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
/*
I2C Slave Demo
i2c-slave-demo.ino
Demonstrate use of I2C bus
Slave receives character from Master and responds
DroneBot Workshop 2019
https://dronebotworkshop.com
*/
// Include Arduino Wire library for I2C
#include <Wire.h>
// Define Escravo I2C Endereço de
#define SLAVE_ADDR 9
// Define Escravo de resposta tamanho
#define ANSWERSIZE 5
// Define string com a resposta ao Mestre
String resposta = “Olá”;
void setup() {
// Inicializar I2C comunicações como Slave
Fio.begin (SLAVE_ADDR);
// Function to run when data requested from master
Wire.onRequest (requestEvent);
/ Function to run when data received from master
Wire.onReceive (fundo a receber);
/ / Setup Serial Monitor
Serial.begin (9600);
Serial.println (“I2C Slave Demonstration”);
}
void receivent () {
// Read while data received
while (0 < Wire.disponível()) {
byte x = Wire.read ();
}
// Print to Serial Monitor
Serial.println (“Receive event”);
}
void requestEvent () {
/ Setup byte variable in the correct size
resposta byte;
/ / Formate the answer as array
for (byte i=0;i<ANSWERSIZE;i++) {
response = (byte)answer.charAt(i);
}
// enviar resposta para o fio principal
Wire.write (response,sizeof (response));
/ Print to Serial Monitor
Serial.println(“Pedido de eventos”);
}
void loop() {
// Tempo de delay no loop
delay(50);
}
|
mais uma Vez vamos começar incluindo a biblioteca do Fio. Como no sketch anterior, também definimos o endereço I2C para o escravo, bem como o número de bytes que estamos planejando enviar de volta para o mestre.
em seguida, definimos a string que vamos enviar de volta para o mestre, neste caso apenas a palavra “Olá”. Se você decidir mudar isso certifique-se de ajustar a constante de ANSWERSIZE em ambos os esboços para ser correto.
na configuração inicializamos a ligação ao bus I2C com uma função begin. Tome nota da maneira diferente que fazemos isso, como este é um escravo que especificamos o endereço I2C que vamos usar. Ao fazer isso, a biblioteca de fios sabe que queremos operar em modo escravo.
Agora precisamos definir os nomes das funções que chamaremos quando dois eventos ocorrerem – um pedido de dados recebido do mestre e os dados recebidos do mestre. Também configuramos e imprimimos para o monitor de série.
a função a receber é chamada quando recebemos dados do mestre. Nesta função Lemos dados enquanto os dados estão disponíveis e atribuímos a um byte (lembre-se, os dados serão recebidos um byte de cada vez).
a função requestEvent é chamada sempre que recebemos um pedido de dados do mestre. Temos de enviar a nossa corda “Olá” de volta para o mestre. Como precisamos enviar os dados um byte de cada vez, dividimos os personagens em “Olá” em itens individuais em uma matriz e, em seguida, enviá-los um a um.
relatamos todos os nossos progressos em ambas as funções para o monitor serial.
O Loop neste sketch apenas adiciona um atraso de tempo, que corresponde ao usado no sketch mestre.
executando os esboços Demo
para executar estes esboços você precisará ser capaz de ver o monitor Serial em cada Arduino. Se você tem dois computadores com o Arduino IDE instalado, então isso vai torná-lo muito mais fácil.
no Microsoft Windows é possível abrir duas instâncias do Arduino IDE. Se isso for feito, você pode exibir ambos os monitores seriais lado a lado na mesma tela.alternadamente, você poderia usar um computador e ligar o segundo Arduino com sua própria fonte de alimentação. Você teria que mudar o computador e a energia entre os dois Arduino’s. fazendo isso você poderia monitorar ambos os telões um a um. na próxima demonstração, ligaremos um potenciômetro ao Mestre Arduino e o levaremos ao escravo. Usaremos o potenciômetro para controlar a velocidade de piscar do LED.
esta é outra demonstração simples, você pode construir sobre ela para criar algo mais prático.
acoplamento de demonstração remoto
Aqui está como este experimento é colocado em conjunto.
é essencialmente a mesma ligação que o experimento anterior, com a adição do potenciômetro no mestre e o LED no escravo.
Note que o LED no escravo foi ligado ao pin 13. Como o Arduino Uno tem um LED embutido no pin 13 Você pode eliminar o LED e sua resistência de queda, se desejar.as observações sobre resistências pull-up também se aplicam a esta ligação.
Sketch Master remoto
o sketch para o lado mestre deste experimento é muito simples, de certa forma o lado I2C é ainda mais simples do que o usado na primeira demonstração. Isto é porque estamos apenas enviando dados para o escravo e não estão esperando obter qualquer de volta.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
/*
I2C Controle Mestre de Demonstração
i2c-mestre-demo-controle.ino
Demonstrate use of I2C bus
Master sends potentimeter position data
DroneBot Workshop 2019
https://dronebotworkshop.com
*/
// Include Arduino Wire library for I2C
#include <Wire.h>
// Define Slave I2C Address
#define SLAVE_ADDR 9
// Analog pin for potentiometer
int analogPin = 0;
// Integer to hold potentiometer value
int val = 0;
void setup () {
/ / inicializar as comunicações I2C como Master
Wire.begin();
}
void loop() {
delay(50);
// Leia pote valor
// Mapa de faixa de 1 a 255 para a taxa de flash
val = mapa(analogRead(analogPin), 0, 1023, 255, 1);
// Escrever uma charatre para o Slave
Fio.beginTransmission (SLAVE_ADDR);
Wire.write (val);
Wire.transmissão final();
}
|
Como sempre, devemos incluir a biblioteca do Fio no início do desenho. Também definiremos uma constante para manter o endereço do escravo.uma vez que estamos usando um potenciômetro, precisaremos definir tanto o pin a que está conectado quanto uma variável para manter seu valor.
tudo o que fazemos na configuração é inicializar a conexão I2C como um mestre.no Loop, lemos o valor do potenciômetro e o mapeamos para um intervalo de 01-255. Precisamos fazer isso, pois estamos enviando um byte de informação e só podemos manter esses muitos valores em um único byte.
Note que invertemos a sequência de numeração na função Arduino Map, isto é feito para que o sistema se comporte da maneira que esperamos – virar o potenciômetro para a direita aumenta a velocidade de flash. Como a” taxa flash ” é especificada por um atraso de tempo um maior número sendo enviado irá igualar a uma taxa flash mais longa.
também note que nós não enviamos o valor 0, que apenas manteria o LED em um estado. Em vez disso, definimos o nosso alcance para terminar à 1.
Agora é apenas uma questão de enviar o byte para o escravo e repetir o Loop novamente.
Demo Receive Sketch remoto
o lado escravo precisa de receber dados do mestre e usá-lo para flash o LED.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
/*
I2C Escravo de Controle de Demonstração
i2c-escravo-demo-controle.ino
Demonstrate use of I2C bus
Receives potentimeter position data
Controls LED blink rate
DroneBot Workshop 2019
https://dronebotworkshop.com
*/
// Include Arduino Wire library for I2C
#include <Wire.h>
// Define Slave I2C Address
#define SLAVE_ADDR 9
// Define LED Pin
int LED = 13;
// Variable for received data
int rd;
// Variable for blink rate
int br;
void setup () {
pinMode (LED, OUTPUT);
// inicializar as comunicações I2C como Slave
Wire.begin (SLAVE_ADDR);
// Function to run when data received from master
Wire.onReceive (fundo a receber);
/ Setup Serial Monitor
Serial.begin (9600);
Serial.println (“I2C Slave Demonstration”);
}
Void receivent () {
/ leia um carácter do I2C
rd = Wire.read ();
/ /Print value of incoming data
Serial.println (rd);
}
void loop() {
delay(50);
// Calcular piscar valor
br = mapa(rd, 1, 255, 100, 2000);
digitalWrite(LED, HIGH);
delay(br);
digitalWrite(LED, BAIXO);
delay(br);
}
|
Vamos começar com a habitual inclusão do Fio biblioteca, bem como definir o endereço escravo. Também definimos um pin para o LED.
um par de variáveis adicionais são definidas, um segurando os dados recebidos, enquanto o outro carrega o valor de atraso de tempo para a taxa de blink.
na configuração, definimos o pin I / o para o LED como uma saída e inicializamos o bus I2C. À medida que usamos o endereço do escravo na função de início, a biblioteca de fios sabe que estamos agindo como um escravo.
só precisamos definir uma função onReceive, ao contrário da última demo que não estamos esperando quaisquer pedidos do mestre. Também configuramos e imprimimos para o monitor Serial, vamos usar o monitor para ver os dados recebidos.
a função de fundo a receber lê os dados recebidos e atribui-os à variável I. Também imprime o valor para o monitor serial.
finalmente, no Loop nós usamos os dados de entrada para piscar o LED. Mais uma vez usamos a função Map para realizar isso, mudando os valores de entrada de 1-255 para uma gama mais ampla. Você pode experimentar mudar este intervalo para fazer o LED piscar mais rápido ou mais lento, se desejar.
As últimas declarações são essencialmente o Arduino Blink sketch disfarçado! Ligamos e desligamos o LED por um período de tempo que determinamos na última etapa.
E depois repetimos o loop.
executando a demonstração Remota
carregue o código e dê energia tanto ao Arduino. poderá usar o seu monitor serial no ‘Slave Arduino’ para ver os dados recebidos.
rodando o potenciômetro deve agora variar a taxa de blink LED no escravo.
conclusão
isto conclui a nossa primeira análise detalhada do I2C.no próximo capítulo, vamos aprender mais sobre a estrutura dos dados que estão a ser trocados. Nós também vamos pegar um sensor regular e transformá-lo em um sensor I2C.feliz comunicação!todos os esboços da I2C utilizados neste artigo.
I2C informações – as Informações relativas ao protocolo I2C