Arduino vlhkoměr-teploměr-tlakoměr
by Ivan
Jak zmíněno ve zprávě o výrobě jogurtu, Arduino je zcela nezbytný doplněk domácnosti.
Domácí kutil dostane do ruky destičku a začně přemýšlet, co originálního vyrobí. Robota, co sám jezdí a vyhýbá se nábytku, psům a ponožkám na podlaze. Nebo něco z hype oblasti IoT. Úplně originální nápad je však meteostanice, nebo její nějaká derivace. Pokud vás nenapadne postavit teploměr, tlakoměr, nebo celou meteostanici, pak prostě nejste originální.
V mém případě se mi stalo, že jsem chtěl vytvořit něco ve stylu retro - viz obrázek. A chtěl jsem, aby to měřilo kromě teploty také tlak a vlhkost ovzduší ve vysušeném panelákovém bytě.
Zapojení kouzelné destičky a jejího okolí je celkem prosté:
Stačí připojit čidlo DHT22, které měří teplotu a vlhkost a čidlo BMP180, které měří tlak a pro změnu teplotu.
Že aby budíky ukazovaly správně, musíte:
- obstarat nějaké originální staré měřáky, nebo, jako v mém případě retro budíky čínské provenience,
- vyrobit na budíky stupnice, na to jsou různé sofistikované programy, nebo taky LibreDraw,
- budíky vybavit možností kalibrace, ta je několikerá: ke každému měřáku je předřazen potenciometr, tlačítko (spojka) CAL po propojení pošle na každý měřák postupně všechny kalibrované hodnoty,
- v programu samotném je iterační utilita, která podle tabulky překládá hodnoty na rozsah stupnice (a v mezilehlých hodnotách lineárně iteruje).
Celý ten orloj b. - d. způsobí, že i když ukazatele nejsou lineární, stupnice nejsou dokonalé a tak vůbec, ručičky na budících ukazují po naladění hodnoty celkem úspěšně přesně (matematicky vyjádřeno, hodnoty jsou tak nějak fajn).
Když budete mít jiné budíky (asi ano), nebo budou mít trochu jiné vlastnosti (určitě, jestli je to čínské zboží), musíte si trochu vyhrát s nastavením překladových tabulek - to jsou pro každý budík ty trojice definic:
#define TEMPERATURE_ANALOG_PIN 9
int temperatureValue[ANALOG_SCALE] = { 15, 20, 23, 25, 30 };
int temperatureOutput[ANALOG_SCALE] = { 18, 89, 134, 163, 237 };
#define PRESSURE_ANALOG_PIN 11
int pressureValue[ANALOG_SCALE] = { 960, 980, 1000, 1020, 1040};
int pressureOutput[ANALOG_SCALE] = { 18, 72, 132, 189, 246 };
#define HUMIDITY_ANALOG_PIN 6
int humidityValue[ANALOG_SCALE] = { 30, 40, 50, 60, 70 };
int humidityOutput[ANALOG_SCALE] = { 18, 71, 128, 187, 236 };
kde ...PIN říká, ke kterému pinu je budík připojen a dvě pole pro každý měřák jsou vlastně překladové tabulky, které říkají, jak se má hodnota (...Value) překládat na výstup (Output). Výstup je v rozsahu 0-255. Takže třeba pro teploměr se 23 stupňů přeloží na hodnotu 134. Jasné?
Pro případ, že by jste měli meteostanici zapnutou i přes noc, je k Arduinu ještě připojen fotoodpor. Programem je ošetřeno, že když je kolem tma, ručičky neukazují, alébrž odpočívají.
Upozornění: jako u všech návodů, programů a zapojení i zde platí, že vše děláte na své riziko. Případné škody, zklamání a materiální a duševní újmy jsou jen a pouze váš problém.
Program je tady a je jednoduchý, upravujte podle libosti a vlastností budíků, nadmořské výšky a tak vůbec:
/* teplota, tlak, vlhkost na analog a volitelne do pocitace * cidlo DHT22: teplota, vlhkost * cidlo BMP180: teplota, tlak * ivan@kolebaba.cz 9.9.2018 */ // prodleva mezi merenim #define DELAY_TO_NEXT_MEASURE 30000 // prodleva pri kalibraci (jak dlouho je kazda hodnota zobrazovana) #define DELAY_WITH_CALIBRE 8000 // LED #define ONBOARD_LED_PIN 13 // PHOTO #define PHOTO_RESISTOR_PIN A0 #define PHOTO_LIMIT 8 // DHT #include #define DHTPIN 8 #define DHTTYPE DHT22 DHT dht(DHTPIN, DHTTYPE); float temperatureDHT, humidityDHT; // BMP #include #include SFE_BMP180 bmp; double temperatureBMP, pressureBMP; // ANALOG // porty meridel a tabulky pro preklad hodnoty do rozsahu 0-255 #define ANALOG_SCALE 5 // 0..4 #define TEMPERATURE_ANALOG_PIN 9 int temperatureValue[ANALOG_SCALE] = { 15, 20, 23, 25, 30 }; int temperatureOutput[ANALOG_SCALE] = { 18, 89, 134, 163, 237 }; #define PRESSURE_ANALOG_PIN 11 int pressureValue[ANALOG_SCALE] = { 960, 980, 1000, 1020, 1040}; int pressureOutput[ANALOG_SCALE] = { 18, 72, 132, 189, 246 }; #define HUMIDITY_ANALOG_PIN 6 int humidityValue[ANALOG_SCALE] = { 30, 40, 50, 60, 70 }; int humidityOutput[ANALOG_SCALE] = { 18, 71, 128, 187, 236 }; // CAL - tlacitko pro kalibraci, postupne zobrazuje hodnoty min az max #define SWITCH_CAL_PIN 2 // USB - tlacitko posila namerene hodnoty take na USB #define SWITCH_PRINT_PIN 4 /* * Inicializace portu a cidel */ void setup () { // LED pinMode(ONBOARD_LED_PIN, OUTPUT); digitalWrite(ONBOARD_LED_PIN, LOW); // PRINT Serial.begin(9600); Serial.println("REBOOT"); // DHT dht.begin(); // BMP if (bmp.begin()) Serial.println("BMP180 uspesna inicializace"); else { Serial.println("BMP180 inicializace selhala"); while(1); } // ANALOG pinMode(TEMPERATURE_ANALOG_PIN, OUTPUT); pinMode(PRESSURE_ANALOG_PIN, OUTPUT); pinMode(HUMIDITY_ANALOG_PIN, OUTPUT); // CAL - pro kalibraci, postupne zobrazuje hodnoty min az max pinMode(SWITCH_CAL_PIN, INPUT); // USB - posila namerene hodnoty take na USB pinMode(SWITCH_PRINT_PIN, INPUT); } void loop () { double a,P,T; if (analogRead(PHOTO_RESISTOR_PIN) > PHOTO_LIMIT) { if (digitalRead(SWITCH_CAL_PIN) == LOW) { // DHT readDHT(); // BMP readBMP(); // data do pocitace if (digitalRead(SWITCH_PRINT_PIN) == HIGH) { printData(); } // data na analog analogOutput(TEMPERATURE_ANALOG_PIN, temperatureDHT, temperatureValue, temperatureOutput); analogOutput(PRESSURE_ANALOG_PIN, pressureBMP, pressureValue, pressureOutput); analogOutput(HUMIDITY_ANALOG_PIN, humidityDHT, humidityValue, humidityOutput); // prodleva pred dalsim merenim if (digitalRead(SWITCH_PRINT_PIN) == LOW) { delay(DELAY_TO_NEXT_MEASURE); } else { delay(DELAY_WITH_CALIBRE); } } else { showScale(); } } else { analogWrite(TEMPERATURE_ANALOG_PIN, 0); analogWrite(PRESSURE_ANALOG_PIN, 0); analogWrite(HUMIDITY_ANALOG_PIN, 0); delay (10000); } } void showScale() { digitalWrite(ONBOARD_LED_PIN, HIGH); // min analogOutput(TEMPERATURE_ANALOG_PIN, temperatureValue[0]-5, temperatureValue, temperatureOutput); analogOutput(PRESSURE_ANALOG_PIN, pressureValue[0]-5, pressureValue, pressureOutput); analogOutput(HUMIDITY_ANALOG_PIN, humidityValue[0]-5, humidityValue, humidityOutput); delay(DELAY_WITH_CALIBRE); // platne hodnoty int i; for(i=0; i<ANALOG_SCALE; i++) { analogOutput(TEMPERATURE_ANALOG_PIN, temperatureValue[i], temperatureValue, temperatureOutput); analogOutput(PRESSURE_ANALOG_PIN, pressureValue[i], pressureValue, pressureOutput); analogOutput(HUMIDITY_ANALOG_PIN, humidityValue[i], humidityValue, humidityOutput); delay(DELAY_WITH_CALIBRE); } // max analogOutput(TEMPERATURE_ANALOG_PIN, temperatureValue[ANALOG_SCALE-1]+5, temperatureValue, temperatureOutput); analogOutput(PRESSURE_ANALOG_PIN, pressureValue[ANALOG_SCALE-1]+5, pressureValue, pressureOutput); analogOutput(HUMIDITY_ANALOG_PIN, humidityValue[ANALOG_SCALE-1]+5, humidityValue, humidityOutput); delay(DELAY_WITH_CALIBRE); digitalWrite(ONBOARD_LED_PIN, LOW); } void printData() { digitalWrite(ONBOARD_LED_PIN, HIGH); Serial.print("DHT temp:"); Serial.print(temperatureDHT,4); Serial.print(" hum:"); Serial.print(humidityDHT,4); Serial.print(" BMP temp:"); Serial.print(temperatureBMP,4); Serial.print(" press:"); Serial.print(pressureBMP,4); Serial.print(" photo:"); Serial.print(analogRead(PHOTO_RESISTOR_PIN)); Serial.println(); digitalWrite(ONBOARD_LED_PIN, LOW); } void analogOutput(int port, double value, int val[], int out[]) { int displVal; displVal = 0; if (value > val[ANALOG_SCALE-1]) { displVal=255; } else { for (int i=0; i<ANALOG_SCALE; i++) { if (value >= val[i] && value <= val[i+1]) { displVal = out[i] + (value-val[i])*(out[i+1]-out[i])/(val[i+1]-val[i]); } } } analogWrite(port, displVal); } void readDHT () { float humidity = dht.readHumidity(); if (isnan(humidity)) { error_msg("ERROR: DHT: retrieving humidity measurement"); } else { float temperature = dht.readTemperature(); if (isnan(temperature)) { error_msg("ERROR: DHT: retrieving temperature measurement"); } else { humidityDHT = humidity; temperatureDHT = temperature; } } } void readBMP() { char bmp_status; double temperature,pressure; // pred ctenim tlaku se musi nacist teplota bmp_status = bmp.startTemperature(); if (bmp_status != 0) { delay(bmp_status); bmp_status = bmp.getTemperature(temperature); if (bmp_status != 0) { bmp_status = bmp.startPressure(3); if (bmp_status != 0) { delay(bmp_status); bmp_status = bmp.getPressure(pressure,temperature); if (bmp_status != 0) { pressureBMP = pressure; temperatureBMP = temperature; } else error_msg("ERROR: BMP: retrieving pressure measurement"); } else error_msg("ERROR: BMP: starting pressure measurement"); } else error_msg("ERROR: BMP: retrieving temperature measurement"); } else error_msg("ERROR: BMP: temperature measurement"); } void error_msg(char* msg) { if (digitalRead(SWITCH_PRINT_PIN) == HIGH) { Serial.println(msg); } digitalWrite(ONBOARD_LED_PIN, HIGH); }
A pak si můžete vyhrát s krabičkou.
A to je všechno.