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這樣能更好的理解串口。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM