3. Hőmérők elkészítése A jelenlegi hőmérőink pt100-as ellenállás hőmérők. Ezeknek az ellenállását szükséges digitális jellé alakítani, és egy 7-szegmenses kijelzővel egy tized pontossággal kijelezni, valamint a mért hőmérsékletet a Peltier-elemeket meghajtó tápegység vezérlő kontrollerjének elküldeni (ez a megfelelő szabályozás miatt fontos). Összesen 3 db ilyen hőmérő-egység szükséges (a felső, hideg oldal; közepső, két Peltier közötti oldal; alsó, hűtendő meleg oldal). 1) Pt100 ellenállásának mérése: A legegyszerűbb megvalósítás - hasonlóan egy multiméterhez - az, hogy nagyon kis áramot (néhány ma) kapcsolunk az ellenállás hőmérőnkre, mely olyan kicsi, hogy melegítő hatása elhanyagolható a környezethez képest. Ezzel egy mérhető, néhány 100mV-os nagyságrendű jelet kapunk. A feladat innen az, hogy ezt a jelet digitalizáljuk, erre a leendő ATMEGA8-as kontroller 10bit-es átalakítója áll rendelkezésre. Számolgassunk kicsit! Először is minden egyes hőmérőnél meg kell vizsgálni, hogy milyen hőmérsékleti tartományban akarjuk hogy mérjen, és milyen pontossággal. Vegyük példának a felső, hűtött oldalra kerülő hőmérőt (ezt ugyanis már végigszámolgattam)! Mondjuk -50 és +50 C között szeretnénk mérni, egy tizedes pontossággal. A pt100-as hőmérő adott hőmérséklethez tartozó ellenállása táblázatokból leolvasható: http://www.intech.co.nz/products/temperature/typert.html R(T= -50 C) = 80,31 Ω R(T= +50 C) = 119,40 Ω Amennyiben I = 1 ma áramot folyatunk az ellenálláson, úgy 80,31-119,4 mv közötti feszültséget kapunk (ideálisan). Ezzel az a baj, hogy mindössze 28 mv különbség áll rendelkezésünkre a 100 C-os tartományban. Gondolom világos, hogy így a tized fokos pontosság eléréséhez már igen kis feszültségeket (μv) kéne mérni, ami nem egyszerű feladat. Szerencsére pt100-ason eső feszültséget néhány műveleti erősítővel kicsit átalakítva nem jelent gondot az elérni kívánt pontosság. A kimenő jelet tehát fel kell erősíteni, és érdemes a számunkra nullpontot jelentő -50 C-hoz tartozó 80,31 mv-os offsetet is kivenni. A cél az, hogy az A/D konverterünkre 0-5V-os jel jusson. A digitális átalakítás azért szükséges, mert mint látni fogjuk, a mikrokontrollerünk bizony csak a digitális jelekkel tud valamit kezdeni. A fent ismertetett feladat áramköri megoldása és az ehhez kapcsoló számítások is megtalálhatóak az alábbi dokumentumban: http://wjsz.ktk.bme.hu/kiskor/sites/default/files/uploads/u5/amppt100-1.pdf 2) Ábrázolandó hőmérsékletek A hőmérséklet kijelzését legegyszerűbben egy 7-szegmenses kijelzővel oldhatjuk meg, melynek digit száma függ attól, hogy hol akarunk vele hőmérsékletet mérni. A bevezetőben leírtak szerint 3 db hőmérőt kell készítenünk, melyek más-más hőmérsékleti tartományban írnak ki értékeket, néhány lehetséges tartomány:
Felső, hűtött oldal: -40- +40 C 3 és fél digit Középső oldal: -30- +40 C 3 és fél digit Alsó, meleg oldal: 0-60 C 3 digit Ezek a tartományok még szűkíthetők, a legkritikusabb a felső, hideg oldal hőmérséklete. Ez a Peltier-elem gyártója által közzétett adatlap szerint nem lehet kisebb -40 C-nál, ekkor ugyanis az eszköz tönkremegy. A középső oldal, vagyis a két Peltier közötti részről nincsenek konkrét mérési információink, mindig csak a meleg és hideg oldalt mértük. Bizonyos azonban, hogy az alsó, nagyobb teljesítményű Peltier-elem is önmagában képes -20 C körüli hőmérséklet létrehozására, így alsó határnak indokolt lehet a -30 C (csakhogy mérnöki túltervezéssel is éljünk). Nem szabad elfelejteni továbbá azt sem, hogy a külső hőmérséklet bizony ezekre a tartományokra igen nagy hatással van: nyári nagy melegben egy kevésbé jól fűtött szobában akár 30 C feletti hőmérséklet is lehet, ugyanakkor télen pedig lehetséges szobahőmérséklet alatti hőmérséklet is, ami elsőre jónak tűnhet, hiszen a hűtőrendszerünket nem kell megterhelni, de ne felejtsük el, hogy itt bizony a túl jó hűtés miatt a -40 C elérése lehet gond. Mindezeket végiggondolva szükséges majd különböző biztonsági intézkedések implementálása a tápegységet vezérlő kontroller szoftverében. Ez annyit tesz, hogy amint megközelítjük a -35 C-t, a kontroller kevesebb áramot ad a felső Peltier-elemnek. 3) 7-szegmenses kijelző müködése és vezérlése shift register IC-vel A hétszegmenses kijelző lényegében egy 8 ledből álló kijelző, melyben az egyes ledeket külön-külön vezérelve különböző karaktereket jeleníthetünk meg. Két nagy típusa van: közös anódos és közös katódos, lásd alább. Az elsőnél egyetlen vonalon tápot adva a kapcsolni kívánt ledeket megfelelő áramkorlátozás mellett földre húzzuk, míg a második esetben közös földeléssel bírnak és a tápot adjuk nekik külön-külön. Mindkét fajtának megvan a maga felhasználási területe, számunkra most a közös anódos a fontos, mivel a shift register IC-vel földre tudjuk húzni a kimeneteket.
Hogyan keltjük éltre a kijelzőnket? A legegyszerűbb megoldás az, ha veszünk egy megfelelően sok lábú mikrokontrollert, és minden egyes lábat külön-külön vezérelünk. Ez mondjuk a felső oldali hőmérő esetében: előjel+tizedes pont+3x7 láb = 23 db kivezetés, ami három 3 és fél digites kijelző esetén már igencsak nagy (és drága) mikrokontrollert igényel. Több megoldás is létezik arra, hogy a vezérelendő kivezetések számát leredukáljuk, egyik ilyen a shift register IC használata. Az ötlet alapvetően a Hobbielektronika honlapról származik, érdemes a cikket végigolvasni: http://www.hobbielektronika.hu/kapcsolasok/led_kijelzok_vezerlese_akar_mar_5_vezeteken.h tml A továbbiakban összefoglalnám a cikk tartalmát, illetve kiegészíteném a számunkra releváns adatokkal, illetve nem triviális ismeretekkel, forráskóddal. A módszer abból áll, hogy mindössze 4 láb segítségével bármekkora kijelzőt tudunk vezérelni (+1 láb kell, ha a kijelző fényerejét is akarjuk állítani, nekünk most nincs rá szükség). Mielőtt belemerülnék az egyes lábak szerepébe, nézzünk meg az általunk használt shift register IC-t (TPIC6B595N, később valószínűleg egy olcsóbb, kisebb áramot bíróra cseréljük)! Jobbra látható blokkdiagram. Az IC-ben taláható 8 db elsőszintű, és 8 db másodszintű tároló; ezek egy-egy bitet képesek tárolni. A SER IN (serial input) lábon érkező adatok először átmennek az első tárolón, majd a következőn és haladnak egészen az utolsó tárolóig, ami az utolsó shift register IC utolsó tárolóját jelenti. Egy szemléletes példa erre: egy vonatszerelvényre emberek szállnak fel, és egymás után töltik fel a helyeket. Amikor egy kocsi (egy shift register IC) megtelt, mennek a következőbe és így tovább. Mivel nem mondtuk szerencsétlen utasoknak, hogy üljenek le (nem volt órajel), ezért egymást folyamatosan lökdösve kiszorítják az újonnan érkezők a régieket így az állomás (kontroller) folyamatosan ontja csak az utasokat. Az utasok leültetéséért, vagyis az adatok letárolásáért az SRCK (shift register clock) vonal felel, ezen egy mintavételező órajellel letároljuk az adatokat az elsőszintű tárolókba. Innen a másodszintű tárolókba akkor kerülnek az adatok, ha az RCK (register clock) lábon erre utasítást adunk. Ezek a tárolók képesek a
kapott biteket addig eltárolni, míg újabb utasítást nem adunk. A invertált engedélyező láb felelős azért, hogy a másodszintű tárolók hatására a kijelzőre kikerüljenek a kívánt értékek úgy, hogy egy-egy FET-et vezérelve földre húzzák az egyes kimeneteket. Hogy miért hasznos ez a kétszintű rendszer? Léteznek olyan register IC-k is, amelyek csakis elsőszintű tárolókkal rendelkeznek. Ezeknek az a rákfenéje, hogy ahogy jönnek az adatok, a kijelző folyamatosan frissül, villódzik, nincs lehetőség értékek hosszabb idejű tárolására. Kétszintű tárolókkal egyszerűbb a helyzet: bár a hőmérséklet folyamatosan változik, stacioner állapotban lehetséges, hogy sokáig nincs szükség a kijelző frissítésére; ekkor egész egyszerűen a másodszintű tárolókból hívjuk le a kijelző tartalmát mindaddig, amíg nincs szükség az adatok felülírására az elsőszintű tárolókból jövő adatok átemelésével. Közvetlenül a tehát az adatok a másodszintű tárolókban nem törölhetőek. Természetesen az elsőszintű tárolóban igen, erre szolgál a szintén invertált (shift register clear) láb. Hogy még világosabb legyen az egyes lábak feladata, íme egy példa arra, hogy milyen jeleket kell az egyes lábakon látni a kijelző működtetéséhez: 4) Egyetlen hétszegmenses kijelző vezérlése mikrokontrollerrel, példaprogram Mivel nincs sok kimenetre szükségünk, ezért egy nagyon kicsi, de annál okosabb mikrokontrollert fogunk használni, egy Attiny13-ast, amelynek lábkiosztása a következő:
Látható, hogy a RESET, VCC és GND lábak nem használhatóak csak kimenetként, ezért összesen 5 láb áll rendelkezésünkre, ebből egyet majd az ellenállás hőmérőhöz tartozó erősítős áramkörből érkező digitalizálandó jelnek hagyunk meg, mint ADC bemenet. Feltűnhet, hogy igazából 5 láb kell a shift register vezérléséhez; mi most annyit könnyítünk a helyzetünkön, hogy a G lábat simán csak földre húzzuk, ami azt eredményezi, hogy amint a másodszintű tárolókba kerül valamilyen adat, az rögtön megjelenik a kijelzőn is, hiszen az engedélyezés folyamatos. Ezért cserébe eggyel kevesebb kimenetet kell vezérelni, és az egész hőmérő modul ezzel a 8 lábú kontrollerrel megvalósítható. A kapcsolásunk az alábbi: Megjegyzés: nincs jelölve, de természetesen a shift register IC is kap 5V tápot. Ez az áramkör egyszerűen összerakható breadboardon is, ahol rögtön neki is láthatunk a kontroller szoftverének a fejlesztéséhez. Magáról a kontroller felprogramozásának fizikai megvalósításáról most nem beszélnék, lényeg hogy ezt egy programozó áramkörrel tehetjük meg, a kontroller megfelelő lábaira való csatlakozása után. Sokféle programozó és ahhoz tartozó szoftver van a piacon, a példában AVR STUDIO-val fordítottam le a C kódot, és AVR ISP mkii programozóval égettem bele a.hex fájlt.
Most tekintsük az alábbi példa programot, amely képes karaktereket kiíratni a kijelzőre egy egyszerű for ciklussal, C nyelven: #include <avr/io.h> #include <util/delay.h> //A szükséges header fájlok void Data(int a) //A SER IN kimenet, erre fogjuk küldeni az adatokat if (a>0) //megnézi, hogy a kapott bit 0 vagy 1 PORTB = (1<<PINB1); //Ha 1, akkor a kimenet HIGH, lásd a forráskód után else PORTB &= ~(1<<PINB1); //Ha 0, akkor a kimenet LOW void Clock() //Ez az órajel függvényünk, az SRCK láb, ez egy 10ms-os négyszögjel-impulzust küldd ki PORTB = (1<<PINB0); //HIGH kimenet //10 ms várakozás PORTB &= ~(1<<PINB0); //negálás történik, vagy a kimenet LOW //10 ms várakozás void Reset() PORTB &= ~(1<<PINB4); PORTB = (1<<PINB4); void Enable() PORTB = (1<<PINB3); PORTB &= ~(1<<PINB3); //Elsőszintű tárolók törlése, vagyis ez megy az SRCLR lábra. Hasonlóan a Clockhoz, ez is egy impulzust ad, csak annak negáltja //Kijelző kiíratás engedélyezése, RCK láb. Impulzus kiadás, akárcsak a Clock-nál char table[ 32 ] = //Megadjuk a kiírható karaktereket egy tömb elemeiként. 0b10101010 jelentése: 0b->bináris, utána 8 bit, ami azt mondja meg, hogy melyik led világítson a nyolcból(sorban: A,B,C,...,G,dot)
/* '0' */ 0b11111100, /* '1' */ 0b01100000, /* '2' */ 0b11011010, /* '3' */ 0b11110010, /* '4' */ 0b01100110, /* '5' */ 0b10110110, /* '6' */ 0b10111110, /* '7' */ 0b11100000, /* '8' */ 0b11111110, /* '9' */ 0b11110110, /* '-' */ 0b00000010, /* 'A' */ 0b11101110, /* 'C' */ 0b10011100, /* 'E' */ 0b10011110, /* 'F' */ 0b10001110, /* 'G' */ 0b10111100, /* 'H' */ 0b01101110, /* '.' */ 0b00000001 ; void Kiiras(char input) for(int i=1;i<256;i*=2) Data(input&i); Clock(); Enable(); //A kiíratás függvénye //Itt történik meg az, hogy beadunk egy karaktert a Data függvénynek, és egy maszk segítségével leolvassuk az egyes helyiértékeken álló biteket a for ciklussal //minden egyes kiolvasott bit után egyben órajelet is küldünk, hogy megtörténjen a mintavételezés //Miután a SER IN lábra kiküldtünk egy karakter kirajzolásához szükséges minden adatot, rögtön beleírjuk ezeket a biteket a másodszintű tárolókba
//------------------------------------ int main(void) //A fő program DDRB = (1<<PINB0) (1<<PINB1) (1<<PINB3) (1<<PINB4); //kimeneti lábak definiálása //Mivel a SRCLR láb alapból HIGH, ezért kicsit várni kell a Reset függvény meghívása előtt,különben a kontroller nem tudja végrehajtani a műveletet, és folyamatosan törölni fog PORTB = (1<<PINB4); //A reset lábat felhúzzuk HIGH-ra Reset(); //kitöröljük az esetlegesen bent maradt adatokat delay_ms(10); for(int j=0;j<32;j++) //A megadott tömb elemeinek egymás után való kiírása, 1 s- os késleltetéssel Kiiras(table[j]); _delay_ms(1000); A szokásostól eltérően itt nem egy while(1)... return 0; ciklusba ágyazott programról van szó, ugyanis most még nincs szükségünk arra, hogy a kontroller folyamatosan fusson, ez csak egy példaprogram, hogy az alapokat megértsük; a gyakorlatban azonban szinte kizárólag egy mindig igaz while ciklusba teszik a fő programot. Sajnos itt most nincs lehetőség a mikrokontroller felépítésének és működésének pontos leírására, így minden ehhez kapcsolód kérdésre majd a mikrokontrollerekről szóló belső szeminárium fog részletes magyarázatot adni. A digitális jelekkel kapcsolatos rész is lehet, hogy sokaknak ismeretlennek vagy idegennek tűnhet, egy kis utána járással és átgondolással azonban könnyen megérthető.