更新:如何知道半双工串行线何时空闲?

时间:2019-06-06 03:18:47

标签: linux serial-port wireless duplex wireless-connection

我有一个基于RS-232的实际串行端口,该端口与Linux一起用于与微控制器进行无线通信。 (我在连接的两端使用无线模块,而不是串行电缆)

有一个问题。整个操作必须为半双工,因为无线模块不支持全双工操作。实际上,它们在发送数据时会忽略传入的数据。

因此,在C语言中,我正在寻找最有效率和最快的代码,以便在开始将代码发送回远程之前,何时检测到没有数据来自远程发送器。

此外,远程设备只给我30mS的数据发送给它,数据本身为47字节,速度为56kbps,因此检测线路静默的例程需要快速执行。

我提供了一些想法,但我试图找出最好的。也许有一个我什至不知道的功能会更好。我尝试了不同的VMIN和VTIME值,但发现自己不成功。

这是我的代码提示:

想法1:

  char b[2]; //incoming character buffer
  int nread=1; //number of bytes read

  int fd=open(dev,O_NOCTTY | O_RDONLY | O_SYNC);
  while (nread > 0){
    nread=read(fd,b,1); //keep reading until no bytes read are reported
  }
  fclose(fd);

想法2:

  int timeout=1; //1 second timeout
  int fd=open(dev,O_NOCTTY | O_RDONLY | O_SYNC);
  time_t then=time(NULL);
  while (time(NULL) - then > timeout){
    nread=read(fd,b,1); 
    if (nread > 0){then=time(NULL);} //reset timer if at least 1 byte is read
  }
  fclose(fd);

想法3:

  char b[2]; //incoming character buffer
  int nread=1; //number of bytes read
  int numfail=0; //number of failed attempts to read bytes
  int fd=open(dev,O_NOCTTY | O_RDONLY | O_SYNC);
  while (numfail < 100){
    nread=read(fd,b,1); //keep reading until no bytes read are reported 100 consecutive times
    if (nread < 1){numfail++;}else{numfail=0;}
  }
  fclose(fd);

第一个可能行不通的想法(除非我很幸运在这里找到特殊的Linux驱动程序配置?)将一直检查端口是否为单个字节,直到找不到该字节然后退出。

第二个想法设置了字符必须进入的特定时间,如果在给定时间内没有字符到达,则该行被认为是空闲的。否则时钟将重置。

最后一个主意是对第一个主意的扩展,除了程序要连续几次尝试从串行线读取一个字节失败之前,程序不会退出。如果检测到至少一个字节,尝试计数器将复位。我觉得这可能是与更好的VTIME和VMIN设置一起使用的最佳选择,但我不确定。

我只需要一个功能,该功能可以花费很少的时间(最多几个微秒)来检测何时没有任何设备在串行线上发送数据。

我目前唯一的解决方案是创建更多硬件,这些硬件从PC收集串行数据,缓冲数据,然后硬件在将数据发送到远程单元之前检测串行线何时空闲,但是我不想浪费更多的电路板和零件。我宁愿有一个软件解决方案(在Linux中)。

有什么想法吗?

为了清楚起见,远程单元使用基于8052的微控制器(型号为89S52),其UART仅具有1个字节的缓存,而我的计算机使用16550 UART,我认为它具有14或16字节的缓存。

更新

我尝试了另一个更好的主意。似乎可以在2mS的间隔内检测到何时空闲或不空闲的线路发生了变化,但我试图在微秒级上检测到更多。

这是我的代码:

  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <unistd.h>
  #include <fcntl.h>
  #include <sys/select.h>

  int main(int argc, char* argv[]){
    int fd=open("/dev/ttyS0",O_NOCTTY | O_RDONLY | O_SYNC);
    if (fd < 0){
        printf("Error\n");
        return -1;
    }
    long v=1;
    if (argc > 1){
      v=strtol(argv[1],NULL,10); //Custom inter-string timeout
    }
    struct timeval t={0,5000}; //set initial timeout to 5mS
    int gotsz=0; //characters received total
    int bpsz=100000; //Most # characters we want
    unsigned char b[bpsz]; //characters
    unsigned char* bp=b; //Active pointer to characters
    bpsz--; //We don't want to wreck memory that isnt ours
    fd_set f; 
    while(1){
      FD_ZERO(&f);
      FD_SET(fd,&f);
      int ret=select(fd+1,&f,NULL,NULL,&t); //check at 5mS intervals for anything
      if (ret < 0){
        printf("Error\n");
        return -1;
      }
      if (ret != 0){
        break; //Stall until anything is received.
      }
    }
    while(1){
      FD_ZERO(&f);
      FD_SET(fd,&f);
      int ret=select(fd+1,&f,NULL,NULL,&t);
      if (ret < 0){
        printf("Error\n");
        return -1;
      }
      if (ret == 0){
        break;    //Only exit loop when there are no more characters in a short time
      }
      int sz=read(fd,bp,bpsz); //fill up buffer advancing start pointer (saves use of strcpy)
      gotsz+=sz;
      bp+=sz;
      bpsz-=sz;
      t.tv_usec=v;
    }
    close(fd);
    //print all that we got in hex
    bp=b;
    printf("Got: ");
    int n;
    for (n=0;n<gotsz;n++){
        printf("%X",*bp);
        bp++;
    }
    printf("\n");
    printf("Intermediate Timeout %ld uS (%ld mS)\n",v,v/1000);
    return 0;
  }

我觉得现在每次我想从串行端口读取数据时,都需要创建某种全局系统锁,以便感测何时读取数据。就是说,我的意思是,例如,如果我将计算机用于多种目的,例如浏览网页和在后台播放音乐或观看视频,并且运行程序,我认为通过使程序冻结上述所有过程来读取串行数据,我认为端口数据将为CPU提供足够的时间来处理串行端口数据。然后,当我的程序结束时,过程可以继续。

有什么主意我能做到吗?

0 个答案:

没有答案