PHP发送十六进制数据需用pack("H*", "a1b2c3")转二进制,再写入串口设备;Linux可用file_put_contents直写/dev/ttyUSB0(需stty配置和权限),Windows需php_serial扩展或fwrite;PHP 8已弃用该扩展,推荐用Python/Node.js处理串口。

PHP 本身不直接支持串口通信,必须借助外部扩展(如 php_serial)或系统命令(如 stty + echo),而发送十六进制数据的关键在于:先用 pack() 将 hex 字符串转为二进制字节流,再原样写入串口设备文件(如 /dev/ttyUSB0 或 COM3)。
如何用 pack() 把十六进制字符串转成可发送的二进制
pack() 不接受形如 "A1B2C3" 的字符串直接转换,必须先拆分成字节对,再用 "H*" 或 "H2" 格式打包。常见错误是误用 hex2bin()(PHP ≥ 5.4.0 才有)却忽略其对非法字符的严格校验。
-
pack("H*", "a1b2c3")→ 正确:把整个 hex 字符串按两位一组解析为字节 -
pack("H2", "a1", "b2", "c3")→ 错误:"H2"每次只取一个参数的前两位,多参数会截断或报错 -
hex2bin("a1b2c3")→ 可用,但遇到空格、非十六进制字符(如"A1 B2")会返回false,需提前str_replace(" ", "", $hex)和ctype_xdigit()校验
Linux 下绕过扩展,用 file_put_contents() 直写串口设备
前提是串口设备已配置好(波特率、停止位等由 stty 设置),且 PHP 进程有设备文件写权限(常需加到 dialout 用户组)。此时发送就是写二进制流,和普通文件无异。
file_put_contents("/dev/ttyUSB0", pack("H*", "02010400ff")); // 发送 6 字节:0x02 0x01 0x04 0x00 0xff
- 必须确保
/dev/ttyUSB0已被stty -F /dev/ttyUSB0 9600 cs8 -cstopb -parenb配置好,否则数据会乱或丢 - 写入后建议
usleep(10000)等待硬件发出,尤其对低速设备(如 1200bps) - Windows 下对应路径是
COM3,但需用fopen("COM3", "wb"),且不能用file_put_contents()直写(会失败)
Windows 下用 php_serial 扩展发送 hex 数据的典型流程
该扩展已多年未更新,仅兼容 PHP 5.x 和旧版 VC 编译器,PHP 7+ 基本不可用。若强行使用,核心是:打开 → 配置 → sendMessage() 传入 pack() 结果。
立即学习“PHP免费学习笔记(深入)”;
$serial = new phpSerial();
$serial->deviceSet("COM3");
$serial->confBaudRate(9600);
$serial->confParity("none");
$serial->confCharacterLength(8);
$serial->confStopBits(1);
$serial->deviceOpen();
$serial->sendMessage(pack("H*", "aa5500ff")); // 发送 4 字节
$serial->deviceClose();
- 扩展内部未做二进制安全处理,若
pack()结果含\x00,可能被 C 层截断(因误判为字符串结尾) - 更稳妥做法是用
fwrite()替代sendMessage():获取资源句柄后fwrite($fp, pack("H*", "aa55")) - PHP 8 完全放弃该扩展,推荐改用 Python/Node.js 处理串口,PHP 只做业务逻辑
真正容易卡住的地方不是 pack() 用法,而是串口设备的硬件层配置是否生效、权限是否到位、以及发送后有没有等待足够时间让设备完成物理传输——这些在脚本里看不见,却决定数据发没发出去。











