首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 操作系统 > UNIXLINUX >

linux下串口读写有关问题 read 一次读不全

2012-03-08 
linux下串口读写问题 read 一次读不全我要在本机(linux)串口上进行读写,一开始时发送接收都正常,但是我用w

linux下串口读写问题 read 一次读不全
我要在本机(linux)串口上进行读写,一开始时发送接收都正常,但是我用windos下的“串口调试助手”发送给我的程序时必须要加上回车换行,否则read函数不返回,后来google了一下,又添加了2条语句设置串口(代码在下面说明),现在收数据可以不用加回车换行了,但是每次read返回的数据都不完整,比如我发了20个字符,read先是读取了8个字符到缓冲区,然后又读取剩下的字符。有没有什么办法可以一次读取全部的,或者可以判断数据还没有收完,接着read,直到结束.

int   speed_arr[]   =   {   B38400,   B19200,   B9600,   B4800,   B2400,   B1200,   B300,
        B38400,   B19200,   B9600,   B4800,   B2400,   B1200,   B300,};
int   name_arr[]   =   {38400,     19200,     9600,     4800,     2400,     1200,     300,   38400,
        19200,     9600,   4800,   2400,   1200,     300,};

/**
*@brief     Set   Serial   Port   BitRate
*@param     fd           Type   :   int   The   File   Description   of   Serial   Port
*@param     speed     Type   :   int     Serial   Speed
*@return     void
*/
void   set_speed(int   fd,   int   speed)
{
        int       i;  
        int       status;  
        struct   termios       Opt;
        tcgetattr(fd,   &Opt);
        for(   i=0;   i   <   (sizeof(speed_arr)   /   sizeof(int));   i++   )
        {
                if   (speed   ==   name_arr[i])
                {
                        tcflush(fd,   TCIOFLUSH);          
                        cfsetispeed(&Opt,   speed_arr[i]);    
                        cfsetospeed(&Opt,   speed_arr[i]);      
                        status   =   tcsetattr(fd,   TCSANOW,   &Opt);    
                        if   (status   !=   0)
                        {
                                perror( "tcsetattr   fd ");    
                                return;          
                        }
                        tcflush(fd,TCIOFLUSH);      
                }
        }
}

/**
*@brief       Set   Serial   Port   Databits,   Stopbits   and   Parity.
*@param     fd           Type:     int   The   File   Description   of   Serial   Port


*@param     databits   Type:     int   Databits   7   or   8
*@param     stopbits   Type:     int   Stopbits   1   or   2
*@param     parity     Type:     int     Parity   Type:   n,N,e,E,o,O,s,S
*/
int   set_Parity(int   fd,int   databits,int   stopbits,int   parity)
{  
        struct   termios   options;  
        if   (   tcgetattr(   fd,&options)     !=     0)
        {
                perror( "SetupSerial   1 ");          
                return(-1);
        }
        options.c_cflag   &=   ~CSIZE;
        switch   (databits)                               /*Set   Datebits*/
        {
        case   7:  
                options.c_cflag   |=   CS7;  
                break;
        case   8:
                options.c_cflag   |=   CS8;
                break;
        default:        
                fprintf(stderr, "Unsupported   data   size\n ");  
                return(-1);
        }

        switch   (parity)   /*Set   Parity*/
        {
        case   'n ':
        case   'N ':        
                options.c_cflag   &=   ~PARENB;       /*   Clear   parity   enable   */
                options.c_iflag   &=   ~INPCK;           /*   Enable   parity   checking   */  
                break;    
        case   'o ':      
        case   'O ':          
                options.c_cflag   |=   (PARODD   |   PARENB);   /*   Odd   Checking*/    
                options.c_iflag   |=   INPCK;                           /*   Disnable   parity   checking   */  
                break;    
        case   'e ':    
        case   'E ':      
                options.c_cflag   |=   PARENB;           /*   Enable   parity   */        


                options.c_cflag   &=   ~PARODD;       /*   Even   Checking*/
                options.c_iflag   |=   INPCK;               /*   Disnable   parity   checking   */
                break;
        case   'S ':  
        case   's ':     /*as   no   parity*/      
                options.c_cflag   &=   ~PARENB;
                options.c_cflag   &=   ~CSTOPB;
                break;    
        default:      
                fprintf(stderr, "Unsupported   parity\n ");        
                return(-1);
        }    

        switch   (stopbits)                               /*Set   Stobits*/
        {
        case   1:        
                options.c_cflag   &=   ~CSTOPB;    
                break;    
        case   2:        
                options.c_cflag   |=   CSTOPB;    
                break;
        default:        
                fprintf(stderr, "Unsupported   stop   bits\n ");    
                return(-1);  
        }  
        /*   Set   input   parity   option   */  
        if   (parity   !=   'n ')
                options.c_iflag   |=   INPCK;
       
        /*以下两句添加后发送方可以不加回车换行,但是read读取不完整*/
        options.c_lflag   &=   ~(ICANON   |   ECHO   |   ECHOE   |   ISIG);           /*Input*/
        options.c_oflag   &=   ~OPOST;     /*Output*/


        tcflush(fd,TCIFLUSH);
        options.c_cc[VTIME]   =   150;   /*   Timeout   in   15   seconds*/      
        options.c_cc[VMIN]   =   0;   /*   Update   the   options   and   do   it   NOW   */
        if   (tcsetattr(fd,TCSANOW,&options)   !=   0)
        {
                perror( "SetupSerial   3 ");      
                return(-1);    


        }
        return(0);    
}

int   main   (int   argc,   char   *argv[])
{
        char   buffer[512]= " ";
        int   ser_fd   =     open( "/dev/ttyS1 ",O_RDWR   |   O_NOCTTY);
        if   (   -1   ==   ser_fd)
        {
                perror( "Cannot   Open   Serial   Port ");
                return(-1);
        }

       
        set_speed(ser_fd,19200);
        if   (   -1   ==   set_Parity(ser_fd,7,1, 'E ')   )
        {
                printf( "Set   Parity   Error\n ");
                close(ser_fd);
                exit   (-1);
        }
        while(   1   )
      {
              nread   =   read(   ser_fd,   buffer,   sizeof(buffer));
              if   (   nread   <   0   )
                      perror( "read   from   Serial   Port   Error:\n ");
      }

}



[解决办法]
int qstatus;
ioctl(ser_fd, FIONREAD, &qstatus);
看qstatus的值,其值为串口缓冲内有多少数据可多.

你可用先判断数据够不够你要的在去读.
[解决办法]
/*//////////////////////////////////////////////////////////////////////////////
Function: CSerial
Description: Constructor of class CSerial
Calls: ---
Called By: ---
Input: ---
Output: ---
Return: ---
Others: public
//////////////////////////////////////////////////////////////////////////////*/
CSerial::CSerial ( void )
{
m_cDataBit = 8;
m_cParityBit = 0;
m_cStopBit = 1;
m_cFlow = 0;
m_hCom = -1;
}

/*//////////////////////////////////////////////////////////////////////////////
Function: ~CSerial
Description: Destructor of class CSerial
Calls: ---
Called By: ---
Input: ---
Output: ---
Return: ---
Others: public
//////////////////////////////////////////////////////////////////////////////*/
CSerial::~CSerial ( void )
{
if ( m_hCom != -1 )
close(m_hCom);
}

/*//////////////////////////////////////////////////////////////////////////////
Function: Initial
Description: 串口初始化
Calls: ---
Called By: ---
Input: tty: 串口号 0~n 代表串口1~n+1
baut: 波特率 如B9600, 参数为系统定义的常量
Output: ---
Return: true: 初始化成功 false:失败
Others: public
//////////////////////////////////////////////////////////////////////////////*/
bool CSerial::Initial ( int tty, int baut )


{
termios termios_old, termios_new;

if ( m_hCom != -1 )
close(m_hCom);


sprintf ( m_sTTY, "/dev/ttyS%d ", tty );
//打开串口
//O_NOCTTY: 通知系统,该程序不想成为此端口的“控制终端”。
// 如果不设,则任何输入(如键盘的中断信号)都会影响程序的运行
//O_NODELAY: 该程序不关注DCD信号线所处的状态,即不管对端设备是在运行还是挂起。
// 若不设置,则程序会被置为睡眠状态,直到DCD信号低为止(可能无流控制时无效)
m_hCom = open ( m_sTTY, O_RDWR | O_NOCTTY | O_NDELAY );

if ( m_hCom == -1 )
return false;

m_nBaut = baut;

bzero(&termios_old, sizeof(termios_old));
bzero(&termios_new, sizeof(termios_new));
cfmakeraw(&termios_new);
tcgetattr(m_hCom, &termios_old);//get the serial port attributions

//------------设置端口属性----------------
//baudrates
cfsetispeed(&termios_new, m_nBaut); //填入串口输入端的波特率
cfsetospeed(&termios_new, m_nBaut); //填入串口输出端的波特率
termios_new.c_cflag |= CLOCAL; //控制模式,保证程序不会成为端口的占有者
termios_new.c_cflag |= CREAD;//控制模式,使能端口读取输入的数据

// 控制模式,flow control
switch(m_cFlow)
{
case 1:
termios_new.c_cflag |= CRTSCTS; //hardware flow control
break;
case 2:
termios_new.c_iflag |= IXON | IXOFF |IXANY; //software flow control
break;
default:
termios_new.c_cflag &= ~CRTSCTS; //no flow control
break;
}

//控制模式,data bits
termios_new.c_cflag &= ~CSIZE; //控制模式,屏蔽字符大小位
switch(m_cDataBit)
{
case 5:
termios_new.c_cflag |= CS5;
case 6:
termios_new.c_cflag |= CS6;
case 7:
termios_new.c_cflag |= CS7;
default:
termios_new.c_cflag |= CS8;
}

//控制模式 parity check
switch(m_cParityBit)
{
case 1:
termios_new.c_cflag |= PARENB; //odd check
termios_new.c_cflag &= ~PARODD;
break;
case 2:
termios_new.c_cflag |= PARENB; //even check
termios_new.c_cflag |= PARODD;
break;
default:
termios_new.c_cflag &= ~PARENB; //no parity check
break;
}

//控制模式,stop bits
switch ( m_cStopBit )
{
case 2:
termios_new.c_cflag |= CSTOPB; //2 stop bits
break;
default:
termios_new.c_cflag &= ~CSTOPB; //1 stop bits
break;
}

//other attributions default
termios_new.c_oflag &= ~OPOST;//输出模式,原始数据输出
termios_new.c_cc[VMIN] = 1;//控制字符, 所要读取字符的最小数量
termios_new.c_cc[VTIME] = 1;//控制字符, 读取第一个字符的等待时间unit: (1/10)second

tcflush(m_hCom, TCIFLUSH);//溢出的数据可以接收,但不读
tcsetattr(m_hCom, TCSANOW, &termios_new);//设置新属性,TCSANOW:所有改变立即生效tcgetattr(fdcom, &termios_old);

return true;
}

/*//////////////////////////////////////////////////////////////////////////////
Function: Cleanup
Description: 串口清理
Calls: ---
Called By: ---
Input: ---
Output: ---
Return: ---
Others: public
//////////////////////////////////////////////////////////////////////////////*/
void CSerial::Cleanup ( void )
{
if ( m_hCom != -1 )
close(m_hCom);
}

/*//////////////////////////////////////////////////////////////////////////////
Function: Send
Description: 通过串口向外发N个字节
Calls: ---
Called By: ---
Input: data: 发送字节首地址
datalen: 发送字节长度
Output: ---
Return: -1: 发送失败 > 0:已经发送的字节
Others: public
//////////////////////////////////////////////////////////////////////////////*/
int CSerial::Send ( char *data, int datalen )


{
if ( m_hCom == -1 ) //串口未被打开
return -1;

int len = 0;

len = write( m_hCom, data, datalen);//实际写入的长度
if(len == datalen)
{
return len;
}
else
{
tcflush(m_hCom, TCOFLUSH);
return -1;
}
}

/*//////////////////////////////////////////////////////////////////////////////
Function: Receive
Description: 从串口读入N个字节
Calls: ---
Called By: ---
Input: data: 读入字节首地址
datalen: 发送字节长度
timeout: 超时时间,单位秒 <0 时代表无限期等待
Output: ---
Return: -1: 读入失败 > 0:已经读入的字节
Others: public, timeout默认-1
//////////////////////////////////////////////////////////////////////////////*/
int CSerial::Receive ( char *data, int datalen, int timeout )
{
int readlen, fs_sel;
fd_setfs_read;
struct timeval tv_timeout;

if ( m_hCom == -1 ) //串口未被打开
return -1;

FD_ZERO(&fs_read);
FD_SET(m_hCom, &fs_read);

if ( timeout > 0 )
{
tv_timeout.tv_sec = timeout; //time out : unit sec
tv_timeout.tv_usec = 0;

fs_sel = select( m_hCom+1, &fs_read, NULL, NULL, &tv_timeout);
}
else//死等
{
fs_sel = select( m_hCom+1, &fs_read, NULL, NULL, NULL );
}
if(fs_sel)
{
readlen = read(m_hCom, data, datalen);
return readlen;
}
else
{
return(-1);
}

return readlen;
}

热点排行