一.结构体
1.termios
struct termios {
tcflag_t c_iflag; /* 输入模式标志 */
tcflag_t c_oflag; /* 输出模式标志 */
tcflag_t c_cflag; /* 控制模式标志 */
tcflag_t c_lflag; /* 本地模式标志 */
cc_t c_line; /* 线路规程 */
cc_t c_cc[NCCS]; /* 控制字符 */
speed_t c_ispeed; /* 输入速率 */
speed_t c_ospeed; /* 输出速率 */
};
二.定义
1.类型定义
typedef unsigned char cc_t;
typedef unsigned int speed_t;
typedef unsigned int tcflag_t;
2.c_cc
#define VINTR 0 //中断 Ctrl-C
#define VQUIT 1 //退出 Ctrl-Z
#define VERASE 2 //擦除 空格BS
#define VKILL 3 //删行 Ctrl-U
#define VEOF 4 //文件结尾 Ctrl-D
#define VTIME 5 //等待时间
#define VMIN 6 //读取的最小字符数
#define VSWTC 7 //
#define VSTART 8 //软件流开始
#define VSTOP 9 //软件流停止
#define VSUSP 10 //
#define VEOL 11 //行结尾 回车CR
#define VREPRINT 12 //
#define VDISCARD 13 //
#define VWERASE 14 //
#define VLNEXT 15 //
#define VEOL2 16 //第二行结尾 进行LF
3.c_iflag
#define IGNBRK 0000001 //忽略任何中断条件
#define BRKINT 0000002 //传送SIGINT,当检测到中断
#define IGNPAR 0000004 //忽略校验错误
#define PARMRK 0000010 //标记校验错误
#define INPCK 0000020 //校验有效
#define ISTRIP 0000040 //剥离校验位
#define INLCR 0000100 //映射NL到CR
#define IGNCR 0000200 //忽略CR
#define ICRNL 0000400 //映射CR到NL
#define IUCLC 0001000 //映射大写到小写
#define IXON 0002000 //软件流控制输出作用
#define IXANY 0004000 //允许任何字符再次启动流
#define IXOFF 0010000 //软件流控制输入作用
#define IMAXBEL 0020000 //在输入线上回显BEL过长
#define IUTF8 0040000
4.c_oflag
#define OPOST 0000001 //输出后处理(不设置=行式输出)
#define OLCUC 0000002 //映射小写到大写
#define ONLCR 0000004 //映射NL到CR-NL
#define OCRNL 0000010 //映射CR到NL
#define ONOCR 0000020 //
#define ONLRET 0000040 //NL实现CR功能
#define OFILL 0000100 //对于延时用填充字符
#define OFDEL 0000200 //填充字符DEL
#define NLDLY 0000400 //在行之间,需要掩蔽延时
#define NL0 0000000 //NL没有延时
#define NL1 0000400 //在换行后,新的输出前延时100ms
#define CRDLY 0003000 //回车到左边,需要掩蔽的延时
#define CR0 0000000 //CR没有延时
#define CR1 0001000 //CR后的延时,依赖于当前的列位置
#define CR2 0002000 //CR后延时100ms
#define CR3 0003000 //CR后延时150ms
#define TABDLY 0014000 //TAB后需要延时
#define TAB0 0000000 //TAB后没有延时
#define TAB1 0004000 //TAB后的延时根据当前的列位置
#define TAB2 0010000 //TAB后延时100ms
#define TAB3 0014000 //TAB扩展为空格
#define XTABS 0014000 //
#define BSDLY 0020000 //BS后需要延时掩蔽
#define BS0 0000000 //BS后无延时
#define BS1 0020000 //BS后延时50ms
#define VTDLY 0040000 //VT后需要延时掩蔽
#define VT0 0000000 //VT后无延时
#define VT1 0040000 //VT后延时2秒
#define FFDLY 0100000 //FF后需要延时掩蔽
#define FF0 0000000 //FF后无延时
#define FF1 0100000 //FF后延时2秒
5.c_cflag
#define CBAUD 0010017 //波特率掩码
#define B0 0000000 //挂起
#define B50 0000001 //50 b/s
#define B75 0000002 //75 b/s
#define B110 0000003 //110 b/s
#define B134 0000004 //134.5 b/s
#define B150 0000005 //150 b/s
#define B200 0000006 //200 b/s
#define B300 0000007 //300 b/s
#define B600 0000010 //600 b/s
#define B1200 0000011 //1200 b/s
#define B1800 0000012 //1800 b/s
#define B2400 0000013 //2400 b/s
#define B4800 0000014 //4800 b/s
#define B9600 0000015 //9600 b/s
#define B19200 0000016 //19200 b/s
#define B38400 0000017 //38400 b/s
#define EXTA B19200 //外部时钟A
#define EXTB B38400 //外部时钟B
#define CSIZE 0000060 //位数据位掩码
#define CS5 0000000 //5位数据位
#define CS6 0000020 //6位数据位
#define CS7 0000040 //7位数据位
#define CS8 0000060 //8位数据位
#define CSTOPB 0000100 //2位停止位
#define CREAD 0000200 //接收有效
#define PARENB 0000400 //校验位有效
#define PARODD 0001000 //奇偶校验
#define HUPCL 0002000 //最后关闭后,挂起
#define CLOCAL 0004000 //本地线-不 改变端口的"拥有者"
#define CBAUDEX 0010000 //
#define BOTHER 0010000 //
#define B57600 0010001 //57600 b/s
#define B115200 0010002 //115200 b/s
#define B230400 0010003 //230400 b/s
#define B460800 0010004 //460800 b/s
#define B500000 0010005 //500000 b/s
#define B576000 0010006 //576000 b/s
#define B921600 0010007 //921600 b/s
#define B1000000 0010010 //1000000 b/s
#define B1152000 0010011 //1152000 b/s
#define B1500000 0010012 //1500000 b/s
#define B2000000 0010013 //2000000 b/s
#define B2500000 0010014 //2500000 b/s
#define B3000000 0010015 //3000000 b/s
#define B3500000 0010016 //3500000 b/s
#define B4000000 0010017 //4000000 b/s
#define CIBAUD 002003600000 //输入波特率
#define CMSPAR 010000000000 /* mark or space (stick) parity */
#define CRTSCTS 020000000000 /* flow control */
#define IBSHIFT 16
6.c_lflag
#define ISIG 0000001 //使SIGINTR,SIGSUSP,SIGDSUSP,SIGQUIT等信号作用
#define ICANON 0000002 //设定规范canonical(或行式raw)
#define XCASE 0000004 //map uppercase\lowercase(废除)
#define ECHO 0000010 //回显输入字符
#define ECHOE 0000020 //回显擦除字符 BS-SP-BS
#define ECHOK 0000040 //在删除字符后,回显NL
#define ECHONL 0000100 //回显NL
#define NOFLSH 0000200 //不在中断后退出字符后刷新输入缓冲
#define TOSTOP 0000400 //传送SIGTTOU信号作为背景
#define ECHOCTL 0001000 //以^char方式回显控制字符和以~?方式显示删除字符
#define ECHOPRT 0002000 //回显提示有删除字符
#define ECHOKE 0004000 //BS-SP-BS整行,在有行删除时
#define FLUSHO 0010000 //刷新输出
#define PENDIN 0040000 //在下次读或输入时,将未决字符重打
#define IEXTEN 0100000
#define EXTPROC 0200000
7.其他
/* tcflow() and TCXONC use these */
#define TCOOFF 0
#define TCOON 1
#define TCIOFF 2
#define TCION 3
/* tcflush() and TCFLSH use these */
#define TCIFLUSH 0
#define TCOFLUSH 1
#define TCIOFLUSH 2
/* tcsetattr 使用到这些参数*/
#define TCSANOW 0 //立即改变,不等待数据结束
#define TCSADRAIN 1 //等待直到所有的都传完
#define TCSAFLUSH 2 //刷新输入输出缓冲,然后改变
三.API函数
1.基本操作
打开串口 O_NOCTTY表示不是系统终端,这样就不会受键盘Ctrl-C等操作影响
fd = open("/dev/ttyXXX", O_RDWR | O_NOCTTY | O_NDELAY);
写(返回写入字节数)
ssize_t write(int fildes, const void *buf, size_t nbyte);
读(返回读取字节数)
ssize_t read(int fildes, void *buf, size_t nbyte);
关闭串口
close(unsigned int fd)
控制
int fcntl(int fildes, int cmd, ...);
fcntl(fd,F_SETFD,FNDELAY); //非阻塞
fcntl(fd,F_SETFD,0); //阻塞
控制命令还有以下几个针对tty的(魔数为0x54xx或‘T’),具体使用参考tty_ioctl函数,
#define TCGETS 0x5401
#define TCSETS 0x5402
#define TCSETSW 0x5403
#define TCSETSF 0x5404
#define TCGETA 0x5405
#define TCSETA 0x5406
#define TCSETAW 0x5407
#define TCSETAF 0x5408
#define TCSBRK 0x5409
#define TCXONC 0x540A
#define TCFLSH 0x540B
#define TIOCEXCL 0x540C
#define TIOCNXCL 0x540D
#define TIOCSCTTY 0x540E
#define TIOCGPGRP 0x540F
#define TIOCSPGRP 0x5410
#define TIOCOUTQ 0x5411
#define TIOCSTI 0x5412
#define TIOCGWINSZ 0x5413
#define TIOCSWINSZ 0x5414
#define TIOCMGET 0x5415
#define TIOCMBIS 0x5416
#define TIOCMBIC 0x5417
#define TIOCMSET 0x5418
#define TIOCGSOFTCAR 0x5419
#define TIOCSSOFTCAR 0x541A
#define FIONREAD 0x541B
#define TIOCINQ FIONREAD
#define TIOCLINUX 0x541C
#define TIOCCONS 0x541D
#define TIOCGSERIAL 0x541E
#define TIOCSSERIAL 0x541F
#define TIOCPKT 0x5420
#define FIONBIO 0x5421
#define TIOCNOTTY 0x5422
#define TIOCSETD 0x5423
#define TIOCGETD 0x5424
#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
#define TIOCSBRK 0x5427 /* BSD compatibility */
#define TIOCCBRK 0x5428 /* BSD compatibility */
#define TIOCGSID 0x5429 /* Return the session ID of FD */
#define TCGETS2 _IOR('T', 0x2A, struct termios2)
#define TCSETS2 _IOW('T', 0x2B, struct termios2)
#define TCSETSW2 _IOW('T', 0x2C, struct termios2)
#define TCSETSF2 _IOW('T', 0x2D, struct termios2)
#define TIOCGRS485 0x542E
#ifndef TIOCSRS485
#define TIOCSRS485 0x542F
#endif
#define TIOCGPTN _IOR('T', 0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TIOCSPTLCK _IOW('T', 0x31, int) /* Lock/unlock Pty */
#define TCGETX 0x5432 /* SYS5 TCGETX compatibility */
#define TCSETX 0x5433
#define TCSETXF 0x5434
#define TCSETXW 0x5435
#define TIOCSIG _IOW('T', 0x36, int) /* pty: generate signal */
#define FIONCLEX 0x5450
#define FIOCLEX 0x5451
#define FIOASYNC 0x5452
#define TIOCSERCONFIG 0x5453
#define TIOCSERGWILD 0x5454
#define TIOCSERSWILD 0x5455
#define TIOCGLCKTRMIOS 0x5456
#define TIOCSLCKTRMIOS 0x5457
#define TIOCSERGSTRUCT 0x5458 /* For debugging only */
#define TIOCSERGETLSR 0x5459 /* Get line status register */
#define TIOCSERGETMULTI 0x545A /* Get multiport config */
#define TIOCSERSETMULTI 0x545B /* Set multiport config */
#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
#define TIOCGICOUNT 0x545D /* read serial port __inline__ interrupt counts */
2.串口设置
int tcgetattr(int fildes, struct termios *termios_p);//获取串口参数
int tcsetattr(int fildes, int optional_actions,const struct termios *termios_p);//设置串口参数
speed_t cfgetispeed(const struct termios *termios_p);//获取输入波特率
int cfsetispeed(struct termios *termios_p, speed_t speed);//设置输入波特率
speed_t cfgetospeed(const struct termios *termios_p);//获取输出波特率
int cfsetospeed(struct termios *termios_p, speed_tspeed);//设置输出波特率
大致这样使用
struct termios options;
tcgetattr(fd, &options); //--------获取属性
//--------设置波特率
if(cfgetispeed(&options)!=B115200) //获取输入波特率
cfsetispeed(&options, B19200); //设置输入波特率
cfsetospeed(&options, B19200); //设置输出波特率
if(cfgetospeed(&options)!=B19200) //获取输出波特率
perror("set baud rates fail!\n");
//--------本地模式|串行数据接收
options.c_cflag!=(CLOCAL|CREAD);
//--------设置数据位格式
ifdef UART_8N1
//8N1 - 无校验
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
#endif
ifdef UART_7E1
//7E1 - 偶校验
options.c_cflag |= PARENB;
options.c_cflag &= ~PARODD;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS7;
#endif
ifdef UART_7O1
//7O1 - 奇校验
options.c_cflag |= PARENB;
options.c_cflag |= PARODD;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS7;
#endif
ifdef UART_7S1
//7S1 - 空校验设置同无校验
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
#endif
//--------硬件流控制
#ifdef CTSRTS
options.c_cflag |= CNEW_RTSCTS;
#else
options.c_cflag &= ~CNEW_RTSCTS;
#endif
tcsetattr(fd, TCSANOW, &options); //--------设置属性
3.其他API函数
int tcflow(int fildes, int action);//软件流控制
int tcflush(int fildes, int queue_selector);//丢弃要写入引用的对象,但是尚未传输的数据,或者收到但是尚未读取的数据
int tcdrain(int fildes);//等待直到所有写入
int tcsendbreak(int fildes, int duration);//传送连续的0值比特流,持续一段时间
pid_t tcgetpgrp(int fildes); //获取组id
int tcsetpgrp(int fildes, pid_t pgid_id); //设置组id
pid_t tcgetsid(int fildes); //获取sid
int isatty(int fildes); //判断使用的是不是tty终端
char *ttyname(int fildes); //获取tty路径名
网上找来个好的例子
/************************Copyright(c)*******************************
** 西安邮电学院
** graduate school
** XNMS项目组
** WebSite :blog.csdn.net/tigerjb
**------------------------------------------FileInfo-------------------------------------------------------
** File name: main.c
** Last modified Date: 2011-01-31
** Last Version: 1.0
** Descriptions:
**------------------------------------------------------------------------------------------------------
** Created by: 冀博
** Created date: 2011-01-31
** Version: 1.0
** Descriptions: The original version
**------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
** Version:
** Descriptions:
*******************************************************************/
//串口相关的头文件
#include /*标准输入输出定义*/
#include /*标准函数库定义*/
#include /*Unix 标准函数定义*/
#include
#include
#include /*文件控制定义*/
#include /*PPSIX 终端控制定义*/
#include /*错误号定义*/
#include
//宏定义
#define FALSE -1
#define TRUE 0
/*******************************************************************
* 名称: UART0_Open
* 功能: 打开串口并返回串口设备文件描述
* 入口参数: fd :文件描述符 port :串口号(ttyS0,ttyS1,ttyS2)
* 出口参数: 正确返回为1,错误返回为0
*******************************************************************/
int UART0_Open(int fd,char* port)
{
fd = open( port, O_RDWR|O_NOCTTY|O_NDELAY);
if(FALSE == fd){
perror("Can't Open Serial Port");
return(FALSE);
}
//恢复串口为阻塞状态
if(fcntl(fd, F_SETFL, 0) < 0){
printf("fcntl failed!\n");
return(FALSE);
}
else{
printf("fcntl=%d\n",fcntl(fd, F_SETFL,0));
}
//测试是否为终端设备
if(0 == isatty(STDIN_FILENO)){
printf("standard input is not a terminal device\n");
return(FALSE);
}
else{
printf("isatty success!\n");
}
printf("fd->open=%d\n",fd);
return fd;
}
/*******************************************************************
* 名称: UART0_Close
* 功能: 关闭串口并返回串口设备文件描述
* 入口参数: fd :文件描述符 port :串口号(ttyS0,ttyS1,ttyS2)
* 出口参数: void
*******************************************************************/
void UART0_Close(int fd)
{
close(fd);
}
/*******************************************************************
* 名称: UART0_Set
* 功能: 设置串口数据位,停止位和效验位
* 入口参数:fd 串口文件描述符
* speed 串口速度
* flow_ctrl 数据流控制 0不使用 1硬件流控制 2软件流控制
* databits 数据位 取值为 7 或者8
* stopbits 停止位 取值为 1 或者2
* parity 效验类型 取值为N,E,O,,S
*出口参数: 正确返回为1,错误返回为0
*******************************************************************/
int UART0_Set(int fd,int speed,int flow_ctrl,int databits,int stopbits,int parity)
{
int i;
int status;
int speed_arr[] = { B115200, B19200, B9600, B4800, B2400, B1200, B300};
int name_arr[] = {115200, 19200, 9600, 4800, 2400, 1200, 300};
struct termios options;
/*tcgetattr(fd,&options)得到与fd指向对象的相关参数,并将其保存于options,该函数还可以测试配置是否正确,
该串口是否可用等。若调用成功,函数返回值为0,若调用失败,函数返回值为1*/
if (tcgetattr( fd,&options)!= 0){
perror("SetupSerial 1");
return(FALSE);
}
//设置串口输入波特率和输出波特率
for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++){
if(speed == name_arr[i]){
cfsetispeed(&options, speed_arr[i]);
cfsetospeed(&options, speed_arr[i]);
}
}
//修改控制模式,保证程序不会占用串口
options.c_cflag |= CLOCAL;
//修改控制模式,使得能够从串口中读取输入数据
options.c_cflag |= CREAD;
//设置数据流控制
switch(flow_ctrl)
{
case 0://不使用流控制
options.c_cflag &= ~CRTSCTS;
break;
case 1://使用硬件流控制
options.c_cflag |= CRTSCTS;
break;
case 2://使用软件流控制
options.c_cflag |= IXON | IXOFF | IXANY;
break;
}
//设置数据位
//屏蔽其他标志位
options.c_cflag &= ~CSIZE;
switch (databits)
{
case 5:
options.c_cflag |= CS5;
break;
case 6:
options.c_cflag |= CS6;
break;
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;
options.c_iflag &= ~INPCK;
break;
case 'o':
case 'O'://设置为奇校验
options.c_cflag |= (PARODD | PARENB);
options.c_iflag |= INPCK;
break;
case 'e':
case 'E'://设置为偶校验
options.c_cflag |= PARENB;
options.c_cflag &= ~PARODD;
options.c_iflag |= INPCK;
break;
case 's':
case 'S': //设置为空格
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);
}
//修改输出模式,原始数据输出
options.c_oflag &= ~OPOST;
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);//我加的
//options.c_lflag &= ~(ISIG | ICANON);
//设置等待时间和最小接收字符
options.c_cc[VTIME] = 1; /* 读取一个字符等待1*(1/10)s */
options.c_cc[VMIN] = 1; /* 读取字符的最少个数为1 */
//如果发生数据溢出,接收数据,但是不再读取 刷新收到的数据但是不读
tcflush(fd,TCIFLUSH);
//激活配置 (将修改后的termios数据设置到串口中)
if (tcsetattr(fd,TCSANOW,&options) != 0){
perror("com set error!\n");
return (FALSE);
}
return (TRUE);
}
/*******************************************************************
* 名称: UART0_Init()
* 功能: 串口初始化
* 入口参数:fd : 文件描述符
* speed : 串口速度
* flow_ctrl 数据流控制
* databits 数据位 取值为 7 或者8
* stopbits 停止位 取值为 1 或者2
* parity 效验类型 取值为N,E,O,,S
*
* 出口参数: 正确返回为1,错误返回为0
*******************************************************************/
int UART0_Init(int fd, int speed,int flow_ctrl,int databits,int stopbits,int parity)
{
int err;
//设置串口数据帧格式
if (UART0_Set(fd,19200,0,8,1,'N') == FALSE){
return FALSE;
}
else{
return TRUE;
}
}
/*******************************************************************
* 名称: UART0_Recv
* 功能: 接收串口数据
* 入口参数: fd :文件描述符
* rcv_buf :接收串口中数据存入rcv_buf缓冲区中
* data_len :一帧数据的长度
* 出口参数: 正确返回为1,错误返回为0
*******************************************************************/
int UART0_Recv(int fd, char *rcv_buf,int data_len)
{
int len,fs_sel;
fd_set fs_read;
struct timeval time;
FD_ZERO(&fs_read);
FD_SET(fd,&fs_read);
time.tv_sec = 10;
time.tv_usec = 0;
//使用select实现串口的多路通信
fs_sel = select(fd+1,&fs_read,NULL,NULL,&time);
if(fs_sel){
len = read(fd,rcv_buf,data_len);
printf("I am right!(version1.2) len = %d fs_sel = %d\n",len,fs_sel);
return len;
}
else{
printf("Sorry,I am wrong!");
return FALSE;
}
}
/********************************************************************
* 名称: UART0_Send
* 功能: 发送数据
* 入口参数:fd :文件描述符
* send_buf :存放串口发送数据
* data_len :一帧数据的个数
* 出口参数:正确返回为1,错误返回为0
*******************************************************************/
int UART0_Send(int fd, char *send_buf,int data_len)
{
int len = 0;
len = write(fd,send_buf,data_len);
if (len == data_len )
{
return len;
}
else
{
tcflush(fd,TCOFLUSH);
return FALSE;
}
}
int main(int argc, char **argv)
{
int fd; //文件描述符
int err; //返回调用函数的状态
int len;
int i;
char rcv_buf[100];
char send_buf[20]="tiger john";
if(argc != 3){
printf("Usage: %s /dev/ttySn 0(send data)/1 (receive data) \n",argv[0]);
return FALSE;
}
fd = UART0_Open(fd,argv[1]); //打开串口,返回文件描述符
do{
err = UART0_Init(fd,19200,0,8,1,'N');
printf("Set Port Exactly!\n");
}while(FALSE == err || FALSE == fd);
if(0 == strcmp(argv[2],"0")){
for(i = 0;i < 10;i++){
len = UART0_Send(fd,send_buf,10);
if(len > 0)
printf(" %d send data successful\n",i);
else
printf("send data failed!\n");
sleep(2);
}
UART0_Close(fd);
}
else{
while (1){ //循环读取数据
len = UART0_Recv(fd, rcv_buf,9);
if(len > 0){
rcv_buf[len] = '\0';
printf("receive data is %s\n",rcv_buf);
printf("len = %d\n",len);
}
else{
printf("cannot receive data\n");
}
sleep(2);
}
UART0_Close(fd);
}
}
/*********************************************************************
End Of File
*********************************************************************/
必须的表