I2C – Master enviando informações? Vamos ver.

Ola Pessoal. Neste post continuamos o estudo de I2C, sendo uma continuação do post anterior, portanto, caso não tenha lido, leia agora no link abaixo:

I2C – Configurações avançadas entre Master e Slave.

Legal, agora que esta por dentro, vamos avançar. No setup anterior, o master controlava o comportamento do slave. Eu sei, eram só bips, mas se atentem que dentro de cada função comportamento00X eu poderia ter qualquer outro código escrito. Esse controle se dava através do master escolhendo randomicamente um valor entre 1 e 4 e enviando ao slave. O slave recebia este valor e escolhia uma função para execução.

Vamos incrementar nosso sketch, e fazer com que o slave receba valores do master que vão influir diretamente na função. Para isso, vamos criar uma nova função, e vamos dar o sugestivo nome de soma para esta função.

I2C – Código do Master atualizado

#include <Wire.h>
#define SLAVE01 0x1

void setup() {
  Serial.begin(9600);
  Wire.begin();
}

void loop() {
  int comando=random(1,6);
  Wire.beginTransmission(SLAVE01);
  Wire.write(comando);
  if (comando == 5){
    Wire.write(random(1,256));
    Wire.write(random(1,256));
  }
  Wire.endTransmission();
  delay(5000);
}

Vamos ver as diferenças do sketch anterior?

Começamos pela função random. Agora ela escolhe um número aleatório entre 1 e 5, afinal criaremos mais uma função no slave. Na sequência enviamos o “comando” para o slave pela linha I2C, e então verificamos se o comando é o 5. Caso seja 5, nós escrevemos mais 2 bytes na linha I2C.

Percebam que a função random retorna um número entre 1 e 255, pois precisamos enviar 1 byte por Wire.write, e um byte suporta exatamente valores entre 0 e 255.

I2C – Código do Slave atualizado.

#include <Wire.h>
#define i2c_address 0x1
char comando = 1;
byte a = 0;
byte b = 0;

void setup(){
  Serial.begin(9600);
  Wire.begin(i2c_address);
  Wire.onReceive(receivEvent);
}

void loop(){
  switch (comando){
    case 1:
    comportamento001();
    break;
    case 2:
    comportamento002();
    break;
    case 3:
    comportamento003();
    break;
    case 4:
    comportamento004();
    break;
    case 5:
    soma();
    break;
    default:
    comando=1;
    break;
  }
  delay(1000);
}

void receivEvent(int x){
  comando=Wire.read();
  if (x == 3) {
    a=Wire.read();
    b=Wire.read();
  }
}

void comportamento001(){
  int i = 0;
  for (i=0;i<1;i++){
    tone(13, 800, 50); // play the tone
    delay(100);
      }
}

void comportamento002(){
  int i = 0;
  for (i=0;i<2;i++){
    tone(13, 800, 50); // play the tone
    delay(100);
      }
}

void comportamento003(){
  int i = 0;
  for (i=0;i<3;i++){
    tone(13, 800, 50); // play the tone
    delay(100);
      }
}

void comportamento004(){
  int i = 0;
  for (i=0;i<4;i++){
    tone(13, 800, 50); // play the tone
    delay(100);
      }
}

void soma(){
  int c = a + b;
  if (c == 0){
    return;
  }
  Serial.print(a);
  Serial.print(" + ");
  Serial.print(b);
  Serial.print(" = ");
  Serial.println(c);
  a=0;
  b=0;
}

Poucas alterações a comentar.

A primeira é a declaração no inicio do código de duas novas variáveis, a e b, ambas do tipo byte e inicializadas com o valor 0. Pulando para o fim do sketch, temos a nova função soma(). Esta função inicializa uma variável c do tipo int, recebendo como valor a soma das variáveis a e b. Se a soma for 0, o código abandona a execução da função, descarta todo o resto. Caso a soma não seja 0, o sketch imprime na Serial as variáveis recebidas e a soma das duas. Ao fim da função temos o “zeramento” das variáveis a e b.

Uma observação importante aqui, a variável c precisa ser no mínimo do tipo int, pois se os valores recebidos pela interface I2C resultarem em uma soma maior que 255, teremos comportamentos indesejados, pois o tipo byte suporta no máximo o valor 255.

Indo agora para o condicional switch, inserimos um “case” a mais, para o caso do valor recebido ser 5. Caso seja, o case chama a função soma().

Por último, alteramos a função receivEvent, que manipula o evento onReceive. Se lembram que no post anterior eu falei que internamente o Arduino chama essa função passando automaticamente um parâmetro com o número de bytes disponíveis pela interface I2C? Pois então, vamos utilizar esta funcionalidade.

Recebemos o primeiro byte disponível na I2C como sendo o “comando” a executar. Na sequência verificamos o número de bytes disponíveis quando o evento foi disparado, caso seja 3 nós lemos os outros 2 (já lemos 1, atribuindo à variável comando) e atribuímos às variáveis a e b.

Bora testar?

As conexões utilizadas são as mesmas do post anterior. Faça upload dos skeches, e abra o Monitor serial da porta correspondente ao slave. Além dos tradicionais bips, teremos uma pausa(silêncio) correspondente á execução da função soma(), e na serial poderemos ver quais os valores informados pelo master, e o resultado da soma. Pode conferir que esta certa a conta 😉

Monitor Serial I2C Master-Slave

Exemplo de saída obtida no setup I2C

Resumo até o momento.

Bem, não sei se consegui que entendessem o espírito da coisa, mas temos várias possibilidades apenas com o que vimos até agora, e sem muita dificuldade. Por exemplo, considerando nosso sketch para a iluminação, poderíamos ter um Arduino conectado com um shield ethernet dedicado a função WEB, recebendo comandos sobre as lâmpadas, e por I2C poderíamos transmitir essa informação a outros Arduinos especializados no controle das lâmpadas. Utilizando a transmissão do master como controle, poderíamos ativar um modo econômico, onde determinadas lâmpadas não serial acessas com base em informações recebidas de sensores de luminosidade, por exemplo.

 

Bem pessoal, por enquanto é isso, no próximo post sobre I2C vamos inserir um novo evento no slave, e então analisar como funciona o envio de informações do slave para o master.

Abs e até a próxima.

 

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

1 × três =