domingo, 19 de junho de 2016

Integrando Raspberry PI com Arduíno via I²C

Olá, neste post iremos explicar como fazer a comunicação entre um Raspberry PI e 2 Arduínos, utilizando o protocolo I²C. Já havíamos explicado como fazer uma integração entre eles, utilizando o barramento serial (para ver o artigo, clique aqui). A vantagem de utilizarmos o I²C, como já explicado nesse artigo Barramento I²C, é que podemos ter no mesmo barramento até 128 dispositivos e via Serial, só podemos ter um dispositivo conectado e como o Raspberry tem poucas portas GPIO's, podemos expandir esse número utilizando um ou mais Arduínos integrados via I²C.

No post Barramento I²C, utilizamos um Arduíno UNO como Master, um Duemilanove e um Nano como Slavers. Neste post, vamos substituir o Arduíno UNO Master por um Raspberry PI.

Segue lista de materiais utilizados:

  • 1 Raspberry PI Rev B
  • 1 Arduíno Duemilanove
  • 1 Arduíno Nano

Na nossa montagem, o Raspberry irá imprimir uma mensagem enviada por cada Arduíno, similar ao post Barramento I²C:


Raspberry PI

Por default, os pinos I²C do Raspberry estão desabilitados. Segue abaixo os passos habilitá-los.

1 - Via console, acesse a ferramenta de configuração
$ sudo raspi-config


2 - Selecione Advanced Options



3 - Selecione A7 I2C


4 - Selecione Yes e depois OK



5 - Selecione Yes e depois OK



6 - Selecione Finish


7 - Desligue o Raspberry como o comando abaixo, desligue a força e faça conexões dos Arduínos.
$ sudo halt

Esquema de ligação

Segue abaixo a lista de pinos do Raspberry PI Rev B


Os pinos I²C são: 3 - SDA(Dados) e 5 - SCL (Clock). O esquema de ligação é exatamente o mesmo do post Barramento I²C.

Segue esquemático:

Apesar de o Raspberry Pi trabalhar a 3,3V e o Arduíno a 5V, como o Raspberry PI será o Master a tensão do barramento será definida por ele e por isso, não se faz necessário montar um circuito para limitar a tensão (se o arduíno for Master, ele pode queimar a porta do Raspberry). Além disso, o Raspberry PI já tem um resistor pull-up nos pinos utilizado no barramento I²C que dispensa o seu uso em outros dispositivos.

Programação dos Arduínos.

A biblioteca que utilizaremos no Raspberry só permite a leitura de um inteiro por vez (não é possível ler um buffer) e por isso, enviaremos a mensagem caractere a caractere, com o primeiro caractere de controle. Explicarei com mais detalhes mais a frente.

Código do Nano:
#include <Wire.h>

void setup()
{
  Wire.begin(0x50);//endereço de I2C               
  Wire.onRequest(requestEvent); 
  
  pinMode(13, OUTPUT);
}

void loop()
{
  digitalWrite(13, HIGH);   
  delay(500);              
  digitalWrite(13, LOW);   
  delay(500);
}

char * buff="*hello I'm Nano";
byte count = 0;
void requestEvent()
{
  Wire.write(buff[count]);
  if(count == 14)
    count = -1; 
  count ++;  
}

Código do Duemilanove:
#include <Wire.h>

void setup()
{
  Wire.begin(0x40);//endereço de I2C               
  Wire.onRequest(requestEvent); 
  
  pinMode(13, OUTPUT);
}

void loop()
{
  digitalWrite(13, HIGH);   
  delay(500);              
  digitalWrite(13, LOW);   
  delay(500);
}

char * buff="*hello I'm Due";
byte count = 0;
void requestEvent()
{
  Wire.write(buff[count]);
  if(count == 13)
    count = -1; 
  count ++;  
}

Programação do Raspberry PI.

Para confirmar se o módulo I²C está ativo, basta digitar a linha de comando abaixo:
$ lsmod | grep i2c

Devemos ter uma saída similar a essa:
pi@raspberrypi:~ $ lsmod | grep i2c
i2c_bcm2708             5988  0 
i2c_dev                 6386  0 

A saída acima indica que o módulo i2c_bmc2708 está ativo.

Agora, vamos instalar a biblioteca para o I²C. Para mais detalhes sobre ela, clique aqui.
$ sudo apt-get install libi2c-dev

O Raspberry vem com um programa para detectar o endereço dos dispositivos conectados no barramento.

Basta digitar o comando abaixo:
$ i2cdetect -y 1

Se seu Raspberry PI for Rev 1, digite:
$ i2cdetect -y 0

Essa diferença acontece, pois houve uma alteração nos pinos utilizados pelo I²C entre Rev 1 e 2.

A saída deve ser de acordo com texto abaixo:
pi@raspberrypi:~ $ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: 50 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --                         

0x40 e 0x50 são os Arduínos conetados no barramento.

Agora vamos a codificação.

Makefile - Crie o arquivo de acordo com o texto abaixo:
#
# Makefile:
#################################################################################


#DEBUG  = -g -O0
DEBUG   = -O3
CC      = gcc
INCLUDE = -I/usr/local/include
CFLAGS  = $(DEBUG) -Wall $(INCLUDE) -Winline -pipe

LDFLAGS = -L/usr/local/lib
LDLIBS    = -lwiringPi -lwiringPiDev -lpthread -lm

# Should not alter anything below this line
###############################################################################

SRC     =       i2cTest.cpp                                             \

Crie um arquivo chamado i2cTest.cpp, de acordo com o texto abaixo:
#include <stdio.h>
#include <wiringPi.h>
#include <wiringPiI2C.h>

void readI2CString(int fd, char*buffer,int length,char charController)
{
 for(;;)//aguardando caractere de controle para guardar a mensagem
  if(wiringPiI2CRead(fd)==charController)
   break;

 for(int i = 0; i < length; i++)//lendo mensagem
 {
  buffer[i]=wiringPiI2CRead(fd);
 }

}

int main (int argc, char *argv[])
{
        int fd1,fd2;//identificadores de cada dispositivo
 char buffer[20];//buffer para armazenar a mensagem
 wiringPiSetup ();//inicializando biblioteca
        fd1=wiringPiI2CSetup (0x40);//conectando com dispositivo 40
 fd2=wiringPiI2CSetup (0x50);//conectando com dispositivo 50
        if(fd1==-1||fd2==-1)
        {
                printf("Can't setup the I2C devices\n");
                return -1;
        }
        else
        {
  for (;;)
                {
   readI2CString(fd1,buffer,13,'*');//Lendo mensagem do dispositivo 40
   buffer[13] = '\0';
   printf("%s\n",buffer);

   readI2CString(fd2,buffer,14,'*');//Lendo mensagem do dispositivo 50
   buffer[14] = '\0';
   printf("%s\n",buffer);

                }
        }
        return 0;
}

Para compilar, basta executar a linha de comando abaixo:
$ make i2cTest

Para executar o programa, basta digitar o comando:
$ sudo ./i2cTest

A saída deverá ser essa:



Entendimento do código

Esse método abaixo, irá chamar o método wiringPiI2CRead da biblioteca wiringPiI2C que retorna um inteiro (valor lido). Como queremos imprimir uma String, se simplesmente imprimíssemos os caracteres no console, poderíamos imprimir llo I'm Duehe ou o I'm Duehello, ou outra combinação, pois o arduíno irá enviar sequencialmente e infinitamente a sequencia de caracteres. Assim, adicionei um caractere de controle para indicar que a mensagem iniciará no próximo caractere e o código irá esperar que venha esse caractere para começar a gravar a mensagem.

void readI2CString(int fd, char*buffer,int length,char charController)
{
 for(;;)//aguardando caractere de controle para guardar a mensagem
  if(wiringPiI2CRead(fd)==charController)
   break;

 for(int i = 0; i < length; i++)//lendo mensagem
 {
  buffer[i]=wiringPiI2CRead(fd);
 }

}

Aqui, a aplicação ficará em loop, lendo as mensagens de cada um dos Arduínos.
for (;;)
                {
   readI2CString(fd1,buffer,13,'*');//Lendo mensagem do dispositivo 40
   buffer[13] = '\0';
   printf("%s\n",buffer);

   readI2CString(fd2,buffer,14,'*');//Lendo mensagem do dispositivo 50
   buffer[14] = '\0';
   printf("%s\n",buffer);

                }

O Arduíno Duemilanove, que está com o endereço 0x40, irá enviar o caractere de controle '*' e a mensagem hello I'm Due, caractere a caractere (13 caracteres excluindo o de controle)

char * buff="*hello I'm Due";
byte count = 0;
void requestEvent()
{
  Wire.write(buff[count]);
  if(count == 13)
    count = -1; 
  count ++;  
}

O Arduíno Nano, que está com o endereço 0x50, irá enviar o caractere de controle '*' e a mensagem hello I'm Nano, caractere a caractere (14 caracteres excluindo o de controle)

char * buff="*hello I'm Nano";
byte count = 0;
void requestEvent()
{
  Wire.write(buff[count]);
  if(count == 14)
    count = -1; 
  count ++;  
}

E por isso, no loop do Raspberry, ele esperará 13 caracteres do Duemianove e 14 do Nano.


Sem comentários:

Enviar um comentário