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
相关产品推荐
相关产品推荐

