全部博文(2005)
分类: LINUX
2010-10-13 16:11:20
资源转自网上,原帖地址为:
http://www.xxlinux.com/linux/article/development/soft/20071029/11228.html
http://blog.csdn.net/jznsmail/archive/2006/03/15/625382.aspx
序号 信号名称 符号 流向 功能 2 发送数据 TXD DTE→DCE DTE发送串行数据 3 接收数据 RXD DTE←DCE DTE接收串行数据 4 请求发送 RTS DTE→DCE DTE请求 DCE 将线路切换到发送方式 5 允许发送 CTS DTE←DCE DCE告诉 DTE 线路已接通可以发送数据 6 数据设备就绪 DSR DTE←DCE DCE 准备好 7 信号地 信号公共地 8 载波检测 DCD DTE←DCE 表示 DCE 接收到远程载波 20 数据终端就绪 DTR DTE→DCE DTE 准备好 22 振铃指示 RI DTE←DCE 表示 DCE 与线路接通,出现振铃
#include /*标准输入输出定义*/
#include /*标准函数库定义*/
#include /*Unix 标准函数定义*/
#include
#include
#include /*文件控制定义*/
#include /*PPSIX 终端控制定义*/
#include /*错误号定义*/
int fd;
/*以读写方式打开串口*/
fd = open( "/dev/ttyS0", O_RDWR);
if (-1 == fd){
/* 不能打开串口一*/
perror(" 提示错误!");
}
struct termio
{ unsigned short c_iflag; /* 输入模式标志 */
unsigned short c_oflag; /* 输出模式标志 */
unsigned short c_cflag; /* 控制模式标志*/
unsigned short c_lflag; /* local mode flags */
unsigned char c_line; /* line discipline */
unsigned char c_cc[NCC]; /* control characters */
};
设置这个结构体很复杂,我这里就只说说常见的一些设置:
struct termios Opt;
tcgetattr(fd, &Opt);
cfsetispeed(&Opt,B19200); /*设置为19200Bps*/
cfsetospeed(&Opt,B19200);
tcsetattr(fd,TCANOW,&Opt);
设置波特率的例子函数:
/**
*@brief 设置串口通信速率
*@param fd 类型 int 打开串口的文件句柄
*@param speed 类型 int 串口速度
*@return void
*/
int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300,
B38400, B19200, B9600, B4800, B2400, B1200, B300, };
int name_arr[] = {38400, 19200, 9600, 4800, 2400, 1200, 300, 38400,
19200, 9600, 4800, 2400, 1200, 300, };
void set_speed(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(fd1, TCSANOW, &Opt);
if (status != 0) {
perror("tcsetattr fd1");
return;
}
tcflush(fd,TCIOFLUSH);
}
}
}
- 效验位和停止位的设置:
无效验 8位 Option.c_cflag &= ~PARENB;
Option.c_cflag &= ~CSTOPB;
Option.c_cflag &= ~CSIZE;
Option.c_cflag = ~CS8;
奇效验(Odd) 7位 Option.c_cflag = ~PARENB;
Option.c_cflag &= ~PARODD;
Option.c_cflag &= ~CSTOPB;
Option.c_cflag &= ~CSIZE;
Option.c_cflag = ~CS7;
偶效验(Even) 7位 Option.c_cflag &= ~PARENB;
Option.c_cflag = ~PARODD;
Option.c_cflag &= ~CSTOPB;
Option.c_cflag &= ~CSIZE;
Option.c_cflag = ~CS7;
Space效验 7位 Option.c_cflag &= ~PARENB;
Option.c_cflag &= ~CSTOPB;
Option.c_cflag &= &~CSIZE;
Option.c_cflag = CS8;
设置效验的函数:
/**
*@brief 设置串口数据位,停止位和效验位
*@param fd 类型 int 打开的串口文件句柄
*@param databits 类型 int 数据位 取值 为 7 或者8
*@param stopbits 类型 int 停止位 取值为 1 或者2
*@param parity 类型 int 效验类型 取值为N,E,O,,S
*/
int set_Parity(int fd,int databits,int stopbits,int parity)
{
struct termios options;
if ( tcgetattr( fd,&options) != 0) {
perror("SetupSerial 1");
return(FALSE);
}
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 sizen"); 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 parityn");
return (FALSE);
}
/* 设置停止位*/
switch (stopbits)
{
case 1:
options.c_cflag &= ~CSTOPB;
break;
case 2:
options.c_cflag = CSTOPB;
break;
default:
fprintf(stderr,"Unsupported stop bitsn");
return (FALSE);
}
/* Set input parity option */
if (parity != ''n'')
options.c_iflag = INPCK;
tcflush(fd,TCIFLUSH);
options.c_cc[VTIME] = 150; /* 设置超时15 seconds*/
options.c_cc[VMIN] = 0; /* Update the options and do it NOW */
if (tcsetattr(fd,TCSANOW,&options) != 0)
{
perror("SetupSerial 3");
return (FALSE);
}
return (TRUE);
}
需要注意的是:如果不是开发终端之类的,只是串口传输数据,而不需要串口来处理,那么使用原始模式(Raw Mode)方式来通讯,设置方式如下:
options.c_lflag &= ~(ICANON ECHO ECHOE ISIG); /*Input*/
options.c_oflag &= ~OPOST; /*Output*/
- 读写串口
设置好串口之后,读写串口就很容易了,把串口当作文件读写就是。
发送数据char buffer[1024];
int Length;
int nByte;
nByte = write(fd, buffer ,Length);
读取串口数据
使用文件操作read函数读取,如果设置为原始模式(Raw Mode)传输数据,那么read函数返回的字符数是实际串口收到的字符数。可以使用操作文件的函数来实现异步读取,如fcntl,或者select等来操作。
char buff[1024];
int Len;
int readByte = read(fd,buff,Len);
- 关闭串口
关闭串口就是关闭文件。close(fd);
例子:下面是一个简单的读取串口数据的例子,使用了上面定义的一些函数和头文件/**********************************************************************代码说明:使用串口二测试的,发送的数据是字符,
但是没有发送字符串结束符号,所以接收到后,后面加上了结束符号。我测试使用的是单片机发送数据到第二个串口,测试通过。
**********************************************************************/
#define FALSE -1
#define TRUE 0
/*********************************************************************/
int OpenDev(char *Dev)
{
int fd = open( Dev, O_RDWR ); // O_NOCTTY O_NDELAY
if (-1 == fd)
{
perror("Can''t Open Serial Port");
return -1;
}
else
return fd;
}
int main(int argc, char **argv){
int fd;
int nread;
char buff[512];
char *dev = "/dev/ttyS1"; //串口二
fd = OpenDev(dev);
set_speed(fd,19200);
if (set_Parity(fd,8,1,''N'') == FALSE) {
printf("Set Parity Errorn");
exit (0);
}
while (1) //循环读取数据
{
while((nread = read(fd, buff, 512))>0)
{
printf("nLen %dn",nread);
buff[nread+1] = '''';
printf( "n%s", buff);
}
}
//close(fd);
// exit (0);
}
- 串口配置参数详解(termios)
大多数系统都支持POSIX终端接口,POSIX终端通过一个termios结构来进行控制,该结构定义在termios.h文件中。termios结构如下:struct termios
{
tcflag_t c_iflag; /* 输入选项标志 */
tcflag_t c_oflag; /* 输出选项标志 */
tcflag_t c_cflag; /* 控制选项标志 */
tcflag_t c_lflag; /* 本地选项标志 */
cc_t c_cc[NCCS]; /* 控制特性 */
};
c_iflag成员:
Flag Description IGNBRK 忽略输入中的BREAK状态 BRKINT 如果设置了IGNBRK,将忽略BREAK。如果没有设置,但是设置了 BRKINT,那么BREAK将使得输入和输出队列被刷新,如果终端是一个前台进程组的控制终端,这个进程组中所有进程将收到SIGINT信号。如果既未设置IGNBRK也未设置BRKINT,BREAK将视为NUL同义字符,除非设置了PARMRK,这种情况下被视为序列\377 IGNPAR 忽略桢错误和奇偶校验错误 PARMRK 如果没有设置IGNPAR,在有奇偶校验错误或者桢错误的字符前插入\377。如果既没有设置IGNPAR也没有设置PARMRK,将所有奇偶校验错误或者桢错误的字符视为 INPCK 启用输入奇偶校验检测 ISTRIP 去掉第八位 INLCR 将输入的NL翻译为CR IGNCR 忽略输入中的回车 ICRNL 将输入中的回车翻译为新行字符(除非设置了IGNCR) IUCLC (不属于POSIX)将输入中的大写字母映射为小写字母 IXON 启用输出的XON/XOFF流控制 IXANY (不属于POSIX。1;XSI)允许任何字符来重新开始输出 IXOFF 启用输入的XON/XOFF流控制 IMAXBEL (不属于POSIX)当输入队列满时响铃。LINUX没有实现该位,总是将其视为已设置
c_oflag成员
Flag Description OPOST 启用具体实现自行定义的输出 OLCUC (不属于POSIX)将输出中的小写字母映射为大写字母 ONLCR (XSI)将输出中的新行符映射为回车-换行 OCRNL 将输出中的回车映射为新行符 ONOCR 不在第0列输出回车 ONLRET 不输出回车 OFILL 发送填充字符作为延时 OFDEL (不属于POSIX)填充字符是ASCII DEL(0177)。如果不设置填充字符则是ASCII NUL NLDLY 新行延时掩码。取值为NL0和NL1 CRDLY 回车延时掩码。取值为CR0,CR1,CR2或CR3 TABDLY 水平跳格延时掩码。取值为TAB0,TAB1,TAB2,TAB3(或XTABS)。取值为TAB3,即XTABS,将扩展跳格为空格(每个跳格符填充8个空格) BSDLY 回车延时掩码。取值为BS0或BS1.(从来没有被实现) VTDLY 竖直跳格掩码。取值为VT0或VT1 FFDLY 进表延时掩码。取值为FF0或者FF1
c_cflag成员
Flag Description CBAUD (不属于POSIX)波特率掩码(4+1位) CBAUDEX (不属于POSIX)扩展的波特率掩码(1位),包含在CBAUD中 CSIZE 字符长度掩码。取值为CS5,CS6,CS7或CS8 CSTOPB 设置两个停止位 CREAD 打开接受者 PARENB 允许输出产生奇偶信息以及输入的奇偶校验 PARODD 输入和输出是奇校验 HUPCL 在最后一个进程关闭设备后,降低MODEM控制线(挂断) CLOCAL 忽略MODEM控制线 LOBLK (不属于POSIX)从非当前SHELL层阻塞输出(用于sh1) CIBAUD (不属于POSIX)输入速度的掩码。CIBAUD各位的值与CBAUD各位相同,左移了IBSHIFT位 CRTSCTS (不属于POSIX)启用RTS/CTS(硬件)控制流
c_lflag成员
Flag Description ISIG 当接收到字符INTR,QUIT,SUSP或DSUSP时,产生相应的信号 XCASE (不属于POSIX;LINUX下不支持)如果同时设置了ICANON,终端只有大写。输入被转换为小写,除了以\前缀的字符。输出时,大写字符被前缀\,小写字符被转换成大写 ECHO 回显输入字符 ECHOE 如果同时设置了ICANON,字符ERASE擦除前一个输入字符,WERASE擦除前一个词 ECHOK 如果同时设置了ICANON,字符KILL删除当前行 ECHONL 如果同时设置了ICANON,回显字符NL,即使没有设置ECHO ECHOCTL (不属于POSIX)如果同时设置了ECHO,除了TAB,NL,START和STOP之外的ASCII控制信号被回显为x,这里X是比控制信号大0x40的ASCII码。例如字符0x08(BS)被回显为H ECHOPRT (不属于POSIX)如果同时设置了ICANON和IECHO,字符在删除的同时被打印 ECHOKE (不属于POSIX)如果同时设置了ICANON,回显KILL时将删除一行中的每个字符,如同指定了ECHOE和ECHORPT一样 DEFECHO (不属于POSIX)只在一个进程读的时候回显 FLUSHO (不属于POSIX;LINUX不支持)输出被刷新。这个标志可以通过键入字符DISCARD来打开和关闭 NOFLSH 禁止产生SIGINT,SIGQUIT和SIGSUSP信号时刷新输入和输出队列 TOSTOP 向试图写控制终端的后台进程组发送SIGTTOU信号 PENDIN (不属于POSIX;LINUX不支持)在读入一个字符时,输入队列中的所有字符被重新输出。(bash用他来处理typeahead) IEXTEN 启用实现自定义的输入处理。这个标志必须与ICANON同时使用,才能解释特殊字符EOL2,LNEXT,REPRINT和WERASE,IUCLC标志才有效
c_cc数组成员
略(这个表太长了,需要查询的话网上有很多).
- 常用设置
设置规范模式
规范模式是面向行的输入方式,输入字符被放入用于和用户交互可以编辑的缓冲区内,直接到读入回车或者换行符号时才结束。可以通过如下方式来设置:
option.c_lflag |= (ICANON | ECHO | ECHOE);设置原始输入模式
原始输入模式是没有处理过的,当接收数据时,输入的字符在它们被接收后立即被传送,使用原始输入模式时候,一般可以选择取消ICANON,ECHO,ECHOE和ISIG选项。例如:
option.c_lflag &= ~(ICANON | ECHO | ECHOE);
设置输入奇偶选项
当激活c_cflag中的奇偶校验后,应该激活输入的奇偶校验。与之相关的标志有INPCK,IGNPAR,PARMRK和ISTRIP。一般是通过选择INPCK和ISTRIP激活检验和移除奇偶位。例如:
option.c_iflag |= (INPCK | ISTRIP);
设置软件控制流
软件控制流通过IXON,IXOFF和IXANY标志来设置.例如:
option.c_iflag |=(IXON | IXOFF | IXANY);
选择预处理输出
通过OPOST标志来设置预处理的输出。例如:
option.c_oflag |= OPOST;
选择原始数据输出
原始数据的输出通过设置c_oflag的OPOST标志。例如:
option.c_oflag &= ~OPOST;
设置软件流控制字符
软件流控制字符是通过c_cc数组中的VSTART和VSTOP来设置的,一般来说,它们应该被设置城DC1(021八进制)和DC3(023八进制),分别表示ASCII码的XON和XOFF字符。
设置读超时
c_cc 数组中的VMIN指定了最少读取的字符数,如果设置为0,那么VTIME 就指定了读取每个字符的等待时间。VTIME是以1/10秒为单位指定接收字符的超时时间的,如果VTIME设置为0,而端口没有用open或者 fcntl设置为NONBLOCK,那么read操作将会阻塞不确定的时间
- 网上找到的另一串口设置程序
设置波特率int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300,
B38400, B19200, B9600, B4800, B2400, B1200, B300, };
int name_arr[] = {38400, 19200, 9600, 4800, 2400, 1200, 300,
38400, 19200, 9600, 4800, 2400, 1200, 300, };
void set_speed(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) //判断传进来是否相等
{
tcflush(fd, TCIOFLUSH); //刷新输入输出缓冲
cfsetispeed(&Opt, speed_arr);//这里分别设置
cfsetospeed(&Opt, speed_arr);
//这是立刻把bote rates设置真正写到串口中去
status = tcsetattr(fd, TCSANOW, &Opt);
if (status != 0)
perror("tcsetattr fd1"); //设置错误
return;
}
tcflush(fd,TCIOFLUSH); //同上
}
}
设置数据位、校验位和停止位
int set_Parity(int fd,int databits,int stopbits,int parity)
{
struct termios options; //定义一个结构
if ( tcgetattr( fd,&options) != 0) //首先读取系统默认设置options中,必须
{
perror("SetupSerial 1");
return(FALSE);
}
options.c_cflag &= ~CSIZE; //这是设置c_cflag选项不按位数据位掩码
switch (databits){ /*设置数据位数*/
case 7:
options.c_cflag |= CS7; //设置c_cflag选项数据位为7位
break;
case 8:
options.c_cflag |= CS8; //设置c_cflag选项数据位为8位
break;
default:
fprintf(stderr,"Unsupported data size\n"); //其他的都不支持
return (FALSE);
}
switch (parity){ //设置奇偶校验,c_cflag和c_iflag有效
case 'n':
case 'N': //无校验 当然都不选
options.c_cflag &= ~PARENB; /* Clear parity enable */
options.c_iflag &= ~INPCK; /* Enable parity checking */
break;
case 'o': //奇校验 其中PARENB校验位有效;PARODD奇校验
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;
default:
fprintf(stderr,"Unsupported parity\n");
return (FALSE);
}
/* 设置停止位*/
switch (stopbits){ //这是设置停止位数,影响的标志是c_cflag
case 1:
options.c_cflag &= ~CSTOPB; //不指明表示一位停止位
break;
case 2:
options.c_cflag |= CSTOPB; //指明CSTOPB表示两位,只有两种可能
break;
default:
fprintf(stderr,"Unsupported stop bits\n");
return (FALSE);
}
/* Set input parity option */
if (parity != 'n') //这是设置输入是否进行校验
options.c_iflag |= INPCK;
// 这个地方是用来设置控制字符和超时参数的,一般默认即可。稍微要注意的是c_cc数组的VSTART 和 VSTOP 元素被设定成DC1 和 DC3,代表ASCII 标准的XON和XOFF字符。所以如果在传输这两个字符的时候就传不过去,这时需要把软件流控制屏蔽 options.c_iflag &= ~(IXON | IXOFF | IXANY);
options.c_cc[VTIME] = 150; // 15 seconds
options.c_cc[VMIN] = 0;
tcflush(fd,TCIFLUSH); //刷新和立刻写进去
if (tcsetattr(fd,TCSANOW,&options) != 0)
{
perror("SetupSerial 3");
return (FALSE);
}
return (TRUE);
}
chinaunix网友2010-10-16 15:32:43
很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com