一.结构体
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<stdio.h> /*标准输入输出定义*/ #include<stdlib.h> /*标准函数库定义*/ #include<unistd.h> /*Unix 标准函数定义*/ #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> /*文件控制定义*/ #include<termios.h> /*PPSIX 终端控制定义*/ #include<errno.h> /*错误号定义*/ #include<string.h> //宏定义 #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 *********************************************************************/
必须的表