免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2391 | 回复: 2
打印 上一主题 下一主题

Linux串口编程怪异问题求解 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2005-01-21 17:31 |只看该作者 |倒序浏览
我考,忙禄了两天的问题竟然被一个小小的printf解决了.自己做了一个串口收发信息的小程序,
portsend.c发信息,portrecv.c收信息,编译通过后出现了一个人问题,即:每发送一批数据后,接收端
可显示出接收到的数据长度,然而printf("%s",&buff)这个命令却执行不了,非要发送方再发一次,该
printf语句才能执行并显示正确数据,然后发送方发送第三次数据时,接收方才显示第二次的数据.
对此我感到非常不解,反复思考,认为应该在发送或接收程序的串口设置出了问题,经反复修改,本人快崩溃之时,随手加上在printf("%s",&buff);后加上了一条printf("\n";,没想到问题居然就解决了.
发送接收都非常正常了.但这是为什么呢?
附源程序如下:
portsend.c:
#include     <stdio.h>;      /*标准输入输出定义*/
#include     <stdlib.h>;     /*标准函数库定义*/
#include     <unistd.h>;     /*Unix标准函数定义*/
#include     <sys/types.h>;  /**/
#include     <sys/stat.h>;   /**/
#include     <fcntl.h>;      /*文件控制定义*/
#include     <termios.h>;    /*PPSIX终端控制定义*/
#include     <errno.h>;      /*错误号定义*/
#define FALSE 0
#define TRUE 1
/***@brief  设置串口通信速率
*@param  fd     类型 int  打开串口的文件句柄
*@param  speed  类型 int  串口速度
*@return  void*/

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, };
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)
           {
               tcflush(fd, TCIOFLUSH);  /*这里不太明白,这个函数干什么用的?*/
            cfsetispeed(&Opt, speed_arr);
            cfsetospeed(&Opt, speed_arr);
            status = tcsetattr(fd, TCSANOW, &Opt);
            if  (status != 0)
                perror("tcsetattr fd1";
            return;
             }
        tcflush(fd,TCIOFLUSH);
   }
}
/**
*@brief   设置串口数据位,停止位和效验位
*@param  fd     类型  int  打开的串口文件句柄*
*@param  databits 类型  int 数据位   取值 为 7 或者8*
*@param  stopbits 类型  int 停止位   取值为 1 或者2*
*@param  parity  类型  int  效验类型 取值为N,E,O,,S
*/
int set_Parity(int fd)
{
    struct termios options;
    if  ( tcgetattr( fd,&options)  !=  0)
    {
          perror("SetupSerial 1";
          return(FALSE);
    }
    options.c_cflag &= ~CSIZE;
    options.c_cflag &= ~PARENB;
    options.c_cflag &= ~CSTOPB;
    options.c_cflag |= CS8;
    options.c_oflag |= OPOST;  /*选择原始输出*/
    tcflush(fd,TCIFLUSH); /* Update the options and do it NOW */
    if (tcsetattr(fd,TCSANOW,&options) != 0)
    {
        perror("SetupSerial 3";
        return (FALSE);
    }
    return (TRUE);
}
/**
*@breif 打开串口
*/
int OpenDev(char *Dev)
{
int        fd = open( Dev, O_RDWR | O_NOCTTY );  //| O_NDELAY | O_NOCTTY
        if (-1 == fd)
                { /*设置数据位数*/
                        perror("Can't Open Serial Port";
                        return -1;
                }
        else
        return fd;

}
/**
*@breif         main()
*/
int main(int argc, char **argv)
{
        int fd,STOP,leng,i;
        STOP=TRUE;
        int nwrite;
        char buff[512];
        char *dev ="/dev/ttyS0";
        fd = OpenDev(dev);
        if (fd>;0)
       set_speed(fd,9600);
        else
                {
               printf("Can't Open Serial Port!\n";
                exit(0);
                }
  if (set_Parity(fd)== FALSE)
  {
    printf("Set Parity Error\n";
    exit(1);
  }
  printf("lease input your string :";
  scanf("%s",&buff);
  leng=strlen(buff);
  buff[leng]='\0';
  printf("\n leng=%d\n",leng);
  //leng++;
  nwrite=write(fd,buff,leng);
  printf("\n nwrite=%d\n",nwrite);
//  for(i=0;i<512;i++);
// { buff='\0'; }
// nwrite=write(fd,buff,leng);
// printf("\n nwrite=%d\n",nwrite);
   close(fd);
   exit(0);
}


portrecv.c:
#include     <stdio.h>;      /*标准输入输出定义*/
#include     <stdlib.h>;     /*标准函数库定义*/
#include     <unistd.h>;     /*Unix标准函数定义*/
#include     <sys/types.h>;  /**/
#include     <sys/stat.h>;   /**/
#include     <fcntl.h>;      /*文件控制定义*/
#include     <termios.h>;    /*PPSIX终端控制定义*/
#include     <errno.h>;      /*错误号定义*/
#define FALSE 0
#define TRUE 1
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, };
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)
           {
               tcflush(fd, TCIOFLUSH);
            cfsetispeed(&Opt, speed_arr);
            cfsetospeed(&Opt, speed_arr);
            status = tcsetattr(fd, TCSANOW, &Opt);
            if  (status != 0)
            perror("tcsetattr fd1";
             return;
             }
   tcflush(fd,TCIOFLUSH);
   }
}
/**
*@brief   设置串口数据位,停止位和效验位
*@param  fd     类型  int  打开的串口文件句柄*
*@param  databits 类型  int 数据位   取值 为 7 或者8*
*@param  stopbits 类型  int 停止位   取值为 1 或者2*
*@param  parity  类型  int  效验类型 取值为N,E,O,,S
*/
int set_Parity(int fd,int databits,int stopbits,int parity)
{
        struct termios options;
if  ( tcgetattr( fd,&options)  !=  0)
  {
          perror("SetupSerial 1";
          return(FALSE);
  }
  options.c_cflag &= ~CSIZE;
  options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG ); /*选择原始输入法*/
  switch (databits) /*设置数据位数*/
  {
          case 7:
                  options.c_cflag |= CS7;
                  break;
          case 8:
                options.c_cflag |= CS8;
                break;
        default:
                fprintf(stderr,"Unsupported data size\n");
                return (FALSE);
        }
  switch (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);  /* 设置为奇效验*/
                options.c_iflag |= INPCK;             /* Disnable parity checking */
                break;
        case 'e':
        case 'E':
                options.c_cflag |= PARENB;     /* Enable parity */
                options.c_cflag &= ~PARODD;   /* 转换为偶效验*/  
                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 (FALSE);
                }
  /* 设置停止位*/   
  switch (stopbits)
          {
          case 1:
                  options.c_cflag &= ~CSTOPB;
                break;
        case 2:
                options.c_cflag |= CSTOPB;
                break;
        default:
                fprintf(stderr,"Unsupported stop bits\n");
                return (FALSE);
        }
  /* Set input parity option */
  if (parity != 'n')
                  options.c_iflag |= INPCK;
    options.c_cc[VTIME] = 150; // 15 seconds
    options.c_cc[VMIN] = 0;

  tcflush(fd,TCIFLUSH); /* Update the options and do it NOW */
  if (tcsetattr(fd,TCSANOW,&options) != 0)
          {
                  perror("SetupSerial 3");
                return (FALSE);
        }
  return (TRUE);
}
/**
*@breif 打开串口
*/
int OpenDev(char *Dev)
{
int        fd = open( Dev, O_RDWR | O_NOCTTY );         //| O_NOCTTY | O_NDELAY
        if (-1 == fd)
                { /*设置数据位数*/
                        perror("Can't Open Serial Port");
                        return -1;
                }
        else
        return fd;

}
/**
*@breif         main()
*/
int main(int argc, char **argv)
{
        int fd;
        int nread;
        char buff[512];
        char *dev ="/dev/ttyS1";
        fd = OpenDev(dev);
        if (fd>;0)
    set_speed(fd,9600);
        else
                {
                printf("Can't Open Serial Port!\n");
                exit(0);
                }
  if (set_Parity(fd,8,1,'N')== FALSE)
  {
    printf("Set Parity Error\n");
    exit(1);
  }
  while(1)
          {
                   while((nread = read(fd,buff,512))>;0)
                   {
                      printf("\nLen=%d\n",nread);
                      buff[nread]='\0';
                      printf("buff=%s",buff);
                printf("\n");  /*问题就出在这里,加了这一句后问题就解决了*/
                    }
          }
    close(fd);
    exit(0);
}

论坛徽章:
0
2 [报告]
发表于 2005-01-21 19:42 |只看该作者

Linux串口编程怪异问题求解

  1. printf("buff=%s\n",buff);
复制代码


收到回车字符后,才会刷新输出。或者 fflush (stdout); 也可以。

论坛徽章:
0
3 [报告]
发表于 2005-01-25 10:03 |只看该作者

Linux串口编程怪异问题求解

当一个程序产生输出时,能够立即看到它有多重要?这取决于程序。

    例如,终端上显示输出并要求人们坐在终端前面回答一个问题,人们能够看到输出以知道该输入什么就显得至关重要了。另一方面,如果输出到一个文件中,并最终被发送到一个行式打印机,只有所有的输出最终能够到达那里是重要的。

    立即安排输出的显示通常比将其暂时保存在一大块一起输出要昂贵得多。因此,C实现通常允许程序员控制产生多少输出后在实际地写出它们。

    这个控制通常约定为一个称为setbuf()的库函数。如果buf是一个具有适当大小的字符数组,则

setbuf(stdout, buf);

将告诉I/O库写入到stdout中的输出要以buf作为一个输出缓冲,并且等到buf满了或程序员直接调用fflush()再实际写出。缓冲区的合适的大小在中定义为BUFSIZ。

    因此,下面的程序解释了通过使用setbuf()来讲标准输入复制到标准输出:

#include

main() {
    int c;

    char buf[BUFSIZ];
    setbuf(stdout, buf);

    while((c = getchar()) != EOF)
        putchar(c);
}

    不幸的是,这个程序是错误的,因为一个细微的原因。

    要知道毛病出在哪,我们需要知道缓冲区最后一次刷新是在什么时候。答案;主程序完成之后,作为库在将控制交回到操作系统之前所执行的清理的一部分。在这一时刻,缓冲区已经被释放了!

    有两种方法可以避免这一问题。

    首先,是用静态缓冲区,或者将其显式地声明为静态:

static char buf[BUFSIZ];

或者将整个声明移到主函数之外。

    另一种可能的方法是动态地分配缓冲区并且从不释放它:

char *malloc();
setbuf(stdout, malloc(BUFSIZ));

注意在后一种情况中,不必检查malloc()的返回值,因为如果它失败了,会返回一个空指针。而setbuf()可以接受一个空指针作为其第二个参数,这将使得stdout变成非缓冲的。这会运行得很慢,但它是可以运行的。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP