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.


domingo, 12 de junho de 2016

Utilizando EEPROM I²C Com Arduíno

Olá, neste post iremos explicar como utilizar uma memória externa EEPROM com o barramento I²C e com um Arduíno. Para mais informações sobre o I²C, consulte o post anterior (clique aqui).

A EEPROM(Electrically-Erasable Programmable Read-Only) é uma memória que permite escrita e gravação e seus dados não são apagados quando não há energia. As memórias flash(pen driver, SD e outros), são uma evolução desse tipo de memória. A EEPROM pode ser utilizada para armazenar algumas informações do seu programa que precisam ser salvas quando não houver energia. Para mais informações sobre esse tipo de memória, consulte aqui.

Os micro-controladores que estão presentes nas mais diversas versões do Arduíno, têm diferentes quantidades de memória EEPROM disponíveis.

  • ATmega328 - 1KB (1024 bytes)
  • ATmega168 e ATmega8 - 512 bytes
  • ATmega1280 e ATmega2560 - 4 KB (4096 bytes)
É possível acessar a EEPROM dos micro-controladores e há uma biblioteca disponível para isso na própria IDE do Arduíno. A documentação pode ser encontrada aqui.

Mas, neste post, iremos focar no uso de EEPROMs externas que utilizam o barramento I²C para leitura e escrita.

Existem no mercado diversas marcas e modelos de memória, com os mais diversos tamanhos e para cada uma delas, há um protocolo definido para se comunicar e por isso, é difícil ter um código genérico de acesso. Esse exemplo funcionará para as EEPROMs do tipo 24C16,que são bem comuns. 

EEPROM 24C16WP

Essa memória tem 16 Kbits (2 Kbytes) de armazenamento, permitindo a leitura e escrita byte-a-byte ou em blocos (páginas). Aqui, iremos abordar a leitura e escrita byte-a-byte.

Montagem

Segue a lista de materiais utilizados:
  • 1 Memória EEPROM 24C16WP
  • 1 Arduíno Uno
  • 1 Protoboard
  • Alguns fios

Segue abaixo os pinos da memória:
Pinagem 24C16WP

Os pinos 6 (SCL) e 5 (SDA), são utilizados para o barramento I²C e devem ser conectados aos pinos analógicos do Arduíno A4 (SDA - Data ) e A5 (SCL - Clock)

O endereçamento I²C da memória inicia em 0x50 e vai até 0x57. Os pinos NC são utilizados para o ajustar esse endereçamento se aterrados(GND) ou ligados ao VCC.

Exemplo:
  • NC - 0, NC - 0, NC - 0 -> Endereço da memória 0x50
  • NC - 0, NC - 0, NC - 1 -> Endereço da memória 0x51
  • NC - 0, NC - 1, NC - 0 -> Endereço da memória 0x52

Essa configuração é interessante, pois podemos colocar até 8 memórias no mesmo barramento.

O pino 7(WC), é utilizado para indicar se a memória está protegida contra gravação ou não. Se "0" - ligado ao GND, a memória pode ser escrita. Se "1" - ligada ao VCC, protegida contra gravação.

Para o nosso exemplo, utlizaremos os pinos abaixo:

EEPROM Arduíno
6(SCL) A5(SCL)
5(SDA) A4(SDA)
8(VCC) VCC
4(VSS) GND
7(WC) GND

Segue abaixo do esquemático:

Esquema feito no programa Fritzing
Vamos ao programa:


#include ‹Wire.h›    
 
#define i2cAddress 0x50 //Endereço da memoria
 
void setup(void)
{
  Serial.begin(115200);
  Wire.begin();  //inicializando I2C

  int sizeBuf = 21;
  char buf[sizeBuf] = "teste gravando eeprom";
  
  Serial.print("Gravando... \n");
  for(int i = 0; i < sizeBuf; i++)
  {
    writeI2CEEPROM(i2cAddress,i,buf[i]);
  }
  
  Serial.print("Lendo... \n");
  for(int i = 0; i < sizeBuf; i++)
  {
    Serial.print((char)readI2CEEPROM(i2cAddress,i));  
  }
  Serial.print("\nFim... \n");
}
 
void loop(){}

void writeI2CEEPROM(int i2cAddr, byte memoryAddress, byte data)
{
  Wire.beginTransmission(i2cAddr);//iniciando barramento para o endereco I2C da memoria
  Wire.write(memoryAddress);//informando endereco da memoria 
  Wire.write(data);//dados
  Wire.endTransmission();//finalizando transmissao do emissor
  delay(5);
}

byte readI2CEEPROM(int i2cAddr, byte memoryAddress)
{
   byte data = 0xFF;
 
   Wire.beginTransmission(i2cAddr);//iniciando barramento para o endereco I2C da memoria
   Wire.write(memoryAddress);//informando endereco da memoria
   Wire.endTransmission();//finalizando transmissao do emissor
   Wire.requestFrom(i2cAddr,1);//avisando a memoria que espera-se dado (1 byte)
   if (Wire.available()){
     data = Wire.read();
  }
  return data;
}


No código acima, iremos escrever na memória a frase "teste gravando eeprom" e na sequência, os valores serão recuperados.

Vamos explicar alguns pontos do código.

void writeI2CEEPROM(int i2cAddr, byte memoryAddress, byte data)
{
  Wire.beginTransmission(i2cAddr);//iniciando barramento para o endereco I2C da memoria
  Wire.write(memoryAddress);//informando endereco da memoria 
  Wire.write(data);//dados
  Wire.endTransmission();//finalizando transmissao do emissor
  delay(5);
}

O método writeI2CEEPROM tem três parâmetros:

  • i2cAddr - Endereço I²C da memória
  • memoryAddress - endereço da memória (0 até 255)
  • data - byte que será gravado

Como já citado anteriormente, essa memória suporta até 2 Kbytes e por isso, ela terá 256 endereços para escrita e leitura (de 0 atá 255). Para escrever na memória, é necessário iniciar a transmissão, indicar o endereço da memória, enviar o byte e finalizar a transmissão. Esse protocolo, está definido no datasheet da memória, que pode ser consultado aqui.

byte readI2CEEPROM(int i2cAddr, byte memoryAddress)
{
   byte data = 0xFF;
 
   Wire.beginTransmission(i2cAddr);//iniciando barramento para o endereco I2C da memoria
   Wire.write(memoryAddress);//informando endereco da memoria
   Wire.endTransmission();//finalizando transmissao do emissor
   Wire.requestFrom(i2cAddr,1);//avisando a memoria que espera-se dado (1 byte)
   if (Wire.available()){
     data = Wire.read();
  }
  return data;
}

O método readI2CEEPROM tem dois parâmetros e retorna o byte gravado.
  • i2cAddr - Endereço I²C da memória
  • memoryAddress - endereço da memória (0 até 255)
Assim como na escrita, o protocolo de leitura está definido no datasheet da memória mas, de maneira resumida temos: inicio da transmissão, envia-se o endereço, finalização a transmissão, requisita-se a resposta e faz-se a leitura do valor se estiver disponível.

Segue a saída desse programa:

Para comprovar a a gravação, você pode comentar o trecho que faz a gravação. Ficando assim:



domingo, 29 de maio de 2016

Barramento I²C

Neste post falaremos um pouco sobre o barramento I²C, mostraremos um exemplo de como utilizá-lo e como fazer um scan no barramento, para descobrir o endereço de outros dispositivos I²C.

I²C

Esse barramento foi desenvolvido para fazer a comunicação entre um dispositivo principal e seus periféricos. E por isso, que ele utiliza o conceito de Master/Slave onde, poderemos ter em um mesmo barramento um Master e "N" Slavers.

O barramento define duas linhas de comunicação. Uma bidirecional para dados (SDA) e outra para o clock (SCL). O clock, irá controlará a velocidade e sincronismo de todos os dispositivos do barramento e será controlado pelo dispositivo Master.

Como poderemos ter até 128 dispositivos Slavers no mesmo barramento, cada um deles precisa ter um endereço único para que possam se comunicar com o Master.


Para mais informações sobre o barramento, clique aqui. De acordo com a especificação física do barramento, também deveremos ter resistores "pull-up" ligados aos pinos SDA e SCL. Mas, os pinos do Arduíno já têm esses resistores e para o nosso exemplo, não serão necessários. Para mais detalhes sobre resistores pull-up no barramento I²C, clique aqui.

Exemplo

Neste exemplo, iremos fazer uma comunicação entre 3 Arduínos onde, um deles será o Master e os outros dois os Slavers. Utilizaremos a biblioteca Wire (clique aqui para mais informações). Essa biblioteca implementa o protocolo I²C e está disponível na IDE do Arduíno. Já havia comentado sobre a biblioteca Wire no post sobre o uso do Tiny RTC I2C Real Time Clock.

Segue a lista de materiais:
  • 1 Arduíno Uno
  • 1 Arduíno Duemilanove
  • 1 Arduíno Nano
  • 1 Protoboard
Montagem

Como já falamos, o barramento utiliza 2 linhas de comunicação. Uma de dados e uma para o clock. No Arduíno, esses pinos são definidos respectivamente pelo pinos:
  • A4 - SDA - Pino de dados
  • A5 - SCL - Pino para o clock
A ligação é muito simples. Basta ligar todos os pinos A4 juntos e todos os pinos A5 juntos. Segue abaixo o esquemático.

Esquemático feito no Fritzing

Nesse exemplo o UNO será o Master e Duemilanove e Nano serão os Slavers. Pode-se utilizar qualquer outro dispositivo, ou Arduíno.

Código do Master

Esse código foi feito com base no exemplo "master_reader" da biblioteca Wire. Ele foi adaptado para se comunicar com 2 dispositivos Slaver.
       
#include ‹Wire.h›

void setup()
{
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
}

int device = 3;
void loop()
{
  
  Wire.requestFrom(device, 14);    // request 14 bytes from slave device

  while (Wire.available())   // slave may send less than requested
  {
    char c = Wire.read(); // receive a byte as character
    Serial.print(c);         // print the character
  }

  Serial.print("\n");
  delay(1000);
  
  device++;
  
  if(device >3)
    device = 2;
}
       

Este programa irá requisitar 14 bytes dos dispositivos 2 e 3 e irá imprimir na serial string recebida.

Código do Slaver 01 (Duemilanove)

Esse código foi feito com base no exemplo "slaver_sender" da biblioteca Wire. Ele foi adaptado para enviar uma mensagem para o master e piscar o Led do pino 13.

       
#include ‹Wire.h›

void setup()
{
  Wire.begin(2);                // join i2c bus with address #2
  Wire.onRequest(requestEvent); // register event
  
  pinMode(13, OUTPUT);
}

void loop()
{
  digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);              // wait for a second
  digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent()
{
  Wire.write("hello I'm Duem"); // respond with message of 14 bytes
  // as expected by master
}
      
 

Este programa irá enviar uma string para o master, quando requisitado.

Código do Slaver 02 (Nano)

A diferença entre o código abaixo e o anterior é somente o endereço (de 2 para 3) e a mensagem (de Duem para Nano).
       
#include ‹Wire.h›

void setup()
{
  Wire.begin(3);                // join i2c bus with address #3
  Wire.onRequest(requestEvent); // register event
  
  pinMode(13, OUTPUT);
}

void loop()
{
  digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);              // wait for a second
  digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent()
{
  Wire.write("hello I'm Nano"); // respond with message of 14 bytes
  // as expected by master
}
   

Quando o console serial for aberto, conectado ao master, teremos a saída abaixo:

Saída Serial - Master

Fazendo um Scan no Barramento

No exemplo acima nós definimos os endereços dos dispositivos escravos. Mas, muitas vezes, quando utilizarmos dispositivos de terceiros (que já vem programados), precisaremos descobrir o endereço do dispositivo. Por exemplo, existe o sensor de temperatura da Dallas (Ds18b20), que utiliza o barramento I²C, ou uma memória EEPROM, ou para o Tiny RTC I2C Real Time Clock, já citado em outro post. Se não tivermos o datasheet do componente poderemos utilizar o código abaixo para descobrir o endereço.

       
#include ‹Wire.h›
 
 
void setup()
{
  Wire.begin();
 
  Serial.begin(115200);
  Serial.println("\nI2C Scanner");
}
 
 
void loop()
{
  byte error, address;
  int nDevices;
 
  Serial.println("Scanning...");
 
  nDevices = 0;
  for(address = 1; address < 127; address++ )
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");
 
      nDevices++;
    }
    else if (error==4)
    {
      Serial.print("Unknow error at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");
 
  delay(5000);           // wait 5 seconds for next scan
}


O programa acima irá testar os endereços de 1 até 127 a cada 5 segundo e se houver uma resposta, irá imprimir na serial os endereços encontrados.

Se carregarmos esse programa no UNO do exemplo anterior (Master), teremos a seguinte saída na serial:

 
Saída serial do Scan.

Como pode-se ver, poderemos ligar vários dispositivos no barramento e só utilizaremos apenas dois pinos do Arduíno. Existe uma série de dispositivos e periféricos que utilizam esse barramento. 

domingo, 22 de maio de 2016

Usando Infravermelho para controlar um aparelho de TV

Olá, neste post iremos mostrar como enviar e receber informações através de emissores e receptores de IR, para controlar um aparelho de TV.

Segue lista de materiais utilizados:
  • 1 Arduíno nano
  • 1 Arduíno UNO
  • 1 Receptor de IR LNF
  • 1 LED Emissor de IR
  • 1 Resistor de 200 ohms
  • 1 Protoboard
  • Alguns fios
Seguem as fotos dos sensores de IR:

Iremos montar a aplicação que faz a leitura e escreve na serial os códigos de IR do controle remoto de um aparelho de TV e depois, iremos montar uma aplicação que envia esses códigos para o aparelho de TV. Assim, você poderá controlar a sua TV ou outro equipamento através de um Arduíno.
Receptor LNF de IR

LED Emissor de IR


Utilizaremos a biblioteca IRremote para enviar e receber os códigos em infravermelho. Para mais informações sobre ela, clique aqui.

Segue abaixo a documentação dos método da biblioteca, que utilizaremos. Para mais detalhes acesse aqui.

Receiving 

IRrecv irrecv(receivePin)
Create the receiver object, using a name of your choice.
irrecv.enableIRIn()
Begin the receiving process. This will enable the timer interrupt which consumes a small amount of CPU every 50 µs.
irrecv.decode(&results)
Attempt to receive a IR code. Returns true if a code was received, or false if nothing received yet. When a code is received, information is stored into "results".
results.decode_type: Will be one of the following: NECSONYRC5RC6, or UNKNOWN.
results.value: The actual IR code (0 if type is UNKNOWN)
results.bits: The number of bits used by this code
results.rawbuf: An array of IR pulse times
results.rawlen: The number of items stored in the array
irrecv.resume()
After receiving, this must be called to reset the receiver and prepare it to receive another code.
irrecv.blink13(true)
Enable blinking the LED when during reception. Because you can't see infrared light, blinking the LED can be useful while troubleshooting, or just to give visual feedback.

Transmitting
IRsend irsend;
Create the transmit object. A fixed pin number is always used, depending on which timer the library is utilizing.
irsend.sendNEC(IRcode, numBits);
Send a code in NEC format.
irsend.sendSony(IRcode, numBits);
Send a code in Sony format.
irsend.sendRC5(IRcode, numBits);
Send a code in RC5 format.
irsend.sendRC6(IRcode, numBits);
Send a code in RC6
irsend.sendRaw(rawbuf, rawlen, frequency);
Send a raw code. Normally you would obtain the contents of rawbuf and rawlen by using the receiver many times and averaging the results. Some adjustments may be necessary for best performance. The frequency is the expected bandpass filter frequency at the receiver, where 38 is the most commonly used.

Cada fabricante utiliza um protocolo para codificar seus códigos de IR e temos basicamente os protocolos a seguir que são reconhecidos por essa biblioteca: NEC, SONY, RC5, RC6 e desconhecido(UNKNOWN) - para mais informações sobre os protocolos de IR, clique aqui.

Leitor de IR

Segue abaixo o esquema de ligação do receptor de IR ao Arduíno Nano


Esquema feito no aplicativo Fritzing

O esquema é muito simples, dispensando uma protoboard. Segue abaixo a pinagem do sensor:
Pinos do sensor LFN IR Receiver 

O pino 01(Out) do sensor será ligado ao pino D11 do Nano.

Vamos ao código para o Arduíno:

       
#include ‹irremote .h›

const int RECV_PIN = 11;
IRrecv irrecv(RECV_PIN); 
decode_results results;


void setup(void) 
{ 

 Serial.begin(115200);
 irrecv.enableIRIn();
 
}
char buf[20];
void loop()
{
    if (irrecv.decode(&results)) {
      
      if (results.decode_type == NEC) {
          Serial.print("NEC: ");
      } else if (results.decode_type == SONY) {
        Serial.print("SONY: ");
      } else if (results.decode_type == RC5) {
        Serial.print("RC5: ");
      } else if (results.decode_type == RC6) {
        Serial.print("RC6: ");
      } else if (results.decode_type == UNKNOWN) {
        Serial.print("UNKNOWN: ");
      }
      Serial.print(results.value, HEX);
      Serial.print(" ");
      Serial.print(" size: ");
      Serial.println(results.bits);
      irrecv.resume(); // Receive the next value
    }
 }

No programa acima, definimos o pino 11 como pino de leitura de dados. No setup é feita a inicialização do IR e serial e no loop, se houver dados, as informações serão impressas na serial (código e tamanho).

Após a carga do programa, utilizei o controle da minha TV como emissor e anotei a saída dos principais botões dele. Segue abaixo um trecho da saída da Serial:


A minha TV é da marca Philips e ela utiliza o protocolo RC-5 para a transmissão de IR. Os códigos acima 0x80C e 0xC (em hexadecimal) são referentes a pressionar o botão power do controle. Ele envia alternadamente cada um desses comandos quando o botão é pressionado. Um deles liga e o outro desliga a TV.

Emissor de IR

Agora vamos montar o emissor de IR. Segue abaixo o esquema de ligação.

Esquema feito no aplicativo Fritzing

O resistor de 200 ohms é para evitar que o LED queime, pois ele não suporta 5V. Por padrão, a biblioteca de envio utiliza o pino D3 do Arduíno como pino de saída.

Vamos ao programa:

       
#include ‹IRremote.h›

//definicoes para TV PHILIPS
#define PHILIPS_LENGHT 12
#define BTN_PHILIPS_PWD_ON 0xC
#define BTN_PHILIPS_PWD_OFF 0x80C
#define BTN_PHILIPS_SOURCE_ON 0x838 
#define BTN_PHILIPS_SOURCE_OFF 0x38
#define BTN_PHILIPS_SLEEP1 0x826
#define BTN_PHILIPS_SLEEP2 0x26
#define BTN_PHILIPS_VOLUP1 0x810
#define BTN_PHILIPS_VOLUP2 0x10
#define BTN_PHILIPS_VOLDOWN1 0x811
#define BTN_PHILIPS_VOLDOWN2 0x11
#define BTN_PHILIPS_MUTE1 0x80D
#define BTN_PHILIPS_MUTE2 0xD

int buff;
char cBuff[4];

int command[100];
int inicializado;

IRsend irsend;

void setup() {

  //PHILIPS COMMANDS 0 - 19
  command[0] = BTN_PHILIPS_PWD_ON;
  command[1] = BTN_PHILIPS_PWD_OFF;
  command[2] = BTN_PHILIPS_SOURCE_ON;
  command[3] = BTN_PHILIPS_SOURCE_OFF;
  command[4] = BTN_PHILIPS_SLEEP1;
  command[5] = BTN_PHILIPS_SLEEP2;
  command[6] = BTN_PHILIPS_VOLUP1;
  command[7] = BTN_PHILIPS_VOLUP2;
  command[8] = BTN_PHILIPS_VOLDOWN1;
  command[9] = BTN_PHILIPS_VOLDOWN2;
  command[10] = BTN_PHILIPS_MUTE1;
  command[11] = BTN_PHILIPS_MUTE2;
    
  Serial.begin(115200);
  inicializado = 0;
}



void loop() {
   
    while (Serial.available() >= 3)//loop de leitura/escrita da serial
    {
      cBuff[0] = Serial.read();
      cBuff[1] = Serial.read();
      cBuff[2] = Serial.read();
      cBuff[3] = '\0';
      Serial.read();
      buff = atoi(cBuff);//convertendo char[] em int
      Serial.write(cBuff);
              
      if(inicializado==1)
      {
        //PHILIPS -> 0 - 19
        if(buff <=19){
          Serial.write("PHILIPS....\n");
          irsend.sendRC5(command[buff],PHILIPS_LENGHT);
        }
       
        Serial.write("comando executado....\n");
      }
      
      if(buff == 999){
        Serial.write("Aguardando comando....\n");
        inicializado = 1;
      }
      if(buff== 998){
        Serial.write("Nao aguardando comando....\n");
        inicializado = 0;      
      }
      
    }
}

Originalmente, esse programa estava preparado para os equipamentos da minha casa (TVs, Console da NET e Home Theater) e recebendo comandos via serial através de um Raspberry PI. Mas, para efeitos didáticos, eu deixei somente os códigos referentes a TV Philips, que estão definidos nos primeiros #define, onde temos o mapeamento de alguns comandos do controle da TV como: ligar/desligar, volume, mudo e outros.  Além dos comandos da TV temos o 999 e 998 que habilitam ou não a interpretação de comandos.

Os comandos são colocados em um array (command[100] na função setup). A aplicação fica em loop esperando dados na serial. A cada 3 bytes disponíveis na serial, ele os converte em número e utiliza esse número como índice do array (exceto 999 e 998) comandos e envia através do IR para a TV.


Foram digitados os seguintes comandos na sequência: 999, 001, 000.

Observações

Você pode utilizar o mesmo Arduíno para fazer ambos os projetos. Utilizei dois, por tê-los disponíveis.
A princípio, é possível controlar qualquer dispositivo IR, bastando ler e reenviar o comando lido.
Assim como temos um sensor receptor pronto, é possível achar um emissor "pronto", dispensando a protoboard e resistor.


domingo, 15 de maio de 2016

Montando um Arduíno

Olá, neste post iremos mostrar como montar um Arduíno bem simples. Você não precisa comprar um Arduíno para cada projeto seu. Basta que você tenha somente uma plaquinha original, ou uma Interface Serial-USB para poder gravar os programas e montar de acordo com as especificações abaixo.


A versão mais comum do Arduíno, que é o Arduíno Uno, trabalha com um processador da Atmel, chamado de ATMEGA328-P PU. É um processador de 8bits com arquitetura RISC. Para maiores informações, clique aqui. No processador, há a identificação do modelo e número de série e gravados na parte superior



Versão Protoboard

Segue lista de materiais utilizados:
  • 1 Capacitor eletrolítico de 100nF
  • 2 Capacitores cerâmicos de 22 pF
  • 1 Resistor de 10k
  • 1 Cristal de 16MHz
  • 1 Botão (Switch Momentary)
  • Uma Protoboard
  • 1 Processador ATMEGA 328P-PU

Placa montada e programa "Blink Led" gravado



Mapeamento dos pinos do processador


Se observarmos, os pinos do processador são mesmos pinos que estão disponíveis na placa do Arduíno. As analógicas A0-A5, as digitais D0(RX),D1(TX) a D13, VCC, GND e outros.

Segue abaixo o esquema de montagem feito no programa Fritzing (mais informações, clique aqui)

Diagrama da montagem do processador e seus componentes na placa


Versão Montada na Placa

Segue lista de materiais utilizados:
  • Além dos componentes utilizados no item anterior (exceto a protoboard);
  • Placa para circuito eletrônico
  • Soquete para ATMEGA328-P
  • Barras de pinos
  • Material de solda
  • Fios    


A disposição dos componentes seguir esquema feito no software Fritzing, já citado.


Lado da frente da placa .


Verso da Placa.

Gravando o Software

A gravação do software pode ser feita de duas maneiras:
  1. Utilizando um Arduíno
  2. Utilizando uma interface Serial-USB
1. Utilizando um Arduíno

A maneira mais simples, que é usar uma placa de um Arduíno, removendo o processador atual e trocando pelo que se deseja gravar. Pode-se ter somente uma placa Arduíno e gravar em "n" processadores. Utilizando a placa do Arduíno como um "gravador".

2.Utilizando uma interface Serial-USB

Pode-se utilizar um adaptador Serial USB para fazer a comunicação entre seu Arduíno montado e o PC ( a placa do Arduíno já tem um embutido).


Basta ligar os pinos de acordo com a tabela abaixo:

   Serial USB
Arduino Montado
GND
GND
5V
VCC
TX
RX
RX
TX
RST
RST


Boot Loader

Quando compramos somente o processador, ele vem de fábrica sem nenhum conteúdo. Vem "zerado" e por isso, que precisamos a primeira vez gravar um bootloader. Esse software que gravamos no Arduíno, de maneira bem resumida, irá fazer a comunicação com a IDE o Arduíno e irá gravar os nossos programas na flash do processador.(Mais detalhes aqui)

As últimas versões da IDE do Arduíno tem uma opção no menu de "Ferramentas", chamada "Gravar Bootloader", que pode ser usada para gravar o bootloader.


domingo, 8 de maio de 2016

Integrando o Arduíno com Raspberry PI via Interface Serial

Nesse artigo, iremos mostrar como integrar um Arduíno com o Raspberry PI 2 através da interface serial, fazendo o LED do pino 13 do Arduíno piscar baseado em um comando enviado pelo Raspberry PI.

Segue abaixo a lista de materiais utilizados:

  • Raspberry PI 2 - clique aqui ver a especificação oficial;
  • Arduíno UNO;
  • 2 Resistores de 10K;
  • Protoboard;
  • Alguns fios.

Foto do projeto montado


No Raspberry utilizado, foi instalada a última versão do sistema operacional disponibilizado pelo NOOBS(clique aqui) - Raspibian, que até a escrita desse artigo estava na Versão 1.9.0 de 18/03/2016. Não iremos abordar a instalação e configuração do Raspberry.

Raspberry PI 2

Esquema elétrico

A Serial do Raspberry está definida nos pinos 14 - TX e 15 - RX, figura abaixo, e iremos utilizar além desses o Ground (qualquer um deles). 

A documentação completa dos pinos pode ser encontrada aqui.


No Arduíno, iremos utilizar também os pinos TX, RX e Ground, que estão definidos na própria placa.



De maneira resumida, no padrão RS-232 (para mais informações sobre a interface serial e protocolo RS-232, clique aqui), os dispositivos que irão conversar devem ter um pino TX e um RX. Onde o TX é o pino emissor e o RX é o pino receptor. Partindo desse princípio, bastaria ligar o TX do Raspberry no RX do Arduíno e ligar o TX do Arduíno no RX do Raspberry. 

Mas, há um porém.O Arduíno trabalha a 5V e o Raspberry a 3,3V. Se ligarmos o TX do Arduíno no RX do Raspberry, poderemos queimar o pino, pois o Arduíno irá enviar 5V e o Raspberry espera até 3,3V. O contrário, não é problema (TX do Raspberry com RX do Arduíno). Pois o Arduíno espera até até 5V e o Raspberry irá enviar até 3,3V.

Para resolver esse problema utilizaremos um circuito divisor de tensão bem simples com dois resistores de 10K entre a ligação do TX do Arduíno com o RX do Raspberry.


Dessa forma, a tensão que vier do Arduíno, será divida entre o Raspberry e o GND(Ground).

Segue abaixo o diagrama completo:

Programação

O programa do Arduíno é bem simples. Temos um loop que enquanto a serial estiver disponível, esperará o caractere "L" pela serial. A cada "L", ele altera o estado do LED de acordo com a variável "state" e responde pela serial o estado do LED (LED Ligado ou Desligado). O programa foi compilado e embarcado usando a IDE oficial do Arduíno.

Fonte para o Arduíno

       
#define PIN_LED 13
char buff;
char state = 1;
 
void setup()
{
  pinMode(PIN_LED, OUTPUT);//Inicializa o Pino 13 como saida
  Serial.begin(115200);//Inicializando a serial em 115200
}
 
void loop()
{
  while (Serial.available() > 0)//loop de leitura/escrita da serial
  {
    buff = Serial.read();
    if (buff == 'L')// se caractere 'L' (LED) vindo na serial
    {
      // Liga/Desliga o LED com base no state ( 0 - LOW, 1 - HIGH)
      digitalWrite(PIN_LED, state);
      // Avisa o receptor do status de LED
      Serial.print("Led: ");
      if (state)
      {
        Serial.println("Ligado");
      }
      else
        Serial.println("Desligado");
    }
    state = !state;
  }
}
 
 

No Raspberry, criaremos um programa em C que inicializa a serial, envia infinitamente o caractere "L" a cada segundo, logando basicamente o estado do LED pelo console (informado pelo Arduíno).

Fonte em C para o Raspberry

       
#include ‹unistd.h› //Usado na serial
#include ‹fcntl.h› //Usado na serial
#include ‹termios.h› //Usado na serial

int uart = -1;
int main(){

 //Abrindo a Serial do raspberry para leitura e escrita
 uart = open("/dev/ttyAMA0",O_RDWR|O_NOCTTY|O_NDELAY);
 if(uart == -1)
  printf("Erro ao abrir UART\n");

 //setup da serial 
 struct termios options;
 options.c_cflag= B115200|CS8|CLOCAL|CREAD;
 options.c_iflag= IGNPAR;
 options.c_oflag= 0;
 options.c_lflag= 0;
 tcflush(uart,TCIFLUSH);
 tcsetattr(uart,TCSANOW,&options);

 unsigned char tx_buff[1];//buffer de envio 
 tx_buff[0] = 'L'; 
        unsigned char rx_buff[256];//buffer de leitura
 int rx_len = 0;

  while(1)//loop infinito
        {
  printf("preparando para escrever\n");
                if(uart != -1 )//send bytes
                {
                        int count = write(uart,&tx_buff[0],1);//escrevendo na serial

                        if(count < 0) 
    printf("Erro de escrita\n");
   else 
    printf("mensagem enviada\n");

                        rx_len = read(uart,(void*)rx_buff,255);//lendo da serial, até 255 bytes

          if(rx_len > 0 )
   {
    rx_buff[rx_len] = '\0';
    printf("Recebido - %s\n",rx_buff);
   }

                }
  else{
   printf("Erro ao escrever na serial");
  }
  sleep(1);//pausa a cada 1 segundo
        }
 close(uart);
 printf("fim\n");
 return 0;
}


Para mai detalhes sobre a inicialização da Serial(UART) em C no Raspberry, clique aqui.

O programa foi compilado usando o compilador G++ nativo da instalação do Raspberry, com a linha de comando abaixo:

       
g++ Serial.cpp -o ardSerial


e executado com a linha:

       
./ardSerial


Segue abaixo um print do console:

Um detalhe importante. Por default, a Serial do Raspberry vem configurada para ficar logando informações para um console. O programa acima irá falhar na abertura da Serial se essa funcionalidade não for desabilitada.

O passo-a-passo de como desabilitar a o console Serial no Raspberry pode ser encontrado aqui.

O programa para o Raspberry pode ser escrito em qualquer outra linguagem, como python, por exemplo.