Introdução
Recentemente a tão conhecida marca Arduino , fundada por Massimo Banzi, David Cuartielles, Tom Igoe e David Mellis e toda uma comunidade, sofreu uma mudança de nome, para os produtos destinados a outros mercados fora dos EUA, passando a usar o nome Arduino apenas nos EUA e o nome Genuino, em todos os restantes mercados. Falo em marca, pois não se refere apenas a uma board, mas a toda uma “marca” de circuitos baseados em microcontroladores e projectos com base numa mesma filosofia de open-hardware. Não me alongando mais sobre o tema, esta mudança teve origem numa questão legal, que é muito bem apresentada por Maximo Banzi, no keynote que apresentou na Maker Fair e pode ser visto no youtube. Assim sendo, de agora avante, neste artigo, o circuito anteriormente conhecido por Arduino, será designado por Genuino.
Passemos agora àquilo que é realmente interessante: comunicar com o Genuino, receber dados e transmitir dados! Recentemente estive a trabalhar num projecto, que começou como trabalho e acabou dando origem a um fork para um hobbie, onde quis receber dados, de um amplo conjunto de sensores, ligados ao microcontrolador e transmiti-los de seguida, usando a ligação de rede existente para essa transmissão, usando a pilha TCP/IP v4, para transmitir dados bidireccionalmente, entre o microcontrolador e um dispositivo ligado à rede. Neste caso concreto foi utilizada uma ligação por cabo, apesar de ser relativamente simples fazer o mesmo com um circuito ethernet, por exemplo um ESP8266-01, ou qualquer outro que suporte a norma 802.11b, quer comunique com o Genuino por UART, quer comunique usando um outro protocolo.
O problema
Neste caso concreto, pretendia obter a informação sobre a humidade relativa do ar, a temperatura e a luminosidade num determinado espaço e de seguida transmitir essa mesma informação via rede.
Posto o problema, claramente definidos os objectivos, como seria de esperar, existe uma pesquisa sobre que sen- sores usar paca cada uma das funções e como o por a comunicar com a rede.
O hardware
Neste projecto concreto, os sensores usados foram um sensor DHT-11, conjuntamente com a respectiva resistência pull-up de 4.7k, na linha de dados, ligado ao Genuino. Este sensor oferece a capacidade de ler a temperatura do ar e a humidade relativa, é amplamente suportado pela comunidade e existe uma excelente biblioteca de suporte para o mesmo, a lib dht11.h disponível no github no repositório da Adafruit.
Para obter a informação da luminosidade, existiam duas possibilidades, logo à primeira vista. Uma seria usar um foto-resistor, a outra usar um circuito mais complexo como o TSL2561 da Sparkfun, que comunica por I2C com o micro- controlador e oferece uma série de funcionalidades interessantes que um fotoresistor não disponibiliza, nomeadamente a capacidade de ler tanto a luminosidade visível como a luminosidade infravermelha, aproximando os valores lidos, daqueles que o olho humano percepciona. Tal como o sensor DHT-11, o TSL2561 tem um amplo suporte de toda a comunidade e bibliotecas que facilitam a sua utilização.
Escolhidos os sensores e a placa Genuino, no caso um Genuino Uno, restou a escolha do circuito ethernet a utilizar, neste caso ethernet shield w5100, com leitor de cartões micro-SD e stacking headers, para ficar acoplado mesmo por cima do Genuino.
Ligações
Escolhido o hardware, é necessário proceder às ligações antes de passarmos à escrita do código destinado a ser executado pelo microcontrolador ATMega328. Para este efeito e uma vez que não se trata de um circuito definitivo, mas ape- nas um circuito de teste, as protoboards, como se pode ver na imagem abaixo, são bastante úteis e facilitam as ligações.
A fim de facilitar as ligações do circuito, na tabela abaixo encontram-se os sensores, indicando o numero de cada pino e o pino a que é ligado no circuito ethernet do Genuino.
DHT11 | Genuino | |
Pino do sensor | Componente | Pino do Genuino |
1 | 5vdc | |
2 | Resistência 4.7k | D2 |
3 | ||
4 | Gnd | |
TSL2561 | Genuino | |
1-SDA | A4 | |
2-SCL | A5 | |
3-GND | GND | |
4-3v3 | 3v3 | |
5-INIT |
As células em branco foram deixadas propositadamente uma vez que nos respectivos locais, não é feita nenhuma ligação, quer seja a um componente intermédio, quer seja ao Genuino.
Programação do Genuino
Chegados a esta parte, está na hora de programar o Genuino de forma a comunicar por rede ethernet, usando o conjunto de protocolos TCP/IP. Felizmente uma parte substancial do trabalho, já vem “pré feito” pela biblioteca ethernet.h
, que nos disponibiliza uma maior abstracção do hardware propriamente dito, deixando-nos livres para a programação da aplicação que será executada. No entanto continua a ser necessário executar algumas tarefas como a definição de um MAC address, a colocação em modo cliente DHCP, caso tenhamos um servidor DHCP na rede, ou a definição de um endereço IP v4, bem como a respectiva máscara de sub-rede e gateway. Desta biblioteca iremos usar maioritariamente o método write
, da classe server
, para enviarmos dados para o nosso cliente TCP, bem como o método read
, para lermos instruções transmitidas pelo servidor.
O código não é complexo e é quase auto-explicativo, não me alongando na sua explicação. De forma muito resumida, inicia a interface ethernet, fica a aguardar por uma conexão e quando a mesma está aberta, aguarda um comando, que executa e devolve o seu resultado, em texto simples. Recomendo a leitura da documentação oficial da biblioteca, para quem pretenda aprofundar os conceitos e conhecimentos.
//thanks to the sparkfun team, for the li //braries, all credits for their work due to //them. #include "DHT.h" #include <SparkFunTSL2561.h> #include <Wire.h> #include <SPI.h> #include <Ethernet.h> #define DHTPIN1 2 // define o pino de dados //do sensor, neste caso 2 #define DHTTYPE DHT11 // DHT 11 (basta uma //constante para dois sensores) SFE_TSL2561 light; boolean gain; //definição do ganho, 0 = X1, //1 = X16; unsigned int ms; byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; IPAddress ip(192,168,1, 177); IPAddress gateway(192,168,1, 1); IPAddress subnet(255, 255, 255, 0); DHT dht1(DHTPIN1, DHTTYPE); EthernetServer server(77); boolean alreadyConnected = false; String commandString; void setup() { dht1.begin(); light.begin(); unsigned char ID; if (light.getID(ID)) {} else { byte error = light.getError(); } gain = 0; unsigned char time = 2; light.setTiming(gain,time,ms); light.setPowerUp(); pinMode(ledPin, OUTPUT); Ethernet.begin(mac, ip, gateway, subnet); server.begin(); Serial.begin(9600); while (!Serial) {;} Serial.print("Socket Server:"); Serial.println(Ethernet.localIP()); } void loop() { EthernetClient client = server.available(); if (client) { if (!alreadyConnected) { client.flush(); commandString = ""; server.println("--> insira um dos comandos disponiveis!"); alreadyConnected = true; } while (client.available()) { char newChar = client.read(); if (newChar == 0x0D) { processCommand(commandString);} else { commandString += newChar; } } } } void processCommand(String command) { //dht11-1 if (command.indexOf("dht1") > -1) { delay(1000); float h1 = dht1.readHumidity(); float t1 = dht1.readTemperature(); if (isnan(h1) || isnan(t1)) { return; } server.print("Humidade "); server.print(String (h1)); server.print("; Temperatura "); server.println(String (t1)); commandString = ""; return; } //light if (command.indexOf("light") > -1) { delay(200); unsigned int data0, data1; if (light.getData(data0,data1)) { double lux; boolean good; //calculo de Lux good = light.getLux (gain,ms,data0,data1,lux); server.print("luminosidade em lux "); server.println(lux); } commandString = ""; return; } commandString = ""; instructions(); } void instructions() server.println("Comando não reconhecido"); server.println("Use um dos seguintes comantos:"); server.println("* dht1, para obter a humidade e temperatura do ar"); server.println("* light, para obter a informação da luminosidade"); } //to my late night owl angel, thanks for the wisdom //inspiration and company, //Stephan|B|
Conclusão
Uma vez feito o upload do código, para o Genuino, basta ligar um cabo de rede e um cliente simples ou usar a nossa própria aplicação para comunicar por sockets com o Genuino, enviando a instrução que pretendemos e recebendo o resultado da mesma. Neste exemplo usei o Putty, para simplificar, apenas defini a porta como 77, pois era uma das portas disponíveis. O objectivo ao usar sockets neste exemplo, prendeu-se com a simplicidade com que se comunica com o dispositivo, bem como com o leque de possibilidades que deixa em aberto para o desenvolvimento de aplicações que interajam com o circuito, como é o caso de aplicações mobile, feitas por exemplo com C# e Xamarin, usando o componente “sockets-for-pcl”, que é bastante simples de usar e bastante intuitivo.