linux 串口特别是接收

来源:互联网 发布:淘宝热销产品 编辑:程序博客网 时间:2024/06/05 02:58

串口open之后就是设置了。设置后就可以进行read,write等类似操作了。
今天写串口程序,写很好写,但是不能读,最找到了读的方法

#include <stdio.h>#include <string.h>#include <sys/types.h>#include <errno.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <termios.h>#include <stdlib.h>int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop){/* 五个参量 fd打开文件 speed设置波特率 bit数据位设置   neent奇偶校验位 stop停止位 */    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){/* fd 打开串口 comport表示第几个串口 */    char *dev[]={"/dev/ttyUSB0","/dev/ttyS1","/dev/ttyS2"};    long vdisable;    if (comport==1)    {    fd = open( "/dev/ttyUSB0", 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";    fd = open( "/dev/ttyUSB0", O_RDWR|O_NOCTTY|O_NDELAY);            if (-1 == fd){                perror("Can't Open Serial Port");                return(-1);            }            else                printf("open ttyUSB0 .....\n");    if((i=set_opt(fd,9600,8,'N',1))<0){    perror("set_opt error");        return -1;    }    printf("fd=%d\n",fd);//    fd=3;    char bbb[]="abde";    char buf[10];  //  tcflush(fd, TCIOFLUSH); //清空缓冲区    while(1)    {    sleep(1);    memset(buf, 0, 10);    nread=read(fd,buf,8);    printf("nread=%d,%s\n",nread,buf);    }    close(fd);    return 0;}



下面是个很有名的程序:

先说下使用方法吧:

comtest -d /dev/ttyUSB0 -o  打开串口USB0

# include <stdio.h># include <stdlib.h># include <termio.h># include <unistd.h># include <fcntl.h># include <getopt.h># include <time.h># include <errno.h># include <string.h>static void Error(const char *Msg){    fprintf (stderr, "%s\n", Msg);    fprintf (stderr, "strerror() is %s\n", strerror(errno));    exit(1);}static void Warning(const char *Msg){     fprintf (stderr, "Warning: %s\n", Msg);}static int SerialSpeed(const char *SpeedString){    int SpeedNumber = atoi(SpeedString);#   define TestSpeed(Speed) if (SpeedNumber == Speed) return B##Speed    TestSpeed(1200);    TestSpeed(2400);    TestSpeed(4800);    TestSpeed(9600);    TestSpeed(19200);    TestSpeed(38400);    TestSpeed(57600);    TestSpeed(115200);    TestSpeed(230400);    Error("Bad speed");    return -1;}static void PrintUsage(void){   fprintf(stderr, "comtest - interactive program of comm port\n");   fprintf(stderr, "press [ESC] 3 times to quit\n\n");   fprintf(stderr, "Usage: comtest [-d device] [-t tty] [-s speed] [-7] [-c] [-x] [-o] [-h]\n");   fprintf(stderr, "         -7 7 bit\n");   fprintf(stderr, "         -x hex mode\n");   fprintf(stderr, "         -o output to stdout too\n");   fprintf(stderr, "         -c stdout output use color\n");   fprintf(stderr, "         -h print this help\n");   exit(-1);}static inline void WaitFdWriteable(int Fd){    fd_set WriteSetFD;    FD_ZERO(&WriteSetFD);    FD_SET(Fd, &WriteSetFD);    if (select(Fd + 1, NULL, &WriteSetFD, NULL, NULL) < 0) {  Error(strerror(errno));    }}int main(int argc, char **argv){    int CommFd, TtyFd;    struct termios TtyAttr;    struct termios BackupTtyAttr;    int DeviceSpeed = B9600;    int TtySpeed = B9600;    int ByteBits = CS8;    const char *DeviceName = "/dev/ttySAC0";    const char *TtyName = "/dev/tty";    int OutputHex = 0;    int OutputToStdout = 0;    int UseColor = 0;    opterr = 0;    for (;;) {        int c = getopt(argc, argv, "d:s:t:7xoch");        if (c == -1)            break;        switch(c) {        case 'd':            DeviceName = optarg;            break;        case 't':            TtyName = optarg;            break;        case 's':    if (optarg[0] == 'd') {DeviceSpeed = SerialSpeed(optarg + 1);    } else if (optarg[0] == 't') {TtySpeed = SerialSpeed(optarg + 1);    } else            TtySpeed = DeviceSpeed = SerialSpeed(optarg);            break;case 'o':    OutputToStdout = 1;    break;case '7':    ByteBits = CS7;    break;        case 'x':            OutputHex = 1;            break;case 'c':    UseColor = 1;    break;        case '?':        case 'h':        default:    PrintUsage();        }    }    if (optind != argc)        PrintUsage();    CommFd = open(DeviceName, O_RDWR, 0);    if (CommFd < 0)Error("Unable to open device");    if (fcntl(CommFd, F_SETFL, O_NONBLOCK) < 0)     Error("Unable set to NONBLOCK mode");    memset(&TtyAttr, 0, sizeof(struct termios));    TtyAttr.c_iflag = IGNPAR;    TtyAttr.c_cflag = DeviceSpeed | HUPCL | ByteBits | CREAD | CLOCAL;    TtyAttr.c_cc[VMIN] = 1;    if (tcsetattr(CommFd, TCSANOW, &TtyAttr) < 0)        Warning("Unable to set comm port");    TtyFd = open(TtyName, O_RDWR | O_NDELAY, 0);    if (TtyFd < 0)Error("Unable to open tty");    TtyAttr.c_cflag = TtySpeed | HUPCL | ByteBits | CREAD | CLOCAL;    if (tcgetattr(TtyFd, &BackupTtyAttr) < 0)Error("Unable to get tty");    if (tcsetattr(TtyFd, TCSANOW, &TtyAttr) < 0)Error("Unable to set tty");    for (;;) {unsigned char Char = 0;fd_set ReadSetFD;void OutputStdChar(FILE *File) {    char Buffer[10];    int Len = sprintf(Buffer, OutputHex ? "%.2X  " : "%c", Char);    fwrite(Buffer, 1, Len, File);}FD_ZERO(&ReadSetFD);FD_SET(CommFd, &ReadSetFD);FD_SET( TtyFd, &ReadSetFD);#define max(x,y) ( ((x) >= (y)) ? (x) : (y) )if (select(max(CommFd, TtyFd) + 1, &ReadSetFD, NULL, NULL, NULL) < 0) {    Error(strerror(errno));}#undef maxif (FD_ISSET(CommFd, &ReadSetFD)) {    while (read(CommFd, &Char, 1) == 1) {WaitFdWriteable(TtyFd);if (write(TtyFd, &Char, 1) < 0) {      Error(strerror(errno));}if (OutputToStdout) {    if (UseColor)fwrite("\x1b[01;34m", 1, 8, stdout);    OutputStdChar(stdout);    if (UseColor)fwrite("\x1b[00m", 1, 8, stdout);    fflush(stdout);}    }}if (FD_ISSET(TtyFd, &ReadSetFD)) {    while (read(TtyFd, &Char, 1) == 1) {       static int EscKeyCount = 0;WaitFdWriteable(CommFd);       if (write(CommFd, &Char, 1) < 0) {      Error(strerror(errno));}if (OutputToStdout) {    if (UseColor)fwrite("\x1b[01;31m", 1, 8, stderr);    OutputStdChar(stderr);    if (UseColor)fwrite("\x1b[00m", 1, 8, stderr);    fflush(stderr);        }      if (Char == '\x1b') {                    EscKeyCount ++;                    if (EscKeyCount >= 3)                        goto ExitLabel;                } else                    EscKeyCount = 0;    }         }    }ExitLabel:    if (tcsetattr(TtyFd, TCSANOW, &BackupTtyAttr) < 0)Error("Unable to set tty");    return 0;}


前面介绍了串口的简单读写

今天研究了下串口的select读,跟大家分享如下
select读主要实现的功能是,在一定时间内不停地看串口有没有数据,有数据则进行读,当时间过去后还没有数据,则返回超时错误。
具体的函数如下;

int read_datas_tty(int fd,char *rcv_buf,int sec,int usec)
{
int retval;
unsigned char tempchar2;
fd_set rfds;
struct timeval tv;
int ret,pos;
tv.tv_sec = sec;//set the rcv wait time
tv.tv_usec = usec;//100000us = 0.1s
while(1){
   FD_ZERO(&rfds);
   FD_SET(fd,&rfds);
   retval = select(fd+1,&rfds,NULL,NULL,&tv);
   if(retval ==-1)
   {
    perror("select()");
    break;
   }
   else if(retval)
   {
    ret= read(fd,rcv_buf,1);
tempchar2 = rcv_buf;
printf("rcv_buf is %s\n",rcv_buf);
         
   }
   else
   {
    break;
   }
}
return 1;  
}


在前面的普通读写里面加上这个函数就可以了

它的调用方式为:

read_datas_tty(fd,buff,10,10);

这就表示等待时间为10S+10us





    Linux下直接用read读串口可能会造成堵塞,或数据读出错误。然而用select先查询com口,再用read去读就可以避免,并且当com口延时时,程序可以退出,这样就不至于由于com口堵塞,程序就死了。我的代码如下:


bool ReadDevice( int hComm, unsigned long uLen, char* pData )

{  

    int      nread = 0;

   char   inbuf[uLen];

   char  buff[uLen];

   memset( inbuff,  '\0', uLen );

   memset( buff, '\0', uLen );

   fd_set readset;
   struct timeval tv;
   int MaxFd = 0;

   int c = 0;
   int z;
   do
   {
       FD_ZERO( &readset );
       if( hComm >= 0 )
       FD_SET( hComm, &readset );
       MaxFd = hComm + 1;
       tv.tv_sec = 0;
       tv.tv_usec = 500000;
      do
      {
           z = select( MaxFd, &readset, 0, 0, &tv);
      }while( z==-1 && errno==EINTR ); 
      if( z == -1 )
           printf("select(2)\n");
      if( z == 0 )
      {
          hComm = -1;
      }
  
      if( hComm>=0 && FD_ISSET(hComm, &readset) )
      {
           z = read( hComm, buff, uLen - c );
           c += z;
           if( z == -1 )
           {
               hComm = -1;
           }
           if( z > 0 )
          {

                buff[ z + 1 ] = '\0';
                strcat( inbuff, buff );
                memset( buff, 0x00, uLen );
           }
           else
          {
               hComm = -1;
          }
      }
   }while( hComm >= 0 );

   memcpy( pData, inbuff, c );

   return true;

}


来源:http://www.moon-soft.com/doc/51500.htm
参考:http://hi.baidu.com/tc22/blog/item/6c82b51259bbc8c3c3fd7882.html
         http://blog.sina.com.cn/s/blog_6b0cfdeb0100n3k1.html
         http://blog.chinaunix.net/space.php?uid=20788636&do=blog&id=1841319
         http://www.ibm.com/developerworks/cn/linux/l-serials/
         http://hi.baidu.com/xdyang1986/blog/item/c863c125436bb621d4074290.html