Chinaunix首页 | 论坛 | 博客
  • 博客访问: 514610
  • 博文数量: 77
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 689
  • 用 户 组: 普通用户
  • 注册时间: 2013-08-12 08:40
文章分类

全部博文(77)

文章存档

2018年(1)

2016年(3)

2015年(24)

2014年(49)

我的朋友

分类: 嵌入式

2014-09-12 11:03:46

1、打开串口


    在Linux下进行串口通信

    在Linux系统中,串口设备是通过串口终端设备文件来访问的,也就是通过访问/dev/ttyS0、/dev/ttyS1、/dev/ttyS2、/dev/ttyS3这些设备文件实现对串口的访问。对串口进行读写要经过下面几个步骤。

    1.1  打开串口

    与打开文件类似,打开串口同样使用open函数注意:对于串口的打开操作,必须使用O_NOCTTY参数。该参数表示:如果打开的是一个终端设备,程序不会成为对应这个端口的控制终端。如果没有使用该标志,任何一个输入(例如,键盘中止信号等)都将影响进程。具体代码如下:

点击(此处)折叠或打开

  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <fcntl.h>

  4. int main(void){

  5. int fd;

  6. //使用open函数打开串口,获得串口设备文件的文件描述符
  7. if((fd=open("/dev/ttyS0",O_RDWR| O_NOCTTY))==-1){
  8. perror("Cannot open the serial port");
  9. return 1;
  10. }


  11. }

2、使用tcgetattr函数与tcsetattr函数控制终端


    为了便于通过程序来获得和修改终端参数,Linux还提供了tcgetattr函数和tcsetattr函数tcgetattr用于获取终端的相关参数,而tcsetattr函数用于设置终端参数。这两个函数的具体信息如表6.2所示。

    表6.2   tcgetattr函数和tcsetattr函数

 头文件

函数形式

int tcgetattr(int fd, struct termios *termios_p);

int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);

返回值

成功

失败

是否设置errno

0

-1

    说明:tcgetattr函数用于获取与终端相关的参数。参数fd为终端的文件描述符,返回的结果保存在termios结构体中,该结构体一般包括如下的成员


点击(此处)折叠或打开

  1. struct termios {
  2. tcflag_t c_iflag;    /* input mode flags */
  3. tcflag_t c_oflag;    /* output mode flags */
  4. tcflag_t c_cflag;    /* control mode flags */
  5. tcflag_t c_lflag;    /* local mode flags */
  6. cc_t c_line;    /* line discipline */
  7. cc_t c_cc[NCCS];    /* control characters */
  8. };
 
    
c_iflag:输入模式标志,控制终端输入方式,具体参数如表6.3所示

    表6.3   c_iflag参数表    其具体意义如下。 

键    值

说    明

IGNBRK

忽略BREAK键输入

BRKINT

如果设置了IGNBRK,BREAK键的输入将被忽略,如果设置了BRKINT ,将产生SIGINT中断

IGNPAR

忽略奇偶校验错误

PARMRK

标识奇偶校验错误

INPCK

允许输入奇偶校验

ISTRIP

去除字符的第8个比特

INLCR

将输入的NL(换行)转换成CR(回车)

IGNCR

忽略输入的回车

ICRNL

将输入的回车转化成换行(如果IGNCR未设置的情况下)

IUCLC

将输入的大写字符转换成小写字符(非POSIX)

IXON

允许输入时对XON/XOFF流进行控制

IXANY

输入任何字符将重启停止的输出

IXOFF

允许输入时对XON/XOFF流进行控制

IMAXBEL

当输入队列满的时候开始响铃,Linux在使用该参数而是认为该参数总是已经设置


    c_oflag:输出模式标志,控制终端输出方式,具体参数如表6.4所示。

    表6.4   c_oflag参数

键    值

说    明

OPOST

处理后输出

OLCUC

将输入的小写字符转换成大写字符(非POSIX)

ONLCR

将输入的NL(换行)转换成CR(回车)及NL(换行)

OCRNL

将输入的CR(回车)转换成NL(换行)

ONOCR

第一行不输出回车符

ONLRET

不输出回车符

OFILL

发送填充字符以延迟终端输出

OFDEL

以ASCII码的DEL作为填充字符,如果未设置该参数,填充字符将是NUL(‘\0’)(非POSIX)

NLDLY

换行输出延时,可以取NL0(不延迟)或NL1(延迟0.1s)

CRDLY

回车延迟,取值范围为:CR0、CR1、CR2和 CR3

TABDLY

水平制表符输出延迟,取值范围为:TAB0、TAB1、TAB2和TAB3

BSDLY

空格输出延迟,可以取BS0或BS1

VTDLY

垂直制表符输出延迟,可以取VT0或VT1

FFDLY

换页延迟,可以取FF0或FF1


    c_cflag:控制模式标志,指定终端硬件控制信息,具体参数如表6.5所示。

    表6.5   c_cflag参数

键    值

说    明

CBAUD

波特率(4+1位)(非POSIX)

CBAUDEX

附加波特率(1位)(非POSIX)

CSIZE

字符长度,取值范围为CS5、CS6、CS7或CS8

CSTOPB

设置两个停止位

CREAD

使用接收器

PARENB

使用奇偶校验

PARODD

对输入使用奇偶校验,对输出使用偶校验

HUPCL

关闭设备时挂起

CLOCAL

忽略调制解调器线路状态

CRTSCTS

使用RTS/CTS流控制


    c_lflag:本地模式标志,控制终端编辑功能,具体参数如表6.6所示。

    表6.6   c_lflag参数

键    值

说    明

ISIG

当输入INTR、QUIT、SUSP或DSUSP时,产生相应的信号

ICANON

使用标准输入模式

XCASE

在ICANON和XCASE同时设置的情况下,终端只使用大写。如果只设置了XCASE,则输入字符将被转换为小写字符,除非字符使用了转义字符(非POSIX,且Linux不支持该参数)

ECHO

显示输入字符

ECHOE

如果ICANON同时设置,ERASE将删除输入的字符,WERASE将删除输入的单词

ECHOK

如果ICANON同时设置,KILL将删除当前行

ECHONL

如果ICANON同时设置,即使ECHO没有设置依然显示换行符

ECHOPRT

如果ECHO和ICANON同时设置,将删除打印出的字符(非POSIX)

TOSTOP

向后台输出发送SIGTTOU信号


    c_cc[NCCS]:控制字符,用于保存终端驱动程序中的特殊字符,如输入结束符等。c_cc中定义了如表6.7所示的控制字符。

    表6.7   c_cc支持的控制字符

说    明

说    明

VINTR

Interrupt字符

VEOL

附加的End-of-file字符

VQUIT

Quit字符

VTIME

非规范模式读取时的超时时间

VERASE

Erase字符

VSTOP

Stop字符

VKILL

Kill字符

VSTART

Start字符

VEOF

End-of-file字符

VSUSP

Suspend字符

VMIN

非规范模式读取时的最小字符数

 

 


    tcsetattr函数用于设置终端的相关参数。参数fd为打开的终端文件描述符,参数optional_actions用于控制修改起作用的时间,而结构体termios_p中保存了要修改的参数。
    optional_actions可以取如下的值:

    TCSANOW:不等数据传输完毕就立即改变属性。
    TCSADRAIN:等待所有数据传输结束才改变属性。
    TCSAFLUSH:清空输入输出缓冲区才改变属性。

    错误信息:
    EBADF:非法的文件描述符。
    EINTR:tcsetattr函数调用被信号中断。
    EINVAL:参数optional_actions使用了非法值,或参数termios中使用了非法值。
    ENCTTY:非终端的文件描述符。

    实例演练:
    程序p6.2.c通过修改终端控制字符,将终端输入结束符由“Ctrl+D”,修改成了“Ctrl+G”。首先,程序调用tcgetattr函数获得标准输入的termios信息,将termios结构体中的c_cc[VEOF]控制字符的修改成0x07(即Ctrl+G);然后,使用tcsetattr函数将修改后的termios参数设置到终端中。具体代码如下所示:

点击(此处)折叠或打开

  1. //p6.2.c 修改终端控制字符示例
  2. #include <stdio.h>
  3. #include <termios.h>
  4. #include <unistd.h>
  5. #include <errno.h>

  6. int main(void){
  7. //term用于存储获得的终端参数信息
  8. struct termios term;
  9. int err;

  10. //获得标准输入的终端参数,将获得的信息保存在term变量中
  11. if(tcgetattr(STDIN_FILENO,&term)==-1){
  12. perror("Cannot get standard input description");
  13. return 1;
  14. }

  15. //修改获得的终端信息的结束控制字符
  16. term.c_cc[VEOF]=(cc_t)0x07;

  17. //使用tcsetattr函数将修改后的终端参数设置到标准输入中
  18. //err用于保存函数调用后的结果
  19. err=tcsetattr(STDIN_FILENO,TCSAFLUSH,&term);

  20. //如果err为-1或是出现EINTR错误(函数执行被信号中断),
  21. //给出相关出错信息
  22. if(err==-1 && err==EINTR){
  23. perror("Failed to change EOF character");
  24. return 1;
  25. }

  26. return 0;
  27. }

    使用gcc编译p6.2.c程序,得到名为p6.2的可执行程序。在执行p6.2程序前,按“Ctrl+D”可以使终端结束。执行p6.2程序后,按“Ctrl+D”失去了作用,而输入“Ctrl+G”实现了原来“Ctrl+D”的功能。

3、设置串口通信参数


    3.1  设置串口通信参数


    串口通信参数指的是波特率、数据位、奇偶校验位和停止位。对串口实现控制的时候同样要用到termio结构体。下面将结合具体的代码说明如何设置这些参数。

    1.波特率设置
    获得端口波特率信息是通过cfgetispeed函数cfgetospeed函数来实现的。cfgetispeed函数用于获得结构体termios_p中的输入波特率信息,而cfgetospeed函数用于获得结构体termios_p中的输出波特率信息。这两个函数的具体信息如表6.9所示。

    表6.9   cfgetispeed函数和cfgetospeed函数

头文件

函数形式

speed_t cfgetispeed(const struct termios *termios_p);

speed_t cfgetospeed(const struct termios *termios_p);

返回值

成功

失败

是否设置errno

返回termios_p结构中的输入/输出端口的波特率

-1


    cfsetispeed函数cfsetospeed函数用于设置端口的输入/输出波特率。一般情况下,输入和输出波特率是相等的。cfsetispeed函数和cfsetospeed函数的函数声明信息如表6.10所示。

    表6.10   cfsetispeed函数和cfsetospeed函数

头文件

函数形式

int cfsetispeed(struct termios *termios_p, speed_t speed);

int cfsetospeed(struct termios *termios_p, speed_t speed);

返回值

成功

失败

是否设置errno

返回termios_p结构中的输入/输出端口的波特率

-1


    cfsetispeed函数和cfsetospeed函数会修改结构体termios_p中的波特率信息,其中参数speed可以使用表6.11中所列出的宏。

    表6.11   speed参数常用波特率信息 

宏  定  义

波特率(单位:bit/s)

宏  定  义

波特率(单位:bit/s)

B0

0

B1800

1800

B50

50

B2400

2400

B75

75

B4800

4800

B110

110

B9600

9600

B134

134

B19200

19200

B150

150

B38400

38400

B200

200

B57600

57600

B300

300

B115200

115200

B600

600

B230400

230400

B1200

1200

 

 


    使用cfsetispeed函数和cfsetospeed函数进行串口波特率设置具体代码如下所示:

#include     //头文件定义
#include 
#include < termios.h >
……
struct termios opt;           /*定义指向termios 结构类型的指针opt*/
……
//获得串口指向termios结构的指针
tcgetattr(fd, &Opt);
cfsetispeed(&opt,B9600 ); /*指定输入波特率,9600bps*/
cfsetospeed(&opt,B9600);/*指定输出波特率,9600bps*/
//将修改后的termios数据设置到串口中
tcsetattr(fd,TCANOW,&Opt);
……


    2.数据位
    数据位指的是每字节中实际数据所占的比特数。要修改数据位可以通过修改termios结构体中c_cflag成员来实现。CS5、CS6、CS7和CS8分别表示数据位为5、6、7和8。值得注意的是,在设置数据位时,必须先使用CSIZE做位屏蔽。具体设置代码如下:

点击(此处)折叠或打开

  1. #include <stdio.h> //头文件定义
  2. #include <unistd.h>
  3. #include < termios.h >
  4. ……
  5. struct termios opt; /*定义指向termios 结构类型的指针opt*/
  6. .......
  7. //获得串口指向termios结构的指针
  8. tcgetattr(fd, &Opt);

  9. //屏蔽其他标志
  10. Opt.c_cflag&=~CSIZE;
  11. //将数据位修改为8bit
  12. Opt.c_cflag |=CS8;


  13. //将修改后的termios数据设置到串口中
  14. tcsetattr(fd,TCANOW,&Opt);
  15. ……

    3.奇偶校验位
    奇偶校验可以选择偶校验、奇校验、空格等方式,也可以不使用校验。如果要设置为偶校验的话,首先要将termios结构体中c_cflag设置PARENB标志,并清除PARODD标志。如果要设置奇校验,要同时设置termios结构体中c_cflag设置PARENB标志和PARODD标志。如果不想使用任何校验的话,清除termios结构体中c_cflag的PARENB位。表6.12所示为设置奇偶校验的具体方法。
    表6.12   设置奇偶校验位


设    置

具 体 代 码

无校验

opt.c_cflag &= ~PARENB;

奇校验

opt.c_cflag |= (PARODD | PARENB);

偶校验

opt.c_cflag &= ~ PARENB;

opt.c_cflag &= ~PARODD;

空格

opt.c_cflag &= ~PARENB;

opt.c_cflag &= ~CSTOPB;


    下面给出将串口通信的奇偶校验设置为偶校验的例子,具体代码如下:

点击(此处)折叠或打开

  1. #include <stdio.h> //头文件定义
  2. #include <unistd.h>
  3. #include < termios.h >
  4. ……
  5. struct termios opt; /*定义指向termios 结构类型的指针opt*/
  6. ……
  7. //获得串口指向termios结构的指针
  8. tcgetattr(fd, &Opt);

  9. opt.c_cflag &= ~ PARENB;
  10. opt.c_cflag &= ~PARODD;

  11. //将修改后的termios数据设置到串口中
  12. tcsetattr(fd,TCANOW,&Opt);
  13. ……

  
    4.数据流控制
    数据流控制指的是使用何种方法来标志数据传输的开始和结束。可以选择不使用数据流控制、使用硬件进行流控制和使用软件进行流控制。数据流控制设置如表6.13所示。

    表6.13  数据流控制设置

设    置

具 体 代 码

不使用数据流控制

opt.c_cflag &= ~CRTSCTS

硬件

opt.c_cflag   |=  CRTSCTS

软件

opt.c_cflag   | = IXON|IXOFF|IXANY


    由于使用硬件流控制需要相应连接的电缆,常用的流控制方法还是使用软件进行流控制。下面给出了设置不使用数据流控制的相关代码:

点击(此处)折叠或打开

  1. #include <stdio.h> //头文件定义
  2. #include <unistd.h>
  3. #include < termios.h >
  4. ……
  5. struct termios opt; /*定义指向termios 结构类型的指针opt*/
  6. ……
  7. //获得串口指向termios结构的指针
  8. tcgetattr(fd, &opt);

  9. opt.c_cflag &= ~CRTSCTS…

  10. //将修改后的termios数据设置到串口中
  11. tcsetattr(fd,TCANOW,&Opt);
  12. ……
阅读(11882) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~