Untuk kode demo yang sesuai dengan standar POSIX seperti yang dijelaskan dalam Mengatur Mode Terminal dengan Benar dan Panduan Pemrograman Serial untuk Sistem Operasi POSIX, berikut ini ditawarkan.
Kode ini harus dijalankan dengan benar menggunakan Linux pada prosesor x86 dan juga ARM (atau bahkan CRIS).
Itu pada dasarnya berasal dari jawaban lain, tetapi komentar yang tidak akurat dan menyesatkan telah diperbaiki.
Program demo ini membuka dan menginisialisasi terminal serial pada baud 115200 untuk mode non-kanonik yang seportabel mungkin.
Program mentransmisikan string teks berkode keras ke terminal lain, dan menunda saat output dilakukan.
Program kemudian memasuki loop tak terbatas untuk menerima dan menampilkan data dari terminal serial.
Secara default, data yang diterima ditampilkan sebagai nilai byte heksadesimal.
Untuk membuat program memperlakukan data yang diterima sebagai kode ASCII, kompilasi program dengan simbol DISPLAY_STRING, mis.
cc -DDISPLAY_STRING demo.c
Jika data yang diterima adalah teks ASCII (bukan data biner) dan Anda ingin membacanya sebagai baris yang diakhiri oleh karakter baris baru, lihat jawaban ini untuk contoh program.
#define TERMINAL "/dev/ttyUSB0"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
int set_interface_attribs(int fd, int speed)
{
struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
printf("Error from tcgetattr: %s\n", strerror(errno));
return -1;
}
cfsetospeed(&tty, (speed_t)speed);
cfsetispeed(&tty, (speed_t)speed);
tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8; /* 8-bit characters */
tty.c_cflag &= ~PARENB; /* no parity bit */
tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */
/* setup for non-canonical mode */
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tty.c_oflag &= ~OPOST;
/* fetch bytes as they become available */
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 1;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
printf("Error from tcsetattr: %s\n", strerror(errno));
return -1;
}
return 0;
}
void set_mincount(int fd, int mcount)
{
struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
printf("Error tcgetattr: %s\n", strerror(errno));
return;
}
tty.c_cc[VMIN] = mcount ? 1 : 0;
tty.c_cc[VTIME] = 5; /* half second timer */
if (tcsetattr(fd, TCSANOW, &tty) < 0)
printf("Error tcsetattr: %s\n", strerror(errno));
}
int main()
{
char *portname = TERMINAL;
int fd;
int wlen;
char *xstr = "Hello!\n";
int xlen = strlen(xstr);
fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0) {
printf("Error opening %s: %s\n", portname, strerror(errno));
return -1;
}
/*baudrate 115200, 8 bits, no parity, 1 stop bit */
set_interface_attribs(fd, B115200);
//set_mincount(fd, 0); /* set to pure timed read */
/* simple output */
wlen = write(fd, xstr, xlen);
if (wlen != xlen) {
printf("Error from write: %d, %d\n", wlen, errno);
}
tcdrain(fd); /* delay for output */
/* simple noncanonical input */
do {
unsigned char buf[80];
int rdlen;
rdlen = read(fd, buf, sizeof(buf) - 1);
if (rdlen > 0) {
#ifdef DISPLAY_STRING
buf[rdlen] = 0;
printf("Read %d: \"%s\"\n", rdlen, buf);
#else /* display hex */
unsigned char *p;
printf("Read %d:", rdlen);
for (p = buf; rdlen-- > 0; p++)
printf(" 0x%x", *p);
printf("\n");
#endif
} else if (rdlen < 0) {
printf("Error from read: %d: %s\n", rdlen, strerror(errno));
} else { /* rdlen == 0 */
printf("Timeout from read\n");
}
/* repeat read to get full message */
} while (1);
}
Untuk contoh program efisien yang menyediakan buffering data yang diterima namun memungkinkan pengiriman input byte-by-byte, lihat jawaban ini.
Saya menulis ini lama sekali (dari tahun 1985-1992, hanya dengan beberapa penyesuaian sejak saat itu), dan cukup salin dan tempel bit yang diperlukan ke dalam setiap proyek.
Anda harus memanggil cfmakeraw
pada tty
diperoleh dari tcgetattr
. Anda tidak dapat menghapus struct termios
, konfigurasikan, lalu atur tty
dengan tcsetattr
. Jika Anda menggunakan metode zero-out, maka Anda akan mengalami kegagalan intermiten yang tidak dapat dijelaskan, terutama pada BSD dan OS X. "Kegagalan intermiten yang tidak dapat dijelaskan" termasuk menggantung di read(3)
.
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
int
set_interface_attribs (int fd, int speed, int parity)
{
struct termios tty;
if (tcgetattr (fd, &tty) != 0)
{
error_message ("error %d from tcgetattr", errno);
return -1;
}
cfsetospeed (&tty, speed);
cfsetispeed (&tty, speed);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as \000 chars
tty.c_iflag &= ~IGNBRK; // disable break processing
tty.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag |= parity;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
if (tcsetattr (fd, TCSANOW, &tty) != 0)
{
error_message ("error %d from tcsetattr", errno);
return -1;
}
return 0;
}
void
set_blocking (int fd, int should_block)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0)
{
error_message ("error %d from tggetattr", errno);
return;
}
tty.c_cc[VMIN] = should_block ? 1 : 0;
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
if (tcsetattr (fd, TCSANOW, &tty) != 0)
error_message ("error %d setting term attributes", errno);
}
...
char *portname = "/dev/ttyUSB1"
...
int fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0)
{
error_message ("error %d opening %s: %s", errno, portname, strerror (errno));
return;
}
set_interface_attribs (fd, B115200, 0); // set speed to 115,200 bps, 8n1 (no parity)
set_blocking (fd, 0); // set no blocking
write (fd, "hello!\n", 7); // send 7 character greeting
usleep ((7 + 25) * 100); // sleep enough to transmit the 7 plus
// receive 25: approx 100 uS per char transmit
char buf [100];
int n = read (fd, buf, sizeof buf); // read up to 100 characters if ready to read
Nilai untuk kecepatan adalah B115200
, B230400
, B9600
, B19200
, B38400
, B57600
, B1200
, B2400
, B4800
, dll. Nilai paritas adalah 0
(artinya tanpa paritas), PARENB|PARODD
(aktifkan paritas dan gunakan ganjil), PARENB
(aktifkan paritas dan gunakan genap), PARENB|PARODD|CMSPAR
(mark parity), dan PARENB|CMSPAR
(paritas spasi).
"Blocking" menyetel apakah sebuah read()
di port menunggu jumlah karakter yang ditentukan tiba. Menyetel tidak ada pemblokiran artinya read()
mengembalikan berapa banyak karakter yang tersedia tanpa menunggu lebih banyak, hingga batas buffer.
Tambahan:
CMSPAR
diperlukan hanya untuk memilih mark dan space parity, yang jarang terjadi. Untuk sebagian besar aplikasi, itu dapat dihilangkan. File header saya /usr/include/bits/termios.h
mengaktifkan definisi CMSPAR
hanya jika simbol preprocessor __USE_MISC
didefinisikan. Definisi itu muncul (dalam features.h
) dengan
#if defined _BSD_SOURCE || defined _SVID_SOURCE
#define __USE_MISC 1
#endif
Komentar pengantar dari <features.h>
mengatakan:
/* These are defined by the user (or the compiler)
to specify the desired environment:
...
_BSD_SOURCE ISO C, POSIX, and 4.3BSD things.
_SVID_SOURCE ISO C, POSIX, and SVID things.
...
*/