Na jó, ez még csak 5 könyvtár, de nem teljes a vezérlés, nincs PID-es mód. Azért alakulgat a fűtésvezérlés.
Sketch uses 10 820 bytes (35%) of program storage space. Maximum is 30 720 bytes. Global variables use 623 bytes (30%) of dynamic memory, leaving 1 425 bytes for local variables. Maximum is 2 048 bytes.
/* YourDuino.com Example: Multiple DS18B20 Temperature Sensors Displayed on 4x20 character LCD display
DS18B20 Pinout (Left to Right, pins down, flat side toward you) - fekete = Ground - sárga = Signal (Pin 10): (with 3.3K to 4.7K resistor to +5 or 3.3 ) - zöld = +5 or +3.3 V
//Get DallasTemperature Library here: http://milesburton.com/Main_Page?title=Dallas_Temperature_Control_Library #include <DallasTemperature.h> // Wire (I2C) Library #include <Wire.h> // LCD Library //#include <LCD.h> #include <LiquidCrystal_I2C.h> // F Malpartida's NewLiquidCrystal library //Download: https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads // Move original LiquidCrystal library elsewhere, copy this in it's place #include <MAX6675.h>
/*-----( Declare Constants and Pin Numbers )-----*/ // Data wire is plugged into port 10 on the Arduino (can be changed) #define ONE_WIRE_BUS 10 // NOTE: No ";" on #define #define HIDEGEBB 6 // relay1 #define MELEGEBB 7 // relay2 #define MOTORFUTASIDO 1000 #define CIKLUSIDOMP 30 /*-----( Declare objects )-----*/ // Setup a oneWire instance to communicate with any OneWire devices // (not just Maxim/Dallas temperature ICs) OneWire oneWire(ONE_WIRE_BUS);
// Pass address of our oneWire instance to Dallas Temperature. DallasTemperature sensors(&oneWire);
// Start the LCD display library LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 20 chars and 4 line display int LED1 = 13; // Status LED Pin int CS = 4; // CS pin on MAX6675 int SO = 3; // SO pin of MAX6675 int SCLK = 5; // SCLK pin of MAX6675 int units = 1; // Units to readout temp (0 = raw, 1 = ˚C, 2 = ˚F) float Celsius = 0.0; // Temperature output variable float hofok10 = 0.0;
// Initialize the MAX6675 Library for our chip MAX6675 temp(CS,SO,SCLK,units);
// Setup Serial output and LED Pin // MAX6675 Library already sets pin modes for MAX6675 chip! /*-----( Declare Variables )-----*/ // Assign the addresses of your 1-Wire temp sensors. // See the tutorial on how to obtain these addresses: // http://arduino-info.wikispaces.com/Brick-Temperature-DS18B20#Read%20individual
//------- Initialize the Temperature measurement library-------------- sensors.begin(); // set the resolution to 10 bit (Can be 9 to 12 bits .. lower is faster) sensors.setResolution(Probe01, 10); sensors.setResolution(Probe02, 10); sensors.setResolution(Probe03, 10); sensors.setResolution(Probe04, 10); lcd.init(); // initialize the lcd lcd.backlight(); Serial.begin(9600); pinMode(LED1, OUTPUT); pinMode(HIDEGEBB, OUTPUT); pinMode(MELEGEBB, OUTPUT);
}//--(end setup )---
void loop() /****** LOOP: RUNS CONSTANTLY ******/ { // Read the temp from the MAX6675 Celsius = temp.read_temp();
if(Celsius < 0) { // If there is an error with the TC, temperature will be < 0 Serial.print("Thermocouple Error on CS"); Serial.println( Celsius ); digitalWrite(LED1, HIGH); } else { Serial.print("Current Temperature: "); Serial.println( Celsius ); digitalWrite(LED1, LOW); } // Wait one second before reading again delay(1000);
int hofok10 = temp.read_temp()*10; if(hofok10 > 300) { digitalWrite(HIDEGEBB, LOW); } if(hofok10 < 290) { digitalWrite(MELEGEBB, LOW); } delay(MOTORFUTASIDO); digitalWrite(HIDEGEBB, HIGH); digitalWrite(MELEGEBB, HIGH); delay(CIKLUSIDOMP*100); { delay(100);} // clear the screen lcd.clear(); lcd.home(); lcd.backlight(); lcd.setCursor(0,0); lcd.print("temperature"); lcd.setCursor(0,1); lcd.print("C="); lcd.print(Celsius); {delay(3000);} sensors.requestTemperatures(); // Send the command to get temperatures lcd.clear(); // Reset the display lcd.home(); lcd.backlight(); //Backlight ON if under program control // Print our characters on the LCD // NOTE: Line number and character number start at 0 not 1
lcd.setCursor(0,0); //Start at character 0 on line 0 lcd.print("1: "); displayTemperature(Probe01);
lcd.setCursor(0,1); //Start at character 0 on line 1 lcd.print("2: "); displayTemperature(Probe02);
lcd.setCursor(0,2); //Start at character 0 on line 2 lcd.print("3: "); displayTemperature(Probe03);
lcd.setCursor(0,3); //Start at character 0 on line 3 lcd.print("4: "); displayTemperature(Probe04); {delay(2000);} }//--(end main loop )---
if (tempC == -127.00) // Measurement failed or no device found { lcd.print("Temperature Error"); } else { lcd.print("C="); lcd.print(tempC); lcd.print(" F="); lcd.print(DallasTemperature::toFahrenheit(tempC)); // Convert to F Serial.println("ds18b20"); Serial.println(tempC); } }// End printTemperature
Egy módosítás: a max6675 Vcc eddig nem a pro minire csatlakozott, most ezt korrigálva elfogadható pontossággal mér. Kialakítottam a ds18b20 1wire csatlakozót is, legközelebb annak a tesztelése következik. Lassan a program mérete kinövi a pro minit.
Jelenleg van a fenti kontroller K hőelemmel, aminek a vezetéke toldott kompenzációs vezetékkel, tehát az M-R1,R2 folytonossága, kémiai azonossága megoldott, R1,R2 azonos hőfokon van a mérőkörrel.
Van továbbá a fenti max6675 breakout K hőelemmel, amiben van 100 nF kondi is, ez kíván szoftveres hőfokkorrekciót, nem instabil, csak láthatóan eltérő hőfokot ad vissza pl szobahőfokon. A krimpelt érintkezőivel még bevisz némi eltérést, + a hőelem tokozás is befolyásolja a pontosságot és a mérés gyorsaságát.
Hegesztettem kompenzációs vezetékből érintkezők nélkül egy darabot, eddig az volt a leggyorsabb, pontosabb.
A breakouton belül nincs nagy távolság a max6675 és a referencia pontok között, a hőfokeltérés minimális lehet. Esetleg a tokozás saját hője befolyásolja a hőfokeltérést.
Ez jó leírás, ha ezt átolvasod rendesen képben leszel. Kiemelném ezt a bekezdést, mert erről beszéltem pont lentebb:
Reference junction compensation: The AD8495, which includes a temperature sensor to compensate for changes in ambient temperature, must be placed near the reference junction to maintain both at the same temperature for accurate reference-junction compensation.
tudni tudja, de ha nem érted hogy mi az, akkor nem azt fogod mérni mint hiszed.
a lényeg, hogy nem csak ott van termoelem ahol a szenzor van. hanem ott is ahol a szenzor vezetéke más anyagú vezetékkel összekapcsolódik. és ezeken a kötéseken is keletkezik termofeszültség, a hőmérséklettel arányosan. ha ennek a kötésnek a hőmérséklete ismert, akkor számolható a feszültség és lehet kompenzálni.
tehát alapból az kell, hogy a szenzor kábele nem lehet toldva, és direktbe kell menjen az ic-re, azaz hogy a kötés azonos hőmérsékleten legyen az ic-vel.
Na én is most kezdtem utánaolvasgatni... Azért ez a K-típ hőmérés nem is olyan egyszerű, vannak buktatók benne. Semmi lehetetlen, de azért írnak 3-4 dolgot amire figyelni kell.
A MAX6675 nálam a következő(ke)t produkálta. 1. szobahőmérsékletek jól mért. 2. kazán füsthőfokát kb. 20 fokkal alámérte. 3. pár begyújtás után 10 fok helyett 0-át mutatott. 4. majd kb 30-40 fokkal alámért a későbbiekben. 5. most kb 25 fokkal mér alá 200 fokos füstgáznál. 6. viszont szobahőmérsékleten rendesen mér.
Hozzá kell tenni, hogy csak a kazán hőmérőjéhez tudom viszonyítani. Ez így elég pontatlan. Tartaléknak és összehasonlításra szerzek egy újabbat és mindkettőt bekötöm. De ez majd csak a következő idényben. Mindez arduino mini pro-n. Ami a kérdésedet illeti, szerintem a tápellátás nem befolyásolhatja de érdemes lehet hidegíteni 100nF-os kondikkal. Alapértelmezetten a float tipust 2 tizedes jegyre írja ki a print funkció. Ja és mégvalami:én a mérést átlagolom, hogy ne ugráljon.
A M ax6675-el érkezett K-hőérzékelő hibásan krimpelt volt. Viszont már másodjára rendeltem a fűtéshez colos motoros irányváltó szelepet, ismét 9 napra megérkezett, elég gyorsan és jó minőségben.
Összeállítottam a termosztátot i2c 20x4-es lcd-vel A MAX6675-el. A legelőször érkezett, amit sikerült kifektetni pontosan mért, ez 13 C-ot csal a pro minivel, 5 V-al.
Ideiglenesen levontam 10 C-ot, de ez így nem az igazi.
Nem lehet, hogy az első a due-vel stabilabb feszt kapott, azért volt pontos?
Az lcd a hőfok érték után még két karktert is megjelenít, ez program hiba?
/* Single_Temp.pde - Example using the MAX6675 Library. Created by Ryan McLaughlin <ryanjmclaughlin@gmail.com>
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License. http://creativecommons.org/licenses/by-sa/3.0/ */ #define HIDEGEBB 6 // relay1 #define MELEGEBB 7 // relay2 #define MOTORFUTASIDO 1000 #define CIKLUSIDOMP 30 #include <MAX6675.h>
#include <Wire.h> #include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 20 chars and 4 line display
int LED1 = 13; // Status LED Pin int CS = 4; // CS pin on MAX6675 int SO = 3; // SO pin of MAX6675 int SCLK = 5; // SCLK pin of MAX6675 int units = 1; // Units to readout temp (0 = raw, 1 = ˚C, 2 = ˚F) float temperature = 0.0; // Temperature output variable float hofok10 = 0.0;
// Initialize the MAX6675 Library for our chip MAX6675 temp(CS,SO,SCLK,units);
// Setup Serial output and LED Pin // MAX6675 Library already sets pin modes for MAX6675 chip! void setup() { lcd.init(); // initialize the lcd lcd.backlight(); Serial.begin(9600); pinMode(LED1, OUTPUT); pinMode(HIDEGEBB, OUTPUT); pinMode(MELEGEBB, OUTPUT); }
void loop() { // Read the temp from the MAX6675 temperature = temp.read_temp()-10;
if(temperature < 0) { // If there is an error with the TC, temperature will be < 0 Serial.print("Thermocouple Error on CS"); Serial.println( temperature ); digitalWrite(LED1, HIGH); } else { Serial.print("Current Temperature: "); Serial.println( temperature ); digitalWrite(LED1, LOW); } // Wait one second before reading again delay(1000);
10-ből 1 szar kb. Meg az áruk minősége ugye aránylik az árhoz (ferde vagy rosszul beforrasztott lábak, kitört előtétellenállás, 80-120 cm-es szakaszokból összeberhelt LED-szalag -- ilyesmikkel találkoztam eddig).
Itthon most a Lomexre vagyok berágva, akik simán eladták rotary encodernek azt a cuccot, ami egy sima forgókapcsoló. (A rotary encoder elvileg úgy megy, hogy ha az egyik láb a, a másik láb b, a kis betű a szakadás a közös lábhoz, a nagy betű meg a rövidzár, akkor ab--Ab--AB--aB az egyik irányban, és ab--aB--AB--Ab a másik irányban. No, ez iránytól függetlenül aB--Ab--aB--Ab.)
A 328-ra esetleg egy új bootloader feltöltést próbálj meg!
Eddig egész jó tapasztalataim voltak az eBay-en, de most becsúszott egy hibás Nano 328 (kompatibilis). CH340G chipes. COM port látszódik, default program led villog, de nem programozható.
3 db-ot rendeltem (most, korábban többet), 2 jó, 1 rossz. Mindegy, kérek refundot. Nektek milyen tapasztalatok vannak?
Fontos volt a hálózatfüggetlen működés és az, hogy ha egy mód van rá, bontás nélkül újra lehessen programozni. Ezért a sima USB van kivezetve, amit egy külső USB tápról hajtok (kb. 400 mA a teljes fogyasztása, a 10 Ah-s akksiról végtelen ideig (gyakorlatilag kb. 15 órán át) mehet. :-D
Nézem most, hogy mbed nem 4, hanem ésszerű keretek között végtelen számú egyedi "stoppert" tud kezelni.
Ami tehát Arduino környezetben egyszerűsítve így fest:
-- referencia idő kiolvasás
-- while cikus ellenőrzéssel, hogy eltelt-e az idő, közben feladat végrehajtása
-- a határidő elérésekhor kilépés a while cikusból,
(Vagy ugyanez if () ellenőrzéssel a void.loop()-on belül.)
az mbed alatt úgy fest, hogy
-- majd ha eltelik ennyi idő, hajtsd végre ezt, addig csináld a többit.
És ez egy időmérési mód (timeout), van még alapból három (wait -- ez kb. megfelel a delay()-nek, ticker -- ez adott időközönként hív egy függvényt, timer -- ez időt mér, nagyjából mint egy stopper), plusz egy (real time clock, mint a time.h könyvtár az Arduino környezetben).
Adott egy eszköz, tulajdonképpen irreleváns, hogy mi az, a lényeg, hogy lakik benne egy mikrokontroller, amely három gombbal vezérelhető (1/2/*), egy visszajelzés van (egy led). Az 1 és a 2 programozható (időkapcsoló), a * csak úgy van. Hasonló eszközök tizedmásodpercnyi pontos programozhatóságot tesznek lehetővé (kijelzővel), ez, kijelző nélkül lényegében az ügyességre alapozva programozható (nyomjon meg valaki kétszer egymás után érintőkapcsolót tizedmásodperc pontossággal ugyanolyan gyorsan -- kb. lehetetlen). Ez volt a kiindulási alap, erre kellett megoldást találni.
A projekt azzal kezdődött, hogy az eszköz mikrokontrollere és a vezérlőpanel közötti szalagkábelbe betettem egy osztást, amellyel minden szálat egy PS/2-höz is használt DIN csatlakozóval kivezettem a házon kívülre. Ennek ellendarabja a képen lévő fehér kábel, itt jön be és megy ki minden.
Fontos volt az eredeti funkcionalitás megtartása, tehát nem használhattam olyan megoldást, amely a gép önálló működését bármilyen formában is befolyásolja. Ebből következik, hogy a „kijelző” (LED) és a vezérlők (gombok) csatolása is galvanikus leválasztással van megoldva. Ez összesen négy darab 4N35 optocsatoló a szükséges előtétellenállásokkal. A bemeneti oldalona LED-hez kicsit játszanom kellett, hogy még legyen elég áram az optocsatoló zárásához, de már ne essen annyira a másik kör feszültsége, hogy a panelen lévő LED ne zárjon. Mindez egy külön leszedhető panelre lett rárakva (a világosabb sárgás darab, amiből a vastag fehér kábel jön ki).
A méretkorlát miatt a Micro 328-at választottam saját mikrokontrollerként. Filléres holmi, mindent tud és egyszerűen kezelhető próbanyákos környezetben. Ehhez két hüvelysor van beforrasztva a próbanyákra, amelybe szépen beleillik a mikrokontroller tüskesora. A huzalozást sima sodort erű vezetékekkel oldottam meg, némi kísérletezés után lényegében atombiztos (bár emiatt némileg nehezen bontható) megoldással.
A kijelző eredetileg egy 16×2 i2c LCD lett volna, de a menüvezérlést nem tudtam rajta jól érthetően megcsinálni, bár sok szempontból jobb megoldás lett volna (lásd később). E helyett lett egy 0,96"-os 128×64 pixeles fekete-fehér oled. A lábfoglalás tehát nem változott, cserébe viszont a befoglaló méret jelentősen csökkent.
A kezelés egy 4×4-es, nagyjából szintén filléres fóliabillentyűzet adja. Ennek két hátránya, hogy 8 lábat foglal (i2c vagy twi porttöbszörözővel ezt meg lehetne oldani, csak gondolkodni kell rajta sokat), illetve hosszú távon a megbízhatósága sokat romlik.
Van még egy vészleállító gomb, ami interrupt-lábon van, és zárásakor egy igen rövid függvényt futtat, ami csak azt vizsgálja, hogy az eszközön a LED világít-e vagy sem, ha világít, akkor a * gomb megnyomásával lekapcsolja (és ezt figyeli folyamatosan).
A képek gyalázatos minősége okán sok nem látszik. Alapvetően négy fő funkciója van:
1. teljesen manuális vezérlés (előre beállított ideig üzemelteti az eszközt),
2. kiolvassa az eszköz két programját (1 és 2), gyakorlatilag megméri, hogy mennyi ideig világít a LED,
3. lehetőséget ad a két program tizedmásodperces pontosságú beállítására,
4. az egészet visszaprogramozza az eszközre, illetve ellenőrzi a beállított programokat.
Kód szempontból a legnagyobb kihívás az, hogy ez az ótvaros oled az u8glib könyvtárral sajnos nagyon elmebeteg módon működik. Nevezetesen kezd egy nyitással, összegyűjti a kijelzőre kerülő minden információt, ezt kiírja, majd lezárja a kapcsolatot. Ez egy rutin, amely ugyan csak tizedmásodperces időmennyiség, de a pontosság oltárán ezt nem nagyon lehet/szabad feláldozni. Olyan tehát nincs, hogy a kód futtatása során valamikor valahol egyetlen információt megváltoztatunk a kijelzőn (mint ahogy ez a 1602-es kijelzőn simán megy párhuzamos és i2c kapcsolat esetén is. Próbáltam több ilyen kijelzőírási függvényt betenni, illetve külön függvénybe kitenni, de tapasztalataim szerint csak úgy ment, ha a loop()-on belül volt, nagyjából egymagában. Így végül is az lett, hogy a loop() összesen két dolgot tartalmaz, az oled vezérlőjének hívását és egy vizsgálatot, hogy történt-e a billentyűzeten valami. Ha történt, akkor annak kezelése történik, amely vagy rövid időn belül visszaér a loop()-ba (pl. érték beírása), vagy szöttyög, akár perceket, anélkül, hogy a kijelző frissülne. Ez utóbbi nem túl szerencsés, de egyelőre nincs frappáns megoldásom rá (illetve van, de a meglévő két tucat mellé még legalább 6-8 változó kellene, amivel lehet, hogy többet veszítenék mint nyernék).
Kis kitérő mbed világba. Ott ugyanis nem egy (pontosabban kettő) óra van, hanem mikrokontrollertől függően 4 vagy még több. Mindegyik tök külön kezelhető, indítható, felfüggeszthető vagy megállítható és ezzel resetelhető. Mivel eléggé időérzékeny rendszerről van szó, sok változóval és sok folyamatos ellenőrzéssel simán összehozható tizedmásodperces hiba, ezért az időméréses feladatoknál szigorúan ügyeltem arra, hogy más ne történjen. Ez Arduino viszonylatban nagy szívás, de teszek majd kísérletet a megoldására (ha van értelme). mbed platform alatt ez szinte úgy működik, mint az arduino interruptja. Teljesen külön szál.
Mivel az időérzékeny történések között minden fagyott állapotban van, szükségesnek láttam egy, a kihúzásnál elegánsabb megszakítási lehetőség beiktatását, ez lett az egy szál interrupt gomb (sima rövidzár az alapból felhúzott 2-es lábon). Ez egy roppant egyszerű ISR-t futtat, ami csak azt nézi, hogy a berendezés üzemel-e, ha igen, leállítha, ha nem, akkor figyeli, hogy történik-e vele valami. Az ISR-ből nincs kiszállás, tehát a reset/áramtalanítás (most még) megoldásra vár, de ez csak kódolás kérdése.
Az egész koncepciónál még fontos szempont volt, hogy a kvázi-kereskedelmi (gyakorlatilag a mindennapokban használható) kinézet mellett prototípus-állapotban maradjon és a későbbi fejlesztésekre legyen lehetőség. Ezért minden moduláris benne a kijelzőtől, a billentyűzeten át a ki/bemeneti modulig. Ez utóbbi helyett SSR is beépíthető, amivel mindez direktben (230 V-os eszközzel) is lehetőséget ad a vezérlésre (ipari szinten erre elég jelentős igény van). A menüről és a működésről majd rakok fel filmet.
No, kész az eddigi legnagyobb projektem. Bruttó 960 sor, 328 Nano-ra fordítva 15,4 kbyte, majd két tucat alkatrész, majdnem kereskedelmi kinézet (kissé nagy és nincs megoldva a jó tápellátás). i2c oled, interrupt, 4x4 billentyűzet, két irányú galvanikus leválasztás, többszintű menüvezérlés.
Nem mondom, hogy elegáns a kód, de néhány részére büszke vagyok.