• Linux 串口读写(二)


    例子

    下面是一个简单的读取串口数据的例子,使用了上面定义的一些函数和头文件

    /**********************************************************************

     * 代码说明:使用串口二测试的,发送的数据是字符,但是没有发送字符串结束符号,

     * 所以接收到后,后面加上了结束符号。我测试使用的是单片机发送数据到第二个串口,测试通过。

     **********************************************************************/

    #define FALSE  -1

    #define TRUE   0

    /*********************************************************************/

    int OpenDev(char *Dev)

    {

        //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 Error\n");

           exit (0);

        }

        while (1) //循环读取数据

        {

           while ((nread = read(fd, buff, 512))>0)

           {

               printf("\nLen %d\n", nread);

               buff[nread+1] = '\0';

               printf("\n%s", buff);

           }

        }

        //close(fd); 

        // exit (0);

    }

     

    1、虚拟机下使用串口的方法
          使用vmwave,默认串口设备是没有添加的,通过vmwave将设备加入即可正常使用串口。虚拟机串口打开后,可能会占用windows下的串口。另外,虚拟机的串口收发比正常的速度的确要慢许多。

    2、消除Linux串口收发的一些规则

    Linux 串口收发有许多模式,如:

    1 接收返回模式: 如果串口没有接收到数据,read()函数不返回。

    2 数据接收\n才返回接收的数据,否则read()函数返回0

    3 特殊字符解析问题,部分特殊字符接收/发送时,会被屏蔽或者转义。如发送0x0A 接收变为0x0A 0x0A 0x0D被屏蔽等。

    4 接收反馈:如串口接收到数据,立即将该数据发送出去。

    (上面是我遇到的一些问题,可能表述不很清楚,呵呵。如果用于收发txt文件,一般不大注意。)

    3、解决问题的方法是,消除这些默认规则,关键是struct termios 的参数影响。

    struct termios  {

           tcflag_t c_iflag;               /**//* 输入模式旗标 */

            tcflag_t c_oflag;               /**//* 输出模式旗标 */

            tcflag_t c_cflag;               /**//* 控制模式旗标 */

            tcflag_t c_lflag;               /**//* 区域模式旗标 */

            cc_t c_line;                    /**//* 行控制 (line discipline) */

            cc_t c_cc[NCCS];           /**//* 控制特性 */

    };

    由于研究不深,如果要消除所有上面的规则,我是如下处理的

    struct termios options;

     串口打开方式:

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

     消除收发模式规则:

    options.c_lflag        = 0;

    options.c_oflag        = 0;

    options.c_iflag        = 0;

     

    消除字符屏蔽规则:

    options.c_cc[VINTR]    = 0;       /**//* Ctrl-c */

    options.c_cc[VQUIT]     = 0;   /**//* Ctrl- */

    options.c_cc[VERASE]    = 0;   /**//* del */

    options.c_cc[VKILL]    = 0;   /**//* @ */

    options.c_cc[VEOF]     = 0;   /**//* Ctrl-d */

    options.c_cc[VTIME]    = 1;   /**//*  */

    options.c_cc[VMIN]     = 0;   /**//*  */

    options.c_cc[VSWTC]    = 0;   /**//* '' */

    options.c_cc[VSTART]   = 0;   /**//* Ctrl-q */

    options.c_cc[VSTOP]    = 0;   /**//* Ctrl-s */

    options.c_cc[VSUSP]    = 0;   /**//* Ctrl-z */

    options.c_cc[VEOL]     = 0;   /**//* '' */

    options.c_cc[VREPRINT] = 0;   /**//* Ctrl-r */

    options.c_cc[VDISCARD] = 0;   /**//* Ctrl-u */

    options.c_cc[VWERASE]  = 0;   /**//* Ctrl-w */

    options.c_cc[VLNEXT]   = 0;   /**//* Ctrl-v */

    options.c_cc[VEOL2]    = 0;   /**//* '' */

    以上设置,在其它参数串口设置前执行,如果你需要保留部分参数,请参阅http://blog.chinaunix.net/article.php?articleId=15964&blogId=60

    RedHat Feroda 4 下编译通过

    = = = = = = = = = = = 非阻塞read= = = = = = = = = = =

    Q:在调用串口read(fd,   buff,   len);,如果串口没有数据,会停在read,请问有没有办法让这个read动作中止?

    A:使用非阻塞方式select函数(I/O多工机制)或者open的时候加O_NONBLOCK参数。

    int select(int n,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout);关于这个函数的使用我会在下篇blog中整理。

    = = = = = = = = = = = 串口收发源码= = = = = = = = = = =

           一下代码已经经过我测试,没有问题。开发环境Redhat9,运行环境s3c2410

    = = = = = = receive.c= = = = = =

    #include   <stdio.h>     

    #include   <stdlib.h>   

    #include   <unistd.h>     

    #include   <sys/types.h> 

    #include   <sys/stat.h>  

    #include   <fcntl.h>    

    #include   <termios.h>  

    #include   <errno.h>    

    #include   <string.h>

    #define TRUE 1

    //初始化串口选项:  

    void setTermios(struct termios * pNewtio, int uBaudRate)

    {

        bzero(pNewtio, sizeof(struct termios)); /* clear struct for new port settings */

        //8N1

        pNewtio->c_cflag = uBaudRate | CS8 | CREAD | CLOCAL;

        pNewtio->c_iflag = IGNPAR;

        pNewtio->c_oflag = 0;

        pNewtio->c_lflag = 0; //non ICANON

        /*

         initialize all control characters

         default values can be found in /usr/include/termios.h, and

         are given in the comments, but we don't need them here

         */

        pNewtio->c_cc[VINTR] = 0; /* Ctrl-c */

        pNewtio->c_cc[VQUIT] = 0; /* Ctrl-\ */

        pNewtio->c_cc[VERASE] = 0; /* del */

        pNewtio->c_cc[VKILL] = 0; /* @ */

        pNewtio->c_cc[VEOF] = 4; /* Ctrl-d */

        pNewtio->c_cc[VTIME] = 5; /* inter-character timer, timeout VTIME*0.1 */

        pNewtio->c_cc[VMIN] = 0; /* blocking read until VMIN character arrives */

        pNewtio->c_cc[VSWTC] = 0; /* '\0' */

        pNewtio->c_cc[VSTART] = 0; /* Ctrl-q */

        pNewtio->c_cc[VSTOP] = 0; /* Ctrl-s */

        pNewtio->c_cc[VSUSP] = 0; /* Ctrl-z */

        pNewtio->c_cc[VEOL] = 0; /* '\0' */

        pNewtio->c_cc[VREPRINT] = 0; /* Ctrl-r */

        pNewtio->c_cc[VDISCARD] = 0; /* Ctrl-u */

        pNewtio->c_cc[VWERASE] = 0; /* Ctrl-w */

        pNewtio->c_cc[VLNEXT] = 0; /* Ctrl-v */

        pNewtio->c_cc[VEOL2] = 0; /* '\0' */

    }

    #define BUFSIZE 512

    int main(int argc, char **argv)

    {

        int fd;

        int nread;

        char buff[BUFSIZE];

        struct termios oldtio, newtio;

        struct timeval tv;

        char *dev ="/dev/ttyS1";

        fd_set rfds;

        if ((fd = open(dev, O_RDWR | O_NOCTTY))<0)

        {

           printf("err: can't open serial port!\n");

           return -1;

        }

        tcgetattr(fd, &oldtio); /* save current serial port settings */

        setTermios(&newtio, B115200);

        tcflush(fd, TCIFLUSH);

        tcsetattr(fd, TCSANOW, &newtio);

        tv.tv_sec=30;

        tv.tv_usec=0;

        while (TRUE)

        {

           printf("wait...\n");

           FD_ZERO(&rfds);

           FD_SET(fd, &rfds);

           if (select(1+fd, &rfds, NULL, NULL, &tv)>0)

           {

               if (FD_ISSET(fd, &rfds))

               {

                  nread=read(fd, buff, BUFSIZE);

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

                  buff[nread]='\0';

                  printf("%s\n", buff);

               }

           }

        }

        tcsetattr(fd, TCSANOW, &oldtio);

        close(fd);

    }

    = = = = = send.c= = = = = =

    #include   <stdio.h>     

    #include   <stdlib.h>   

    #include   <unistd.h>     

    #include   <sys/types.h> 

    #include   <sys/stat.h>  

    #include   <fcntl.h>    

    #include   <termios.h>  

    #include   <errno.h>    

    #include   <string.h>

    //初始化串口选项:  

    void setTermios(struct termios * pNewtio, int uBaudRate)

    {

        bzero(pNewtio, sizeof(struct termios)); /* clear struct for new port settings */

        //8N1

        pNewtio->c_cflag = uBaudRate | CS8 | CREAD | CLOCAL;

        pNewtio->c_iflag = IGNPAR;

        pNewtio->c_oflag = 0;

        pNewtio->c_lflag = 0; //non ICANON

        /*

         initialize all control characters

         default values can be found in /usr/include/termios.h, and

         are given in the comments, but we don't need them here

         */

        pNewtio->c_cc[VINTR] = 0; /* Ctrl-c */

        pNewtio->c_cc[VQUIT] = 0; /* Ctrl-\ */

        pNewtio->c_cc[VERASE] = 0; /* del */

        pNewtio->c_cc[VKILL] = 0; /* @ */

        pNewtio->c_cc[VEOF] = 4; /* Ctrl-d */

        pNewtio->c_cc[VTIME] = 5; /* inter-character timer, timeout VTIME*0.1 */

        pNewtio->c_cc[VMIN] = 0; /* blocking read until VMIN character arrives */

        pNewtio->c_cc[VSWTC] = 0; /* '\0' */

        pNewtio->c_cc[VSTART] = 0; /* Ctrl-q */

        pNewtio->c_cc[VSTOP] = 0; /* Ctrl-s */

        pNewtio->c_cc[VSUSP] = 0; /* Ctrl-z */

        pNewtio->c_cc[VEOL] = 0; /* '\0' */

        pNewtio->c_cc[VREPRINT] = 0; /* Ctrl-r */

        pNewtio->c_cc[VDISCARD] = 0; /* Ctrl-u */

        pNewtio->c_cc[VWERASE] = 0; /* Ctrl-w */

        pNewtio->c_cc[VLNEXT] = 0; /* Ctrl-v */

        pNewtio->c_cc[VEOL2] = 0; /* '\0' */

    }

    int main(int argc, char **argv)

    {

        int fd;

        int nCount, nTotal, i;

        struct termios oldtio, newtio;

        char *dev ="/dev/ttyS1";

        if ((argc!=3) || (sscanf(argv[1], "%d", &nTotal) != 1))

        {

           printf("err: need tow arg!\n");

           return -1;

        }

        if ((fd = open(dev, O_RDWR | O_NOCTTY))<0)

        {

           printf("err: can't open serial port!\n");

           return -1;

        }

        tcgetattr(fd, &oldtio); /* save current serial port settings */

        setTermios(&newtio, B115200);

        tcflush(fd, TCIFLUSH);

        tcsetattr(fd, TCSANOW, &newtio);

        for (i=0; i<nTotal; i++)

        {

           nCount=write(fd, argv[2], strlen(argv[2]));

           printf("send data\n");

           sleep(1);

        }

        tcsetattr(fd, TCSANOW, &oldtio);

        close(fd);

        return 0;

    }

    = = = = = =.makefile= = = = = =

    CC = /usr/local/arm/2.95.3/bin/arm-linux-gcc

    all:receive send

    receive: receive.c

        $(CC) receive.c -o  receive

    send: send.c

        $(CC) send.c -o  send

    clean:

        -rm -rf testCOM receive send

    到此基本就结束了,可能代码注释比较少些,写的太着急了,等有时间整理一下。最好再看看上一篇blog这样能更好的理解串口。

  • 相关阅读:
    你的人生许多痛苦源于盲目较劲
    这些HTML、CSS知识点,面试和平时开发都需要 (转)
    拿什么拯救你,我的代码--c#编码规范实战篇 (转)
    最近的面试总结
    感恩和珍惜现在的生活
    我眼中的领域驱动设计(转)
    《生活就像练习》读书笔记(四)——意识状态和类型
    《生活就像练习》读书笔记(三)——发展路线
    .NET面试题解析(07)-多线程编程与线程同步 (转)
    C#进阶系列——WebApi身份认证解决方案:Basic基础认证 (转)
  • 原文地址:https://www.cnblogs.com/meronzhang/p/2786166.html
Copyright © 2020-2023  润新知