Serial port 为什么serial.available在此代码段中不起作用?

Serial port 为什么serial.available在此代码段中不起作用?,serial-port,processing,Serial Port,Processing,我有一个处理草图,需要设置2个与USB设备的连接。我无法预先告诉您哪个设备是USB0,哪个是USB1。(至少我不知道) 其中一台设备与另一台设备打招呼,但另一台根本不应答。因此,我编写了一个简单的超时代码。在设置中,我不断检查是否有字节要读取。但是,while和if语句都会产生错误的结果 while( dccCentral.available() < 5 ) { if( dccCentral.available() >= 5) break; if(millis() &

我有一个处理草图,需要设置2个与USB设备的连接。我无法预先告诉您哪个设备是USB0,哪个是USB1。(至少我不知道)

其中一台设备与另一台设备打招呼,但另一台根本不应答。因此,我编写了一个简单的超时代码。在设置中,我不断检查是否有字节要读取。但是,while和if语句都会产生错误的结果

while( dccCentral.available() < 5 ) {
    if( dccCentral.available() >= 5) break;
    if(millis() > 5000 ) {
        println("timeout occured");
        println(dccCentral.available());
        break;
    }
}
在此超时发生之前,应该已经中断while循环。当接收到5个或更多字节时,while循环本身也应该退出

为什么这两条线都有

while( dccCentral.available() < 5 ) {
    if( dccCentral.available() >= 5) break;
while(dccCentral.available()<5){
如果(dccCentral.available()>=5)中断;

失败?

就我个人而言,我尽量避免while循环,除非没有其他方法(例如,在线程内部),也就是避免逻辑陷阱和干扰可能需要一点时间初始化的其他对象的生命周期

如果您从Arduino发送字符串并同时使用
println()
,那么您可以初始化端口,使用Serial与to finally一起轻松捕获该端口

一旦开始获取数据,您可以:

  • 使用对您要使用的串行端口的引用,以及一些额外的引用,直到您知道哪个端口是哪个端口为止
  • 使用布尔“切换”仅处理“hello”一次
  • 如果收到hello,可以使用
    serialEvent()
    Serial
    参数分配
    dccCentral
    ,并通过消除过程分配另一个端口
  • 下面是一个注释过的草图来说明这个想法:

    import processing.serial.*;
    
    // be sure to set this to the baud rate your device use with Arduino as well
    final int BAUD_RATE = 115200;
    // reference to Serial port sending "Hello" (when that get's detected)
    Serial dccCentral;
    // reference to the other Serial port
    Serial otherDevice;
    // temporary references
    Serial usb0;
    Serial usb1;
    // 'toggle' to keep track where the hello was received and handled or not (by default initialised as false)
    boolean wasHelloReceived;
    
    void setup(){
        usb0 = initSerial("/dev/ttyUSB0", BAUD_RATE);
        usb1 = initSerial("/dev/ttyUSB1", BAUD_RATE);
    }
    
    Serial initSerial(String portName, int baudRate){
        Serial port = null;
    
        try{
            port = new Serial(this, portName, baudRate);
            // if sending strings and using println() from Arduino
            // you can buffer all chars until the new line ('\n') character is found
            port.bufferUntil('\n');
        }catch(Exception e){
            println("error initialising port: " + portName);
            println("double check name, cable connections and close other software using the same port");
            e.printStackTrace();
        }
    
        return port;
    }
    
    void draw(){
        background(0);
        text("wasHelloReceived: " + wasHelloReceived + "\n"
            +"dccCentral: " + dccCentral + "\n" 
            +"otherDevice: " + otherDevice , 10 ,15);
        // do something with the devices once they're ready (e.g. send a message every 3 seconds)
        if(millis() % 3000 == 0){
            if(dccCentral != null){
                dccCentral.write("ping\n");
            }
            if(otherDevice != null){
                otherDevice.write("pong\n");
            }
        }
    }
    
    void serialEvent(Serial port){
        try{
            String serialString = port.readString();
            // if the received string is not null, nor empty
            if(serialString != null && !serialString.isEmpty()){
                // for debugging purposes display the data received
                println("received from serial: " + serialString);
                // trim any white space
                serialString = serialString.trim();
                // check if "hello" was received
                if(serialString.equals("hello")){
                    println("hello detected!");
                    // if the dccCEntral (hello sending) serial port wasn't assigned yet, assign it
                    // think of this as debouncing a button: setting the port once "hello" was received should happen only once
                    if(!wasHelloReceived){
    
                        // now what dccCentral is found, assign it to the named reference
                        dccCentral = port;
    
                        // by process elimiation, assign the other port 
                        // (e.g. if dccCentral == usb0, then other is usb1 and vice versa)
                        otherDevice = (dccCentral == usb0 ? usb1 : usb0);
                        /*
                        the above is the same as
                        if(dccCentral == usb0){
                            otherDevice = usb1;
                        }else{
                            otherDevice = usb0;
                        }
                        */
    
                        wasHelloReceived = true;
                    }
                }
            }
        }catch(Exception e){
            println("error processing serial data");
            e.printStackTrace();
        }
    }
    
    注意上述代码尚未经过测试,因此可能包含语法错误,但希望能够理解这一点

    我忍不住注意到,USB0/USB1是串行设备在Linux上有时出现的方式。 如果您使用的是覆盆子Pi,如果您熟悉Python,我可以推荐一种稍微简单一点的方法

  • 您只需调用:
    python-m serial.tools.list_ports-v
    ,它将列出带有额外信息的端口,如串行转换器芯片组的序列号。无论使用哪家制造商和USB端口,这都有助于区分哪个设备是哪个
  • 除了串行端口名称/位置之外,它还支持多种方式(URL)访问端口,使用一个非常聪明的:将允许您根据设备的唯一序列号过滤设备
  • 以下是使用相同芯片组的两台设备的基本
    列表\u端口-v
    输出:

    column 1
    
    /dev/ttyUSB9        
        desc: TTL232R-3V3
        hwid: USB VID:PID=0403:6001 SER=FT94O21P LOCATION=1-2.2
    
    column 2
    
    /dev/ttyUSB8        
        desc: TTL232R-3V3
        hwid: USB VID:PID=0403:6001 SER=FT94MKCI LOCATION=1-2.1.4
    
    要使用串行方式分配设备,请使用以下命令:

    "hwgrep://FT94O21P"
    "hwgrep://FT94MKCI"
    
    更新

    逐步调试系统并一次尝试一个端口可能会有所帮助。 这样做的目的是让读取预期串行字符串的代码位紧凑。 下面是一个基本示例,它只需一次将一个字符累积成一个字符串并显示:

    import processing.serial.*;
    
    Serial port;
    
    String fromSerial = "";
    
    void setup(){
      size(300,300);
      port = initSerial("/dev/ttyUSB0", 115200);
    }
    
    Serial initSerial(String portName, int baudRate){
        Serial port = null;
    
        try{
            port = new Serial(this, portName, baudRate);
            // if sending strings and using println() from Arduino
            // you can buffer all chars until the new line ('\n') character is found
            port.bufferUntil('\n');
        }catch(Exception e){
            println("error initialising port: " + portName);
            println("double check name, cable connections and close other software using the same port");
            e.printStackTrace();
        }
    
        return port;
    }
    
    void draw(){
      
      if(port != null){
        if(port.available() > 0){
          char inChar = port.readChar();
          fromSerial += inChar;
          if(inChar == '\n'){
            println("newline encountered");
            println(fromSerial.split("\n"));
          }
        }
      }
      
      background(0);
      text("from serial:" + fromSerial, 10,15);
    }
    
    如果来自
    dccCentral
    的数据符合预期:很好,代码可以简化,并在将来应用正确的条件来过滤设备, 否则,它将有助于pin点通信问题首先获得“hello”(如果从Arduino使用
    Serial.println()
    发送,则为6个字节(“hello”(5)+'\n))


    关于Python,一点问题都没有。如果这个想法将来有用,您可以查看。(AFAIK Processing Serial在幕后使用JSSC)

    我知道在while循环中,.available()的结果一直都是0。但为什么超时发生时会显示12?为什么会发生这种情况?thnx。通常我根本不使用while循环,也不使用延迟,不是在处理中,不是在C中(主循环除外)。但是在设置中,我仍然偶尔使用它们来处理这些事情。另外,为什么推荐“SerialEvent”?我曾经尝试过使用它,它给了我我见过的最原子错误的代码。我发现在void循环开始时读取字节比在随机未定义的地方读取字节更可靠。我也不能/不会使用python。我不能简单地重新编码我的项目,当我交换硬件组件时,设备ID是无用的。@bask185不用担心。感谢您提供的最新信息:支持的人越多越好。我过去从未遇到过
    serialEvent
    问题。如果在该事件中解析数据时出现问题,它将在我经历的第一次失败后自动禁用。我在上面发布了一个小草图,以测试从Arduino.Ho接收字符的情况这将有助于再次检查您是否正确地从Arduino接收到所有信息。理论上,如果您只需检查哪个设备发送数据(例如,
    if(port.available()>0))
    ),而不必等待完整的hello?
    import processing.serial.*;
    
    Serial port;
    
    String fromSerial = "";
    
    void setup(){
      size(300,300);
      port = initSerial("/dev/ttyUSB0", 115200);
    }
    
    Serial initSerial(String portName, int baudRate){
        Serial port = null;
    
        try{
            port = new Serial(this, portName, baudRate);
            // if sending strings and using println() from Arduino
            // you can buffer all chars until the new line ('\n') character is found
            port.bufferUntil('\n');
        }catch(Exception e){
            println("error initialising port: " + portName);
            println("double check name, cable connections and close other software using the same port");
            e.printStackTrace();
        }
    
        return port;
    }
    
    void draw(){
      
      if(port != null){
        if(port.available() > 0){
          char inChar = port.readChar();
          fromSerial += inChar;
          if(inChar == '\n'){
            println("newline encountered");
            println(fromSerial.split("\n"));
          }
        }
      }
      
      background(0);
      text("from serial:" + fromSerial, 10,15);
    }