当前位置: 技术问答>linux和unix
使用ST16C2552IJ扩展linux串口收发数据不全问题.谁遇到这现象.
来源: 互联网 发布时间:2016-08-31
本文导语: 测试过程如下: 测试用电脑标准串口给arm-linux开发扳发送gps数据 例如:$GPRMC,022920.567,A,2233.6433,N,11405.4822,E,13.36,338.74,100604,,*3C 在linux中收到: 没有中间一不部分数据: $GPRMC,015503.56*35 有时也会连续收到两条没尾巴的数...
测试过程如下:
测试用电脑标准串口给arm-linux开发扳发送gps数据
例如:$GPRMC,022920.567,A,2233.6433,N,11405.4822,E,13.36,338.74,100604,,*3C
在linux中收到:
没有中间一不部分数据:
$GPRMC,015503.56*35
有时也会连续收到两条没尾巴的数据:
$GPRMC,020341.56
$GPRMC,020342.5638,E
发送5条数据,才会接收成功接收一条完整的数据.
不知道怎么搞的。
我这个串口使用的是ST16C2552IJ芯片扩展的Linux串口,难道是因为使用了扩展芯片的原因吗?不过我想不会这么不可靠吧.
难道是我程序问题,贴两个关键函数,一个打开串口和接收串口数据函数.
/**
*@brief 设置串口数据位,停止位和效验位并打开串口
*@param sTTYName 串口文件描述符
*@param speed 串口波特率
*@param databits 数据位 取值 为 7 或者8
*@param stopbits 停止位 取值为 1 或者2
*@param parity 效验类型 取值为N,E,O,,S
*@param fl 标志位1表示使用异步方式打开,0表示用阻塞方式打开串口
*@return 成功返回打开串口指针,失败返回-1
*@explam OpenDev("/dev/ttyS0",B9600,8,1,'N',1)
*/
int OpenDev(const char *sttyname,int speed,int databits,int stopbits,int parity,char fl)
{
int i = 0;
int status = 0;
int fd = 0; //打开串口指针
int flage = 0; //打开标志位
struct termios Opt; //串口设置结构
struct termios t_mybuf;
bzero(&Opt,sizeof(Opt));
bzero(&t_mybuf,sizeof(t_mybuf));
flage = fl?O_RDWR|O_NOCTTY|O_NONBLOCK:O_RDWR|O_NOCTTY;
fd = open(sttyname,flage); //通过串口设备名打开串口
if(fd == -1){
perror("open");
return -1;
}
if(tcgetattr(fd,&Opt) == -1){ //获取当前串口设置
perror("tcgetattr");
return -1;
}
if(cfsetispeed(&Opt,speed) == -1){ //设置串口波特率
perror("cfsetispeed");
return -1;
}
if(cfsetospeed(&Opt,speed) == -1){
perror("cfsetospeed");
return -1;
}
/*取消一些设置*/
Opt.c_cflag &= ~CSIZE; /*需要设置字符大小*/
Opt.c_lflag &= ~(ICANON|ECHO|ECHOE|ISIG);
Opt.c_oflag &= ~OPOST; /*选择原始输出*/
/*一些必须设置的项*/
Opt.c_cflag |= CLOCAL | CREAD | O_NDELAY;
Opt.c_iflag |= IGNPAR; //忽略奇偶校验错误给数据放行
/*设置数据位数*/
switch(databits)
{
case 7:
Opt.c_cflag |= CS7; //设置7位一字节
break;
case 8:
Opt.c_cflag |= CS8; //设置8位一字节
break;
default:
printf(" no set databits !n");
return -1;
}
/*设置校验方式*/
switch(parity)
{
case 'n':
case 'N': /*无校验*/
Opt.c_cflag &= ~PARENB;
Opt.c_iflag &= ~INPCK; /*INPCK用于设置奇偶位校验位是否有效*/
break;
case 'o':
case 'O': /*奇校验*/
Opt.c_cflag |= (PARODD | PARENB);
Opt.c_iflag |= INPCK;
break;
case 'e':
case 'E': /*偶校验*/
Opt.c_cflag |= PARENB;
Opt.c_cflag &= ~PARODD;
Opt.c_iflag |= INPCK;
break;
case 'S':
case 's': /*无*/
Opt.c_cflag &= ~PARENB;
Opt.c_cflag &= ~CSTOPB;
break;
default:
printf(" no set parity !n");
return -1;
}
/* 设置停止位*/
switch (stopbits)
{
case 1:
Opt.c_cflag &= ~CSTOPB;
break;
case 2:
Opt.c_cflag |= CSTOPB;
break;
default:
printf(" no set parity !n");
return -1;
}
Opt.c_cc[VTIME] = 1;
Opt.c_cc[VMIN] = 0;
tcflush(fd,TCIFLUSH); //清空缓冲区
if(tcsetattr(fd,TCSANOW,&Opt) == -1){
perror("tcsetattr");
}
return fd;
}
/**
*@brief 接收串口数据
*@param s_fd 打开的串口指针
*@param buf 接收数据指针
*@return 成功返回接收到的数据长度,超时返回-1,错误返回-2
*/
int ReadDev(int s_fd,char *buf)
{
int available = 0;
static unsigned int rectimer;
fd_set rfds;
int maxfd = 0;
int se_cnt = 0;
struct timeval timeout;
do{
FD_ZERO (&rfds);
FD_SET(s_fd, &rfds);
timeout.tv_sec=0;
timeout.tv_usec=1000; //10*1000
maxfd = s_fd;
se_cnt = select(maxfd+1, &rfds, NULL, NULL, &timeout);
if(se_cnt > 0)
{
if(FD_ISSET(s_fd, &rfds))
{
if((available = read(s_fd, &buf[0], 256)) != -1 ){
return(available);
}
}
}else if(se_cnt == 0 ){
return -1;
}
FD_CLR(s_fd, &rfds);
}while(se_cnt 0){
buf[rd_len] = '';
printf("[%dB]%sn",rd_len,buf); //打印输出
}
我可以通过输出自己把包拼起来,但发现好多包都是不全的.
谁知道这个现象是什么引起的呢?????
测试用电脑标准串口给arm-linux开发扳发送gps数据
例如:$GPRMC,022920.567,A,2233.6433,N,11405.4822,E,13.36,338.74,100604,,*3C
在linux中收到:
没有中间一不部分数据:
$GPRMC,015503.56*35
有时也会连续收到两条没尾巴的数据:
$GPRMC,020341.56
$GPRMC,020342.5638,E
发送5条数据,才会接收成功接收一条完整的数据.
不知道怎么搞的。
我这个串口使用的是ST16C2552IJ芯片扩展的Linux串口,难道是因为使用了扩展芯片的原因吗?不过我想不会这么不可靠吧.
难道是我程序问题,贴两个关键函数,一个打开串口和接收串口数据函数.
/**
*@brief 设置串口数据位,停止位和效验位并打开串口
*@param sTTYName 串口文件描述符
*@param speed 串口波特率
*@param databits 数据位 取值 为 7 或者8
*@param stopbits 停止位 取值为 1 或者2
*@param parity 效验类型 取值为N,E,O,,S
*@param fl 标志位1表示使用异步方式打开,0表示用阻塞方式打开串口
*@return 成功返回打开串口指针,失败返回-1
*@explam OpenDev("/dev/ttyS0",B9600,8,1,'N',1)
*/
int OpenDev(const char *sttyname,int speed,int databits,int stopbits,int parity,char fl)
{
int i = 0;
int status = 0;
int fd = 0; //打开串口指针
int flage = 0; //打开标志位
struct termios Opt; //串口设置结构
struct termios t_mybuf;
bzero(&Opt,sizeof(Opt));
bzero(&t_mybuf,sizeof(t_mybuf));
flage = fl?O_RDWR|O_NOCTTY|O_NONBLOCK:O_RDWR|O_NOCTTY;
fd = open(sttyname,flage); //通过串口设备名打开串口
if(fd == -1){
perror("open");
return -1;
}
if(tcgetattr(fd,&Opt) == -1){ //获取当前串口设置
perror("tcgetattr");
return -1;
}
if(cfsetispeed(&Opt,speed) == -1){ //设置串口波特率
perror("cfsetispeed");
return -1;
}
if(cfsetospeed(&Opt,speed) == -1){
perror("cfsetospeed");
return -1;
}
/*取消一些设置*/
Opt.c_cflag &= ~CSIZE; /*需要设置字符大小*/
Opt.c_lflag &= ~(ICANON|ECHO|ECHOE|ISIG);
Opt.c_oflag &= ~OPOST; /*选择原始输出*/
/*一些必须设置的项*/
Opt.c_cflag |= CLOCAL | CREAD | O_NDELAY;
Opt.c_iflag |= IGNPAR; //忽略奇偶校验错误给数据放行
/*设置数据位数*/
switch(databits)
{
case 7:
Opt.c_cflag |= CS7; //设置7位一字节
break;
case 8:
Opt.c_cflag |= CS8; //设置8位一字节
break;
default:
printf(" no set databits !n");
return -1;
}
/*设置校验方式*/
switch(parity)
{
case 'n':
case 'N': /*无校验*/
Opt.c_cflag &= ~PARENB;
Opt.c_iflag &= ~INPCK; /*INPCK用于设置奇偶位校验位是否有效*/
break;
case 'o':
case 'O': /*奇校验*/
Opt.c_cflag |= (PARODD | PARENB);
Opt.c_iflag |= INPCK;
break;
case 'e':
case 'E': /*偶校验*/
Opt.c_cflag |= PARENB;
Opt.c_cflag &= ~PARODD;
Opt.c_iflag |= INPCK;
break;
case 'S':
case 's': /*无*/
Opt.c_cflag &= ~PARENB;
Opt.c_cflag &= ~CSTOPB;
break;
default:
printf(" no set parity !n");
return -1;
}
/* 设置停止位*/
switch (stopbits)
{
case 1:
Opt.c_cflag &= ~CSTOPB;
break;
case 2:
Opt.c_cflag |= CSTOPB;
break;
default:
printf(" no set parity !n");
return -1;
}
Opt.c_cc[VTIME] = 1;
Opt.c_cc[VMIN] = 0;
tcflush(fd,TCIFLUSH); //清空缓冲区
if(tcsetattr(fd,TCSANOW,&Opt) == -1){
perror("tcsetattr");
}
return fd;
}
/**
*@brief 接收串口数据
*@param s_fd 打开的串口指针
*@param buf 接收数据指针
*@return 成功返回接收到的数据长度,超时返回-1,错误返回-2
*/
int ReadDev(int s_fd,char *buf)
{
int available = 0;
static unsigned int rectimer;
fd_set rfds;
int maxfd = 0;
int se_cnt = 0;
struct timeval timeout;
do{
FD_ZERO (&rfds);
FD_SET(s_fd, &rfds);
timeout.tv_sec=0;
timeout.tv_usec=1000; //10*1000
maxfd = s_fd;
se_cnt = select(maxfd+1, &rfds, NULL, NULL, &timeout);
if(se_cnt > 0)
{
if(FD_ISSET(s_fd, &rfds))
{
if((available = read(s_fd, &buf[0], 256)) != -1 ){
return(available);
}
}
}else if(se_cnt == 0 ){
return -1;
}
FD_CLR(s_fd, &rfds);
}while(se_cnt 0){
buf[rd_len] = '';
printf("[%dB]%sn",rd_len,buf); //打印输出
}
我可以通过输出自己把包拼起来,但发现好多包都是不全的.
谁知道这个现象是什么引起的呢?????
|
你读的太快了,简单的,select 成功后你sleep 一秒,就应该都能读到。
实际上,你应该循环读取,直到把所有的都读完,而不是read一下就返回回去。
实际上,你应该循环读取,直到把所有的都读完,而不是read一下就返回回去。