Úloha 5 k mamce

Sériová komunikace

Zadání

Napište program, teletype. Tento program otevře sériový port a vyšle na něj každý z klávesnice zapsaný znak a vypíše každý jednotlivý znak ze sériové linky přijatý. Pomocí sériového kabelu propojte COM1 a COM2 a spusťte 2 instance programu teletype. Který COM se bude používat specifikujte z příkazové řádky při spouštění programu.

O sériové komunikaci

Princip sériové komunikaci spočívá ve vysílání jednotlivých bitů přenášeného slova postupně. To má výhodu v tom, že ušetříme výstupy a dráty.

RS232

PC architektura používá pro sériovou komunikaci standardně rozhraní RS232 obsluhované řadičem 8250 zvaným UART.

Na fyzické vrstvě odpovídá logické 1 hodnota napětí -25V až -3V, logické 0 hodnota napětí +3V až +25V.

Konektor (Canon 9) pro RS232. Zapojení nulového modemu pro propojení dvou PC.

Sériová komunikace v Linuxu

Terminál

V Unixu byl sériový terminál prvním a základním způsobem, jak se připojit k operačnímu systému. Zkratka TTI pochází ze slova teletype. Jak se Unix rozvíjel vznikly i jiné terminály, než sériový (např. konzole, xterm), avšak k terminálu a k sériovému portu se z programů přistupuje stále stejně. Terminály se však liší jmény odpovídajících zařízení.

Typ terminálu, kterým jsme připojeni zjistíme příkazem tty

Pro nastavení a zjišťování parametrů terminálu slouží příkaz stty. Např. stty -F /dev/ttyS0 -a vypíše nastavení parametrů portu COM1.

[fanda@lab3-2 examples]$ stty -F /dev/ttyS0 -a speed 9600 baud; rows 0; columns 0; line = 0; intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0; -parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke [fanda@lab3-2 examples]$


Vidíme, že je toho opravdu hodně, co se dá nastavit, naštěstí se nenastavuje všechno. Zejména je nutné si rozmyslet, zda chceme náš terminál (sériový port) provozovat v kanonickém nebo nekanonickém režimu.

V kanonickém režimu (ten je implicitní) se data z terminálu odesílají až po ukončení řádku. To nám dává možnost je editovat.

V nekanonickém režimu (nutno nastavit parametrem -icanon) se data z terminálu odesílají okamžitě jak se objeví (objevit se mohou z klávesnice v případě terminálu, nebo jsou přijata v případě sériové linky). To nám dává možnost je editovat.

Nejjednodušší způsob jak vysílat znaky na sériovou linku je cat > /dev/ttyS0.
A nejjednodušší způsob jak číst znaky ze sériové linky je cat /dev/ttyS0.

Pokud si to vyzkoušíte uvidíte, že to nefunguje, tak jak očekáváte. Zjistíte, že přenesená zpráva je donekonečna opakována, je to proto, že /dev/ttyS0 i /dev/ttyS1 mají nastaven flag echo a s posílanou zprávou si hrají ping-pong.
Přítrž tomuto chování uděláte příkazem stty -F /dev/ttyS0 -echo.
Chcete-li, aby byly znaky kopírovány po jednotlivých písmenkách, je třeba vysílací terminál a přijímající COM přepnout do nekanonického režimu.
stty -icanon
stty -F /dev/ttyS1 -icanon

Jak na to v jazyku C

struktura termios

Struktura termios zachycuje chování terminálu a slouží i pro jeho nastavování.

typedef unsigned char	cc_t;
typedef unsigned int	speed_t;
typedef unsigned int	tcflag_t;

struct termios
  {
    tcflag_t c_iflag;		/* input mode flags */
    tcflag_t c_oflag;		/* output mode flags */
    tcflag_t c_cflag;		/* control mode flags */
    tcflag_t c_lflag;		/* local mode flags */
    cc_t c_line;		/* line discipline */
    cc_t c_cc[NCCS];		/* control characters */
    speed_t c_ispeed;		/* input speed  (new interface)*/
    speed_t c_ospeed;		/* output speed (new interface)*/
#define _HAVE_STRUCT_TERMIOS_C_ISPEED 1
#define _HAVE_STRUCT_TERMIOS_C_OSPEED 1
  };

Nastavení parametrů terminálu

Tyto funkce se používají strukturu termios pro čtení a nastavení parametrů terminálu.

int tcgetattr(int fildes, struct termios *termios_p);
int tcsetattr(int fildes, int optional_actions, conststruct termios *termios_p);

Nastavení parametrů terminálu ukazuje příklad 2.

Nastavení rychlosti terminálu

Starší implementace používali k nastavení rychlosti c_cflag, novější používají c_ispeed, c_ospeed. Abychom nemuseli řešit tyto implementační závislosti, nastavujeme rychlost terminálu pomocí čtveřice funkcí viz. příklad použití.

speed_t cfgetispeed(const struct termios *termios_p);
speed_t cfgetospeed(const struct termios *termios_p);
int cfsetispeed(struct termios *termios_p, speed_t speed);
int cfsetospeed(struct termios *termios_p, speed_t speed);

Doplňující funkce

Tyto funkce nepotřebují strukturu termios a pracují přímo s filedescriptorem terminálu.

int isatty(int fildes);
int tcdrain(int fildes);
int tcflush(int fildes, int queue_selector);
int tcflow(int fildes, intaction);

Příklady

1. Čtení sériového portu.
2. Přepnutí terminálu do nekanonického režimu.
3. Příklad knihovny pro konfiguraci a použití sériového portu. zdroják, header

Odkazy

Serial Programming Guide for POSIX Operating Systems
Interfacing the Serial / RS232 Port
  k mamce