Tartalmi kivonat
Budapesti Műszaki Főiskola Neumann János Informatikai Kar A soros port Pogáts Dávid Kárer Győző Hegyi Gergő Károly NMI III/16 Az aszinkron soros kommunikáció A PC-k soros kommunikációs portjai az ún. COM portok, amelyeken keresztül az RS232 szabvány szerinti aszinkron soros kommunikációt valósíthatunk meg más eszközökkel. Az RS232 egy elterjedt és bevált aszinkron kommunikációs szabvány, amelyet szinte minden mai számítógép és egyéb számítógéphez kapcsolható eszköz (scanner, printer, terminál) kezelni képes, azaz rendelkezik RS232-es soros felülettel. A PC-ben alapesetben két kommunikációs port szokott lenni, ezek a COM1 és a COM2 neveket viselik. A BIOS fizikailag csak négy független (COM1, COM2, COM3 és COM4 elnevezésű) portot tud kezelni, de elméletben nincs akadálya ennél több független COM port megvalósításának sem, persze ebben az esetben nem a BIOS megszakításait kell használnunk, hanem valamely más egyedi
kommunikációs programot. A soros porton történő adatátvitelt megvalósíthatjuk a BIOS ide vonatkozó funkcióival, vagy a soros kommunikációs áramkör egyéni programozásával is. A PC-ben a soros kommunikációt az Intel 8250-es (a továbbiakban UART) aszinkron soros kommunikációs áramköre vezérli, az újabb alaplapokon és IDE kártyákon ennek az áramkörnek egy továbbfejlesztett változatát, az NS 16450 vagy 16550 típusú LSI áramkört használják. A modemek és a soros kommunikáció Az aszinkron soros kommunikációt, a soros vonalakat eredetileg arra a célra fejlesztették ki, hogy ezzel egy modemre csatlakozzanak, amely aztán telefonvonalon keresztül más számítógépekhez képes csatlakozni. A modem szó a Modulator, DEModulator szavak összeillesztéséből ered, funkcióját tekintve pedig azokat az eszközöket tekintjük modemnek, amelyek a terminál eszközről érkező bemeneti jelet valamilyen formában modulálják (átalakítják), így egy
más jellegű kommunikációs hálózaton továbbítani tudják a bemenő adatokat, míg a kommunikációs hálózatból érkező jeleket demodulálják (visszaalakítják), és visszaadják a kommunikációt kérő terminál eszköznek. Tágabb értelemben tehát bármilyen kétirányú jeltranszformációra képes eszközt modemnek tekinthetünk. A számítógépekhez kapcsolható modemek ennél sokkal jobban specifikáltak. Ezek a modemek a számítógép felől RS232 felületen érkező digitális jeleket frekvenciamodulált jellé alakítva továbbítják a telefonhálózaton keresztül, míg az onnan érkező hangfrekvenciás jeleket demodulálják az RS232 szabványnak megfelelő digitális jelekké. Ilyen módon két távoli számítógép két modemen és egy telefonvonalon keresztül összeköthető egymással. A tipikus elrendezést mutatja az alábbi ábra: Az adatokat továbbító berendezéseket jelen esetben a modemeket adatátviteli DCE (Data Communication Equipment)
eszközöknek, az adatokat szolgáltató berendezéseket jelen esetben a számítógépeket pedig adatterminál DTE (Data Terminal Equipment) eszközöknek nevezzük. A kommunikáció természetesen annál jobb, minél gyorsabb és minél megbízhatóbb A 2 megbízhatóságot különböző hibajavító és hibafelfedő eljárással növelni tudjuk. Az elrendezés alapján az is látható, hogy kétféle kommunikációs vonal van: • DTE-DCE vonal, ez a terminál eszközt köti össze az adattovábbító eszközzel. Esetünkben ez egy RS232-CS aszinkron soros kommunikációs vonal, amelynek sebességét az RS232 szabvány rögzíti. • DCE-DCE vonal. amely a két adattovábbító eszközt (a két modemet) köti össze Itt ez a telefonvonal, amelynek sebességét korlátozza a vonal minősége, a vonalra jellemző hangfrekvenciás sávkorlátozások, illetve a két továbbító eszköz saját álviteli sebessége. Az aszinkron soros adatátvitel A soros kommunikáció során
két eszköz kommunikál egymással, az ADÓ {Transmitter} és a VEVŐ (Receiver). A soros kommunikációnak alapvetően kétféle változata van: szinkron és aszinkron. Szinkron esetben az adó és a vevő egész adatblokkok erejéig szinkronban maradnak, a bitek továbbításához közös szinkronizáló jelet használnak. Az aszinkron kommunikáció esetében viszont az adó és a vevő csupán egyetlen karakter átküldésének idejéig szinkronizálódik össze, ráadásul mindkettő saját belső szinkronjelet használ, a karakter elküldése után a kommunikációs vonal meghatározatlan ideig inaktív állapotba kerülhet. A kommunikáció során az adó által küldött bitek időütemezve sorban egymás után „átmennek" a vevőhöz, azaz a bitekhez tartozik egy bizonyos átviteli időütem. Természetesen az időütemet a kommunikáció megkezdése előtt kell definiálnunk, utána ez már állandó. Ennek az időtartamnak a hossza definiálja az átvitel
sebességét: minél rövidebb az egy bithez tartozó átviteli idő, annál gyorsabb a kommunikáció. Természetesen az adónak és a vevőnek ugyanazt az időt kell hozzárendelni a bitekhez, máskülönben az átvitt információ teljesen hibás lesz. A kommunikációs vonal alapesetben inaktív az RS232 szabvány esetében magas állapotban van. Amikor az adó adatot szeretne küldeni a vevőnek, ezt jeleznie kell valahogyan. Az adás kezdetét az ún start bit jelzi, amely még nem az adat része, csupán kiegészítő információ. Példaképpen nézzük meg, hogy hogyan küldünk át egy bájtot, mondjuk a C5h értéket. (Ez binárisan: 11000101) Láthatjuk, hogy a valódi adatot kiegészítő, pontosabban keret (framing) bitek veszik körül. Az adás kezdetét a start bit (egészen pontosan ennek első lefutó éle) jelzi. amely mindig alacsony szintű (10 átmenet). Ezt követik az adatbitek, jelen esetben nyolc bit, de a szabvány ettől kevesebb bitszámot is megenged.
Az adatok után az adó elhelyez egy stop bitet, amely a karakter átvitelének végét jelzi. A stop bitek száma állítható, a szabvány megenged 1, 15 vagy 2 stop bitet. A méret ebben az esetben természetesen a stop bit idejére vonatkozik, azaz 15 stop bit esetén a stop bit időtartama másfél bitütemet jelent. Ha a vevő a stop bitet érzékelte, ismét következhet egy újabb start bit, ami újabb karakter vételére szólítja fel a vevőt. Az átvitel során kérhetünk paritásos hibaellenőrzést is, ekkor a stop bitet a paritás bit előzi meg. A paritásos 3 hibaellenőrzés lényege, hogy az átvitt adat egyes bitjeinek számát a paritás típusától függően a paritásbit páros vagy páratlan értékre egészíti ki. Ha az átvitel során egy bit megsérült, akkor a kiegészítés miatt az adó és a vevő között nem fog egyezni az egyes bitek száma, azaz paritáshiba lép fel. Statisztikailag kimutatható, hogy annak a valószínűsége kicsi, hogy
egyetlen átvitt adatban több bit is hibás legyen, ezért a paritás ellenőrzéssel az ilyen hibákat megbízhatóan detektálni lehet. Az átvitelt mindezek alapján négy jellemző adattal írhatjuk le: • Az átvitel sebessége, azaz az időegység alatt átvitt bitek száma. Ezt bitütemezésnek, angol elnevezéssel BAUD RATE-nek nevezzük, és bit/sec-ben (bps-ben) mérjük. Az RS232 szabvány rögzíti a megengedett sebességeket. Baud Rate 150 bps 300 bps 600 bps 1200 bps 2400 bps 4800 bps 9600 bps 19200 bps 38400 bps Bitütem, egyetlen bit időtartama 6,66666 msec 3,33333 msec 1,66666 msec 0,83333 msec 0,41666 msec 0,20833 msec 0,10416 msec 0,05208 msec 0,02604 msec A PC-n a soros időütemet egy 1.8432 MHz-es órajelből osztással állítják elő, így a szabványban rögzítettől elérő sebességeket is be tudunk állítani. A legkisebb osztó 16 lehet, így a legnagyobb bitütem 1843200/16=115200 Hz, azaz az elérhető legnagyobb baud rate 115200 bps. Ezek a
sebességek a DTE-DCE vonalra érvényesek A DCE- DCE sebességet a telefonvonalakra vonatkozó jelenlegi hangfrekvenciás sávkorlátozások miatt nemigen lehet 56 kbps felé emelni. A DTE-DCE és a DCE-DCE sebességek közötti különbséget a modem korrigálni tudja. Ha a DTE-DCE sebesség nagyobb, mint a DCE-DCE, akkor a modem az adatokat előbb hardveresen tömöríti, majd így továbbítja, ezért virtuálisan nagyobb sebességgel folyik a kommunikáció, mint amekkora az átviteli sebesség a DCEDCE vonalon valójában. (Így fordulhat elő például, hogy egy 14400 bps sebességű modem kapcsolódni tud 38.400 bps sebességgel is, noha a telefonvonalon az átvitel csak 14400 bps-el történik.) • Az átvitel során használt adatbitek száma. Ez 5, 6, 7 és 8 bit lehet • Az átvitel során használt stop bitek száma. A szabvány 1, 15 és 2 stop bitet enged meg, de a 1.5 stop bit csak az 5 bites adatbitszám mellett használható • Az átvitel során használt paritás
ellenőrzés típusa. A paritás ellenőrzést nem szükséges használnunk. de amennyiben használjuk, kérhetünk páros, illetve páratlan paritás számot Ezeket a jellemzőket tetszés szerint kombinálhatjuk. így aztán sokféle kommunikációs típust állíthatunk be. Az adatátvitel persze csakis akkor lehet sikeres, ha mind az adó mind a vevő ugyanazokat a paramétereket használja. Ma már elég jó minőségű modemeket gyártanak, ezért a 8 adatbites, 1 stop bites, paritás ellenőrzés nélküli nagysebességű (19.200 bps vagy 38.400 bps) kommunikáció is megfelelően biztonságos Készülékek összekötése 4 Az adó és a vevő összekötésére elméletileg elegendő egyetlen érpár, a soros összeköttetés azonban számos kiegészítő jelet is tartalmaz. Tágabb értelemben nem is az adóról és a vevőről kell beszélnünk, hanem két olyan eszközről, amely teljesen függetlenül adni és venni is tud egyidőben. Az ilyen készülékeket duplex
eszközöknek nevezzük Az RS232 szabvány kilenc vezetéket ír elő az összeköttetésre, ezekből csupán három (az RxD, a TxD és a GND vezeték) elengedhetetlen az egyszerű duplex kommunikációhoz, a többit csak abban az esetben szükséges használnunk, ha modemmel kommunikálunk vagy, ha a modemvezérlő jeleknek egyéb funkciót (például kézfogásos, handshake vezérlési feladatokat) is szánunk. (A táblázatban azt is feltüntettük, hogy a DTE, azaz a számítógép szempontjából melyik vonal kimenet és melyik bemenet. A modemnél ez természetesen fordítva van) A jel neve A jel funkciója TxD (output) Adási vezeték (Transmit Data) RxD (input) Vételi vezeték (Receive Data) RTS (output) Az adatterminál adási kérelme (Request To Send) CTS (input) Az adattovábbító kész az adása (Clear To Send) DTR (output) Az adatterminál üzemkész (Data Terminal Ready) DSR (input) Az adattovábbító üzemkész (Data Set Ready) DCD (input) Az adatvivőjel
érzékelhető (Data Carrier Detect) RI (input) Csengetés érzékelő (Ring Indicator) GND Föld vezeték (Ground) 9 lábú csatlakzó 3 2 7 8 4 6 1 9 5 25 lábú csatlakozó 2 3 4 5 20 6 8 22 7 A PC-n kétféle soros csatlakozót találunk: egy 9 és egy 25 pólusú csatlakozót. A csatlakozón az RS232 szabványnak megfelelően nem TTL jelszinteket, hanem a szabvány szerint rögzített feszültségeket használják. J elentés TTL jelszínt alacsony (0) 0V0.8V magas (1) 2.4V5V RS232 jelszínt 3V15V (-15)V. (-3)V Megjegyezzük, hogy a PC-ben az RS232 meghajtása csak a +12 V . -12 V tartományba esik A csatlakozók kiosztását láthatjuk a mellékelt ábrán. Függetlenül attól, hogy milyen készülékeket kötünk össze soros vonalon, az RS232 szabványos készülék összekötése két alapvető esetre korlátozódik: a DTE-DCB és a DTE-DTE összeköttetésre. • Adatterminál és adattovábbító összekötése, azaz DTE-DCE összeköttetés. Ebben az esetben
tudnunk kell, hogy a DTE minden kimeneti vonala a DCE ugyanazon elnevezésű bemeneteire csatlakozik, a DTE bemenetekre pedig a DCE azonos elnevezésű kimenetei 5 kapcsolódnak, • Két adatterminál összekötése, azaz DTE-DTE összeköttetés. Az ilyen összekötést nullmodem üzemnek is nevezzük, mert ilyenkor nincs modem a rendszerben A két számítógép közvetlenül az RS232 felületen keresztül egymáshoz kapcsolódik. Ebben az esetben viszont az egyik DTE kimeneteit a másik DTE megfelelő bemeneteire kell kapcsolnunk, hogy a kommunikáció létrejöhessen. A legelterjedtebb összekötési fajtákat az alábbi ábrák mutatják. A szabványos modemkábelek a 2. kapcsolás szerint az összes jelet átkötik a számítógép és a modem között. Ez a kapcsolás megbízható és elégséges a DTE-DCE kapcsolathoz Két gép soros porton történő összekötésére már jóval több lehetőség kínálkozik, a DTE-DTE összekötésnél mindig azt kell pontosan
eldöntenünk, hogy mely jeleket használjuk majd a kommunikáció során. Ha a BIOS rutinokat használjuk fel az adatkapcsolatra, akkor a 4., 6, 7, és a 8 kapcsolás jöhet 6 szóba. mert a BIOS megszakítások figyelik némelyik modemvezérlő jelet Ha a Norton Commander Link parancsával szeretnénk két gépet összekapcsolni, akkor a legjobb megoldás a 6. kapcsolás, de a 4 is használható, ha kevesebb vezeték áll csak rendelkezésre A belső önhurkos kapcsolások (a 4. és a 6 és 7) egyébként bizonyos fokig becsapják a soros vezérlőáramkört, mert saját kérési kimeneteiket kötjük vissza a nyugtázó bemenetekre. A legegyszerűbb esetben egyébként a 3. kapcsolást is használhatjuk, de ehhez saját kommunikációs programot kell készíteni (ahogyan ezt majd meg is tesszük), mert a BIOS nem támogatja a háromvezetékes null-modem kapcsolást. BIOS megszakítások A soros kommunikációt a BIOS négy funkcióval támogatja. A függvényeket az INT 14h
hívással aktiválhatjuk. Egyébként a BIOS csupán az egyszerű lekérdezéses adatátvitelt támogatja, a soros portok által kezelhető megszakításos álvitelt nem, ezért igazán hatékony kommunikációs programot nem építhetünk a funkciókra. Az INT 14h használatakor a függvények funkciókódjait az ah regiszterben, a használni kívánt COM port számát a dx regiszterben, az egyéb adatokat pedig az al regiszteren keresztül adhatjuk át, illetve kaphatjuk vissza. A COM portok sorszámozása a következő: A dx regiszter értéke 0000h 0001h 0002h 0003h ah = 00h A kiválasztott soros port COM1 COM2 COM3 COM4 Initalize selected serial port A megadott számú aszinkron kommunikációs port inicializálása. A dx regiszterben megadott sorszámú portot leállítja az al regiszterben megadott paraméterekre. Az al bitmezőkre osztva tartalmazza a kommunikáció paramétereit. Az al regiszter bitmezői az inicializáláskor: Bitszám 7-5 4-3 2 1-0 A bitérték
jeléntése Átviteli sebesség bitmező (Baud Rate) Paritásellenőrzési bitmező (Parity Check Type) Stop bit bitmező (Stop Bit) Adathossz bitmező (Data Size) 7 Az átvitel sebesség bitmezői jelentése: Érték 000 001 010 011 100 101 110 111 Jelentés 110 bps 150 bps 300 bps 600 bps 1200 bps 2400 bps 4800 bps 9600 bps A paritásellenőrzési bitmező jelentése: Érték X0 01 11 Jelentés Nincs paritás ellenőrzés Páratlan paritás Páros paritás A stop bit bitmező jelentése: Érték 0 1 Jelentés 1 stop bit 2 (5 bites adatnál 1,5) stop bit Az adathossz bitmező jelentése: Érték 00 01 10 11 Jelentés 5 bites adatok 6 bites adatok 7 bites adatok 8 bites adatok Az al regiszter bitmezői tetszőleges módon kombinálhatók, a BIOS nem ellenőrzi az értékét, így 256 féle átviteli mód adható meg. A funkció visszatéréskor az al és az ah regiszterekben visszaadja a port vonali és modem állapotregiszterét. A bitek kiosztása megegyezik a 03h
funkciónál leírtakkal. ah = 01h Send character Egy karakter elküldése a megadott számú aszinkron kommunikációs porton. A dx regiszterben megadott sorszámú porton keresztül elküldi az al regiszterben megadott adatot. Nyolc adatbitnél kisebb karakterhossz esetén az al felső kieső bitjeit a funkció figyelmen kívül hagyja. Amennyiben időtúllépés lép fel (time-out), az ah regiszter 7. bitje 1 lesz 8 ah = 02h Receive character Karakter vétele a megadott aszinkron portról. A funkció a dx regiszterben megadott sorszámú COM portról beolvas egy karaktert, majd ezt az al regiszterbe helyezi. Amennyiben időtúllépés lép fel (time-out), az ah regiszter 7. bitje 1 lesz ah = 03h Get serial port state A megadott számú aszinkron kommunikációs port állapotának lekérdezése. A funkció a dx regiszterben megadott sorszámú COM port vonali és modem állapotregiszterét lekérdezi, majd ezeket az ah és az al regiszterben adja vissza. A vonali
állapotregiszter (Line Status Register) bitjei az ah regiszterben: Bitszám 7 6 5 4 3 2 1 0 A bit jelentése Időtúllépés Az adó léptetőregisztere üres Az adő átmeneti regisztere üres BREAK detektálás Keret hiba Paritáshiba Ráfutás az előző karakterre A vevő adatregiszterében érvényes adat van A modem állapotregiszter (Modem Status Register) bitjei az al regiszterben: Bitszám 7 6 5 4 3 2 1 0 A bit jelentése A DCD jel értéke (Data Carrier Detect) Az RI jel értéke (Ring Indicator) A DSR jel értéke (Data Set Ready) A CTS jel értéke (Clear To Send) Változás a DCD utolsó olvasása óta Változás az RI utolsó olvasása óta Változás a DSR utolsó olvasása óta Változás a CTS utolsó olvasása óta Mj : Az újabb BIOS verziók még két további funkciót tartalmaznak. De használatuk során programjaink kompatibilitási gondokba ütközhetnek, ha esetleg egy régebbi gépen futtatjuk azokat. Ezen funkciók megléte ráadásul a mostani BIOS
verziókban sem garantált ah = 04h Initalize selected serial port A megadott számú aszinkron kommunikációs port bővített inicializálása. A rutin bemenő paraméterei a következők: cl – átviteli sebesség 00h 110 bps 01h 150 bps 02h 300 bps 9 Mj : ah = 04h 03h 600 bps 04h - 1200 bps 05h - 2400 bps 06h - 4800 bps 07h - 9600 bps 08h - 19200 bps ch – adathossz 00h - 5 bites karakterek 01h - 6 bites karakterek 02h - 7 bites karakterek 03h - 8 bites karakterek cl – stopo bitek száma 00h – 1 stop bit 01h – 2 stop bit ch – paritás 00h – nincs paritás ellenőrzés 01h – páratlan paritás 02h – páros paritás al – 1 BREAK engedélyezve Set/Get modem control register (MCR) A modem vezérlőregiszter olvasása vagy írása. A funkcióval a dx regiszterben megadott COM port modem vezérlőregiszterét olvashatjuk ki vagy állíthatjuk be. A rutin bemenő paraméterei a következők: al –alfunkciók 00h – az MCR olvasása 01h – at MCR írása bl –
az MCR adatbitjai 4. bit : Diagnosztikai visszacsatolás jel (modem init) 3. bit : az OUT2 jel érétke 2. bit : az OUT1 jel érétke 1. bit : az RTS jel érétke 0. bit : a DSR jel érétke Az Intel 8250 aszinkron soros illesztő és regiszterei Az UART áramkörnek jóval több szolgáltatása van, mint amennyit kihasználnak a BIOS rutinok. Az áramkör és a vele kompatíbilis NS 16450, 16550 későbbi típusok duplex üzemmódban dolgoznak, azaz a vevő és az adó rész egymástól függetlenül, egyidőben működhet. Az UART intelligens periféria, az elküldendő adatot egyetlen bájtban kell megadnunk, ezt automatikusan bitekre bontja és elküldi a soros vonalon. A vett karakter bitjelből összeállítja a kimenő adatot, a keret biteket automatikusan a felkonfigurált adatoknak megfelelően előállítja (stop bitek, paritás). Bizonyos események bekövetkezésekor megszakítást generál, így a soros kommunikáció gyakorlatilag a háttérben is folyhat, csak
minimális időt igényel a processzortól. A kommunikáció során esetleg fellépő hibákat automatikusan detektálja, ezeket az állapotregisztereiben jelzi. Ilyen módon a soros kommunikáció a programozó szempontjából csupán néhány regiszter írását és olvasását jelenti (esetleg megszakításkezelést). Az áramkörnek 10 nyolc egymást követő I/O portra és egy szabad megszakítási vonalra van szüksége. A PC-n szabványosan négy COM port kialakítására van lehetőség, de az esetleg szabadon maradt I/O tartományokban a nem használt IRQ vonalak felhasználásával többet is megvalósíthatunk. Asszinkron illesztő COM1 COM2 COM3 COM4 I/O tartomány 03F8h-03FFh 02F8h-02FFh 02E8h-02EFh 03E8h-03EFh Megszakítás IRQ4, INT 0Ch IRQ3, INT 0Bh IRQ4, INT 0Ch IRQ3, INT 0Bh A COM3 és a COM4 portokat leginkább a belső modemek szokták használni (pontosabban ezekre a címekre szokták őket állítani). A megszakítások a COM1 és a COM3 valamint a COM2 és
a COM4 esetében azonosak, de ez elvileg nem okoz gondot, mert az UART regisztereiből detektálni lehet, hogy melyik illesztő kért valójában megszakítást. A gondot inkább az szokta okozni, hogy a modemekhez mellékelt szoftverek nem ellenőrzik ezt, ezért megszakítás összeakadás előfordulhat. Ilyen esetben a COM3 és a COM4 portnak válasszunk valamilyen más megszakítást, például az IRQ5-öt. Ez a második nyomtató illesztő (LPT2) megszakítása és az esetek többségében szabad. Az áramkör egy belső frekvenciaosztó segítségével állítja elő a bemenő 1.8432MHz-es órajelből a szükséges Baud rate-nek megfelelő bitütemet. Alapesetben a bemenő órajelet 16-tal osztja, ezért a legnagyobb bitütem 115200Hz lehet. Az osztó értékét az ún Divisor Latch regiszterben kell megadnunk, amelynél az 1 érték a 16-os osztást jelenti. Az áramkör Base báziscíméhez relatívan adjuk meg a regisztereket, jelezve, hogy írhatók (W), olvashatók (R), vagy
írhatók és olvashatók is egyben (R/W). THR Base+00h (W) Transmit Holding Register Az adó adatregisztere. Az LCR (lásd később) regiszter DLA bitjének 0 állapotánál érhető el, ebbe a regiszterbe kell beírni az elküldeni kívánt adatot. Nyolc bitnél kisebb karakterhossz esetén a felső biteket az UART nem veszi figyelembe. RBR Base+00h (R) Receive Buffer Register A vevő bufferregisztere. Az LCR regiszter DLA bitjének 0 állapotánál érhető el, ebből a regiszterből olvashatjuk ki a legutoljára vett adatot. Nyolc bitnél kisebb karakterhossz esetén a felső bitek érvénytelenek DLL Base+00h (R/W) Divisor Latch Low A frekvenciaosztó Divisor Latch regiszterének alsó bájtja. Az LCR regiszter DLA bitjének 1 állapotánál érhető el, itt adhatjuk meg, illetve innen olvashatjuk ki a bitütemhez szükséges 16 bites osztó szó alsó bájtját. Az osztó 000lh értéke a 115200Hz-es frekvenciát jelenti. DLH Base+0lh (R/W) Divisor Latch High A frekvenciaosztó
Divisor Latch regiszterének felső bájtja. Az LCR regiszter DLA bitjének 1 állapotánál érhető el, itt adhatjuk meg illetve innen olvashatjuk ki a bitütemhez szükséges 16 bites osztó szó felső bájtját. Az oszló 000lh értéke a 115200Hz-es frekvenciát jelenti. 11 IER Base+021 (R/W) Interrupt Enable Register Megszakítás engedélyező regiszter. Az LCR regiszter DLA bitjének 0 állapotánál érhető el, ebben a regiszterben adhatjuk meg, hogy az áramkör milyen események bekövetkezésekor kérjen megszakítást a processzortól. Bitszám 7-4 3 2 1 0 IIR A bit jelentése Nem használt bitek Modem állapotváltozás megszakítás (Modem Status Interrupted) Vonali állapotváltozás megszakítás (Line Status Interrupted) Az adóregiszter üres megszakítás (THR Empty Interrupted) A vett adat érvényes megszakítás (RBR Data Ready Interrupted) Base+02h (R) Interrupt ldentification Register Megszakítás azonosító regiszter. A regisztert a soros vonali
megszakítás elején olvassuk ki, hogy a megszakítás okát detektálni tudjuk. A 18250 esetében csak az alsó három bit érvényes, a 16550 áramkörön a FIFO tár miatt egyéb kiegészítő információkat is tartalmaz. Bitszám 7 6 5 4 3 2 1 0 A bit jelentése 18250 : nem használt bitek 16550 : FIFO mód jelzése Nem használt bitek 16550 : az utolsó 4 adatciklusban nem volt adatkezelés II : Megszakítás azonosító bitmező (Interrupted Identification) Ha 0, a megszakítást ez az áramkör kérte Az II bitmező értékei: 00 - Modem állapotváltozás. A modem állapotregiszter (MCR) kiolvasása törli a kérést. 01 - Az adó adatregisztere (THR) kiürült, A THR újraírása törli a kérést. 10 - A vevő adatregiszterében (RBR) érvényes adat van. Az RBR regiszter kiolvasása törli a kérést. 11 - Vételi állapotváltozás. A vonali állapotregiszter (LSR) kiolvasása törli a kérést FCR Base+02h (W) FIFO Control Register A 16550 FIFO vezérlőregisztere. Ez
a regiszter az 18250 áramkörben nem található meg A regiszterrel a FIFO buffer működésének jellemzőit adhatjuk meg. 12 Bitszám 7 6 5 4 3 2 1 0 A bit jelentése FIFO végérték 00- 1 byte,01 – 4 byte, 10 – 8 byte, 11 – 14 byte Nem használt DMA mód Az adó FIFO buffer töltése A vevő FIFO buffer töltése A FIFO mód engedélyezése,tiltása LCR Base+03h (R/W) Line Control Register Vonali vezérlőregiszter. A vezérlőregiszterben az átvitel jellemzőit adhatjuk meg Bitszám 7 6 5 4 3 2 1 0 A bit jelentése DLA bit (Divisor Latch Access) 0 – adatregiszterek elérhetőek 1- A Divisor Latch regiszeterei(DLL,DLH) elérhetőek Az átvitel megszakítása A paritás negálása. A paritásvezérlő bit negáltja lesz a paritásbit Paritás típusa 0 – Páratlan paritás 1 – Páros paritás A paritás ellenőrzés engedélyezése Stop bitek száma 0 – 1 stop bit 1 – 2 stop bit Karakterhossz 00 – 5 bit, 01 – 6 bit, 10 – 7 bit, 11 – 8 bit A Divisor
Latch elérését a DLA bit vezérli. Az általánosan elfogadott konvenció az, hogy a DLA bit alapesetben mindig 0, csak a DLL és DLH regiszterek átírása idejére állítjuk be. MCR Base+04h (R/W) Modem Control Register Modem vezérlőregiszter. Bitszám 7–5 4 3 2 1 0 A bit jelentése Nem használt A vezérlő be és kimeneteinek összekötése ellenőrzésre. A bit 1 állapota a modemet inicializálja Az OUT2 jel vezérlése. Negált vezérlés Az OUT1 jel vezérlése. Negált vezérlés Az RTS jel vezérlése. Negált vezérlés A DTR jel vezérlése. Negált vezérlés 13 LSR Base+05h (R) Line Status Register Vonali állapotregiszter. A regiszterből a vonal állapotát, az esetleg bekövetkezett hibákat olvashatjuk ki. Bitszám 7 6 5 4 3 2 1 0 A bit jelentése FIFO hiba Az adó shiftregisztere kiürült (Transmit Shift Register Empty) Az adó adatregisztere kiürült (Transmit Holding Register Empty) BREAK jel detektálása Kerethiba (Framing Error) Paritáshiba
(Parity Error) Ráfutási hiba a vevő bufferben Érvényes adat a vevőbufferben MSR Base+06h (R) Modem Status Register Modem állapotregiszter. A regiszterből a modem vezérlőjelek állapotát olvashatjuk ki Bitszám 7 6 5 4 3 2 1 0 A bit jelentése DCD jel értéke (Data Carrier Detect) Az RI jel értéke (Ring Iindicator) A DSR jel értéke (Data Set Ready) A CTS jel értéke (Clear To Send) Változás a DCD utolsó olvasása óta Változás az RI utolsó olvasása óta Változás a DSR utolsó olvasása óta Változás a CTS utolsó olvasása óta SCR Base+07h (R/W) Scratch Register Általános regiszter, az áramkör működését nem befolyásolja. Soros kommunikáció BIOS függvényekkel A BIOS funkciókkal történő lekérdezéses üzemmód itt azt jelenti, hogy folyamatosan figyeljük a vevő állapotbitjeit, és ha egy karakter érkezik, akkor kiolvassuk és megjelenítjük azt. Ugyanekkor a billentyűzetet is figyeljük, és ha billentyűlenyomás történik, akkor a
lenyomott betű kódját elküldjük az adón keresztül. Ez tehát egy duplex kommunikáció, virtuálisan veszünk és adunk is egyszerre. Hátránya a dolognak, hogy a lekérdezés a processzort szinte teljesen leköti, így az mást nem is nagyon tud csinálni. Két PC esetében az átvitelhez a belső hurkos null-modem kapcsolást használjuk, mert a BIOS rutinok a kommunikáció során figyelik a modemvezérlő jeleket is. Ha számítógépet és modemet akarunk összekötni akkor a full-duplex kapcsolást kell használni. A programban a lehetséges kommunikációs paraméterek beállításához állandókat definiálunk(átviteli sebességhez, paritás ellenőrzéshez, stop bitek számához, adatszélesség beállításához és a COM port számához is), ezekkel könnyen és olvashatóan megadhatjuk a jellemző értékeket. Az állandók bithelyesek, így a beállítást egyszerű logikai VAGY művelettel tudjuk megadni az inicializáló rutin számára. 14 Mj : Ebben a
programban csupán két változót használunk. A COMport(byte típusú) tárolja a kommunikációhoz használt COM port sorszámát, a c karaktert pedig a billentyű leolvasásához használjuk. InitSerialPort Asm mov dl,COM {dl-be töltjük a COM port számát} xor dh,dh {nullázuk a dh regisztert} mov COMport,dx {tároljuk a COMport változóban a COM port számát} xor ah,ah {ssoros port inicializálása} mov al,Defaults {az alapbeállításokat az al-be töltjük} int 14h End; InitSerialPort: A kommunikációhoz használt soros port beállítása. Az eljárás a COM paraméterrel megadott számú soros portot inicializálja és beállítja a Defaults-ban megadott kommunikációs paramétereket. A működési paramétereket a definiált állandók logikai VAGY kapcsolatával adhatjuk meg, A rutin a COMport változó értékét inicializálja. a további eljárások pedig ezt használják a soros port kiválasztásánál. SendChar Asm wait: mov dx,COMport {dx-be töltjük a COMport
számát} mov ah,03h {állapotregiszterek lekérdezése} int 14h and ah,00100000b {az LSR regiszter 5.bitjét vizsgáljuk} jz wait {Várakozunk,a míg a THR regiszter kiürül} mov dx,COMport {a dx-be töltjük a COM port számát} mov ah,01h {egy karakter elküldése} mov al,C {az al regiszterbe tesszük az adatot} int 14h End; SendChar: Egy karakter elküldése a soros porton. Az eljárás a paraméterként megadott C karaktert elküldi a COMport változó által meghatározott illesztőn. A rutinban a 03h funkcióval vizsgáljuk, hogy az adó THR regisztere szabad-e. Amennyiben itt még van adat, várakozunk, majd a 01h funkcióval elküldjük a C karaktert. Function ReceiveChar : char Asm mov dx,COMport {dx-be töltjük a COM port számát} mov ah,02 {karakter vétele} int 14h End; ReceiveChar: Egy karakter vétele a soros porton. A függvény a COMport változó által meghatározott illesztőről beolvas egy karakter. A karakter érvényességét ebben a függvényben nem
vizsgáljuk, csupán a 02h funkcióval elvégezzük a beolvasást. 15 Function DataReady : bolean Asm mov dx,COMport {dx-be töltjük a COM port számát} mov ah,03 {állapotregiszterek lekérdezése} int 14h mov al,ah {a vonali állapotregisztert az al-be töltjük} and al,00000001b {}csak a DataReady bitet hagyjuk meg End; DataReady: A vételi buffer vizsgálata. Ezzel a függvénnyel a 03h funkción keresztül lekérdezzük a vonali állapotregisztert, majd ennek 0. bitjét adjuk vissza A 0 bit (Data Ready) jelzi, ha az RBR regiszterben újabb vett karakter van. Ha tehát ez a függvény igaz értékkel tér vissza, a ReceiveChar eljárással ki lehet olvasni a vett adatot. A főprogramban az InitSerialPort eljárással inicializáljuk a soros portot, jelen esetben a COM2-t. Amennyiben két gépet kötöttünk össze, úgy minden paramétert azonosra kell állítani mindkét oldalon, máskülönben a gépek nem tudnak kommunikálni. Az inicializálás után ha egy billentyűt
lenyomunk, akkor a SendChar eljárással elküldjük azt a soros porton, majd kijelezzük a képernyőn. A vétel hasonlóképpen egyszerű: figyeljük a DataReady függvénnyel, hogy érkezette új karakter Ha igen, akkor a ReceiveChar függvénnyel beolvassuk azt, majd megjelenítjük /if DataReady then write(ReceiveChar)/ A sebesség korlátozott, csak 9600 bps-el lehet adni és venni, ráadásul a folyamatos lekérdezés feleslegesen terheli a processzort. (A BIOS rutinok is korlátoznak minket, hiszen az UART ennél sokkal többet tud.) Lekérdezéses adatátvitel A következő metódusok segítségével bemutatjuk, hogy a soros port BIOS rutinokkal megvalósított eljárásait és függvényeit hogyan tudjuk kiváltani az UART regisztereinek közvetlen elérésével. A közvetlen elérés amellett, hogy gyorsabb is, mint a BIOS szubrutinok, nagyobb szabadságot enged meg, az áramkör több képességét is használhatjuk, ugyanakkor ezen a módon a legegyszerűbb
háromvezetékes null-modem összekötést is használhatjuk két gép között. Itt is állandókat definiálunk a paraméterek megadásához. Lényeges különbség viszont, hogy a sebességet most a Divisor Latch osztó osztási értékeivel adjuk meg. így a 9600 bps-nél magasabb sebességet is megadhatunk. PL: bps 9600=12, bps 57600=2, bps 115200=1 A COM portokat itt nem sorszámozzuk, hanem közvetlenül a báziscímekkel hivatkozunk rájuk.(lásd egy korábbi táblázatban) A paritás ellenőrzés típusa, a stop bitek száma és a karakterek hossza bithelyesen az LCR regiszterbe írható, ezért itt is az egyszerű logikai VAGY kapcsolattal adhatjuk meg a kommunikáció paramétereit. A regiszterek neveit és eltolásaikat a bázishoz képest összerendeljük. Erre igazából nem lenne ugyan szükség, de az assembler listákat olvashatóbbá teszi, ha az eltolásokat nevekkel adjuk meg. 16 SetSpeed Asm mov dx,Base {a COMport báziscímét a dx –ben tároljuk} add
dx,LCR {LCR=$03/ a dx-et az LCR-re állítjuk} in al,dx {LCR értékét beolvassuk} or al,10000000b {DLA bitet bebillentjük} out dx,al {LCR értékét visszírjuk,így a DLL és a DLH regiszterek elérhetőek} mov bl,al {LCR utolsó értékét tároljuk} sub dx,LCR {dx az LCR-re mutat} mov ax,Speed {az ax-be beolvassuk a Divisor Latch sebességosztót} out dx,ax {átírjuk a DLL és DLH regisztereket} add dx,LCR mov al,bl {az LCR tárolt értékét az al-ba töltjük} and al,01111111b {DLA-t kinullázzuk} out dx,al {LCR eredeti értékét visszaírjuk} End; SetSpeed: A kommunikáció sebességének beállítása. Ez az eljárás a Speed 16 bites értékkel megadott osztót állítja be a Divisor Latch-be. Az eljárás elején az LCR regiszter DLA bitjét 1re állítjuk, ekkor a DLL és a DLH regiszterek elérhetővé válnak A Speed értékét kiírjuk a DLL és DLH regiszterekbe, majd figyelembe véve az LCR eredeti értékét, az LCR-t visszaállítjuk, de a DLA bit 0 lesz. A
kommunikáció során a DLA bit mindvégig 0 is marad, ezért az adásnál a THR, a vételnél pedig az RBR regiszter mindig elérhető. A sebességet természetesen a kommunikáció megkezdése előtt beállítjuk, azután már nem módosítjuk. InitSerialPort Asm mov dx,COM {a COM port báziscíme a dx-be kerül} mov Base,dx {dx-ből a COM port báziscíme a Base változóba kerül} in al,dx {RBR /vezérlő buffer regiszter/-t olvassuk} mov al,Defaults {a kommunikáció paraméterei az al-be kerülnek} and al,01111111b {a DLA bitet nullázzuk} add dx,LCR {a dx az LCR-re mutat} out dx,al {LCR-be írjuk a paramétereket} inc dx {a dx-et az MCR-re állítjuk} in al,dx {az MCR értékét az al-be olvassuk} and al,$01 {csak a DTR bitet hagyjuk meg} or al,$0a {OUT2=1 és RTS=1/alacsony jelszintre állítjuk őket} out dx,al {MCR / modem vezérlő regiszter/ értékét kiirjuk} mov dx,Base {a dx az RBR-re mutat} in al,dx {RBR-t kiolvassuk} add dx,MSR in al,dx {MSR-t kiolvassuk} dec dx in
al,dx {LSR-t/vonali állapot regiszter/ kiolvassuk} sub dx,3 in al,dx {IIR-t/megszakítás azonosító regiszter/ kiolvassuk} End; InitSerialPort: A kiválasztott illesztő inicializálása és beállítása a megadott kommunikációs paraméterekre. A paramétereket a Defaults paraméterben (Paritás ellenőrzés beállítása, Stop bit számának beállítása, Adatbitek száma) kell megadni, amelyet a fentebb definiált állandók logikai VAGY kapcsolatából képezhetünk. Az eljárás beállítja a vonali vezérlő LCR regisztert a Defaults értékre, de a DLA bitet következetesen nullázza. Az LCR mellett a modemvezérlő 17 MCR regisztert is beállítjuk: a DTR jelet meghagyjuk, de az Out2 és az RTS jelet alacsony szintre állítjuk. Ezután elvégzünk néhány feleslegesnek tűnő - de a helyes működéshez elengedhetetlen - kiolvasást. Az UART ezeket a kiolvasásokat protokollárisan igényli, ez az inicializálás része. Ha ezeket az olvasásokat nem végeznénk
el, az áramkör nem működne helyesen. SendChar Asm mov dx,Base {a COM port báziscímét a dx-be töltjük} add dx,LSR {a dx-et az LSR-re álljtjuk} wait: in al,dx {vonali állapotregiszter beolvasása} and al 00100000b {a THR /adó adatregisztere/ üres-e} jz wait sub dx,5 {dx-et a THR-re állítjuk} mov al,C {al-be töltjük a küldendő karaktert} out dx,al {THR-be írjuk az adatot} End; SendChar: Egy karakter elküldése. Az eljárás a C karaktert elküldi a Base által kiválasztott illesztőn. Az eljárásban figyeljük a vonali állapotregiszter 5 bitjét, amely akkor billen 1-be, ha az adó egy karaktert teljes egészében elküldött, tehát a THR regiszter (az adó adatregisztere) kiürült. Ameddig ez a bit 0, várakozunk, ha pedig 1-re vált, a C karaktert beírjuk a THR regiszterbe, amelyet az UART így elkezdi elküldeni. Function ReceiveChar : Char Asm mov dx,Base {a COM port báziscímét a dx-be töltjük} in al,dx {RBR-t /vevő buffer regisztere/ beolvassuk} End;
ReceiveChar: Egy karakter vétele. A függvény egyszerűen beolvassa az RBR regiszter (vevő bufferregisztere) tartalmát, majd visszaadja azt. A vett karakter érvényességét itt nem vizsgáljuk, az a DataReady függvény feladata. Function DataReady : boolean Asm mov dx,Base {a COM port báziscímét a dx-be olvassuk be} add dx,LSR {a dx-et az LSR-re állítjuk} in al,dx {az LSR-t / vonali állapotregiszter/ beolvassuk} and al,00000001b {csak a DataReady bitet hagyjuk meg} End; DataReady: A vett karakter érvényességének ellenőrzése. A függvény beolvassa a vonali állapotregisztert, majd visszaadja ennek 0. bitjét A 0 bit a DataReady bit, amely abban az esetben billen 1-be, ha a vevő által vett karakter teljes egészében megérkezett, azaz érvényes. A soros port inicializálása ebben az esetben két eljárás meghívását jelenti. Elsőként beállítjuk a kommunikáció jellemzőit az InitSerialPort eljárással az előre definiált állandók segítségével
(Paritás ellenőrzés beállítása, Stop bit számának beállítása, Adatbitek száma). Utána a SetSpeed eljárással beállítjuk a frekvenciaosztót a kívánt sebességre. A két eljárás időben nem cserélhető fel, mert az InitSerialPort ad kezdőértéket a Base változónak, amit aztán az összes 18 többi rutin - így a SetSpeed is - a soros port báziscímének tekint. Ezért a programban az InitSerialPort eljárást semmilyen más - a kommunikációs portot kezelő - rutin nem előzheti meg. Az adó rész megvizsgálja, hogy volt-e billentyűlenyomás, és ha igen, akkor a karaktert elküldi a SendChar eljárással. A vevő rész a DataReady bit alapján eldönti, hogy érkezett-e újabb karakter az RBR regiszterbe, és ha igen, kiolvassa, majd kijelzi azt. A módszernek van néhány alapvető hibája. Ha mondjuk egy modemmel próbálunk kommunikálni és a sebességet felvisszük 19200 bps felé, rögtön kitűnik, hogy sajnos néhány karakter a vétel során
egyszerűen elveszik. Ennek oka, hogy a lekérdezéses üzemmód nem garantálja, hogy minden vett karaktert ki tudunk olvasni. Ráadásul hibadetektálást sem csináltunk. Így aztán nagyobb sebességeknél előfordulhat, hogy az RBR bufferben (vevő bufferregisztere) lévő érvényes karaktert még ki sem olvassuk, máris újabb karakter érkezik. Ez a ráfutási {Overrun) hiba, amely ebben az esetben sajnos elkerülhetetlen. Az adatvesztés nélküli kommunikációt megszakításos adatátvitellel érhetjük el. Megszakításos adatátvitel A megszakításos átvitel alapja, hogy az UART a kommunikációs közegben - az RS232 vonaton bekövetkező változásokat detektálja és megszakítást kér a processzortól. A processzor így „azonnal" ki tudja szolgálni az UART kérelmeit, nincs felesleges várakozási idő. Az UART négy esetben kérhet megszakítást: • • • • A modem állapotregiszterben (MSR) változás történik. Ezzel bármilyen - a modem
állapotában bekövetkező - változást detektálni tudunk, és a megfelelő módon reagálhatunk rá. A megszakítás kérését az MSR regiszter kiolvasása törli, ebből tudja az UART, hogy a kérés kiszolgálása megkezdődött. A vonali állapotregiszterben (LSR) változás történik. A kommunikáció során fellépő hibákat detektálhatjuk vele, azonnali beavatkozásra van lehetőségünk. A kiszolgálás első lépéseként ki kell olvasnunk az LSR regisztert, ez jelzi az UART-nak, hogy a kérést elfogadtuk. Az adó adatregisztere (THR) kiürül. Megszakításos adásnál ez az esemény jelzi, hogy az UART az aktuális karaktert elküldte, így kész az újabb adat továbbítására. Ezt a kérést is törölnünk kell, ebben az esetben a THR regiszter újrafeltöltése a feladat. A vevő bufferregisztere (RBR) megtelik. Megszakításos vételnél ez az esemény jelzi, hogy a vevő bufferregiszterében érvényes adat van, azt ki lehet olvasni. A kérést az RBR
regiszter kiolvasása törli. Ezen a módon a vett karakter szinte azonnal kiolvasható az RBR regiszterből, tehát a ráfutási hibát kiküszöbölhetjük. A megszakítást azonosító (IIR) regiszterben mind a négy esetet külön bit jelzi, hiszen adódhat olyan helyzet, hogy a megszakításokat kiváltó események egyszerre következnek be. Például egy karakter teljes elküldése a THR regiszter kiürülését és a vonali állapotregiszter változását is előidézi, tehát két megszakítást kiváltó ok is lesz. Az IIR regiszterben a 0 bit ráadásul még azt is jelzi, hogy egyáltalán az adott illesztő kérte-e a megszakítást. Mindezek alapján pontosan detektálható, hogy melyik soros illesztő milyen esemény bekövetkezése miatt kért megszakítást még akkor is, ha két illesztő - mint például a COM1 és a COM3 - ugyanazt a megszakítási vonalat használja. A COM3 és a COM4 portok esetében elő szokott fordulni, hogy ezek az illesztők az IRQ5 vagy az
IRQ7 vonalat használják A megszakítások ütközését mindenképpen ki kell küszöbölnünk 19 Általában az adási rész ugyanúgy működik majd, mint a Lekérdezéses adatátvitel esetén. A vételnél viszont megszakítást alkalmazunk. Minden karakter vételénél az UART egy megszakítást generál. A megszakítási rutin beolvassa a karaktert az RBR regiszterből, majd ezt egy átmeneti bufferterületre helyezi. A főprogram figyeli a buffert, és ha újabb karakter érkezik bele, kiolvassa, azután pedig kijelzi azt. A bufferezéshez most az ún körforgásos buffertechnikát alkalmazzuk. A megszakítás egy adott hosszúságú fenntartott memóriaterületre írja ki sorban a vett karaktereket. Ha a kiírás eléri a buffer végét, akkor ismét az elejéről kezdjük el feltölteni A folyamatos olvasása a buffernek ugyanezzel a technikával történik. Amikor az olvasás eléri a buffer végét, az elejéről kezdjük az olvasást. A bufferre két mutató mutat: az
írási mutató - a programban az RBS (Receive Buffer Start) -, amely mindig a következő irható bájtra mutat, és az olvasási mutató - a programban az RBE (Receive BufferEnd) -, amely mindig a következő kiolvasandó bájtot mutatja. Az RBS mutató mindig az RBE előtt jár, hiszen a beírás előbb történik meg, mint a kiolvasás. Ha az RBE utoléri az RBS-et, az azt jelenti, hogy nincs több kiolvasatlan karakter a bufferben, tehát az összes beérkezett karaktert feldolgoztuk. Ha viszont valamilyen oknál fogva nem olvassuk ki a buffert időben, akkor - a buffer körkörös jellegénél fogva - előfordulhat, hogy az RBS éri utol az RBE-t. Ez viszont azt jelenti, hogy a buffer túlcsordult, hiszen egy olyan karakterre kellene ráírni, amelyet még ki sem olvastunk. A buffer túlcsordulását elkerülhetjük, ha programunk megfelelő gyorsasággal dolgozza fel a beérkező adatokat, és ha elég nagy a buffer mérete. A vevő buffer méretét definiálja a BufferHossz
változó. A BufferMask ennél eggyel kisebb értéket vesz fel. A buffer hosszának 2 hatványát választottuk Ez azért jó így, mert a buffer végénél a mutatókat egy egyszerű logikai ÉS kapcsolattal - bitmaszkolással - tudjuk nullázni. ReceiveIRQ Asm push DS { a DS-t a veremben tároljukj} pusha {általános regiszterek letétele a verembe} mov dx,Seg @DATA mov DS,dx {DS-t az adatszegmensre állítjuk} mov dx,Base {a COM port báziscímét a dx-be töltjük} in al,dx {RBR-t /vevő buffer regisztere/ beolvassuk} lea bx,Buffer {dx-et a vevő buffer elejére állítjuk} add bx,RBS {a következő üres helyre pozícionálunk} mov [bx],al {tároljuk a bufferben a karaktert} inc RBS {növeljük az írási mutatót} and RBS,BufferMask {maszkoljuk a mutatót} mov al,$20 {megsazakítás vége jel} out $20,al popa pop DS {regisztereket visszaolvassa a veremből} iret {visszatérünk a megszakításból} End; 20 A ReceiveIRQ megszakítási rutin végzi a karakterek vételét. Az
eljárás elején elmentjük a felhasznált regisztereket, majd a DS szegmensregisztert a program adatszegmensére állítjuk. Ezután kiolvassuk az UART RBR regiszterét, amelyben a vett karakter található. Most felesleges megvizsgálni, hogy a Data Ready bit érvényes adatot mutat-e, hiszen éppen azért következett be a megszakítás, mert az adat érvényes. A beolvasott adatot eltároljuk a Buffer vevőbufferben, majd növeljük az RBS mutatót. A mutató BufferMask értékkel való maszkolása biztosítja, hogy az RBS a buffer végén ismét nullázódjon. Végül jelezzük a 8259A áramkörnek, hogy a megszakítást kiszolgáltuk. A regiszterek visszaolvasása után visszatérünk GetChar Asm mov RDS,0 {töröli a vett karakter érvényes jelet} mov ax,RBS cmp axRBE {egyezik-e az írási és az olvasási mutató} jz exit lea bx,Buffer {bx-et a vételi bufferre állítjuk} add bx,RBE {a következő olvasási helyre pozícionálunk} mov al,[bx] {beolvassuk a karaktert} inc RBE
{növeli az olvasási mutató értékét} and RBE,BuffeMask {maszkoljuk a mutatót} inc RDS {a vett karakter érvényes jelet beállítjuk} exit: End; GetChar: A következő vett karakter kiolvasása. Ezt a függvényt hívja a főprogram a vett karakterek kiolvasására. Az eljárás visszatér a vett karakterrel Az RDS változót igaz értékre állítja, ha a karakter érvényes. A szubrutin elején az RDS-t hamisra állítjuk, majd megvizsgáljuk, hogy az RBS és RBE buffermutatók egyenlők-e. Ha egyenlők, az azt jelenti, hogy még nem érkezett újabb karakter, ekkor visszatérünk, az RDS pedig hamis értékű lesz. Ha viszont az RBS nem egyenlő az RBE-vel, akkor a bufferben új karakter van. Ezt kiolvassuk onnan. majd az RBE mutatót növeljük A mutató BufferMask értékkel való maszkolása biztosítja, hogy az RBE a buffer végén ismét nullázódjon, azaz az olvasás a buffer elejétől folytatódjon. Kilépés előtt igaz értékre állítjuk az RDS-et, hiszen a vett
karakter most érvényes. Lehetőség van megszakítási vonalainak engedélyezése és tiltása. (port[$21]-en /$21 portcímű porton/). Ezzel a két eljárással a megszakításvezérlő áramkör megszakítási maszkbájtját tudjuk állítani. A megszakítási maszkbájtban a 0 bitek engedélyezik, az 1 bitek pedig tiltják az adott vonal megszakítását. Ezzel a két eljárással csak az első megszakításvezérlőt tudjuk állítani, tehát csak az IRQ0.IRQ7 megszakítási vonalakat vezérelhetjük velük Az összes szükséges beállítást el kell végezni a kommunikáció megkezdése előtt. Elsőként beállítjuk a Base és az IRQ változókat. Kiolvassuk az eredeti megszakításvektort és eltároljuk (pl: OldVect változóban).Következő lépésként letíltjuk a megszakításokat (asm cli end;) Ezután beállítjuk a kommunikáció jellemzőit az InitSerialPort eljárással, majd megadjuk a sebességet a SetSpeed rutinnal. A véteti megszakítások engedélyezéséhez
az IER UART regiszter 0 bitjét 1be billentjük, majd beállítjuk a megszakítási paramétereket a SetIRQ-val A végén újra engedélyezzük a megszakításokat (asm sti end;) A megfelelő beállítások után a vétel és az adás automatikus, a vétel megszakítás alatt folyik. Az adás a következő módon történik. A ReceiveChar eljárás a GetChar-t használja a karakterek 21 kiolvasására, amely a vételi bufferből olvas, magához az UART áramkörhöz semmi köze. A buffer írása a ReceiveIRQ megszakítási rutin feladata. A bufferezési mechanizmuscélja, hogyha a bejövő adatokat fel is kell dolgozni, az már jelentős időt elvehet a processzortól, és ez alatt a megszakítás akkor is venni fog, amikor a főprogram éppen teljesen mást csinál. A vétel folyamatos marad, bármilyen egyéb bűvészkedésre is kényszerülünk a beérkező adatokkal. (Ha például a meglévő rutinokra egy mester-szolga rendszerű adatkommunikációt - esetleg valamilyen
terminál emulációt - akarunk felépíteni, ott a szolgagépnek a mestertől érkező parancsokat fel kell dolgoznia.) A programrészletekben használt assembler parancsok jelentése : • add : összeadja a két operandust, az eredményt az elsőbe helyezi el • and : a két operandust bitről bitre ÉS kapcsolatba hozza, eredményt az elsőbe teszi • cli : a megszakítás jelzőbit törlése, nem szolgálja ki a processzort • cmp : összehasonlítás, az operandusok változatlanok maradnak • dec : a megadott regiszter vagy memória rekesz értékét eggyel csökkenti • in : az elsőként megadott regiszterbe(al vagy ax) beolvas a második operandusként megadott portról • inc : a megadott regiszter vagy memória rekesz értékét eggyel növeli • int : SW megszakítás generálása • iret : visszatérés a megszakítást kiszolgáló rutinból • jz : ugrás, ha Zéro bit értéke 1 • lea : effektív címbetöltés • loop : hátultesztelő ciklus feltételes
vége • mov : az első operandus értékét a másodikba másolja át • nop : üres utasítás • or : bitenkénti vagy kapcsolatba hozza a két operandust, eredményt az elsőbe helyezi • out : az elsőkint jelzett regiszter tartalmát kiküldi a másodikként jelzett portra • pop :kiemeli a veremből az SS:SP által mutatott szót, majd növeli az SP-t 2-vel. • popa : általános regiszterek kiemelése a veremből • push : csökkenti az SP-t 2-vel, szó letétele a verembe az SS:SP címre • pusha : általános regiszterek letétele a verembe • sti : a megszakítási jelzőbit beállítása • sub : a második operandusból kivonja az elsőt és elhelyezi az eredményt az elsőben • xor : bitenkénti KIZÁRÓ VAGY műveletet végez el, majd az eredményt az elsőben elhelyezi 22 Felhasznált irodalom : [1] Markó Imre (2001) : PC HARDVER – Konfigurálás és installálás LSI Oktatóközpont, Bp [2] Abonyi Zsolt : PC hardver kézikönyv [3]
www.viddatacom/vidlinkshtm [4] www.radcom/networks/1995/rs232/rs232htm 23