開啟方式
int open(const char *pathname, int flags);
pathname:開啟路徑
flags:開啟方式
O_RDWR:可讀可寫
O_APPEND:以附加方式開啟
O_CREAT:不存在就建立
O_NDELAY:非阻塞式,讀不到值回傳0,就算讀完了也回傳0
O_NONBLOCK:和 O_NDELAY 一樣,差在讀完了會回傳-1,並設置 errno 為 EAGAIN
O_SYNC:以同步IO方式打開文件
O_NOCTTY:這個程式不控制TTY介面。
如果不設定這個旗標,有些輸入(例如鍵盤的abort)信號可能影響程式
回傳:檔案代號 (-1: 讀取失敗)
開啟後也可再次設定 flags
int flag = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, (flag | O_NONBLOCK | O_SYNC));
讀取
ssize_t read(int fd, void *buf, size_t count);
fd:用 open 得到的值
buf:讀取後要存放的位置
count:讀取長度
回傳:讀取長度 (-1: 讀取失敗)
寫入
ssize_t write(int fd, const void *buf, size_t count);
fd:用 open 得到的值
buf:要寫入的資料
count:寫入長度
回傳:寫入長度 (-1: 寫入失敗)
關閉
int close(int fd);
fd:用 open 得到的值
回傳:0:成功, -1:失敗
使用 select
int select(int fd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
用法範例
struct timeval tv;
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
tv.tv_sec = 30;
tv.tv_usec = 0;
if (select(fd + 1, &readfds, NULL, NULL, &tv) > 0) {
len = read(fd, buf, sizeof(buf));
}
等待到fd有資料可讀時再讀取, 最長等30秒
pipe 取得標準輸出入
int fds[2];
pipe(fds);
fds[0] // 取得標準輸入(讀) fd
fds[1] // 取得標準輸出(寫) fd
Device open 範例
#define FALSE -1
#define TRUE 1
int speed_arr[] = {
B115200, B38400, B19200, B9600, B4800, B2400, B1200, B300,
};
int name_arr[] = {
115200, 38400, 19200, 9600, 4800, 2400, 1200, 300,
};
int openDev(char *dev) {
int fd = open(dev, O_RDWR | O_NOCTTY);
if (fd < 0) {
perror("open dev failed !!");
return (FALSE);
}
return fd;
}
/**
*@brief 設置串口資料位元,停止位元和效驗位
*@param fd 類型 int 打開的串口文件控制碼*
*@param databits 類型 int 資料位元 取值 為 7 或者8*
*@param stopbits 類型 int 停止位 取值為 1 或者2*
*@param parity 類型 int 效驗類型 取值為N,E,O,S
*/
int setParity(int fd, int databits, int stopbits, int parity) {
struct termios options;
if (tcgetattr(fd, &options) != 0) {
perror("SetupSerial 1");
return (FALSE);
}
options.c_cflag = 0;
options.c_iflag = 0;
options.c_oflag = 0;
options.c_lflag = 0;
options.c_cflag = CREAD | CLOCAL; // +++++
options.c_cflag &= ~CSIZE;
switch (databits) /*設置數據位元數*/
{
case 7:
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag |= CS8;
break;
default:
fprintf(stderr, "Unsupported data size\n");
return (FALSE);
}
switch (parity) {
case 'n':
case 'N':
options.c_cflag &= ~PARENB; /* Clear parity enable */
options.c_iflag &= ~INPCK; /* Enable parity checking */
break;
case 'o':
case 'O':
options.c_cflag |= (PARODD | PARENB); /* 設置為奇效驗*/
options.c_iflag |= INPCK; /* Disnable parity checking */
break;
case 'e':
case 'E':
options.c_cflag |= PARENB; /* Enable parity */
options.c_cflag &= ~PARODD; /* 轉換為偶效驗*/
options.c_iflag |= INPCK; /* Disnable parity checking */
break;
case 'S':
case 's': /*as no parity*/
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
break;
default:
fprintf(stderr, "Unsupported parity\n");
return (FALSE);
}
/* 設置停止位*/
switch (stopbits) {
case 1:
options.c_cflag &= ~CSTOPB;
break;
case 2:
options.c_cflag |= CSTOPB;
break;
default:
fprintf(stderr, "Unsupported stop bits\n");
return (FALSE);
}
/* Set input parity option */
if (parity != 'n')
options.c_iflag |= INPCK;
options.c_cc[VTIME] = 0; // 15 seconds
options.c_cc[VMIN] = 0;
tcflush(fd, TCIFLUSH); /* Update the options and do it NOW */
if (tcsetattr(fd, TCSANOW, &options) != 0) {
perror("SetupSerial 3");
return (FALSE);
}
return (TRUE);
}
void setSpeed(int fd, int speed) {
int i;
int status;
struct termios Opt;
tcgetattr(fd, &Opt);
for (i = 0; i < sizeof(speed_arr) / sizeof(int); i++) {
if (speed == name_arr[i]) {
tcflush(fd, TCIOFLUSH);
cfsetispeed(&Opt, speed_arr[i]);
cfsetospeed(&Opt, speed_arr[i]);
status = tcsetattr(fd, TCSANOW, &Opt);
if (status != 0)
perror("tcsetattr fd1");
return;
}
tcflush(fd, TCIOFLUSH);
}
}
使用方式
#define BAUDRATE 9600
#define DATABITS 8
#define STOPBITS 1
#define PARITY 0x4E // 'N'
static char sendBuf_Cmd[] = { 0x02, 0x30, 0x03 };
char buf[32];
int buf_size = sizeof(buf);
int fd, len = 0, ret_len = 0, n, data_len = 0;
memset(buf, '\0', sizeof(buf));
if((fd = openDev(dev)) > 0) {
setSpeed(fd, BAUDRATE);
if (setParity(fd, DATABITS, STOPBITS, PARITY) == FALSE) {
printf("Set Parity Error\n");
exit(1);
}
while(1) {
ret_len = read(fd, &buf[len], buf_size - len);
if(ret_len < 0) {
usleep(100000);
continue;
}
len += ret_len;
if(len > 0) {
while(len > 0) {
if(buf[0] == 0x6) { // ACK
write(fd, sendBuf_Cmd, sizeof(sendBuf_Cmd)); // 送命令
data_len = 1;
} else if(buf[0] == 0xXX) { // ...
// ...
data_len = xx;
} else // unknown
data_len = len;
len -= data_len;
if(len > 0)
memcpy(buf, &buf[data_len], len);
}
}
}
close(fd);
}
也可讀寫改用 pthread 的方式
沒有留言:
張貼留言