arduinoo.cz
Projekt číslo 9.
Don't touch box
Sestrojil jsem krabici známou jako "Don´t touch" Výše jsou vidět elektronické moduly, které jsem použil.
Cena modulů: IR modul (4kč), zvuk.modul ISD1820 (50kč), arduino nano (50kč), kolébkový vypínač (3kč),
páčkový vypínač (11kč), akumulátor z ČR (115kč), servo sg90 (15kč), servo MG996 (86kč)
A vodiče. Já jsem použil vodiče s piny na snadné propojování. Vše krom akumulátoru je z Číny.
Vzadu krabice jsou dvě "svorky" k nabíjení akumulátoru a power vypínač. IR senzor je umístěný pod
páčkovým vypínačem. Níže je schéma zapojení. Určitě bude třeba přepsat hodnoty pro servo motorky, protože
hodnoty budou jiné, vzhledem k jinak položeným servům a tak. Ale to s pomocí najdi a přepiš vše
se usnadňuje. Do zvukového modulu si nahrajete vlastní zvuk přes mikrofon na modulu.
Krabice je z 5mm sololitu a má rozměry 210x115mm výška 85mm. je to na uvážení a možnostech každého z nás.
#include <Servo.h> Servo packaServo; Servo vikoServo; int prepinac = 0, akce = 1, infra = 0 , plus = 0; void setup() { packaServo.attach(7); vikoServo.attach(8); packaServo.write(180); //start pozice vikoServo.write(26); //start pozice pinMode(5, INPUT); //vstup infra pinMode(4, OUTPUT); //výstup sound modul } void loop() { prepinac = digitalRead(9); // první akce---------------------------------------------------------------------------- if (prepinac == LOW) { if (akce == 1) { for (int i = 26; i <= 62; i++) { vikoServo.write(i); delay(2); } delay(300); for (int i = 180; i >= 24; i--) { packaServo.write(i); delay(1); } delay(500); packaServo.write(18); delay(200); for (int i = 26; i <= 180; i++) { packaServo.write(i); delay(2); } digitalWrite(4, HIGH); delay(50); digitalWrite(4, LOW); for (int i = 62; i >= 26; i--) { vikoServo.write(i); delay(2); } akce++; } // druhá akce---------------------------------------------------------------------------- else if (akce == 2) { for (int i = 26; i <= 62; i++) { vikoServo.write(i); delay(4); } delay(550); packaServo.write(18); delay(550); packaServo.write(180); delay(550); vikoServo.write(26); delay(800); for (int i = 26; i <= 62; i++) { vikoServo.write(i); delay(6); } delay(2000); vikoServo.write(26); digitalWrite(4, HIGH); delay(50); digitalWrite(4, LOW); akce++; } // třetí akce---------------------------------------------------------------------------- else if (akce == 3) { for (int i = 26; i <= 62; i++) { vikoServo.write(i); delay(6); } delay(1000); vikoServo.write(26); delay(1000); for (int i = 26; i <= 62; i++) { vikoServo.write(i); delay(6); } packaServo.write(18); delay(550); packaServo.write(180); delay(500); vikoServo.write(26); digitalWrite(4, HIGH); delay(50); digitalWrite(4, LOW); akce++; } // čtvrtá akce---------------------------------------------------------------------------- else if (akce == 4) { for (int i = 26; i <= 62; i++) { vikoServo.write(i); delay(20); } for (int i = 180; i >= 35; i--) { packaServo.write(i); delay(10); } delay(2000); packaServo.write(18); delay(200); packaServo.write(180); delay(400); vikoServo.write(26); digitalWrite(4, HIGH); delay(50); digitalWrite(4, LOW); akce++; } // pátá akce---------------------------------------------------------------------------- else if (akce == 5) { for (int i = 26; i <= 62; i++) { vikoServo.write(i); delay(6); } delay(2000); packaServo.write(52); delay(550); packaServo.write(32); delay(200); packaServo.write(52); delay(200); packaServo.write(32); delay(200); packaServo.write(52); delay(200); packaServo.write(32); delay(200); packaServo.write(52); delay(200); packaServo.write(32); delay(200); packaServo.write(52); delay(200); packaServo.write(32); delay(1400); packaServo.write(18); delay(400); packaServo.write(180); delay(400); vikoServo.write(26); digitalWrite(4, HIGH); delay(50); digitalWrite(4, LOW); akce++; } // šestá akce---------------------------------------------------------------------------- else if (akce == 6) { for (int i = 26; i < 62; i++) { vikoServo.write(i); delay(20); } delay(1000); for (int i = 0; i < 6; i++) { for (int j = 26; j <= 62; j++) { vikoServo.write(j); delay(6); } delay(200); } for (int i = 180; i >= 35; i--) { packaServo.write(i); delay(20); } packaServo.write(18); delay(400); packaServo.write(180); delay(400); vikoServo.write(26); delay(1500); for (int i = 26; i <= 40; i++) { vikoServo.write(i); delay(6); } delay(3000); vikoServo.write(26); digitalWrite(4, HIGH); delay(50); digitalWrite(4, LOW); akce++; } // sedmá akce---------------------------------------------------------------------------- else if (akce == 7) { for (int i = 26; i <= 62; i++) { vikoServo.write(i); delay(6); } delay(400); packaServo.write(18); delay(1000); for (int i = 0; i < 5; i++) { for (int j = 26; j <= 62; j++) { vikoServo.write(j); delay(6); } delay(200); } delay(500); packaServo.write(180); delay(400); vikoServo.write(26); digitalWrite(4, HIGH); delay(50); digitalWrite(4, LOW); akce++; } // osmá akce---------------------------------------------------------------------------- else if (akce == 8 & plus == 0) { for (int i = 26; i <= 62; i++) { vikoServo.write(i); delay(6); } packaServo.write(18); delay(2000); for (int i = 0; i < 7; i++) { packaServo.write(75); delay(100); packaServo.write(40); delay(100); } delay(500); packaServo.write(180); delay(1000); vikoServo.write(26); digitalWrite(4, HIGH); delay(50); digitalWrite(4, LOW); plus = 1; } // devátá akce---------------------------------------------------------------------------- else if (akce == 9) { for (int i = 26; i <= 62; i++) { vikoServo.write(i); delay(6); } delay(1500); vikoServo.write(62); for (int i = 180; i >= 35; i--) { packaServo.write(i); delay(40); } delay(500); packaServo.write(18); delay(200); for (int i = 18; i <= 180; i++) { packaServo.write(i); delay(40); } vikoServo.write(26); delay(2000); vikoServo.write(62); delay(3000); vikoServo.write(26); digitalWrite(4,HIGH); delay(50); digitalWrite(4,LOW); akce++; } // desátá akce---------------------------------------------------------------------------- else if (akce == 10) { for (int i = 26; i <= 62; i++) { vikoServo.write(i); delay(50); } delay(1000); for (int i = 0; i < 10; i++) { for (int j = 26; j <= 62; j++) { vikoServo.write(j); delay(6); } delay(100); } vikoServo.write(62); delay(100); packaServo.write(18); delay(650); packaServo.write(180); delay(400); vikoServo.write(26); digitalWrite(4,HIGH); delay(50); digitalWrite(4,LOW); akce++; } // jedenáctá akce---------------------------------------------------------------------------- else if (akce == 11) { for (int i = 26; i <= 62; i++) { vikoServo.write(i); delay(4); } packaServo.write(18); delay(2000); for (int i = 0; i < 3; i++) { packaServo.write(65); delay(200); packaServo.write(40); delay(200); } delay(1500); packaServo.write(180); delay(400); vikoServo.write(26); delay(1500); for (int i = 26; i <= 62; i++) { vikoServo.write(i); delay(6); } packaServo.write(18); delay(3000); packaServo.write(180); delay(400); vikoServo.write(26); digitalWrite(4,HIGH); delay(50); digitalWrite(4,LOW); akce++; } // dvanáctá akce---------------------------------------------------------------------------- else if (akce == 12) { for (int i = 26; i <= 62; i++) { vikoServo.write(i); delay(50); } delay(1000); for (int i = 180; i >= 26; i--) { packaServo.write(i); delay(50); } delay(1000); packaServo.write(18); delay(200); packaServo.write(180); delay(400); vikoServo.write(26); digitalWrite(4,HIGH); delay(50); digitalWrite(4,LOW); akce++; } // třináctá akce---------------------------------------------------------------------------- else if (akce == 13) { for (int i = 26; i <= 62; i++) { vikoServo.write(i); delay(6); } delay(2000); for (int i = 180; i >= 62; i--) { packaServo.write(i); delay(20); } for (int i = 0; i < 3; i++) { packaServo.write(62); delay(200); packaServo.write(40); delay(800); } packaServo.write(18); delay(2000); packaServo.write(180); delay(500); vikoServo.write(26); digitalWrite(4,HIGH); delay(50); digitalWrite(4,LOW); akce++; } // čtrnáctá akce---------------------------------------------------------------------------- else if (akce == 14) { for (int i = 26; i <= 62; i++) { vikoServo.write(i); delay(6); } delay(4000); vikoServo.write(62); packaServo.write(18); delay(650); packaServo.write(180); delay(500); vikoServo.write(62); delay(4000); vikoServo.write(26); digitalWrite(4,HIGH); delay(50); digitalWrite(4,LOW); akce++; } // patnáctá akce---------------------------------------------------------------------------- else if (akce == 15) { for (int i = 26; i <= 62 ; i++) { vikoServo.write(i); delay(6); } delay(1000); for (int i = 0; i < 3; i++) { for (int j = 26; j <= 50; j++) { vikoServo.write(j); delay(50); } for (int j = 50; j >= 26; j--) { vikoServo.write(j); delay(50); } } for (int j = 26; j <= 62; j++) { vikoServo.write(j); delay(50); } for (int i = 180; i >= 35; i--) { packaServo.write(i); delay(40); } delay(1000); packaServo.write(18); delay(400); packaServo.write(180); delay(400); vikoServo.write(26); digitalWrite(4,HIGH); delay(50); digitalWrite(4,LOW); akce = 1; } } // akce je spuštěna IR senzorem--------------------------------------------------------------- if (akce == 8 & plus == 1) { if (digitalRead(5) == 0) { vikoServo.write(54); delay(362); vikoServo.write(26); infra++; } } // konec akce spouštění IR senzorem------------------------------------------------------------ if (infra == 8) { digitalWrite(4, HIGH); delay(50); digitalWrite(4, LOW); infra = 0; akce++; plus = 0; } }
Projekt číslo 10.
Čítač impulzů na elektroměru.
Cena elektřiny neustále stoupá a já jsem potřeboval vědět kde se dá ušetřit a kde jsou zbytečně zapojené spotřebiče.
Digitální elektroměr ukazuje sice digitálně, ale jen celé kWh. Bliká tam však červená LED, která blikne-li 500 krát
naskočí jedna kWh. Toho musím využít řekl sem si. Použil jsem fotorezistor jako čidlo blikání, kde bliknutí způsobí
malý odpor fotorezistoru. Pak stačilo zapojit arduino, jeden rezistor 22k a pár drátků. Vyrobil jsem si ze sololitu
(lze použít karton z krabice) takovou masku, kterou jen nasadím na elektroměr a to z toho důvodů, aby když otevřu dvířka
k elektroměru nebyl fotorezistor rušený okolním světlem. Jako zdroj napětí jsem použil powerbanku. Je potřeba údaje
nějak zobrazit. Já použil LCD displej s I2C sběrnicí. Můžete samozřejmě použít např. i OLED displej, ale je třeba předělat
program. Na LCD displeji se mi zobrazuje aktuální spotřeba ve wattech tj. časová prodleva mezi jednotlivými impulzi,
dále celková spotřeba v kWh ta se počítá z celkového počtu impulzů, dále čas od spuštění měření v hodinách (desítkově)
a nakonec samotný počet impulzů. Použil jsem Arduino UNO, protože zařízení nebude sloužit trvale a v případě znovu použití
stačí propojit pár drátků. Takto lze sledovat i pomocí vypnutí některých jističů spotřebu a hledat zbytečné úniky proudu.
Při oživování je třeba správně nastavit úrověň vstupu A1, protože každý fotorezistor je jiný.
V mém případě mi hodnota při bliknutí ukazovala 600-620 proto jsem v podmínce zvolil hodnotu >300.
To lze vysledovat přidáním Serial.begin(9600) a sledovat mezní hodnoty fotorezistoru na sériovém monitoru.
#include <Wire.h> #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x27, 20, 4); int senzor = 0; int impuls = 0; int long cas = 0; int long mezicas; int watt; void setup() { pinMode(A1, INPUT); lcd.begin(); lcd.backlight(); lcd.setCursor(0, 0); lcd.print("500imp/1kWh"); delay(2000); lcd.clear(); } void loop() { senzor = analogRead(A1); lcd.setCursor(9, 1); lcd.print(float(float(millis()) / 3600000)); lcd.print("h"); if (senzor > 300) { mezicas = millis() - cas; watt = (7200000 / mezicas); impuls++; lcd.setCursor ( 0, 0 ); lcd.print(watt); lcd.print("W "); lcd.setCursor ( 9, 0 ); lcd.print(impuls); lcd.print("i."); cas = millis(); lcd.setCursor ( 0, 1 ); lcd.print(float(float(impuls) / 500)); lcd.print("kWh"); delay(1200); } }
Projekt číslo 11.
Čítač impulzů na elektroměru Wifi.
Tady jsem použil modul ESP8266 D1 mini. Tento je napájen starou USB nabíječkou. Zapojení fotorezistoru je shodné jako
u projektu 10. Co se týče odesílání dat na vzdálený server tak to máte popsáno v projektu 8.
Stav můžete tak sledovat on-line na mobilu a i v grafu.
V tomto případě se odesílají data o aktuální spotřebě ve watech a celková spotřeba od zapnutí zařízení v kWh.
#include <ESP8266WiFi.h> int long impuls = 0; int long cas = 0; int long mezicas; float kwh; int watt; int senzor = 0; String apiKlic = "xxxxxxxxxxxx"; //write API key const char* nazevWifi = "yyyyyyyyyyyyyy"; // název vaší wifi sítě const char* hesloWifi = "zzzzzzzzzzzzzz"; //heslo k vaší wifi siti const char* server = "api.thingspeak.com"; WiFiClient client; void setup() { WiFi.begin(nazevWifi, hesloWifi); while (WiFi.status() != WL_CONNECTED) { delay(500); pinMode(A0, INPUT); pinMode(LED_BUILTIN, OUTPUT); } } void loop() { senzor = analogRead(A0); if ( (senzor) > 300) { mezicas = millis() - cas; watt = (7200000 / mezicas); impuls++; kwh = float(float(float(impuls) / 500)); //Serial.println(analogRead(A0)); cas = millis(); digitalWrite(LED_BUILTIN, LOW); delay(5); digitalWrite(LED_BUILTIN, HIGH); odeslat(); delay(800); } } void odeslat() { if (client.connect(server, 80)) { String zprava = apiKlic; zprava += "&field1="; zprava += String(watt); zprava += "&field2="; zprava += String(kwh); zprava += "\r\n\r\n"; client.print("POST /update HTTP/1.1\n"); client.print("Host: api.thingspeak.com\n"); client.print("Connection: close\n"); client.print("X-THINGSPEAKAPIKEY: " + apiKlic + "\n"); client.print("Content-Type: application/x-www-form-urlencoded\n"); client.print("Content-Length: "); client.print(zprava.length()); client.print("\n\n"); client.print(zprava); } client.stop(); }
Projekt číslo 12.
Generátor impulzů s AD9833.
Našel jsem v šuplíku modul AD9833 tak sem si řekl, že postavím tento generátor impulzů.
Nejdřív jsem použil víceotáčkový potenciometr, ale nebylo to ono. Rozhodl jsem se, že použiji klávesnici,
která se snadno mačká a zároveň její pomocí zadávám jak frekvenci tak i tvar vlny. Použil jsem i buzzer
pro kotrolu stisku klávesy a potvrzování. Tento obvod by mě zvládat frekvenci do 12,5 MHz samozřejmě ale sinusovku.
Každopádně se nejeví tento modul až tak špatně, má omezení jako počet průběhů sinus, odbélník a trojúhelnik.
Nedá ne měnit střída ani napětí Vpp. U obdélníku je Vpp 5 voltů a u SIN a TRI je Vpp 0,65 Voltů.
Zařízení jsem navrhnul tak, že po zapnutí přístroje se nastaví 1kHz Sinus. Na LCD displeji se zobrazuje
tvar vlny tedy SINUS a frekvence. Po stisku "nuly" se ukazatel vynuluje a pomocí klávesnice
zadám novou frekvenci např. 21350 Hz a potvrdím křížkem. Tím je nová frekvence nastavena.
Tvar vlny měním stiskem hvězdičky a potvrdím opět křížkem. To je vše.
Scméma zapojení je jednoduché. Nejlepší je použít pájecí uni desku. Krabičku lze např. vytisknout na 3D tiskárně
Napájení doporučuji powerbankou přes USB arduina nano nebo galvanicky odděleným lineárním zdrojem 6 - 8 voltů
Nakonec si provedeme pár měření stolním osciloskopem a podíváme se na jednotlivé křivky.
V programu jsem zavedl limit frekvence pro sinus max. 10 Mhz a pro obdelnik a trojúhelník 5 Mhz.
Při zadání vyšší hodnoty na klávesnici se zobrazí varování o překročení limitu
a frekvence se nastaví na 1 khz. Program si můžete upravit podle svých potřeb.
Na níže uedených obrázcích je pár příkladů různých frekvencí. Pro příklad jsem použil
frekvence 1kHz 10kHz 500kHz 1MHz 2,5Mhz 5 a 10MHz.
V pohodě zvládá i nízké frekvence jako 1 Hz. Podle měření bych řekl, že Sinus je použitelný
do frekvence do 3MHz pak už je modulace křivky víc a víc disharmonická viz. 10Mhz.
U trojúhelníku do 1 Mhz a u obdélníku tak překvapivě do 2,5MHz je pěkný průběh.
Co se týká frekvence tak je celkem stabilní. Sinus při 10MHz je už velmi deformovaný
#include <Keypad.h> #include <Wire.h> #include <LiquidCrystal_I2C.h> #include <AD9833.h> #define pinFsync 9 AD9833 gen(pinFsync); LiquidCrystal_I2C lcd(0x27, 16, 2); const byte radky = 4; const byte sloupce = 3; String frekvence = ""; int vlna = 0; int long frekvenceNum = 1000; int lcdPozice; int prep = 0; int nulace = 0; char keys[radky][sloupce] = { {'1', '2', '3'}, {'4', '5', '6'}, {'7', '8', '9'}, {'*', '0', '#'} }; byte pinyRadku[radky] = {7, 2, 3, 5}; byte pinySloupcu[sloupce] = {6, 8, 4 }; Keypad klavesnice = Keypad( makeKeymap(keys), pinyRadku, pinySloupcu, radky, sloupce); void setup() { lcd.begin(); lcd.clear(); gen.Begin(); gen.EnableOutput(true); pinMode(10, OUTPUT); // pipak digitalWrite(10, HIGH); lcd.setCursor(9, 1); lcd.print(frekvenceNum); lcd.print(" Hz"); gen.ApplySignal(SINE_WAVE, REG0, 1000); define(); } void loop() { char klavesa = klavesnice.getKey(); if (klavesa) { pip(); if (klavesa == 35) { AD_9833(); prep = 0; } if (klavesa == 42 ) { define(); } if (klavesa > 47 && klavesa < 58) { frekvence = frekvence + klavesa; frekvenceNum = frekvence.toInt(); lcdPozice = (frekvence.length()); lcd.setCursor(13 - lcdPozice, 1); lcd.print((frekvence + " Hz")); } if (frekvence.length() == 1 && klavesa == 48) { lcd.setCursor (0, 1); lcd.print(" "); frekvence = ""; } } } void define() { vlna++; delay(50); switch (vlna) { case 1: lcd.setCursor(8, 0); lcd.print(" SINUS"); break; delay(50); case 2: lcd.setCursor(8, 0); lcd.print("TRIANGLE"); break; delay(50); case 3: lcd.setCursor(8, 0); lcd.print(" SQUARE"); vlna = 0; delay(50); break; } } void AD_9833() { if (frekvenceNum > 5000000L && vlna == 0) { prep = 1; lcd.setCursor(0, 1); lcd.print("OUT LIMIT "); pip3(); delay(1000); lcd.setCursor(0, 1); lcd.print("max. 5 Mhz"); delay(1400); lcd.setCursor(0, 1); lcd.print(" 1000"); frekvenceNum = 1000; frekvence = ""; } if (frekvenceNum > 10000000L && vlna == 1) { prep = 1; lcd.setCursor(0, 1); lcd.print("OUT LIMIT "); pip3(); delay(1000); lcd.setCursor(0, 1); lcd.print("max. 10 Mhz"); delay(1400); lcd.setCursor(0, 1); lcd.print(" 1000"); frekvenceNum = 1000; frekvence = ""; } if (frekvenceNum > 5000000L && vlna == 2) { prep = 1; lcd.setCursor(0, 1); lcd.print("OUT LIMIT "); pip3(); delay(1000); lcd.setCursor(0, 1); lcd.print("max. 5 Mhz"); delay(1400); lcd.setCursor(0, 1); lcd.print(" 1000"); frekvenceNum = 1000; frekvence = ""; } if (prep == 1) return; pip2(); if (vlna == 1) { gen.ApplySignal(SINE_WAVE, REG0, frekvenceNum); } if (vlna == 2) { gen.ApplySignal(TRIANGLE_WAVE, REG0, frekvenceNum); } if (vlna == 0) { gen.ApplySignal(SQUARE_WAVE, REG0, frekvenceNum); } frekvence = ""; } void pip() { digitalWrite(10, LOW); delayMicroseconds(500); digitalWrite(10, HIGH); } void pip2() { digitalWrite(10, LOW); delay(20); digitalWrite(10, HIGH); delay(100); digitalWrite(10, LOW); delay(20); digitalWrite(10, HIGH); } void pip3() { digitalWrite(10, LOW); delay(300); digitalWrite(10, HIGH); }
Projekt číslo 13.
Úlová váha s Wifi připojením.
Zadání tohoto projektu bylo následující: Vytvořit váhu pro úl, který je je umístěn na zahradě. Data o váze pomocí
Wifi připojení přenášet na vzdálený server thinkspeak a data sledovat na mobilu či počítači. Zajistit nezávislé napajení
zařízení pomocí solárního panelu.
Rám je lepený a sešroubovaný ze střešních latí. V rozích zpevněný plechem z nerezové oceli.
Ta slouží i jako pevná opora pro tenzometry, které jsou v držácím vyrobených na 3D tiskárně.
Ve spodním rámu jsou čtyři 8mm ocelové kulatiny a v horním rámu čtyři hliníkové trubky s vnitřním
průměrem 10mm pro stabilizaci obou rámů u sebe. Ocelové kulatiny jsou natřeny vazenínou nebo lubrikačním voskem.
Toto zabrání případnému sesunutí horního rámu.
Jako Wifi modul jsem použil WEMOS D1 pro - který má integrovanou keramickou anténu
na desce, ale i externí anténu prutovou. Při použití externí antény je nutno přepájet na desce nulový SMD odpor
u ker. antény. Bohužel jsem omylem cvrnknul na jeden ze vstupů +12 volty a celý modul šel do kytek.
Vytáhl sem tedy WEMOS D1 mini a naletoval tu prutovou anténu na desku. Je třeba ale přerušit anténu na desce.
Zařízení má OLED displej pro kontrolu připojení, zobrazuje OFFset a samotnou hmotnost. Lze použít i LCD displej 16x2
s I2C komunikací. Obě verze programů uvádím níže. Zapojení vodičů je stejné jako u OLED.
Nyní k zapojení zařízení. Hodně věcí sem měl doma po ruce, takže je možné použít i jiné komponenty.
Napájení: solární panel 12V/10W dává až 18V proto sem použit MPPT modul, ale lze použít i klasický StepDown modul 3A.
MPPT nabíjí jen v případě dostatečného výkonu solárního panelu a dá se nastavit max. nabíjecí proud což je velká
výhoda, kdy se akumulátor zejména při menších kapacit nepřebíjí. Toto u StepDown modulu nejde, ale zase se průběžně
dobíjí a pokud použijete přiměřený solární panel s akumulátorem tak proč ne.
Dále nám jde napětí z akumulátoru do StepDown modulu kde je třeba trimrem nastavit výstupní napětí 5 Voltů.
Tímto napětím napájím Wemos D1, převodník HX711 a TTL převodník. Lze použít i TTL převodník TXS0108E udělá stejnou službu.
Tento převádí 5V logiku z HX711 na 3,3V jelikož Wemos pracuje s logikou 3,3 voltů. Co se týče napájení OLED a EEPROM tyto nápájím
+5V ale přes dvě diody 1N4148 které mají úbytek napětí každá cca 640mV. Napětí se tím sníží na 3,8V a měřeno osciloskopem
je napětí úrovní bylo 3,4V což je OK. Bylo by možné oba napájet přímo 3,3V z Wemos, ale přece jen jsem nechtěl zatěžovat
jeho lineární stabilizátor. Také by bylo možné použití zenerovy diody a nebo využít volné piny TTL převodníku. To už nechám
na uvážení konstruktéra.
A proč EEPROM ??? Ono při zapnutí zažízení nebo při resetu Wemos desky či nechtěnému přerušení napájení, prostě pokud
k něčemu podobnému dojde, Wemos se restartuje a program naběhne znovu a provede se tzv. TARE váhy teda vynulování,
bez ohledu na to, jaké závaží se na váze nachází.
Příklad: váha je v provozu delší dobu, ukazuje např. 65kg. Dojde k restartu a nyní ukazuje 0kg, protože se provedla
operace TARE a pokud se zvýší hmotnost o 1kg, váha zobrazí 1kg nikoliv 66kg. Proto sem se rozhodl, že budu pro tyto
případy data zálohovat do EEPROM po určitých intervalech (např. po 15 minutách) Takže program průběžně ukládá hmotnost a pokud
dojde k restartu, tak se k nulové hodnotě připočtou data načtená z EEPROM (OFFset). Použil sem externí EEPROM také pro
případnou snadnou výměnu z patice do patice. Tlačítko RESET přivedené na vstup D4 slouží k resetu váhy a provede
TARE čili vynulování stastovní váhy a zapsání hodnoty nula do EEPROM. Je třeba je podržet dokud se na displeji nezobrazí
RESET. Jak zřídit účet na Thingspeak najdete na internetu, není to žádná věda. Co budete potřebovat do programu je
název vaší Wifi sitě, heslo k ní a write APIkey z vašeho thingspeak účtu.
Níže je verze programu s OLED a verze s LCD 16x2 I2C.
Ještě na upozornění kolegy uvádím, že je třeba před nahráním hlavního programu provést kalibraci
To se provádí tak, že se na váhu umístí závaží, které si předem zvážíme na kuchyňské váze.
Já použil závaží cca 3,5 kg. a pak se postupuje podle programu. Kalibrační číslo je poté třeba doplnit
do hlavního programu. Kalibrační program uvádím dole.
Dole je schéma zapojení a moduly, které budete potřebovat. Jen si vybrat OLED nebo LCD.
#include "HX711.h" //OLED verze #include <ESP8266WiFi.h> #include <Wire.h> #include "SSD1306Wire.h" SSD1306Wire display(0x3c, D2, D1); //D2=SDK D1=SCK int cas = 0; float offset; int cislo; String apiKey = "XXXXXXXXXX"; const char *ssid = "název wifi"; const char *pass = "heslo k wifi"; const char* server = "api.thingspeak.com"; WiFiClient client; HX711 scale(D5, D6); int rbutton = D4; float weight; float calibration_factor = -21305; // doplnit po kalibraci void setup(void) { pinMode(rbutton, INPUT_PULLUP); scale.set_scale(); scale.tare(); //Reset the scale to 0 long zero_factor = scale.read_average(); Wire.begin(D2, D1); display.init(); display.flipScreenVertically(); display.clear(); display.setTextAlignment(TEXT_ALIGN_LEFT); display.setFont(ArialMT_Plain_24); display.drawString(0, 26, "Bee * Scale"); display.display(); delay(2000); display.clear(); display.setTextAlignment(TEXT_ALIGN_LEFT); display.setFont(ArialMT_Plain_24); display.drawString(0, 26, "WiFi.........."); display.display(); delay(1000); WiFi.begin(ssid, pass); { delay(1000); } display.clear(); display.setTextAlignment(TEXT_ALIGN_LEFT); display.setFont(ArialMT_Plain_24); display.drawString(0, 26, "Pripojeno"); display.display(); delay(1000); int a1 = read_EEPROM(0x50, 0); int a2 = read_EEPROM(0x50, 1); float offset = (float(a1 * 256) + a2) / 100; display.clear(); display.setTextAlignment(TEXT_ALIGN_LEFT); display.setFont(ArialMT_Plain_24); display.drawString(0, 26, "OFFSET:"); display.display(); delay(800); display.clear(); display.setTextAlignment(TEXT_ALIGN_LEFT); display.setFont(ArialMT_Plain_24); display.drawString(0, 26, "+" + String (offset)); display.display(); delay(1000); display.clear(); display.setTextAlignment(TEXT_ALIGN_LEFT); display.setFont(ArialMT_Plain_24); display.drawString(0, 26, "----------------"); display.display(); delay(1800); } void loop() { scale.set_scale(calibration_factor); weight = scale.get_units(5); int a1 = read_EEPROM(0x50, 0); int a2 = read_EEPROM(0x50, 1); float offset = (float(a1 * 256) + a2) / 100; display.clear(); display.setTextAlignment(TEXT_ALIGN_LEFT); display.setFont(ArialMT_Plain_24); display.drawString(0, 26, String(offset + weight) + " kg"); display.display(); delay(3000); cas++; if (cas == 395) { int cislo = ((offset + weight) * 100); int num_1 = (cislo / 256); int num_2 = (cislo % 256); write_EEPROM(0x50, 0, num_1); delay(5); write_EEPROM(0x50, 1, num_2); delay(5); scale.set_scale(); scale.tare(); display.clear(); display.setTextAlignment(TEXT_ALIGN_LEFT); display.setFont(ArialMT_Plain_24); display.drawString(0, 26, "EEPROM ->"); display.display(); delay(1500); cas = 0; } if ( digitalRead(rbutton) == LOW) { scale.set_scale(); scale.tare(); write_EEPROM(0x50, 0, 0); delay(5); write_EEPROM(0x50, 1, 0); display.clear(); display.setTextAlignment(TEXT_ALIGN_LEFT); display.setFont(ArialMT_Plain_24); display.drawString(0, 26, "RESET !!"); display.display(); delay(1000); } if (client.connect(server, 80)) { String postStr = apiKey; postStr += "&field1="; postStr += String((weight + offset)); postStr += "\r\n\r\n"; client.print("POST /update HTTP/1.1\n"); client.print("Host: api.thingspeak.com\n"); client.print("Connection: close\n"); client.print("X-THINGSPEAKAPIKEY: " + apiKey + "\n"); client.print("Content-Type: application/x-www-form-urlencoded\n"); client.print("Content-Length: "); client.print(postStr.length()); client.print("\n\n"); client.print(postStr); } client.stop(); delay(1500); } void write_EEPROM( int deviceaddress, unsigned int eeaddress, byte data ) { int rdata = data; Wire.beginTransmission(deviceaddress); Wire.write((int)(eeaddress)); Wire.write((int)(eeaddress & 0xFF)); Wire.write(rdata); Wire.endTransmission(); } byte read_EEPROM( int deviceaddress, unsigned int eeaddress ) { byte rdata = 0xFF; Wire.beginTransmission(deviceaddress); Wire.write((int)(eeaddress)); Wire.write((int)(eeaddress & 0xFF)); Wire.endTransmission(); Wire.requestFrom(deviceaddress, 1); if (Wire.available()) rdata = Wire.read(); return rdata; }
#include "HX711.h" //LCD 16x2 verze #include <ESP8266WiFi.h> #include <Wire.h> #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x27, 16, 2); int cas = 0; float offset; int cislo; String apiKey = "XXXXXXXXXX"; const char *ssid = "název wifi"; const char *pass = "heslo k wifi"; const char* server = "api.thingspeak.com"; WiFiClient client; HX711 scale(D5, D6); int rbutton = D4; float weight; float calibration_factor = -21305; // doplnit po kalibraci void setup(void) { pinMode(rbutton, INPUT_PULLUP); scale.set_scale(); scale.tare(); //Reset the scale to 0 long zero_factor = scale.read_average(); Wire.begin(D2, D1); lcd.begin(); lcd.setCursor(2, 0); lcd.print("Bee scale"); lcd.setCursor(0, 1); lcd.print("Vaha max. 200 kg"); delay(2000); lcd.clear(); lcd.print("pripojuji Wifi"); lcd.setCursor(0, 1); lcd.print("& Thingspeak"); WiFi.begin(ssid, pass); { delay(1000); lcd.clear(); } lcd.clear(); lcd.print("WiFi pripojeno"); delay(1000); lcd.clear(); int a1 = read_EEPROM(0x50, 0); int a2 = read_EEPROM(0x50, 1); float offset = (float(a1 * 256) + a2) / 100; lcd.print("offset="); lcd.print(offset); delay(2000); } void loop() { scale.set_scale(calibration_factor); weight = scale.get_units(5); int a1 = read_EEPROM(0x50, 0); int a2 = read_EEPROM(0x50, 1); float offset = (float(a1 * 256) + a2) / 100; lcd.setCursor(0, 0); lcd.print("Aktualni Vaha "); lcd.setCursor(0, 1); lcd.print (weight + offset); lcd.print(" kg "); delay(4900); lcd.clear(); cas++; if (cas == 180) { int cislo = ((offset + weight) * 100); int num_1 = (cislo / 256); int num_2 = (cislo % 256); write_EEPROM(0x50, 0, num_1); delay(5); write_EEPROM(0x50, 1, num_2); delay(5); scale.set_scale(); scale.tare(); lcd.print("zaloha EEPROM"); delay(1500); cas = 0; } if ( digitalRead(rbutton) == LOW) { scale.set_scale(); scale.tare(); write_EEPROM(0x50, 0, 0); delay(5); write_EEPROM(0x50, 1, 0); lcd.clear(); lcd.print("RESET:"); lcd.setCursor(0, 1); lcd.print("vaha + offset"); delay(800); } if (client.connect(server, 80)) { String postStr = apiKey; postStr += "&field1="; postStr += String((weight + offset)); postStr += "\r\n\r\n"; client.print("POST /update HTTP/1.1\n"); client.print("Host: api.thingspeak.com\n"); client.print("Connection: close\n"); client.print("X-THINGSPEAKAPIKEY: " + apiKey + "\n"); client.print("Content-Type: application/x-www-form-urlencoded\n"); client.print("Content-Length: "); client.print(postStr.length()); client.print("\n\n"); client.print(postStr); } client.stop(); delay(1500); } void write_EEPROM( int deviceaddress, unsigned int eeaddress, byte data ) { int rdata = data; Wire.beginTransmission(deviceaddress); Wire.write((int)(eeaddress)); Wire.write((int)(eeaddress & 0xFF)); Wire.write(rdata); Wire.endTransmission(); } byte read_EEPROM( int deviceaddress, unsigned int eeaddress ) { byte rdata = 0xFF; Wire.beginTransmission(deviceaddress); Wire.write((int)(eeaddress)); Wire.write((int)(eeaddress & 0xFF)); Wire.endTransmission(); Wire.requestFrom(deviceaddress, 1); if (Wire.available()) rdata = Wire.read(); return rdata; }
//============= KALIBRACE =============== #include "HX711.h" #define DOUT D5 #define CLK D6 HX711 scale(DOUT, CLK); //Change this calibration factor as per your load cell once it is found you many need to vary it in thousands float calibration_factor = -21305; //-106600 worked for my 40Kg max scale setup //============================================================================================= // SETUP //============================================================================================= void setup() { Serial.begin(9600); Serial.println("HX711 Calibration"); Serial.println("Remove all weight from scale"); Serial.println("After readings begin, place known weight on scale"); Serial.println("Press a,s,d,f to increase calibration factor by 10,100,1000,10000 respectively"); Serial.println("Press z,x,c,v to decrease calibration factor by 10,100,1000,10000 respectively"); Serial.println("Press t for tare"); scale.set_scale(); scale.tare(); //Reset the scale to 0 long zero_factor = scale.read_average(); //Get a baseline reading Serial.print("Zero factor: "); //This can be used to remove the need to tare the scale. Useful in permanent scale projects. Serial.println(zero_factor); } //============================================================================================= // LOOP //============================================================================================= void loop() { scale.set_scale(calibration_factor); //Adjust to this calibration factor Serial.print("Reading: "); Serial.print(scale.get_units(), 3); Serial.print(" kg"); //Change this to kg and re-adjust the calibration factor if you follow SI units like a sane person Serial.print(" calibration_factor: "); Serial.print(calibration_factor); Serial.println(); if(Serial.available()) { char temp = Serial.read(); if(temp == '+' || temp == 'a') calibration_factor += 10; else if(temp == '-' || temp == 'z') calibration_factor -= 10; else if(temp == 's') calibration_factor += 100; else if(temp == 'x') calibration_factor -= 100; else if(temp == 'd') calibration_factor += 1000; else if(temp == 'c') calibration_factor -= 1000; else if(temp == 'f') calibration_factor += 10000; else if(temp == 'v') calibration_factor -= 10000; else if(temp == 't') scale.tare(); //Reset the scale to zero } }
Projekt číslo 14.
Macro focusing rail.
Jednoduchý návod na výrobu motorizovaného posunu fotoaparátu pro makro snímky.
Slouží pro pořízení vícenásobných snímků (řezy objektu) s jejich ostrosti a následném
zpracování ve speciálním programu. Takto dostaneme ostrý snímek.
Posun se provádí po navolení DIP přepínače, který vyjadřuje binární číslo viz foto. Na ovladači
krokového motoru je nastaven čtvrtinový impulz a tím je nastaven nejmenší posun při 200 otáčkách krokového
motoru na 0,01 mm. (trapézová tyč - stoupání 8mm/otáčka)
Jeden čtvrtinový impulz je: 200x4=800 8mm/800=0,01mm
Takže na DIP přepínači lze navolit od 0,01 do 2,55mm.
Při polovičním impulzu je to pak od 0,02 do 5,1mm.
Dvě jazýčková relé ovládají závěrku spouště. Nejdřím zaostření a pak domáčkutí.
Samozřejmě se nepoužívá aut. ostření ale manuální.
Malý step down měnič je nastaven cca 7,5 Voltů (12 Voltů je na vstup arduina nano moc).
Potenciometrem se nastavuje prodleva mezi snímky 1 - 6 sekund (nabití blesku, eliminace otřesů)
Místo DIP přepínače je možné použít potenciometr, ale nebudete mít přesnou kontrolu posunu
pro případnou 3D modulaci v softwaru.
Odpory jsem použil SMD je to nejlepší volba. Ještě pozor na to, že některá jazýčková relé
mohou mít ochranou diody proto pozor na správné zapojení.
Vypínač S1 slouží k zap/vyp posunu.
Použité díly: tapézový závit 8mm 300mm, dvě trapézové matky, vodící tyč 2 kusy 300mm, LM8UU ložisko 4 kusy,
Pružná spojka 5x8mm, krokový motor, držák arca swiss z Číny za 200kč a další drobnosti.
Zapojení je snadné a program jednoduchý.
Závitová tyč je na konci v ložisku, u pružné spojky není. Oba díly včetně vozíku jsou vytištěné
na 3D tiskárně, tím se zajistí přesné uložení vodících tyčí a bezproblémový chod.
#define dirPin 2 #define stepPin 3 int s; void setup() { pinMode(stepPin, OUTPUT); pinMode(dirPin, OUTPUT); pinMode(4, INPUT); pinMode(5, INPUT); pinMode(6, INPUT); pinMode(7, INPUT); pinMode(8, INPUT); pinMode(9, INPUT); pinMode(10, INPUT); pinMode(11, INPUT); pinMode(A2, INPUT); pinMode(A3, INPUT); //data z potenciometru pinMode(12, OUTPUT); //zaostření pinMode(13, OUTPUT); //domáčknutí } void loop() { s = B00000000; if (digitalRead(11) == 1) { s = s + B00000001; } if (digitalRead(10) == 1) { s = s + B00000010; } if (digitalRead(9) == 1) { s = s + B00000100; } if (digitalRead(8) == 1) { s = s + B00001000; } if (digitalRead(7) == 1) { s = s + B00010000; } if (digitalRead(6) == 1) { s = s + B00100000; } if (digitalRead(5) == 1) { s = s + B01000000; } if (digitalRead(4) == 1) { s = s + B10000000; } if (digitalRead(A2) == HIGH && s > 0) { step_motor(); } } void step_motor() { for (int i = 1; i <= s; i++) { digitalWrite(stepPin, HIGH); delayMicroseconds(640); digitalWrite(stepPin, LOW); delayMicroseconds(640); } int time = analogRead(A3); time = map(time, 0, 1023, 1000, 6000); delay(time); delay(1000); digitalWrite(12, HIGH); delay(1000); digitalWrite(13, HIGH); delay(150); digitalWrite(13, LOW); delay(50); digitalWrite(12, LOW); }
Děkuji za návštěvu