You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Arduino通过USB Host Shield向PL2303接口湿度计发送0x20失败求助

问题:Arduino USB Host Shield无法向PL2303转USB的湿度计发送0x20指令

我开发了一款带RS232输出、集成PL2303转USB线的湿度计。PC端用Python脚本可以正常读取设备返回的0x10,并发送0x20获取测量数据,但用Arduino搭配USB Host Shield时,无法获取0x20对应的响应数据,SndData函数返回rcode为0。

Arduino源码

/* Arduino terminal for PL2303 USB to serial converter and DealeXtreme GPRS modem. */
/* USB support */
#include <usbhub.h>

/* CDC support */
#include <cdcacm.h>

#include <cdcprolific.h>

// Satisfy the IDE, which needs to see the include statment in the ino too.
#ifdef dobogusinclude#include <spi4teensy3.h>

#endif#include <SPI.h>

class PLAsyncOper: public CDCAsyncOper {
  public: uint8_t OnInit(ACM * pacm);
};

uint8_t PLAsyncOper::OnInit(ACM * pacm) {
  uint8_t rcode;

  // Set DTR = 1
  rcode = pacm -> SetControlLineState(1);

  if (rcode) {
    ErrorMessage < uint8_t > (PSTR("SetControlLineState"), rcode);
    return rcode;
  }

  LINE_CODING lc;
  lc.dwDTERate = 2400;
  lc.bCharFormat = 0;
  lc.bParityType = 0;
  lc.bDataBits = 8;

  rcode = pacm -> SetLineCoding( & lc);

  if (rcode)
    ErrorMessage < uint8_t > (PSTR("SetLineCoding"), rcode);

  return rcode;
}
USB Usb;
//USBHub     Hub(&Usb);
PLAsyncOper AsyncOper;
PL2303 Pl( & Usb, & AsyncOper);

void setup() {
  Serial.begin(2400);
  #if!defined(__MIPSEL__)
  while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection
  #endif
  Serial.println("Start");

  if (Usb.Init() == -1)
    Serial.println("OSCOKIRQ failed to assert");

  delay(200);
}

void loop() {
  Usb.Task();

  if (Usb.getUsbTaskState() == USB_STATE_RUNNING) {
    uint8_t rcode;

    /* reading the converter */
    /* buffer size must be greater or equal to max.packet size */
    /* it it set to 64 (largest possible max.packet size) here, can be tuned down
    for particular endpoint */
    uint8_t buf[64];
    uint16_t rcvd = 64;

    rcode = Pl.RcvData( & rcvd, buf);
    if (rcode && rcode != hrNAK)
      ErrorMessage < uint8_t > (PSTR("Ret"), rcode);

      if (rcvd) { //more than zero bytes received
        for (uint16_t i = 0; i < 64; i++) {
            Serial.print(buf[i], HEX);
            Serial.print(" ");
        }

        if (rcvd == 1) {
          Serial.println("Size = 1");
          Serial.print("HEX from device: ");
          Serial.println(buf[0], HEX);
          //Confirm if we got 0x10 response from device
          if (buf[0] == 0x10) {
            Serial.println("Got data ready to send response from device ");
            //Send 0x20 to device
            uint8_t rq = 0x20;
            rcode = Pl.SndData(1, &rq);
            
            if (rcode) {
                ErrorMessage < uint8_t > (PSTR("SndData"), rcode);
                Serial.print("HEX from user: ");
                Serial.println(rcode, HEX);
            }
          }
        } else {
          Serial.println("Size > 1");
          Serial.println(sizeof(buf));
          for (uint16_t i = 0; i < rcvd; i++) {
            Serial.print(buf[i], HEX);
            Serial.print(" ");
          }
        }
      }
  }
}

PC端正常运行的Python脚本

import serial

ser = serial.Serial('COM17', 2400)

# Check if serial is available then print what is read
if ser.isOpen():
    print(ser.name + ' is open...')
    # Make the handshake Xon/Xoff
    #ser.write(b'\x11')
    # Make the handshake RTS/CTS
    #ser.setRTS(True)
    # Setup flow control to RTS/CTS
    #ser.setRTS(True)
    while True:
        # Read bytes from serial
        data = ser.read()
        # Print what is read
        print(data.hex)
        # Check if we get 0x10
        if data == b'\x10':
            # Send 0x20
            ser.write(b'\x20')
            # Send 0x20 as uint8
            #ser.write(bytes([0x20]))
            # Send 32 as uint8
            #ser.write(bytes([32]))
            # Then check if we got data, if so print it
            #data = ser.read()
            #print(data)
            if ser.in_waiting > 0:
            #    print(ser.read())
                # Convert to hex
            #    print(ser.read().hex())
                print("Got data")
            else:
                print("No data")
else:
    print('serial not available')

湿度计设备

湿度计外观


解决思路

1. 明确SndData返回值的意义

SndData返回0代表发送操作成功,没有响应不是因为发送失败,而是后续读取逻辑的问题。当前代码发送0x20后没有主动等待并读取响应,仅依赖下一次循环的被动读取,可能存在时序偏差。

2. 优化发送后的读取逻辑

发送0x20后添加短延时(根据设备响应速度调整,比如100ms),然后主动调用RcvData读取响应:

if (buf[0] == 0x10) {
    Serial.println("Got data ready to send response from device ");
    uint8_t rq = 0x20;
    rcode = Pl.SndData(1, &rq);
    
    if (rcode) {
        ErrorMessage < uint8_t > (PSTR("SndData"), rcode);
        Serial.print("SndData error code: ");
        Serial.println(rcode, HEX);
    } else {
        Serial.println("0x20 sent successfully");
        // 等待设备生成响应
        delay(100);
        // 主动读取响应数据
        uint16_t resp_len = 64;
        uint8_t resp_buf[64];
        rcode = Pl.RcvData(&resp_len, resp_buf);
        if (resp_len > 0) {
            Serial.println("Received response:");
            for (uint16_t i = 0; i < resp_len; i++) {
                Serial.print(resp_buf[i], HEX);
                Serial.print(" ");
            }
            Serial.println();
        } else {
            Serial.println("No response received");
        }
    }
}

3. 统一串口控制参数

Python脚本中注释了流控制相关代码,说明设备可能不需要硬件流控制,但Arduino代码仅设置了DTR=1,未处理RTS。尝试同时设置DTR和RTS:

// 设置DTR=1,RTS=1
rcode = pacm->SetControlLineState(0x03);

4. 清理调试输出

当前代码会打印整个64字节缓冲区,包含大量无效0值,干扰调试。修改为仅打印实际收到的rcvd个字节:

if (rcvd) {
    Serial.print("Received ");
    Serial.print(rcvd);
    Serial.println(" bytes:");
    for (uint16_t i = 0; i < rcvd; i++) {
        Serial.print(buf[i], HEX);
        Serial.print(" ");
    }
    Serial.println();
    
    // 后续判断逻辑...
}

5. 检查库与硬件兼容性

部分旧版本的usbhub、cdcprolific库对PL2303的支持不完善,尝试更新到最新版本;也可以更换其他PL2303 USB Host驱动库测试,排除库的兼容性问题。


内容的提问来源于stack exchange,提问作者Nguyễn Thanh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 09:10:05