Plataforma Multi-Sensor Ambiental MKR1000 – Relâmpagos, Gás, UV, Temperatura, Umidade e Pressão
Componentes e Materiais
| Componente | Quantidade |
|---|---|
| Arduino MKR1000 | 1 |
| Sensor de Relâmpagos MOD-1016 | 1 |
| Sensor de Gás DFRobot MQ-9 | 1 |
| Sensor de Umidade e Temperatura Adafruit | 1 |
| Sensor de Pressão/Altitude/Temperatura Adafruit | 1 |
| Sensor UV ML8511 SparkFun | 1 |
| RTC Chronodot | 1 |
| Shield Photon Weather SparkFun | 1 |
| NeoPixels Adafruit | 1 |
| Protoboard (genérico) | 1 |
| Fios jumpers (genéricos) | 1 |
Sobre o Projeto
Adoro observar o clima e queria tentar capturá-lo e graficá-lo. Estações meteorológicas domésticas me permitem ver os detalhes do "agora", e às vezes totais da última hora ou dia. Eu queria fazer mais e usar um Arduino para o trabalho. Todos começam com Temperatura e Umidade, às vezes Pressão Barométrica, mas eu queria mais! Velocidade do vento e medição de chuva cada uma queria entradas de hardware. Uma vez que dominei o uso de I2C, encontrei coisas como o Detector de Relâmpagos AS3935! E então a tristeza se instalou... Não tinha interrupções de hardware suficientes para fazer o trabalho com seu Arduino básico. A Sparkfun até tem uma placa de sensor climático para o Photon, mas ainda é limitada. Eu teria que escolher e ficar sem alguns sensores. :-(
Então vi o MKR1000, e notei a MELHOR CARACTERÍSTICA: ele tem 8 interrupções de hardware! Agora eu poderia ter tudo!
Escolhendo seus Sensores
Sensores vêm em três sabores básicos:
- Analógicos: luz (incluindo IR e UV), direção do vento, gases, células de carga...
- I2C: temperatura, umidade, pressão barométrica, acelerômetro, giroscópio...
- Interrupções: medidores de chuva, velocidade do vento, relâmpagos, timers... (Recursos como serial, PWM, relógios, servos usam interrupções de temporização)
O MKR1000 tem bastante I/O para todos estes!
NOTA SOBRE QUAL VOLTAGEM VOCÊ PRECISA PARA SEU I/O EM I2C E INTERRUPÇÕES! Por exemplo, o MKR1000, o Photon e muitos sabores de Arduino usam I/O de 3.3v em vez de 5v. Se seu CPU e os sensores que você quer usam voltagens diferentes, você também precisará usar conversores de nível entre esses dispositivos.
Todos os sensores que estou usando são comuns o suficiente, disponíveis na Adafruit, SparkFun, Element-14 e outros, e geralmente custam entre $5-10 (US). Sensores de gás geralmente custam $10-$20. Para o detector de relâmpagos (chip AS3935), escolhi o Embedded Adventures MOD-1016, que custa $26 (US) para obter a antena na placa também. Também comprei o Sparkfun Photon Weather Shield, já que tenho um Photon, e provavelmente comprarei os "weather meters" deles (instrumentos de velocidade e direção do vento). Talvez eu adicione um sensor de Umidade do Solo, uma vez que descobrir onde vou montar o MKR1000. Alguns sensores não gostam de ter fios longos.
Atribua seus Sensores aos Pinos
Uma vez que você saiba quais sensores quer, saberá que tipo de entradas precisará. O próximo passo é decidir quais sensores irão em quais pinos. Começo no papel, mas também adicionarei esta lista como comentário em bloco no meu código, como lembrete.
Aqui estão as atribuições de pinos do MKR1000 que fiz para meu deck de sensores.
- A0 (Estou guardando A0 caso precise do DAC depois...)
- A1 Sensor UV ML8511
- A2 Sensor de luz visível
- A3 Sensor de temperatura local TMP36
- A4 Sensor de gás MQ-9
- A5 Sensor de umidade
- A6 Sensor de velocidade do vento?
- 0 (HW INT) Botão
- 1 (HW INT) Detector de Relâmpagos AS
- 2 (HW INT) Anemômetro de velocidade do vento (interrupção por rotação)
- 3 (HW INT) Medidor de chuva…
- 4
- 5
- 6 (compartilhado com LED onboard)
- 7 Saída NeoPixel…
Começando...
Para os iniciantes entre vocês, sugiro começar com cada sensor que você vai usar, um de cada vez, e começar carregando o código de exemplo e instalando as bibliotecas necessárias. Lembre-se de alterar o pino do sensor para corresponder à atribuição de pino de sua escolha, e salve uma cópia do código de demonstração na pasta do seu projeto.
Quando você puder rodar o código de teste e ler os resultados no Monitor Serial, você estará pronto para tentar adicionar outro. E quando terminar de testar cada sensor, todos estarão conectados e prontos para começar a construir seu sketch maior!
Meu tinkering original com os sensores incluía usar um RTC (Real-Time Clock) baseado em I2C, para poder registrar em um cartão de memória SD. Embora o MKR1000 tenha seu próprio RTC e uma bateria, não consegui fazer o relógio manter a hora apenas com a bateria, então manterei o ChronoDot v2.1 I2C RTC também.
Olhando a protoboard na minha imagem abaixo, você pode ver os vários jumpers em uso. Os laranjas são para a alimentação de 3.3v para cada sensor, então posso plugá-los apenas quando estiver pronto para trabalhar com eles. (É fácil desabilitar um sensor desplugando o jumper laranja.)
Uma Nota sobre Bibliotecas
Descobri que algumas das bibliotecas que você pode instalar NÃO funcionam perfeitamente com o MKR1000, e/ou com a versão 1.6.7 da Arduino.cc IDE, e você pode precisar fazer alguns ajustes, dependendo da idade do seu sensor. Um exemplo disso são as macros ATOMIC_* mais antigas na biblioteca AVR libc mais antiga (foram removidas na Arduino IDE 1.6.5), e há um ótimo tópico sobre problemas e soluções sugeridas em um fórum no Arduino.cc. Fazer algumas das mudanças sugeridas é algo para um hacker intermediário de Arduino, mas provavelmente será intimidante para hackers mais novos. E, para bibliotecas ligeiramente mais antigas, o autor original pode não estar por perto para atualizar a biblioteca e eliminar a dependência.
Infelizmente, você geralmente não saberá quais bibliotecas precisam ser ajustadas antes de comprar seus sensores e testá-los. Nesse ponto, recomendo que você observe as mensagens de erro que aparecem em laranja quando tentar fazer upload do seu sketch cuidadosamente, para ver se o problema está no seu código ou em uma biblioteca, antes de começar a mudar seu código. Se estiver na biblioteca, faça uma busca na web por "arduino" e a mensagem de erro. Se não encontrar solução, tente enviar email ao autor e avise sobre o erro, e talvez eles atualizem a biblioteca.
Comprei chips individuais tentando economizar dinheiro. Decidi que, até estar pronto e capaz de fazer minhas próprias placas de circuito (provavelmente usando EagleCAD e OSHPark), é mais fácil comprar módulos de sensores da Adafruit e SparkFun, já que eles são ótimos em manter suas bibliotecas atualizadas.
Um Pouco sobre WiFi e Criptografia
Também pensei no WiFi para fazer meus sensores climáticos reportarem para um site. Temos até um motor de criptografia no MKR1000, para ajudar a manter nossos dados seguros em trânsito pela Internet! Mas isso é mais do que conseguirei fazer neste primeiro projeto. Está na minha lista para fazer, porque tornar a segurança de dados parte do seu design é importante para a Internet das Coisas, mas estou sem tempo para adicionar minha entrada para o concurso MKR1000. Fique atento à minha "versão 2" deste projeto. Aqui está um diagrama de bloco do módulo SAMD que é o coração da sua placa.
Posso oferecer uma dica para começar com o WiFi onboard: Certifique-se de que está usando a versão mais atual da biblioteca WiFi101! Se não usar, seu sketch não reconhecerá o módulo WiFi, e seus sketches WiFi apenas reportarão erro (se houver verificação de erro nas chamadas ao módulo WiFi). Preciso agradecer Charif Mahmoudi por apontar isso no excelente tutorial "Getting Started with MKR1000" aqui no Hackster! Na época do meu hacking, você podia encontrar o WiFi101 GitHub aqui.
Dicas para Sensores Analógicos
A maioria dos módulos de sensor com "saída analógica" produzirá uma simples saída de tensão analógica, e isso é facilmente lido usando o analogRead do pino do sensor. Mas então você precisa saber o que isso significa. Normalmente, você precisará usar o comando map, ou pode precisar fazer um pouco de matemática. Elementos resistivos geralmente precisarão de circuitos extras. Você pode querer adicionar um potenciômetro para "ajustar finamente" a tensão.
Em outros casos, você precisará de equações para transformar a tensão de saída em algo que humanos entendam. O sensor de temperatura TMP36 é um exemplo bem documentado disso. Esta peça foi projetada para ler em graus Celsius, então você precisa medir a tensão e fazer um pouco de matemática para obter C, e se quiser Fahrenheit, precisará converter C para F. Ler as folhas de dados dos componentes explicará como a peça funciona, mas você achará mais fácil seguir os passos de outra pessoa enquanto constrói sua experiência.
Outros sensores precisam de um amplificador, para fazer as minúsculas variações de tensão grandes o suficiente para seu ADC obter uma boa faixa de alta a baixa. Estes tipos de sensores (células de carga, umidade, acelerômetro) são onde acho melhor gastar um pouco de dinheiro e comprar um módulo que já tenha um amplificador e uma biblioteca para ajudar a entender a faixa de saída.
Dicas para Usar Dispositivos I2C
I2C às vezes é chamado de "interface de dois fios", porque você precisa de um sinal de clock, bem como um sinal de dados. (Você precisa apenas de um fio de dados, porque o "mestre" e o(s) "escravo(s)" se revezarão enviando dados nele.) Claro, seus sensores I2C também precisarão de um terra e um fio de alimentação, e esse terra precisa estar ligado de volta ao seu CPU.
Todo dispositivo I2C terá um endereço hexadecimal no barramento. É melhor evitar usar múltiplos dispositivos com o mesmo endereço. (Se quiser ter múltiplos, você precisa gerenciá-los com circuitos extras, para "habilitar" o que você quer comunicar, e então desabilitá-lo quando terminar, antes de habilitar outro para comunicação.) A documentação deve dizer quais endereços um dispositivo pode ter. (NOTA: Se você tem dois dispositivos no barramento I2C com o mesmo endereço, e ambos têm um pino "Enable" ou "Shutdown", você poderá desabilitar um enquanto o outro está acordado. No entanto, você não pode simplesmente desligar a alimentação do pino vdd, pois os sensores podem captar alguma energia dos pinos SDA e SCL, resultando em leituras ruins para aquele endereço. A verificação de erro do I2C não é boa o suficiente para detectar/corrigir este caso.)
As especificações I2C nos dizem que devemos ter um resistor de "pull-up forte" tanto no clock quanto nos fios de dados, no sensor que está mais longe no fio. Por causa disso, alguns módulos de sensor já têm resistores onboard, e você pode precisar apenas adicionar alguns jumpers, então certifique-se de ler a documentação do(s) módulo(s).
Além dos "resistores de terminação do barramento", também encontrei uma dica de um hacker há muito tempo, para adicionar um resistor em linha tanto nos fios de dados (SDA) quanto de clock (SCL). Isso melhorou muito a confiabilidade das leituras de dados de alguns sensores. Com o MKR1000, usando sinalização de 3.3v, estou usando resistores de 220 ohm. Em um CPU de 5-v, você pode querer tentar 330 ohm. Veja o esquemático abaixo para ver a diferença nas colocações.
O que você fará com os dados?
Agora, estou apenas enviando para o Monitor Serial. Você poderia adicionar um LCD. Ia adicionar um cartão SD, mas agora que tenho WiFi embutido, quero enviar os dados para a nuvem... imagine ter alguns desses decks de sensores por aí, sabendo sua latitude e longitude, e sendo capaz de triangular um relâmpago comparando as leituras de potência de cada estação para um determinado relâmpago!
NOTA LATERAL: 2017-11-29; Não consegui fazer as interrupções de hardware funcionarem no MKR1000. Estou fazendo anotações e experimentos de sensores para uma aula do 9º ano (idade 13-14), e talvez você ache os sketches interessantes. A aula é construída em torno da placa Adalogger M0, e salva os dados em um cartão SD, e ainda há muitos pinos para um módulo WiFi. https://arduinoclass.pbworks.com
Enquanto trabalhava nos sensores, também notei a luminária SODERSVIK na IKEA (Veja a imagem abaixo). Imagine substituir os LEDs brancos dentro desta lâmpada por 20 Neopixels, e adicionar um receptor IR remoto. Vento soprando poderia parecer nuvens passando, e a cor poderia indicar a temperatura. O controle remoto também poderia escolher mostrar momentaneamente alguma outra informação, como a mudança de temperatura nas últimas 12 horas.
O que você quer monitorar e exibir?
Código
Sketch completo de monitoramento (Arduino)
Há muitos sensores reportando neste sketch, e as bibliotecas estão funcionando bem juntas. No entanto, os métodos clássicos de travamento de interrupção no AVR-libc foram removidos nas versões recentes da Arduino IDE, o que desabilitou as bibliotecas para NeoPixel e para o sensor de Relâmpagos. Espero que isso seja resolvido ainda este ano, mas isso significa que os deixei fora do sketch final.
/* RTC-Weather-Sensors_v6_MKR1000 by Zonker Harris Spring 2016
* Hurray! Uma placa pequena, com mais de 2 interrupções de hardware!
* Mais WiFi, *e* crypto (MUITO necessário para aplicações IoT!)
*
* Nota para hackers mais novos: Coloquei MUITOS comentários no meu código, como você vê.
* Quando você clica em upload, *comentários são IGNORADOS*, e não consomem memória!
* Recomendo que você também adicione muitos comentários quando fizer mudanças
* e adições, para ajudar a lembrar POR QUE você fez o que fez meses atrás.
* Eles também ajudarão aqueles que vierem depois de você, a aprender uma ou duas coisas.
*
* Agora, bibliotecas *CONTAM* contra sua memória de programa...
*/
#include
#include
#include
#include
// Incluindo neopixels como placeholder, mas o vetor de interrupção da biblioteca precisa de atualização.
// Inclua a biblioteca Adafruit_NeoPixel https://github.com/adafruit/Adafruit_NeoPixel
//#include
//const int numLeds = 1; // Quantos neopixels na string? usado para configurar a biblioteca NeoPixel
// Parâmetro 1 = número de pixels na strip
// Parâmetro 2 = número do pino (a maioria é válida)
// Parâmetro 3 = flags de tipo de pixel, some conforme necessário:
// NEO_RGB Pixels conectados para bitstream RGB
// NEO_GRB Pixels conectados para bitstream GRB
// NEO_KHZ400 400 KHz bitstream (ex. pixels FLORA)
// NEO_KHZ800 800 KHz bitstream (ex. LED strip High Density)
//Adafruit_NeoPixel strip = Adafruit_NeoPixel(numLeds, 6, NEO_GRB + NEO_KHZ800);
/* O driver BMP085_U usa a biblioteca unified sensor da Adafruit (Adafruit_Sensor), que fornece um 'tipo' comum
para dados de sensor e algumas funções auxiliares. (O BMP180 é compatível com esta biblioteca, e dá a mesma saída,
mas a biblioteca identificará o BMP180 como um BMP085.)
Para usar este driver você também precisará baixar a biblioteca Adafruit_Sensor e incluí-la na sua pasta de bibliotecas.
Você também deve atribuir um ID único a este sensor para uso com a Adafruit Sensor API para que possa identificar
este sensor particular em quaisquer logs de dados, etc. Para atribuir um ID único, simplesmente forneça um valor
apropriado no construtor abaixo (12345 é usado por padrão neste exemplo). */
Adafruit_BMP085_Unified bmp = Adafruit_BMP085_Unified(10180);
/* Este sketch também foi projetado para funcionar com o sensor HTU21D-F da Adafruit ----> https://www.adafruit.com/products/1899 */
Adafruit_HTU21DF htu = Adafruit_HTU21DF();
/* Macetech Chronodot v2.1 Real-Time Clock (RTC) com bateria...
https://docs.macetech.com/doku.php/chronodot
(porque a bateria no meu MKR1000 não parece manter o RTC onboard vivo)
Informações da biblioteca Adafruit Real-Time Clock (RTC)
https://learn.adafruit.com/adafruit-data-logger-shield/using-the-real-time-clock
Analog Devices TMP36 sensor de temperatura analógico calibrado. Requer um pouco de matemática
https://learn.adafruit.com/tmp36-temperature-sensor
https://www.analog.com/media/en/technical-documentation/data-sheets/TMP35_36_37.pdf
ML8511 Sensor UV...
Este sensor detecta luz 280-390nm mais efetivamente. Isso é categorizado como parte do espectro UVB (raios que queimam)
e a maior parte do espectro UVA (raios que bronzeiam).
MOD-1016 (Sensor de Relâmpagos AS3935) endereço i2c 0x03 - Sensor de Relâmpagos AS3935
Adafruit tem um anemômetro que fornece tensão DC (0.4-2.0v)
https://www.adafruit.com/products/1733
https://www.instructables.com/id/Breezefinder-Citizen-Science-Windpower-Tool/step2/Build-the-housing/
Detector de Umidade do Solo (sensor YL-69 ou similar) requer entrada analógica...
https://www.instructables.com/id/Arduino-LCD-Soil-Moisture-Sensor/step3/Connect-moisture-sensor/
Minhas Conexões MKR1000 (Todos os sensores devem ser sinalização 3.3v!)
=========== */
int UVOUT = A1; // Saída do sensor UV MV8511
int lightOut = A2; // Saída do sensor de luz visível TEMT6000
int tmp36out = A3; // Saída do sensor de temperatura Analog Devices TMP36
int mq9out = A4; // Saída do sensor DFrobot MQ-9 CO/Gases Combustíveis
/* A5 Sensor de Umidade
A6 Sensor de velocidade do vento?
0 (HW INT) botão
1 (HW INT) Detector de Relâmpagos AS
2 (HW INT) Anemômetro de velocidade do vento? (interrupção por rotação)
3 (HW INT) Medidor de chuva…
4
5 */
int sounderPin = 6; // Saída do buzzer piezo (compartilhado com LED onboard)
// (Você pode usar um jumper para desabilitar o buzzer, mas o LED onboard piscará)
int neopixelPin = 7; // Saída NeoPixel, para visualização usando LEDs baseados em shift-register
/*11 i2c SDA
12 i2c SCL */
// Declarando variáveis para o Chronodot I2C RTC...
int addrRTC = (0x68); // Endereço I2C do RTC
int seconds; // BCD combinado do RTC (00h)
int seconds1; // 0-9
int seconds10; // 0-5
int minutes; // BCD combinado do RTC (01h)
int minutes1; // 0-9
int minutes10; // 0-6
int hours; // BCD combinado do RTC (02h)
int hours1; // 0-9
int hours10; // 0-2
int day; // 1-7 (03h)
int date; // 01-31 (04h)
int month; // 01-12 (05h)
int years; // 0-99; (06h)
int a1secs; // (07h) obtém segundos do Alarme 1
int a1mins; // (08h) obtém minutos do Alarme 1
int a1hrs; // (09h) obtém horas do Alarme 1
int a1daydate; // (0Ah) obtém bits de dia e data do Alarme 1
int a2mins; // (0Bh) obtém minutos do Alarme 2
int a2hrs; // (0Ch) obtém horas do Alarme 2
int a2daydate; // (0Dh) obtém bits de dia e data do Alarme 2
int rtcstatus; // (0Eh) obtém bits de status do RTC
int aginginfo; // (0Fh) obtém info de envelhecimento
// o que é 10h?
int temprtc; // BCD combinado do RTC (11h)
int tempfrtc; // BCD combinado do RTC (12h)
/**************************************************************************/
// Função setup do Arduino (chamada automaticamente na inicialização)
/**************************************************************************/
void setup(void) {
Serial.begin(9600);
delay(1000);
Serial.println("i2c Sensor Deck");
// Lembre-se de configurar seus pinos de entrada e saída!
pinMode(UVOUT, INPUT); // o sensor UV ML8511
pinMode(lightOut, INPUT); // o sensor de luz visível TEMT6000
pinMode(tmp36out, INPUT); // o sensor de temperatura Analog Devices TMP36
pinMode(sounderPin, OUTPUT); // HIGH fará o buzzer emitir som
pinMode(neopixelPin, OUTPUT); // Use resistor de 220-ohm em linha para a strip
/* Inicializa o sensor BMP085/BMP180 */
if(!bmp.begin()) {
/* Houve um problema detectando o BMP085/180 ... verifique suas conexões */
Serial.print("Ooops, no BMP085/180 detected ... Check your wiring or I2C ADDR!");
while(1);
}
/* Exibe algumas informações básicas sobre este sensor, BMP180 reporta como BMP085 */
displaySensorDetails();
/* Inicializa o sensor HTU21D */
if (!htu.begin()) {
Serial.println("Couldn't find the HTU21-DF sensor!");
while (1);
}
// Inicializa o relógio RTC Chronodot
//(mude os valores, descomente, faça upload para definir a hora, depois comente novamente)
/* seconds = 0; minutes = 41; hours = 20; day = 7; date = 3; month = 1; years = 16; initChrono(); */
}
void loop(void) {
beep(50, 2); // anuncia o início do loop no buzzer
// Define neopixel para Teal...
//int red = 0; int green = 45; int blue = 30;
//strip.setPixelColor(0, (red, green, blue));
//strip.show();
/**********************************************************************/
/* Puxa info do Chronodot endereço i2c 0x68 - DS1307 RTC */
/* Info da placa: https://docs.macetech.com/doku.php/chronodot */
/* DS3231 datasheet: https://datasheets.maxim-ic.com/en/ds/DS3231.pdf */
/**********************************************************************/
int temprtc;
/* Obtém novo timestamp */
Wire.beginTransmission(0x68); // 0x68 é endereço do dispositivo DS3231
Wire.write((byte)0); // começa no registrador 0
Wire.endTransmission();
Wire.requestFrom(0x68, 13); // solicita 19 bytes (é o # de bytes DEC ou HEX?)
// (seconds, minutes, hours, day, date, month, hrs,
// a1secs, a1mins, a1hrs
// a1secs, a1mins, a1hrs
// Aging offset, Temp integer, temp fraction)
while(Wire.available()) {
seconds = Wire.read(); // (00h) obtém segundos
minutes = Wire.read(); // (01h) obtém minutos
hours = Wire.read(); // (02h) obtém horas
day = Wire.read(); // (03h) obtém dia da semana
date = Wire.read(); // (04h) obtém data do mês
month = Wire.read(); // (05h) obtém o mês, e bit de século
years = Wire.read(); // (06h) obtém o ano
int a1secs = Wire.read(); // (07h) obtém segundos do Alarme 1
int a1mins = Wire.read(); // (08h) obtém minutos do Alarme 1
int a1hrs = Wire.read(); // (09h) obtém horas do Alarme 1
int a1daydate = Wire.read(); // (0Ah) obtém bits de dia e data do Alarme 1
int a2mins = Wire.read(); // (0Bh) obtém minutos do Alarme 2
int a2hrs = Wire.read(); // (0Ch) obtém horas do Alarme 2
int a2daydate = Wire.read(); // (0Dh) obtém bits de dia e data do Alarme 2
int rtcstatus = Wire.read(); // (0Eh) obtém bits de status do RTC
int aginginfo = Wire.read(); // (0Fh) obtém info de offset de envelhecimento
temprtc = Wire.read(); // (11h) obtém parte inteira da temp, e sinal
tempfrtc = Wire.read(); // (12h) obtém parte fracionária da temp
// Lê nossos bits, e normaliza os dados com padding zero à esquerda
// NOTA: O Chronodot não sabe sobre Horário de Verão, seu código deveria?
seconds10 = ((seconds & 0b11110000)>>4);
seconds1 = ((seconds & 0b00001111));
// converte BCD para decimal
minutes10 = ((minutes & 0b11110000)>>4);
minutes1 = (minutes & 0b00001111);
// converte BCD para decimal
hours10 = (((hours & 0b00100000)>>5)*2 + ((hours & 0b00010000)>>4)*1);
hours1 = (hours & 0b00001111);
// converte BCD para decimal (assume modo 24 horas)
years = (years + 2000);
temprtc = ((temprtc & 0b01111111) + (((tempfrtc & 0b11000000)>>6)*0.25));
}
get_date(); // Este é um lugar onde você poderia adicionar decisões de Horário de Verão para alterar horas...
Serial.print("ChronoDot - ");
Serial.print(hours10);
Serial.print(hours1);
Serial.print(":");
Serial.print(minutes10);
Serial.print(minutes1);
Serial.print(":");
Serial.print(seconds10);
Serial.print(seconds1);
Serial.print(" 20");
Serial.print(years);
Serial.print(" ");
Serial.print(month);
Serial.print(" ");
Serial.print(date);
Serial.print(" \t");
Serial.print(temprtc);
Serial.println(" C");
delay(100); // para que isso termine de imprimir, caso o próximo sensor trave
/**********************************************************************/
/* Obtém dados BMP180 endereço i2c 0x77 - BMP180 Pressão Barométrica e Temp */
/* dados: https://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf */
/**********************************************************************/
sensors_event_t event;
bmp.getEvent(&event);
/* Primeiro obtemos a temperatura atual do BMP085/BMP180 */
float BMPtemperature;
bmp.getTemperature(&BMPtemperature);
float BMPtempF = (BMPtemperature * 1.8 + 32);
Serial.print("Temp: ");
Serial.print(BMPtemperature);
Serial.print(" C (");
Serial.print(BMPtempF);
Serial.print(" F) \t");
/* Exibe os resultados (pressão barométrica medida em hPa) */
if (event.pressure) {
/* Exibe pressão atmosférica em hPa */
Serial.print("BMP180 - Pres: ");
Serial.print(event.pressure);
Serial.print(" hPa\t");
/* Calculando altitude com precisão razoável requer pressão
* pressão ao nível do mar para sua posição no momento em que os dados são
* convertidos, bem como a temperatura ambiente em graus
* celsius. Se você não tem esses valores, um valor 'genérico' de
* 1013.25 hPa pode ser usado (definido como SENSORS_PRESSURE_SEALEVELHPA
* em sensors.h), mas isso não é ideal e dará resultados variáveis
* de um dia para o outro.
* converter polegadas-mercúrio https://www.csgnetwork.com/pressinmbcvt.html
* Por exemplo, para Paris, França você pode verificar a pressão média
* atual e nível do mar em: https://bit.ly/16Au8ol */
/* Então converte a pressão atmosférica, e SLP para altitude */
/* Atualize a próxima linha com o SLP atual para melhores resultados */
float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA;
Serial.print("Alt: ");
Serial.print(bmp.pressureToAltitude(seaLevelPressure, event.pressure));
Serial.println(" m");
delay(100); // para que isso termine de imprimir, caso o próximo sensor trave
} else {
Serial.println("Sensor error");
}
/**********************************************************************/
/* Obtém dados HTU21-DF endereço i2c 0x40 - Sensor de Umidade e Temp */
/* https://learn.adafruit.com/adafruit-htu21d-f-temperature-humidity-sensor/overview */
/**********************************************************************/
float HTUtemperature = htu.readTemperature();
float HTUtempF = (HTUtemperature * 1.8 + 32);
Serial.print("HTU21-DF - Temp: ");
Serial.print(HTUtemperature);
Serial.print(" C (");
Serial.print(HTUtempF);
Serial.print(" F)\tHum: ");
Serial.print(htu.readHumidity());
Serial.println("%");
delay(100); // para que isso termine de imprimir, caso o próximo sensor trave
/**********************************************************************/
/* Analog Devices venerável sensor de temperatura de precisão TMP36
* isso requer um pouco de matemática após ler a saída...
* https://learn.adafruit.com/tmp36-temperature-sensor/using-a-temp-sensor
/**********************************************************************/
//obtendo a leitura de tensão do sensor de temperatura
int reading = averageAnalogRead(tmp36out);
// 0.0032258064516129 são as unidades DAC para 3.3v
float tmp36voltage = 0.0032258064516129 * reading;
// imprime a tensão
Serial.print("TMP36 - temp: ");
float tmp36temperatureC = (tmp36voltage - 0.5) * 100; //convertendo de 10 mv por grau com offset 500 mV para graus ((tensão - 500mV) vezes 100)
Serial.print(tmp36temperatureC);
Serial.print(" C \t");
// agora converte para Fahrenheit
float tmp36temperatureF = (tmp36temperatureC * 9.0 / 5.0) + 32.0;
Serial.print(tmp36temperatureF);
Serial.print(" F, out: ");
Serial.print(tmp36voltage);
Serial.println("v");
delay(100); // para que isso termine de imprimir, caso o próximo sensor trave
/**********************************************************************/
* Sensor de Luz Visível Vishay TEMT6000 - leitura analógica
* https://www.sparkfun.com/products/8688
/**********************************************************************/
int vLevel = averageAnalogRead(lightOut);
// 0.0032258064516129 é (3.3v (tensão de ref DAC) \ 1023 * uvLevel)
float newVOutVolts = 0.0032258064516129 * vLevel;
Serial.print("TEMT6000 out: ");
Serial.println(vLevel);
delay(100); // para que isso termine de imprimir, caso o próximo sensor trave
/**********************************************************************/
* ML8511 Sensor UV - leitura analógica
* https://learn.sparkfun.com/tutorials/ml8511-uv-sensor-hookup-guide
/**********************************************************************/
int uvLevel = averageAnalogRead(UVOUT);
// 0.0032258064516129 é (3.3v (tensão de ref DAC) \ 1023 * uvLevel)
float newOutVolts = 0.0032258064516129 * uvLevel;
// Converte a tensão para nível de intensidade UV
float uvIntensity = mapfloat(newOutVolts, 0.99, 2.8, 0.0, 15.0);
Serial.print("ML8511 UV out: ");
Serial.print(uvLevel);
Serial.print(" / UV Intensity (mW/cm^2): ");
Serial.println(uvIntensity);
delay(100); // para que isso termine de imprimir, caso o próximo sensor trave
/**********************************************************************/
* DFrobot MQ-9 Sensor CO/Gases Combustíveis - leitura analógica
* https://www.dfrobot.com/wiki/index.php/Analog_Gas_Sensor(MQ9)_(SKU:SEN0134)
* https://www.pololu.com/category/83/gas-sensors Existem muitos disponíveis
* Mas, decifrar o que os níveis de saída significam é um exercício para o comprador. :-(
/**********************************************************************/
int MQ9volts = analogRead(mq9out); // Lê valor do gás do sensor MQ-9
Serial.print("MQ-9 Gas: ");
Serial.println(MQ9volts,DEC);
delay(100); // para que isso termine de imprimir, caso o próximo sensor trave
Serial.println("");
delay(3500); // procurando cronometrar o loop em cerca de 5 segundos...
// Fim do loop principal...
}
/**************************************************************************/
/* O código abaixo são subrotinas de suporte */
/**************************************************************************/
/* Subrotinas relacionadas ao Chronodot
* initChrono, set_date, get_date, set_time, get_time, get_temp,
* setHour, SetMinutes, decToBcd, bcdToDec */
/**************************************************************************/
void initChrono() {
set_time();
set_date();
}
void set_date() {
Wire.beginTransmission(104);
Wire.write(4);
Wire.write(decToBcd(day));
Wire.write(decToBcd(date));
Wire.write(decToBcd(month));
Wire.write(decToBcd(years));
Wire.endTransmission();
}
void get_date() {
Wire.beginTransmission(104);
Wire.write(3);//define registrador para 3 (day)
Wire.endTransmission();
Wire.requestFrom(104, 4); //obtém 4 bytes(day,date,month,year);
day = bcdToDec(Wire.read());
date = bcdToDec(Wire.read());
month = bcdToDec(Wire.read());
years = bcdToDec(Wire.read());
}
void set_time() {
Wire.beginTransmission(104);
Wire.write((byte)0);
Wire.write(decToBcd(seconds));
Wire.write(decToBcd(minutes));
Wire.write(decToBcd(hours));
Wire.endTransmission();
}
void get_time() {
Wire.beginTransmission(104);
Wire.write((byte)0);//define registrador para 0
Wire.endTransmission();
Wire.requestFrom(104, 3);//obtém 3 bytes (seconds,minutes,hours);
seconds = bcdToDec(Wire.read() & 0x7f);
minutes = bcdToDec(Wire.read());
hours = bcdToDec(Wire.read() & 0x3f);
}
void get_temp() {
Wire.beginTransmission(104);
Wire.write((byte)0); //define registrador para 0
Wire.endTransmission();
Wire.requestFrom(104, 3);//obtém 3 bytes (seconds,minutes,hours);
seconds = bcdToDec(Wire.read() & 0x7f);
minutes = bcdToDec(Wire.read());
hours = bcdToDec(Wire.read() & 0x3f);
}
void setHour() {
hours++;
if (hours > 23) {
hours = 0;
seconds = 0;
minutes = 0;
}
set_time();
}
void setMinutes() {
minutes++;
if (minutes > 59) {
minutes = 0;
}
seconds = 0;
set_time();
}
byte decToBcd(byte val) {
return ( (val / 10 * 16) + (val % 10) );
}
byte bcdToDec(byte val) {
return ( (val / 16 * 10) + (val % 16) );
}
/**************************************************************************/
/* Exibe algumas informações básicas sobre este sensor da API unified sensor sensor_t type (veja Adafruit_Sensor para mais informações) */
/**************************************************************************/
void displaySensorDetails(void) {
sensor_t sensor;
// bmp.getSensor(&sensor);
Serial.println("------------------------------------");
Serial.print ("Sensor: ");
Serial.println(sensor.name);
Serial.print ("Driver Ver: ");
Serial.println(sensor.version);
Serial.print ("Unique ID: ");
Serial.println(sensor.sensor_id);
Serial.print ("Max Value: ");
Serial.print(sensor.max_value);
Serial.println(" hPa");
Serial.print ("Min Value: ");
Serial.print(sensor.min_value);
Serial.println(" hPa");
Serial.print ("Resolution: ");
Serial.print(sensor.resolution);
Serial.println(" hPa");
Serial.println("------------------------------------");
Serial.println("");
delay(500);
}
/**************************************************************************/
/* Tira uma média de leituras em um pino dado, Retorna a média
* usada para leituras do TMP36 e Sensor UV ML8511.
/**************************************************************************/
int averageAnalogRead(int pinToRead) {
byte numberOfReadings = 8;
unsigned int runningValue = 0;
for(int x = 0 ; x < numberOfReadings ; x++)
runningValue += analogRead(pinToRead);
runningValue /= numberOfReadings;
return(runningValue);
}
//A função Map do Arduino mas para floats
//De: https://forum.arduino.cc/index.php?topic=3922.0
float mapfloat(float x, float in_min, float in_max, float out_min, float out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
void beep(int duration, int count) {
for(int loop = 0 ; loop < count ; loop++) {
digitalWrite(sounderPin, HIGH);
delay(duration);
digitalWrite(sounderPin, LOW);
delay(duration);
}
}
Leitura Analógica Média
Este foi um hack inteligente que encontrei na biblioteca SparkFun para o Sensor UV ML8511, mas estou destacando especificamente, já que você pode usá-lo para qualquer leitura analógica! Se você encontrar Nathan Seidl, por favor compre uma cerveja para ele (é licença Beerware.)
//Tira uma média de leituras em um pino dado
//Retorna a média
int averageAnalogRead(int pinToRead) {
byte numberOfReadings = 8;
unsigned int runningValue = 0;
for(int x = 0 ; x < numberOfReadings ; x++)
runningValue += analogRead(pinToRead);
runningValue /= numberOfReadings;
return(runningValue);
}
Scanner de Barramento I2C
Se você não sabe o endereço base para seus dispositivos I2C, use isto para escanear a faixa de endereços válidos. Ele conhece os sensores com os quais estou trabalhando. Você pode adicionar seções para seus outros sensores.
// --------------------------------------
// i2c_scanner
//
// Found at https://playground.arduino.cc/Main/I2cScanner?action=sourceblock&num=1
// 26 OCT 2015
//
// Version 1
// This program (or code that looks like it)
// can be found in many places.
// For example on the Arduino.cc forum.
// The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
// Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26 2013
// V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
// by Arduino.cc user Krodal.
// Changes by louarnold removed.
// Scanning addresses changed from 0...127 to 1...119,
// according to the i2c scanner by Nick Gammon
// https://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
// As version 4, but address scans now to 127.
// A sensor seems to use address 120.
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//
// Zonker Harris added device descriptions, comments. OCT 10 2015
//
#include
void setup() {
Wire.begin();
Serial.begin(9600);
Serial.println("\nI2C Scanner");
}
void loop() {
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 1; address < 127; address++ ) {
// O i2c_scanner usa o valor de retorno de
// Write.endTransmisstion para ver se
// um dispositivo reconheceu o endereço.
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.print(address); Se necessário, imprima o endereço em decimal
//
// Agora, detalhe sensores que conhecemos ou esperamos...
if (address == 3) { // DEC 3 = 0x03 HEX = AS3935 Lightning Sensor
Serial.print(" - AS3935 Lightning Sensor");
}
if (address == 64) { // DEC 64 = 0x40 HEX = HTU21D Humidity and Temp Sensor
Serial.print(" - HTU21D Humidity and Temp Sensor");
}
if (address == 104) { // DEC 104 = 0x68 HEX = DS1307 (Chrono-Dot?) RTC
Serial.print(" - DS1307 RTC (Chrono-Dot?)");
}
if (address == 119) { // DEC 119 = 0x77 HEX = BMP180 Barometric Pressure and Tem Sensor
Serial.print(" - BMP180 Barometric Pressure and Tem Sensor");
}
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 (address == 3) { // DEC 3 = 0x03 HEX = AS3935 Lightning Sensor
Serial.print(" - AS3935 Lightning Sensor");
}
if (address == 64) { // DEC 64 = 0x40 HEX = HTU21D Humidity and Temp Sensor
Serial.print(" - HTU21D Humidity and Temp Sensor");
}
if (address == 104) { // DEC 104 = 0x68 HEX = DS1307 (Chrono-Dot?) RTC
Serial.print(" - DS1307 RTC (Chrono-Dot?)");
}
if (address == 119) { // DEC 119 = 0x77 HEX = BMP180 Barometric Pressure and Tem Sensor
Serial.print(" - BMP180 Barometric Pressure and Tem Sensor");
}
}
}
if (nDevices == 0) Serial.println("No I2C devices found\n");
else Serial.println("done\n");
delay(5000); // espera 5 segundos para próxima varredura
}
/* A saída parece com isso...
*
* Scanning...
* I2C device found at address 0x03 - AS3935 Lightning Sensor
* I2C device found at address 0x40 - HTU21D Humidity and Temp Sensor
* I2C device found at address 0x68 - DS1307 RTC (Chrono-Dot?)
* I2C device found at address 0x77 - BMP180 Barometric Pressure and Tem Sensor
* done
* */
Código Demo ML8511
Modificado para uso com CPU nativa 3.3v (para unidades de referência DAC).
/*
* De https://learn.sparkfun.com/tutorials/ml8511-uv-sensor-hookup-guide 19 MAR 2016
* (Adaptado para MKR1000 por Zonker Harris, MAR 2016)
* ML8511 UV Sensor Read Example
* Por: Nathan Seidle
* SparkFun Electronics
* Data: January 15th, 2014
* Licença: Este código é domínio público mas você me compra uma cerveja se usar isso e nos encontrarmos algum dia (licença Beerware).
* O Sensor UV ML8511 emite um sinal analógico em relação à quantidade de luz UV que detecta.
* Conecte o seguinte breakout board ML8511 ao Arduino:
* 3.3V = 3.3V
* OUT = A1
* GND = GND
* EN = 3.3V
* A demo da Sparkfun pressupõe VCC 5v, mas o MKR1000 é nativo 3.3v.
* Por causa disso, o segundo valor de tensão de referência será sempre "1023".
* Como resultado dos testes, cortei essa parte... -Z-
* Teste seu sensor iluminando com luz do dia ou LED UV: https://www.sparkfun.com/products/8662
* Este sensor detecta luz 280-390nm mais efetivamente. Isso é categorizado como parte do espectro UVB (raios que queimam)
* e a maior parte do espectro UVA (raios que bronzeiam).
* Há muitas boas leituras sobre radiação UV por aí:
* https://www.ccohs.ca/oshanswers/phys_agents/ultravioletradiation.html
* https://www.iuva.org/uv-faqs
*/
//Definições de pinos de hardware
int UVOUT = A1; //Saída do sensor
void setup() {
Serial.begin(9600);
pinMode(UVOUT, INPUT);
Serial.println("ML8511 example");
}
void loop() {
int uvLevel = averageAnalogRead(UVOUT);
float newOutVolts = 0.0032258064516129 * uvLevel; // Isto é 3.3v \ 1023 * uvLevel
float uvIntensity = mapfloat(newOutVolts, 0.99, 2.8, 0.0, 15.0); //Converte a tensão para nível de intensidade UV
Serial.print("ML8511 out: ");
Serial.print(uvLevel);
Serial.print(" / UV Intensity (mW/cm^2): ");
Serial.print(uvIntensity);
Serial.println();
delay(100);
}
//Tira uma média de leituras em um pino dado
//Retorna a média
int averageAnalogRead(int pinToRead) {
byte numberOfReadings = 8;
unsigned int runningValue = 0;
for(int x = 0 ; x < numberOfReadings ; x++)
runningValue += analogRead(pinToRead);
runningValue /= numberOfReadings;
return(runningValue);
}
//A função Map do Arduino mas para floats
//De: https://forum.arduino.cc/index.php?topic=3922.0
float mapfloat(float x, float in_min, float in_max, float out_min, float out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
Esquemáticos
Sou novo demais no Fritzing, e não consegui encontrar muitas peças na biblioteca, então fiz este mock-up.
Processo de manufatura
- Integração de Dados de Sensores no Raspberry Pi: Guia Prático
- Sensor de Rastreamento de Linha com Raspberry Pi – Detector KY‑033 Simples para Porta/Linha
- Construa API Robusta de Temperatura e Sensores no Raspberry Pi com Módulo GY‑91
- Construa um Sistema Aeropônico Automatizado com Raspberry Pi e Sensor de Umidade
- Domine GPIO do Raspberry Pi: Interface com Sensor PIR de Movimento no B+/Modelo 2
- Integrando Radar Pulsado Acconeer A111 com Raspberry Pi: Guia Prático
- Como Conectar, Calibrar e Programar Sensor PIR HC‑SR501 com Raspberry Pi
- Logger de Sensores Python/MicroPython: Armazene Dados de Sensores no Google Sheets Facilmente
- Enviando Dados do IMU Adafruit 10DOF do Raspberry Pi 2 ao Azure Event Hubs com Windows 10 IoT Core
- Desligamento Gracioso e Modo Sleep para Raspberry Pi – Circuito DIY de Gerenciamento de Energia