您的位置:首页 > 运维架构 > Linux

linux C串口常规设置参考

2016-08-02 22:37 246 查看
据通信的基本方式可分为并行通信与串行通信两种。

· 并行通信是指利用多条数据传输线将一个资料的各位同时传送。它的特点是传输速度

快,适用于短距离通信,但要求传输速度较高的应用场合。

· 串行通信是指利用一条传输线将资料一位位地顺序传送。特点是通信线路简单,利用

简单的线缆就可实现通信,降低成本,适用于远距离通信,但传输速度慢的应用场合。

串口设置详解

本节主要讲解设置串口的主要方法。

如前所述,设置串口中最基本的包括波特率设置,校验位和停止位设置。串口的设置主

要是设置struct termios结构体的各成员值,如下所示:

#include

struct termio

{      

      unsigned short c_iflag; /* 输入模式标志 */

      unsigned short c_oflag; /* 输出模式标志 */

      unsigned short c_cflag; /* 控制模式标志*/

      unsigned short c_lflag; /*本地模式标志 */

      unsigned char c_line; /* line discipline */

      unsigned char c_cc[NCC]; /* control characters */

};

在这个结构中最为重要的是c_cflag,通过对它的赋值,用户可以设置波特率、字符大小、

数据位、停止位、奇偶校验位和硬件流控等。另外c_iflag 和c_cc 也是比较常用的标志。在

此主要对这3 个成员进行详细说明。

                 c_cflag支持的常量名称

CBAUD        波特率的位掩码

B0           0波特率(放弃DTR)

B1800        1800波特率

B2400        2400波特率

B4800        4800波特率

B9600        9600波特率

B19200       19200波特率

B38400       38400波特率

B57600       57600波特率

B115200      115200波特率

EXTA         外部时钟率

EXTB         外部时钟率

CSIZE        数据位的位掩码

CS5          5个数据位

CS6          6个数据位

CS7          7个数据位

CS8          8个数据位

CSTOPB       2个停止位(不设则是1个停止位)

CREAD        接收使能

PARENB       校验位使能

PARODD       使用奇校验而不使用偶校验

HUPCL        最后关闭时挂线(放弃DTR)

CLOCAL       本地连接(不改变端口所有者)

LOBLK        块作业控制输出

CNET_CTSRTS  硬件流控制使能

      c_iflag支持的常量名称

INPCK        奇偶校验使能

IGNPAR       忽略奇偶校验错误

PARMRK       奇偶校验错误掩码

ISTRIP       除去奇偶校验位

IXON         启动出口硬件流控

IXOFF        启动入口软件流控

IXANY        允许字符重新启动流控

IGNBRK       忽略中断情况

BRKINT       当发生中断时发送SIGINT信号

INLCR        将NL映射到CR

IGNCR        忽略CR

ICRNL        将CR映射到NL

IUCLC        将高位情况映射到低位情况

IMAXBEL      当输入太长时回复ECHO

      c_cc 支持的常量名称

VINTR     中断控制,对应键为CTRL+C

VQUIT     退出操作,对应键为CRTL+Z

VERASE    删除操作,对应键为Backspace(BS)

VKILL     删除行,对应键为CTRL+U

VEOF      位于文件结尾,对应键为CTRL+D

VEOL      位于行尾,对应键为Carriage return(CR)

VEOL2     位于第二行尾,对应键为Line feed(LF)

VMIN      指定了最少读取的字符数

VTIME     指定了读取每个字符的等待时间

串口控制函数

Tcgetattr         取属性(termios结构)

Tcsetattr         设置属性(termios结构)

cfgetispeed     得到输入速度

Cfgetospeed           得到输出速度

Cfsetispeed            设置输入速度

Cfsetospeed           设置输出速度

Tcdrain           等待所有输出都被传输

tcflow           挂起传输或接收

tcflush           刷清未决输入和/或输出

Tcsendbreak           送BREAK字符

tcgetpgrp              得到前台进程组ID

tcsetpgrp               设置前台进程组ID

      [color=#ff0000]完整的串口配置模板,实用!把常用的选项在函数里面列出,可大大方便用户的调试使用[/color]

int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)

{

    struct termios newtio,oldtio;

    /*保存测试现有串口参数设置,在这里如果串口号等出错,会有相关的出错信息*/

    if ( tcgetattr( fd,&oldtio) != 0)

    {

        perror("SetupSerial 1");

         return -1;

     }

    bzero( &newtio, sizeof( newtio ) );

    /*步骤一,设置字符大小*/

    newtio.c_cflag |= CLOCAL | CREAD;

    newtio.c_cflag &= ~CSIZE;

    /*设置停止位*/

    switch( nBits )

    {

        case 7:

            newtio.c_cflag |= CS7;

            break;

        case 8:

            newtio.c_cflag |= CS8;

            break;

    }

/*设置奇偶校验位*/

    switch( nEvent )

    {

        case 'O': //奇数

            newtio.c_cflag |= PARENB;

            newtio.c_cflag |= PARODD;

            newtio.c_iflag |= (INPCK | ISTRIP);

        break;

        case 'E': //偶数

            newtio.c_iflag |= (INPCK | ISTRIP);

            newtio.c_cflag |= PARENB;

            newtio.c_cflag &= ~PARODD;

        break;

            case 'N': //无奇偶校验位

            newtio.c_cflag &= ~PARENB;

        break;

    }

    /*设置波特率*/

    switch( nSpeed )

    {

        case 2400:

            cfsetispeed(&newtio, B2400);

            cfsetospeed(&newtio, B2400);

        break;

        case 4800:

            cfsetispeed(&newtio, B4800);

            cfsetospeed(&newtio, B4800);

        break;

        case 9600:

            cfsetispeed(&newtio, B9600);

            cfsetospeed(&newtio, B9600);

        break;

        case 115200:

            cfsetispeed(&newtio, B115200);

            cfsetospeed(&newtio, B115200);

        break;

        case 460800:

            cfsetispeed(&newtio, B460800);

            cfsetospeed(&newtio, B460800);

        break;

        default:

            cfsetispeed(&newtio, B9600);

            cfsetospeed(&newtio, B9600);

        break;

    }

    /*设置停止位*/

    if( nStop == 1 )

        newtio.c_cflag &= ~CSTOPB;

    else if ( nStop == 2 )

        newtio.c_cflag |= CSTOPB;

    /*设置等待时间和最小接收字符*/ 

    newtio.c_cc[VTIME] = 0;

    newtio.c_cc[VMIN] = 0;

    /*处理未接收字符*/

    tcflush(fd,TCIFLUSH);

    /*激活新配置*/

    if((tcsetattr(fd,TCSANOW,&newtio))!=0)

    {

        perror("com set error");

        return -1;

    }

    printf("set done!\n");

    return 0;



            

            

            

            

           

串口使用详解

在配置完串口的相关属性后,就可对串口进行打开,读写操作了。其使用方式与文件操作一样,区别在于串口是一个终端设备。

打开串口

fd = open( "/dev/ttyS0", O_RDWR|O_NOCTTY|O_NDELAY);

   Open函数中除普通参数外,另有两个参数O_NOCTTY和O_NDELAY。

   O_NOCTTY: 通知linix系统,这个程序不会成为这个端口的控制终端。

   O_NDELAY: 通知linux系统不关心DCD信号线所处的状态(端口的另一端是否激活或者停止)。

然后,恢复串口的状态为阻塞状态,用于等待串口数据的读入。用fcntl函数:

       fcntl(fd, F_SETFL, 0);

   接着,测试打开的文件描述府是否引用一个终端设备,以进一步确认串口是否正确打开。

       isatty(STDIN_FILENO);

串口的读写与普通文件一样,使用read,write函数。

       read(fd,buff,8);

       write(fd,buff,8);

实例

#i nclude stdio.h>

#i nclude string.h>

#i nclude sys/types.h>

#i nclude errno.h>

#i nclude sys/stat.h>

#i nclude fcntl.h>

#i nclude unistd.h>

#i nclude termios.h>

#i nclude stdlib.h>

int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)

{

    struct termios newtio,oldtio;

    if ( tcgetattr( fd,&oldtio) != 0) { 

        perror("SetupSerial 1");

        return -1;

    }

    bzero( &newtio, sizeof( newtio ) );

    newtio.c_cflag |= CLOCAL | CREAD; 

    newtio.c_cflag &= ~CSIZE; 

    switch( nBits )

    {

    case 7:

        newtio.c_cflag |= CS7;

        break;

    case 8:

        newtio.c_cflag |= CS8;

        break;

    }

    switch( nEvent )

    {

    case 'O':

        newtio.c_cflag |= PARENB;

        newtio.c_cflag |= PARODD;

        newtio.c_iflag |= (INPCK | ISTRIP);

        break;

    case 'E': 

        newtio.c_iflag |= (INPCK | ISTRIP);

        newtio.c_cflag |= PARENB;

        newtio.c_cflag &= ~PARODD;

        break;

    case 'N': 

        newtio.c_cflag &= ~PARENB;

        break;

    }

switch( nSpeed )

    {

    case 2400:

        cfsetispeed(&newtio, B2400);

        cfsetospeed(&newtio, B2400);

        break;

    case 4800:

        cfsetispeed(&newtio, B4800);

        cfsetospeed(&newtio, B4800);

        break;

    case 9600:

        cfsetispeed(&newtio, B9600);

        cfsetospeed(&newtio, B9600);

        break;

    case 115200:

        cfsetispeed(&newtio, B115200);

        cfsetospeed(&newtio, B115200);

        break;

    default:

        cfsetispeed(&newtio, B9600);

        cfsetospeed(&newtio, B9600);

        break;

    }

    if( nStop == 1 )

        newtio.c_cflag &= ~CSTOPB;

    else if ( nStop == 2 )

    newtio.c_cflag |= CSTOPB;

    newtio.c_cc[VTIME] = 0;

    newtio.c_cc[VMIN] = 0;

    tcflush(fd,TCIFLUSH);

    if((tcsetattr(fd,TCSANOW,&newtio))!=0)

    {

        perror("com set error");

        return -1;

    }

    printf("set done!\n");

    return 0;

}

int open_port(int fd,int comport)

{

    char *dev[]={"/dev/ttyS0","/dev/ttyS1","/dev/ttyS2"};

    long vdisable;

    if (comport==1)

    {    fd = open( "/dev/ttyS0", O_RDWR|O_NOCTTY|O_NDELAY);

        if (-1 == fd){

            perror("Can't Open Serial Port");

            return(-1);

        }

        else 

            printf("open ttyS0 .....\n");

    }

    else if(comport==2)

    {    fd = open( "/dev/ttyS1", O_RDWR|O_NOCTTY|O_NDELAY);

        if (-1 == fd){

            perror("Can't Open Serial Port");

            return(-1);

        }

        else 

            printf("open ttyS1 .....\n");

    }

    else if (comport==3)

    {

        fd = open( "/dev/ttyS2", O_RDWR|O_NOCTTY|O_NDELAY);

        if (-1 == fd){

            perror("Can't Open Serial Port");

            return(-1);

        }

        else 

            printf("open ttyS2 .....\n");

    }

    if(fcntl(fd, F_SETFL, 0)0)

        printf("fcntl failed!\n");

    else

        printf("fcntl=%d\n",fcntl(fd, F_SETFL,0));

    if(isatty(STDIN_FILENO)==0)

        printf("standard input is not a terminal device\n");

    else

        printf("isatty success!\n");

    printf("fd-open=%d\n",fd);

    return fd;

}

int main(void)

{

    int fd;

    int nread,i;

    char buff[]="Hello\n";

    if((fd=open_port(fd,1))0){

        perror("open_port error");

        return;

    }

    if((i=set_opt(fd,115200,8,'N',1))0){

        perror("set_opt error");

        return;

    }

    printf("fd=%d\n",fd);

//    fd=3;

    nread=read(fd,buff,8);

    printf("nread=%d,%s\n",nread,buff);

    close(fd);

    return;

 

}

下面给出了串口配置的完整的函数。通常,为了函数的通用性,通常将常用的选项都在函数中列出,这样可以大大方便以后用户的调试使用。该设置函数如下所示:

int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)

{

      struct termios newtio,oldtio;

/*保存测试现有串口参数设置,在这里如果串口号等出错,会有相关的出错信息*/

      if  ( tcgetattr( fd,&oldtio)  !=  0) { 

             perror("SetupSerial 1");

             return -1;

      }

      bzero( &newtio, sizeof( newtio ) );

/*步骤一,设置字符大小*/

      newtio.c_cflag  |=  CLOCAL | CREAD; 

      newtio.c_cflag &= ~CSIZE; 

/*设置停止位*/

      switch( nBits )

      {

      case 7:

             newtio.c_cflag |= CS7;

             break;

      case 8:

             newtio.c_cflag |= CS8;

             break;

      }

/*设置奇偶校验位*/

      switch( nEvent )

      {

      case 'O': //奇数

             newtio.c_cflag |= PARENB;

             newtio.c_cflag |= PARODD;

             newtio.c_iflag |= (INPCK | ISTRIP);

             break;

      case 'E': //偶数

             newtio.c_iflag |= (INPCK | ISTRIP);

             newtio.c_cflag |= PARENB;

             newtio.c_cflag &= ~PARODD;

             break;

      case 'N':  //无奇偶校验位

             newtio.c_cflag &= ~PARENB;

             break;

      }

/*设置波特率*/

switch( nSpeed )

      {

      case 2400:

             cfsetispeed(&newtio, B2400);

             cfsetospeed(&newtio, B2400);

             break;

      case 4800:

             cfsetispeed(&newtio, B4800);

             cfsetospeed(&newtio, B4800);

             break;

      case 9600:

             cfsetispeed(&newtio, B9600);

             cfsetospeed(&newtio, B9600);

             break;

      case 115200:

             cfsetispeed(&newtio, B115200);

             cfsetospeed(&newtio, B115200);

             break;

      case 460800:

             cfsetispeed(&newtio, B460800);

             cfsetospeed(&newtio, B460800);

             break;

      default:

             cfsetispeed(&newtio, B9600);

             cfsetospeed(&newtio, B9600);

            break;

      }

/*设置停止位*/

      if( nStop == 1 )

             newtio.c_cflag &=  ~CSTOPB;

      else if ( nStop == 2 )

             newtio.c_cflag |=  CSTOPB;

/*设置等待时间和最小接收字符*/

      newtio.c_cc[VTIME]  = 0;

      newtio.c_cc[VMIN] = 0;

/*处理未接收字符*/

      tcflush(fd,TCIFLUSH);

/*激活新配置*/

      if((tcsetattr(fd,TCSANOW,&newtio))!=0)

      {

             perror("com set error");

             return -1;

      }

      printf("set done!\n");

      return 0;

}

下面给出了一个完整的打开串口的函数,同样写考虑到了各种不同的情况。程序如下所示:

/*打开串口函数*/

int open_port(int fd,int comport)

{

       char *dev[]={"/dev/ttyS0","/dev/ttyS1","/dev/ttyS2"};

       long  vdisable;

       if (comport==1)//串口 1

       {     fd = open( "/dev/ttyS0", O_RDWR|O_NOCTTY|O_NDELAY);

            if (-1 == fd){

                   perror("Can't Open Serial Port");

                   return(-1);

            }

       }

       else if(comport==2)//串口 2

       {     fd = open( "/dev/ttyS1", O_RDWR|O_NOCTTY|O_NDELAY);

            if (-1 == fd){

                   perror("Can't Open Serial Port");

                   return(-1);

            }

       }

       else if (comport==3)//串口 3

       {

            fd = open( "/dev/ttyS2", O_RDWR|O_NOCTTY|O_NDELAY);

            if (-1 == fd){

                   perror("Can't Open Serial Port");

                   return(-1);

            }

       }

/*恢复串口为阻塞状态*/

       if(fcntl(fd, F_SETFL, 0)<0)

            printf("fcntl failed!\n");

       else

            printf("fcntl=%d\n",fcntl(fd, F_SETFL,0));

/*测试是否为终端设备*/

       if(isatty(STDIN_FILENO)==0)

            printf("standard input is not a terminal device\n");

       else

            printf("isatty success!\n");

       printf("fd-open=%d\n",fd);

       return fd;

}

 

 

从串口中读取数据

 

int read_datas(int fd, char *rcv_buf,int rcv_wait)

{

       int retval;

       fd_set rfds;

       struct timeval tv;

 

       int ret,pos;

 

       tv.tv_sec = rcv_wait;      // wait 2.5s

        tv.tv_usec = 0;

 

       pos = 0; // point to rceeive buf

      

       while (1)

       {

              FD_ZERO(&rfds);

                FD_SET(fd, &rfds);

 

              retval = select(fd+1 , &rfds, NULLNULL, &tv);

 

                if (retval == -1)

              {

                        perror("select()");

                        break;

                }

              else if (retval)

              {// pan duan shi fou hai you shu ju

                        ret = read(fd, rcv_buf+pos, 2048);

                        pos += ret;

                        if (rcv_buf[pos-2] == '\r' && rcv_buf[pos-1] == '\n')

                     {

                                FD_ZERO(&rfds);

                                FD_SET(fd, &rfds);

 

                                retval = select(fd+1 , &rfds, NULLNULL, &tv);

 

                                if (!retval) break;// no datas, break

                        }

                }

              else

              {

                        printf("No data\n");

                        break;

                }

       }

 

       return 1;

}

 

向串口传数据

int send_data(int fd, char *send_buf)

{

    ssize_t ret;

   

    ret = write(fd,send_buf,strlen(send_buf));

    if (ret == -1)

        {

                printf ("write device %s error\n", DEVICE_TTYS);

                return -1;

        }

 

    return 1;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux c语言 通信