Warning
This page is located in archive.

Nastavení sériového portu

Zápis/čtení do/z sériového portu

Přestože je sériový port blokové zařízení, které je v OS reprezentované souborem v adresáři /dev/ a lze s ním tak pracovat jako s běžným souborem funkcemi ze standardní knihovny např. fopen() nebo fwrite(), je z důvodu přímého přístup výhodnější využít funkce systémové knihovny jako jsou open(), close(), read() a write(). Tyto funkce nepracují s ukazatelem na strukturu FILE*, ale přímo s tzv. file deskriptorem, který je reprezentovaný celým číslem typu int.

Nastavení parametrů komunikace je možné prostřednictvím funkce knihovny <termios.h>, například nastavení rychlosti 115200 bps spolu s VMIN a VTIME (viz např. Understanding UNIX termios VMIN and VTIM) lze ralizovat

int fd = open(fname, O_RDWR | O_NOCTTY | O_SYNC);
struct termios term;prg_serial.h a 
tcgetattr(fd, &term);
cfmakeraw(&term);
term.c_cc[VTIME] = 2; //set vtime 
term.c_cc[VMIN] = 1;
cfsetispeed(&term, BAUD_RATE);
cfsetospeed(&term, BAUD_RATE);
tcsetattr(fd, TCSADRAIN, &term) >= 0);
fcntl(fd, F_GETFL) >= 0);
tcsetattr(fd, TCSADRAIN, &term);
fcntl(fd, F_GETFL);
tcflush(fd, TCIFLUSH);
tcsetattr(fd, TCSANOW, &term);

kde pro jednoduchost netestujeme hodnoty návratových hodnot volání jednotlivých funkcí.

Pro znakově orientovaný vstup/výstup pak můžeme zapouzdřit volání read/write do samostatných funkcí např.

int serial_close(int fd)
{
   return close(fd);
}
 
int serial_putc(int fd, char c)
{
   return write(fd, &c, 1);
}

Příslušné funkce pro otevření, zavření a čtení/zápis znaku jsou implementované v modulu prg_serial.

V Linuxu kompilujte s přepínačem -std=gnu99.

Sériový port v neblokovaném režimu

V případě blokového načítání ze souboru, například getc() nebo read() je voláním načtení požadovaného počtu bytů předáno operačnímu systému a vykonávání programu je pozastaveno do doby než jsou požadovaná data k dispozici. V případě čtení dat ze sériového portu v samostatném vlákně můžeme vyžadovat takové načítání ukončit, např. z důvodu požadavku na ukončení programu. Kromě volání exit(), které ukončí celý program, můžeme využít neblokovaného čtení dat ze souboru. V takovém případě funkce read() vrací

  • -1 pokud se stala chyba při čtení
  • 0 pokud nejsou žádná data k dispozici
  • počet načtených bytů, který může být nižší než požadovaný

Nastavení neblokovaného režimu soubor odkazovaného file deskriptorem fd lze realizovat např.

   int flags = fcntl(fd, F_GETFL);
   flags &= ~O_NONBLOCK;
   assert(fcntl(fd, F_SETFL, flags) >= 0);

Pak můžeme v programu aktivně vyčítát data ze sériového portu až do doby, než jsou načtena všechna data. Volání funkce read() proběhne okamžitě a můžeme tak testovat, zdali nastal požadavek na ukončení načítání. Takové řešení je funkční, ale cyklus načítání spotřebuje mnoho zdrojů (CPU čas), proto můžeme po volání pokusu načtení vlákno uspat, např. funkcí usleep(). Takové řešení je také funkční a bude méně výpočetně náročné, ale není přiliš elegantní neboť, zpožďujeme načítání. Výhodnější je použít funkce poll() pro monitorování množiny události nad množinou file deskritorů. Implementace načtení znaku ze seriového portu modulu prg_serial (viz serial pak může vypadat například:

int serial_getc_timeout(int fd, int timeout_ms, char *c)
{
   struct pollfd ufdr[1];
   int r = 0;
   ufdr[0].fd = fd;
   ufdr[0].events = POLLIN | POLLRDNORM;
   if ((poll(&ufdr[0], 1, timeout_ms) > 0) && (ufdr[0].revents & (POLLIN | POLLRDNORM))) {
      r = read(fd, c, 1);
   }
   return r;
}

kde pro jednoduchost vytváříme a inicializujeme proměnou typu struct pollfd, čemuž se lze vyhnout a uspořit tak další zdroje.

Příslušné funkce pro otevření a čtení znaku v neblokovaném režimu jsou dostupné prg_serial_nonblock.

courses/b3b36prg/tutorials/serial.txt · Last modified: 2022/04/27 15:19 by faiglj