串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用。常用的串口是RS-232-C接口(又称EIA RS-232-C)它是在1970年由美国电子工业协会(EIA)联合贝尔系统、调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准。串口通讯指的是计算机依次以位(bit)为单位来传送数据,串行通讯使用的范围很广,在嵌入式系统开发过程中串口通讯也经常用到通讯方式之一。 Linux对所有设备的访问是通过设备文件来进行的,串口也是这样,为了访问串口,只需打开其设备文件即可操作串口设备。在linux系统下面,每一个串口设备都有设备文件与其关联,设备文件位于系统的/dev目录下面。如linux下的/ttyS0,/ttyS1分别表示的是串口1和串口2。下面来详细介绍linux下是如何使用串口的: 1. 串口操作需要用到的头文件 #include <stdio.h> /*标准输入输出定义*/ #include <stdlib.h> /*标准函数库定义*/ #include <unistd.h> /*Unix 标准函数定义*/ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> /*文件控制定义*/ #include <termios.h> /*POSIX 终端控制定义*/ #include <errno.h> /*错误号定义*/ #include <string.h> /*字符串功能函数*/ 2. 串口通讯波特率设置 波特率的设置定义在<asm/termbits.h>,其包含在头文件<termios.h>里。 常用的波特率常数如下: B0-------à0 B1800-------à1800 B50-----à50 B2400------à2400 B75-----à75 B4800------à4800 B110----à110 B9600------à9600 B134----à134.5 B19200-----à19200 B200----à200 B38400------à38400 B300----à300 B57600------à57600 B600----à600 B76800------à76800 B1200---à1200 B115200-----à115200 假定程序中想要设置通讯的波特率,使用cfsetispeed( )和cfsetospeed( )函数来操作,获取波特率信息是通过cfgetispeed()和cfgetospeed()函数来完成的。比如可以这样来指定串口通讯的波特率: #include <stdio.h> //头文件定义 ........ ........ ....... struct termios opt; /*定义指向termios 结构类型的指针opt*/
/***************以下设置通讯波特率****************/ cfsetispeed(&opt,B9600 ); /*指定输入波特率,9600bps*/ cfsetospeed(&opt,B9600);/*指定输出波特率,9600bps*/ /************************************************/ ......... .......... 一般来说,输入、输出的波特率应该是一致的。 3. 串口属性配置 在程序中,很容易配置串口的属性,这些属性定义在结构体struct termios中。为在程序中使用该结构体,需要包含文件<termbits.h>,该头文件定义了结构体struct termios。该结构体定义如下: #define NCCS 19 struct termios { tcflag_t c_iflag; /* 输入参数 */ tcflag_t c_oflag; /* 输出参数 */ tcflag_t c_cflag; /* 控制参数*/ tcflag_t c_ispeed; /* 输入波特率 */ tcflag_t c_ospeed; /* 输出波特率 */ cc_t c_line; /* 线控制 */ cc_t c_cc[NCCS]; /* 控制字符*/ }; 其中成员c_line在POSIX(Portable Operating System Interface for UNIX)系统中不使用。对于支持POSIX终端接口的系统中,对于端口属性的设置和获取要用到两个重要的函数是: (1).int tcsetattr(int fd,int opt_DE,*ptr) 该函数用来设置终端控制属性,其参数说明如下: l fd:待操作的文件描述符 l opt_DE:选项值,有三个选项以供选择: TCSANOW: 不等数据传输完毕就立即改变属性 TCSADRAIN:等待所有数据传输结束才改变属性 TCSAFLUSH:清空输入输出缓冲区才改变属性 l *ptr:指向termios结构的指针 函数返回值:成功返回0,失败返回-1。 (2).int tcgetattr(int fd,*ptr) 该函数用来获取终端控制属性,它把串口的默认设置赋给了termios数据数据结构,其参数说明如下: l fd:待操作的文件描述符 l *ptr:指向termios结构的指针 函数返回值:成功返回0,失败返回-1。 4. 打开串口 在前面已经提到linux下的串口访问是以设备文件形式进行的,所以打开串口也即是打开文件的操作。函数原型可以如下所示: int open(“DE_name”,int open_Status) 参数说明: (1).DE_name:要打开的设备文件名 比如要打开串口1,即为/dev/ttyS0。 (2).open_Status:文件打开方式,可采用下面的文件打开模式: l O_RDONLY:以只读方式打开文件 l O_WRONLY:以只写方式打开文件 l O_RDWR:以读写方式打开文件 l O_APPEND:写入数据时添加到文件末尾 l O_CREATE:如果文件不存在则产生该文件,使用该标志需要设置访问权限位mode_t l O_EXCL:指定该标志,并且指定了O_CREATE标志,如果打开的文件存在则会产生一个错误 l O_TRUNC:如果文件存在并且成功以写或者只写方式打开,则清除文件所有内容,使得文件长度变为0 l O_NOCTTY:如果打开的是一个终端设备,这个程序不会成为对应这个端口的控制终端,如果没有该标志,任何一个输入,例如键盘中止信号等,都将影响进程。 l O_NONBLOCK:该标志与早期使用的O_NDELAY标志作用差不多。程序不关心DCD信号线的状态,如果指定该标志,进程将一直在休眠状态,直到DCD信号线为0。 函数返回值: 成功返回文件描述符,如果失败返回-1 例如假定以可读写方式打开/dev/ttyS0设备,就可以这样操作: #include<stdio.h> //头文件包含 ...... ...... int fd; /* 文件描述符 */ fd = open("/dev/ttyS0", O_RDWR | 0_NOCTTY); /*以读写方式打开设备*/ if(fd == -1) perror("Can not open Serial_Port 1\n!");/*打开失败时的错误提示*/ ........ ........
5. 串口读操作(接收端) 用open函数打开设备文件,函数返回一个文件描述符(file descriptors,fd),通过文件描述符来访问文件。读串口操作是通过read函数来完成的。函数原型如下: int read(int fd, *buffer,length); 参数说明: (1).int fd:文件描述符 (2).*buffer:数据缓冲区 (3).length:要读取的字节数 函数返回值: 读操作成功读取返回读取的字节数,失败则返回-1。 6. 串口写操作(发送端) 写串口操作是通过write函数来完成的。函数原型如下: write(int fd, *buffer,length); 参数说明: (1).fd:文件描述符 (2).*buffer:存储写入数据的数据缓冲区 (3).length:写入缓冲去的数据字节数 函数返回值: 成功返回写入数据的字节数,该值通常等于length,如果写入失败返回-1。 例如:向终端设备发送初始化命令 #include<stdio.h> //头文件包含 ...... ......
int n sbuf[]={Hello,this is a Serial_Port test!\n };//待发送数据 int len_send="sizeof"(sbuf);//发送缓冲区字节数定义 n = write(fd,sbuf,len_send); //写缓冲区 if(n == -1) { printf("Wirte sbuf error.\n"); } ...... ...... 7. 关闭串口 对设备文件的操作与对普通文件的操作一样,打开操作之后还需要关闭,关闭串口用函数close( )来操作,函数原型为: int close(int fd); 参数说明: fd:文件描述符 函数返回值: 成功返回0,失败返回-1。 NAMEtermios, tcgetattr, tcsetattr, tcsendbreak, tcdrain, tcflush, tcflow, cfmakeraw, cfgetospeed, cfgetispeed, cfsetispeed, cfsetospeed - 获取和设置终端属性,行控制,获取和设置波特率 SYNOPSIS 总览 #include <termios.h> int tcgetattr(int fd, struct termios *termios_p); int tcsetattr(int fd, int optional_actions, struct termios *termios_p); int tcsendbreak(int fd, int duration); int tcdrain(int fd); int tcflush(int fd, int queue_selector); int tcflow(int fd, int action); int cfmakeraw(struct termios *termios_p); speed_t cfgetispeed(struct termios *termios_p); speed_t cfgetospeed(struct termios *termios_p); int cfsetispeed(struct termios *termios_p, speed_t speed); int cfsetospeed(struct termios *termios_p, speed_t speed); DESCRIPTION 描述termios 函数族提供了一个常规的终端接口,用于控制非同步通信端口。 这里描述的大部分属性有一个 termios_p 类型的参数,它是指向一个 termios 结构的指针。这个结构包含了至少下列成员:
c_iflag 标志常量:
POSIX.1 中定义的 c_oflag 标志常量:
其余 c_oflag 标志常量定义在 POSIX 1003.1-2001 中,除非另外说明。
c_cflag 标志常量:
(POSIX 规定波特率存储在 termios 结构中,并未精确指定它的位置,而是提供了函数 cfgetispeed() 和 cfsetispeed() 来存取它。一些系统使用 c_cflag 中 CBAUD 选择的位,其他系统使用单独的变量,例如 sg_ispeed 和 sg_ospeed 。)
c_lflag 标志常量:
c_cc 数组定义了特殊的控制字符。符号下标 (初始值) 和意义为:
|