返回

PHP串口写入失败?问题分析与解决指南

php

使用 PHP 进行串口写入的问题分析与解决

使用 PHP 与串口进行通信,常见的一个需求是向连接到计算机的硬件设备发送数据。 这个过程中可能出现的问题,如无法打开串口设备或写入数据失败,会困扰许多开发者。本篇文章会围绕这些问题,详细分析原因,并提供相应的解决策略。

问题:串口设备未正确设置

在使用 php_serial.class.php 类时,一个常见的错误是“The device must be set before to be open”。 此错误表明在尝试打开串口之前,并没有正确指定需要使用的串口设备路径。该类在没有正确设置设备路径的情况下调用设备打开函数时,会出现这种警告。这会直接导致串口无法被打开,使得后续的发送数据操作也无法进行。

解决方案:

  • 确保在实例化 phpSerial 类后、调用 deviceOpen() 函数前,使用 deviceSet() 正确设置设备路径。通常,Linux 系统上的串口设备文件位于 /dev/tty*,例如 /dev/ttyACM0 或者 /dev/ttyUSB0 。设备路径的选择取决于具体连接的硬件。

代码示例:

<?php
include "php_serial.class.php";

$serial = new phpSerial;
$serial->deviceSet("/dev/ttyACM0"); // 正确设置设备路径
$serial->confBaudRate(57600);
$serial->confParity("none");
$serial->confCharacterLength(8);
$serial->confStopBits(1);

$tempString="4,123,456,789,0,10,100#";

$serial->deviceOpen(); // 现在应该能正确打开串口了
$serial->sendMessage($tempString);
$serial->deviceClose();

?>

操作步骤:

  1. 确定串口设备的正确路径。可以使用 ls /dev/tty* 命令列出系统中的所有串口设备。
  2. deviceSet() 方法中指定正确的路径,替换示例代码中的 /dev/ttyACM0
  3. 重新执行 PHP 脚本。

问题:权限不足,无法访问串口设备

即便是设置了正确的串口设备路径,也可能遇到因权限不足无法访问串口设备的问题。这通常是因为运行 PHP 脚本的用户没有访问串口设备的权限。例如,在 Web 服务器环境下,PHP 脚本常常以 www-data 用户运行,如果此用户没有加入 dialout 组,它就没有操作串口的权限。

解决方案:

  • 将执行 PHP 脚本的用户添加到 dialout 组。这需要使用 Linux 命令行完成,并可能需要以 root 或具有 sudo 权限的用户执行。
  • 修改串口设备的权限。

代码示例: (命令行操作)

# 查看当前用户
whoami
# 将用户加入 dialout 组 (需以 root 或有 sudo 权限的用户运行)
sudo usermod -a -G dialout <用户名> #例如: sudo usermod -a -G dialout admin
# 可能需要退出当前用户并重新登录
sudo chown admin:admin /dev/ttyACM0
sudo chmod 660 /dev/ttyACM0
# 或者可以使用:
#sudo chmod a+rw /dev/ttyACM0 (这种做法不是很安全,请了解风险)

#  或者为了保险起见,重新给tty相关权限
sudo chmod 777 /dev/tty*

#或者使用  chmod o+rw  或者 chmod 777 可以开放所有权限(一般用于测试或者Debug阶段, 真实环境请不要这样设置)。

# 查看用户所属的用户组,确认 dialout 组已添加。
groups <用户名>

操作步骤:

  1. 使用 whoami 确认执行 PHP 脚本的用户名。
  2. 使用 sudo usermod -a -G dialout <用户名> 将该用户添加到 dialout 组。注意,<用户名> 要替换成你的实际用户名。
  3. 检查 groups <用户名> 命令输出,确认用户已经加入 dialout 组。
  4. 如果上述方法仍然无法解决问题,可能需要更改设备权限。

额外的安全建议:

  • 使用 chmod 660 将设备访问权限限制在 dialout 组的用户,这是更安全的做法,比使用 chmod 777 或者 chmod a+rw 开放所有权限要好。

问题:deviceOpen 方法返回失败状态

观察 php_serial.class.php 的输出可以看到 ["_dState"]=> int(0),表示串口并没有成功打开。 这也验证了问题点主要集中在串口打开这一步。这往往和设备权限不足,或者设备设置错误有关系。

解决方案:

  • 仔细检查设备路径。deviceSet() 中的路径,和实际设备的路径需要对应。 使用 ls /dev/tty* 命令验证。
  • 确认串口设备是活动的,如果使用了USB转串口模块,尝试重新插拔该模块。 并且检查系统的设备日志,排查驱动是否有异常。
  • 增加PHP代码中日志调试的功能,以便更好地排查问题所在。例如打印当前的用户,增加 error_log() 方法将错误打印到系统日志。

代码示例: (添加日志输出)

<?php
include "php_serial.class.php";
error_log("当前用户: " . get_current_user());


$serial = new phpSerial;
$serial->deviceSet("/dev/ttyACM0"); 
$serial->confBaudRate(57600);
$serial->confParity("none");
$serial->confCharacterLength(8);
$serial->confStopBits(1);

$tempString="4,123,456,789,0,10,100#";


error_log("尝试打开串口");

if ($serial->deviceOpen()) {
   error_log("串口成功打开");
   $serial->sendMessage($tempString);
    
}else {
    error_log("串口打开失败!");
}
$serial->deviceClose();

?>

操作步骤:

  • 运行带有日志功能的PHP脚本,在Linux环境下,可以在/var/log/apache2/error.log 或者 /var/log/php-fpm.log (根据服务器的不同配置可能不同)文件中查找相关日志信息,分析问题的细节,进一步找到正确的解决方向。
  • 根据打印的日志分析用户是否有权限、以及是否能顺利打开串口。

总结

PHP操作串口并非难事,只要理清逻辑,按照步骤检查,基本上可以解决各种问题。仔细排查错误、理解底层工作机制才是正确解决问题的关键。希望以上的解决方案和建议能够帮助到遇到类似问题的开发者。