Ovládání externích zařízení přes sériový port a Delay( ) 

Počítač může sloužit nejenom jako chytrý psací stroj nebo kalkulačka, ale může ovládat i jiná zařízení k němu připojená. Pokud zprostředkujeme počítači vhodné vstupy a výstupy, můžeme počítač použít k měření, regulaci či ovládání jiných přístrojů a zřízení.

Pro tento účel, pokud pomineme speciální desky, se jeví nejlepší k použití standardní rozhraní tiskárny a sériových linek. Pomocí programového vybavení a vhodného hardware připojeného na standardní porty můžeme svůj počítač rozšířit o vstupy, výstupy, připojit AD převodník a pomocí něho měřit napětí, proudy snímat výstupy různých snímačů a čidel, případně připojit externí LCD displej. Příklady jednoduchých zařízení je možno najít na stránkách I2C Školky.

Port tiskárny - poskytuje 8 datových linek pro vstup nebo výstup dle režimu portu a několik vstupních a výstupních linek.
Sériový port - poskytuje 5 vstupních a 3 výstupní linky.

Pro seznámení s prací s těmito porty pod DOSem doporučuji knihu „Využití rozhraní PC“ od Burkhard Kainka. V této knize je dobře a podrobně popsáno použití portů na různých příkladech. Příklady uvedené v knize jsou napsány v Turbo Pascalu a v Basicu.

Pokud chceme používat porty pod operačním systémem Windows existuje obdobná kniha „Využití rozhraní PC pod Windows“ od stejného autora. Probírá obdobné příklady jako pod DOSem, jen jako programovací jazyky jsou použity DELPHI a Visual Basic.

Dále je popisováno jen ovládání sériových portů.. 
Tyto jsou ve většině počítačů dva a využit je většinou jen jeden pro myš, případně žádný pokud je myš připojena přes zásuvku PS2 nebo přes USB. Dalším důvodem pro použití sériových portů pod Windows je jejich přímá podpora systémem mnoha funkcemi. Není zde popsáno využití sériových komunikačních portů v jejich základním použití, to je pro sériovou komunikaci, ale využití vstupu a výstupu v bitovém režimu. Pokud budeme chtít použít sériové porty pro sériovou komunikaci, bude nejlepší využít komponenty pro komunikaci, např: „ComPort Library“ od Dejan Crnila

Na Sériovém portu jsou k dispozici jsou tyto linky:
Vstupní
CTS
DSR
DCD
RING

Výsupní
RTS
DTR
TX

Pokud nevíte jak jsou jednotlivé linky rozloženy na konektoru, můžete se podívat na článek o rozhraní RS232na HW.CZ.

A P I
 
Programy v knize „Využití rozhraní PC pod Windows“ využívají ke zprostředkování styku s porty knihovnu PORT.DLL. Tato sice usnadňuje programování, ve skutečnosti však také zakrývá skutečný postup přístupu k sériovým portům.

Ve Windows můžeme použít k přístupu k portům samozřejmě přímý přístup na hw porty, ale může se stát že Windows nám porty neuvolní, většinou pokud máme Windows novější než W98 . Proto je lepší využít systémových API funkcí pro obsluhu komunikačních portů, pak nemusíme znát ani fyzické adresy portů. Pokud využijeme API pro ovládání, program se nezkomplikuje ani nezvětší. Popis API funkcí je možno najít ke stažení třeba na stránkách LCC.
Program pro obsluhu sériových portů je na konci článku. Je vněm jen základní obsluha pro nastavení výstupních linek a přečtení vstupních.

Delay( )
 

Další problém, s kterým jsem se setkal při přechodu programování pod Windows je, že žádný programovací jazyk pro Windows nenabízí funkci, proceduru, Delay, tak jak jsem byl zvyklý z programování v Turbo Paskalu nebo C pod DOSem. Jediné, co je přímo použitelné je funkce Sllep(), při experimentování s ní jsem zjistil, že se nechová tak, jak bych si představoval, ale spíš asi vykonává něco jako VzavamSeCasuNa x milisekund. I časovač implementovaný v komponentách BCB se neprojevil jako nejlepší. Mezi API funkcemi se najdou funkce, které umožní potřebné prodlevy realizovat.

Jedná se o funkce :
QueryPerformanceFrequency - vrací rozlišení tiku za sekundu.
QueryPerformanceCounter - vrací hodnotu čítače, s frekvencí QueryPerformanceFrequency.

Vhodným použitím těchto API funkcí lze realizovat kýženou funkci Delay( ), a to dokonce s větším rozlišením než v původní, a to na cca 1. mikrosekundu.

Výsledky otestování na několika strojích vyšly následovně:
pro WIN98:
QueryPerformanceFrequency=1193180
tj. rozlišení = 0,838 mikrosekund, prěsneji 1/1193180

zakladní chyba, dvě čtení QueryPerformanceCounter okamžitě po sobě:
největší = 29 tiku 486/100MHz
nejmenší = 5 tiku PII/800Mhz

pro WIN2000
QueryPerformanceFrequency=3579545
tj. rozlišení = 0,2794 mikrosekund, prěsneji 1/3579545

zakladní chyba, dvě čtení QueryPerformanceCounter okamžitě po sobě:
největší = 5tiku Celer/750MHz
nejmenší = 3 tiku Celer/900Mhz

Děkuji Šimonovi za spolupráci při testování.

Další funkci, kterou jsem našel pro časování je časovač pro multimédia, ten je zařazen v multimediálních API funkcích. Tento časuje po jedné milisekundě a po prohlédnutí hlavičkového souboru pro multimédia, kde je tento časovač umí pravděpodobně i další kousky.
Oba dva časovače, čítače jsou použity v přiloženém programu pro vytvoření funkcí:

Wait_us( ); časuje s rozlišením jedné mikrosekundy
Wait_ms( ); časuje s rozlišením jedné milisekundy

Pokud použijeme funkce tak, jak jsou zde napsány, je třeba počítat s tím, že po dobu jejich běhu není okno občerstvováno. Což při občasném osahavání hw připojeného na sériové rozhraní nemusí být na závadu. Pokud budeme chtít časování ještě vylepšit; můžeme funkcím zvýšit prioritu, případně spustit v samostatném vlákně. Samozřejmě můžeme pro časování použít i komponenty stažené z Internetu, tyto komponenty mohou poskytovat větší komfort i ovládání než zde uvedené funkce, ale jednodušeji to již asi nejde. Všechny zde uvedené funkce a programy jsou napsané v Borland C++Builder 5 Standard a odzkoušené pod WIN98.

Pomocí zde popsaných funkcí můžeme například rozsvítit ledku.
Program a zdrojáky pro blikání na DTR

Případně můžeme realizovat I2C sběrnici a připojit si například nějaký HW například ze stránky o I2C školce. Pokud budete zkoušet I2C nezapomeňte, že je zapotřebí upravit napěťové úrovně z RS232 na úrovně vhodné pro sběrnici I2C, k tomu můžete použít Převodník na I2C pro připojení PC přes COM.

Pro odzkoušení některých integrovaných obvodů můžete použít program I2C_TEST. Zatím jsou funkční jen první tři záložky. Původní program byl napsán v DELPHI s využitím PORT.DLL, po vypršení trial verze jsem si zakoupil BCB a program přepisuji s využitím API funkcí zde popsaných, takže ne vše je ještě funkční.

  

Programy jsou freeware, co do užívání tak i šíření, za dodržení platných zákonů a slušného chování. Je poskytován tak, jak je bez jakýchkoliv záruk a používání je na vlastní nebezpečí.



PortCom.h - hlavičkový soubor
#ifndef header_PortCom
#define header_PortCom

#include 
#include 
#include 
//--------------------------------------------------------------------------//
bool OpenCom(int CisloComu);
void CloseCom(void);
void Wait_us(unsigned __int64 prodleva);
void CloseI2C(void);
void SetDTR(bool x);
void SetRTS(bool x);
void SetTX(bool x);
bool GetCTS(void);
bool GetDSR(void);
bool GetRing(void);
bool GetRLSD(void);
void Wait_us(unsigned __int64 prodleva);
void Wait_ms(int prodleva);

#endif


PortCom.C - funkce pro přístup a čtení linek seriového poru. #include "PortCom.h" HANDLE ComHandle; //Handle pro COM //--------------------------------------------------------------------------// // Otevr COM port pro dalsi pouziti bool OpenCom(int CisloComu) { char JmenoComu[6]; CloseHandle(ComHandle); sprintf(JmenoComu,"COM%i",CisloComu); ComHandle=CreateFile(JmenoComu,GENERIC_READ|GENERIC_WRITE, 0,NULL,OPEN_EXISTING,0,NULL); if(ComHandle==INVALID_HANDLE_VALUE) return (0); else return (1); } //--------------------------------------------------------------------------// // Uzavre COM port void CloseCom(void) { CloseHandle(ComHandle); } //--------------------------------------------------------------------------// // Podle predaneho parametru nastavi DTR void SetDTR(bool x) { EscapeCommFunction( ComHandle,x ? SETDTR : CLRDTR ); } //--------------------------------------------------------------------------// // Podle predaneho parametru nastavi RTS void SetRTS(bool x) { EscapeCommFunction( ComHandle,x ? SETRTS : CLRRTS ); } //--------------------------------------------------------------------------// // Podle predaneho parametru nastavi TX void SetTX(bool x) { EscapeCommFunction( ComHandle,x ? SETBREAK : CLRBREAK ); } //--------------------------------------------------------------------------// // Nacte stav vstupu CTS bool GetCTS(void) { DWORD ModemStatus; GetCommModemStatus(ComHandle,&ModemStatus); ModemStatus=ModemStatus & MS_CTS_ON; return ((bool)ModemStatus); } //--------------------------------------------------------------------------// // Nacte stav vstupu DSR bool GetDSR(void) { DWORD ModemStatus; GetCommModemStatus(ComHandle,&ModemStatus); ModemStatus=ModemStatus & MS_DSR_ON; return ((bool)ModemStatus); } //--------------------------------------------------------------------------// // Nacte stav vstupu RING bool GetRing(void) { DWORD ModemStatus; GetCommModemStatus(ComHandle,&ModemStatus); ModemStatus=ModemStatus & MS_RING_ON; return ((bool)ModemStatus); } //--------------------------------------------------------------------------// // Nacte stav vstupu RLSD bool GetRLSD(void) { DWORD ModemStatus; GetCommModemStatus(ComHandle,&ModemStatus); ModemStatus=ModemStatus & MS_RLSD_ON; return ((bool)ModemStatus); } //--------------------------------------------------------------------------// // Prodlevu v mikrosekundach void Wait_us(unsigned __int64 prodleva) { unsigned __int64 frekvence,citac,stop; QueryPerformanceCounter((LARGE_INTEGER *)&citac); QueryPerformanceFrequency((LARGE_INTEGER *)&frekvence); stop=((prodleva*frekvence)/1000000)+citac+1; while (stop>citac) QueryPerformanceCounter((LARGE_INTEGER *)&citac); } //--------------------------------------------------------------------------// // Prodleva v milisekundach void Wait_ms(int prodleva) { int stop ; timeBeginPeriod (1); stop = timeGetTime() + prodleva; while (stop>timeGetTime ()); timeEndPeriod (1); } //---------------------------------------------------------------------------
Vlastní program, bliká na DTR COM1: #include #include "PortCom.h" //--------------------------------------------------------------------------- int main(int argc, char* argv[]) { OpenCom(1); while (1) { SetDTR(true); Wait_ms(200); SetDTR(false); Wait_us(200000); } } //---------------------------------------------------------------------------



Literatura s dalšími informacemi:

WIN32.HLP
Popis COMů a RS232
Využití rozhraní PC, Burkhard Kainka
Využití rozhraní PC pod Windows, Burkhard Kainka
C++Builder, David Matoušek
Udělejte si z PC, David Matoušek

Programy a zdrojové kódy:
Program I2C_TEST
Popis API ke stažení, WIN32.HLP
Program a zdrojáky pro blikání na DTR