PHP 怎么串口通信

wen PHP项目 3

本文目录导读:

PHP 怎么串口通信

  1. 使用 PHP Serial 扩展(推荐)
  2. 使用 dio 扩展(Direct I/O)
  3. 使用 exec() 调用系统命令
  4. 使用 file functions(文件操作)
  5. 封装一个完整的串口类
  6. 异步通信示例
  7. 注意事项

PHP 进行串口通信主要通过以下几种方式实现,我来详细介绍:

使用 PHP Serial 扩展(推荐)

安装扩展

# Ubuntu/Debian
sudo apt-get install php-dev
git clone https://github.com/Xowap/PHP-Serial.git
cd PHP-Serial
phpize
./configure
make
sudo make install
# 在 php.ini 中添加
extension=php_serial.so

基本使用示例

<?php
include 'php_serial.class.php';
// 创建串口对象
$serial = new phpSerial();
// 设置串口参数
$serial->deviceSet('/dev/ttyUSB0');  // Linux/Mac
// $serial->deviceSet('COM3');       // Windows
// 配置串口
$serial->confBaudRate(9600);         // 波特率
$serial->confParity('none');         // 校验位
$serial->confCharacterLength(8);     // 数据位
$serial->confStopBits(1);            // 停止位
$serial->confFlowControl('none');    // 流控制
// 打开串口
$serial->deviceOpen();
// 发送数据
$serial->sendMessage("Hello Serial!");
$serial->sendMessage(chr(0x01) . chr(0x02)); // 发送二进制数据
// 读取数据
$read = $serial->readPort();
$read = $serial->readPort(10); // 读取10个字符
// 关闭串口
$serial->deviceClose();
?>

使用 dio 扩展(Direct I/O)

安装扩展

# Ubuntu/Debian
sudo apt-get install php-dio

使用示例

<?php
// 打开串口
$fd = dio_open('/dev/ttyS0', O_RDWR | O_NOCTTY | O_NONBLOCK);
// 设置串口参数
dio_fcntl($fd, F_SETFL, O_RDWR | O_NONBLOCK);
// 配置串口
dio_tcsetattr($fd, array(
    'baud' => 9600,
    'bits' => 8,
    'stop' => 1,
    'parity' => 0
));
// 写入数据
$data = "Hello Serial!";
dio_write($fd, $data);
// 读取数据
$input = dio_read($fd, 1024);
// 关闭串口
dio_close($fd);
?>

使用 exec() 调用系统命令

Linux 使用 stty 和 cat/echo

<?php
// 配置串口
exec('stty -F /dev/ttyUSB0 9600 cs8 -cstopb -parenb');
exec('stty -F /dev/ttyUSB0 raw');
// 发送数据
$fp = fopen('/dev/ttyUSB0', 'w');
fwrite($fp, "Hello Serial!");
fclose($fp);
// 或使用 echo
exec('echo "Hello" > /dev/ttyUSB0');
// 读取数据
$fp = fopen('/dev/ttyUSB0', 'r');
$data = fread($fp, 1024);
fclose($fp);
?>

使用 file functions(文件操作)

<?php
// Windows 环境
$comPort = "COM3";
exec("mode " . $comPort . " BAUD=9600 PARITY=N data=8 stop=1 xon=off");
// 打开串口
$fp = fopen("\\\\\\\\.\\\\" . $comPort, "r+");
if (!$fp) {
    die("无法打开串口");
}
// 设置非阻塞模式
stream_set_blocking($fp, 0);
// 发送数据
fwrite($fp, "Hello Serial!");
// 读取数据
$data = fread($fp, 1024);
// 关闭串口
fclose($fp);
?>

封装一个完整的串口类

<?php
class SerialPort {
    private $device;
    private $baudRate;
    private $handle;
    public function __construct($device = '/dev/ttyUSB0', $baudRate = 9600) {
        $this->device = $device;
        $this->baudRate = $baudRate;
    }
    public function open() {
        // 使用 exec 配置串口
        exec("stty -F " . $this->device . " " . $this->baudRate . " cs8 -cstopb -parenb raw");
        // 打开设备
        $this->handle = fopen($this->device, 'w+');
        if (!$this->handle) {
            throw new Exception("无法打开串口设备");
        }
        // 设置非阻塞模式
        stream_set_blocking($this->handle, 0);
        return true;
    }
    public function send($data) {
        if (!$this->handle) return false;
        return fwrite($this->handle, $data);
    }
    public function receive($length = 1024) {
        if (!$this->handle) return false;
        return fread($this->handle, $length);
    }
    public function close() {
        if ($this->handle) {
            fclose($this->handle);
            $this->handle = null;
        }
    }
    public function flush() {
        exec("stty -F " . $this->device . " -echo");
    }
}
// 使用示例
try {
    $serial = new SerialPort('/dev/ttyUSB0', 9600);
    $serial->open();
    // 发送数据
    $serial->send("AT\r\n");
    // 等待响应
    usleep(500000); // 500ms
    // 接收数据
    $response = $serial->receive();
    echo "Response: " . $response . "\n";
    $serial->close();
} catch (Exception $e) {
    echo "错误: " . $e->getMessage() . "\n";
}
?>

异步通信示例

<?php
// 使用非阻塞模式进行异步通信
$fp = fopen('/dev/ttyUSB0', 'r+');
stream_set_blocking($fp, 0);
// 发送多个命令
$commands = array("ATZ", "ATI", "ATE0");
foreach ($commands as $cmd) {
    fwrite($fp, $cmd . "\r\n");
    usleep(200000); // 200ms
    $response = fread($fp, 4096);
    echo "发送: " . $cmd . "\n";
    echo "接收: " . $response . "\n---\n";
}
fclose($fp);
?>

注意事项

  1. 权限问题:Linux 下需要给用户添加 dialout 组权限

    sudo usermod -a -G dialout $USER
  2. 超时设置:可以设置超时避免阻塞

    stream_set_timeout($fp, 1); // 1秒超时
  3. 调试方法

    // 添加错误处理
    if (!$fp) {
     error_log("无法打开串口", 3, "/var/log/serial.log");
    }

// 查看串口状态 exec('dmesg | grep ttyS0'); exec('ls -l /dev/ttyUSB*');


4. **性能考虑**:对于高频率通信,建议使用 PHP 扩展或 C/C++ 扩展
选择哪种方式取决于:
- 你的 PHP 环境(是否有权限安装扩展)
- 平台(Linux/Windows)
- 性能需求
- 通信的稳定性要求
对于项目开发,推荐使用 **PHP-Serial 扩展** 或封装的类,它们提供了更可靠的通信机制。

抱歉,评论功能暂时关闭!