PHP串口数据从Arduino返回

15

我想知道是否有一种方法可以通过PHP读取我的串口 - 而且是行得通的 :-)

在练习我的Arduino技能时,我开发了一个简单的LED开/关程序。 它通过在串行监视器中输入 on off 来工作。

下一步,我创建了一个网页作为GUI界面,通过点击链接执行上述开和关的功能。这个基于Web的GUI通过PHP工作。 我正在使用PHP SERIAL类与我的Arduino所使用的串口进行交互。

问题在于我需要找到一种从串口获得反馈的方法。使用Arduino IDE串行监视器,我可以看到我的打印消息响应每个串行输入,并且我需要在我的PHP代码中检索相同的反馈。

PHP Serial类提供了一个 readPort() 函数,但它不返回我的数据。

更新[2]:

ARDUINO:

const int greenPin = 2;
const int bluePin = 3;
const int redPin = 4;

int currentPin = 0; //current pin to be faded
int brightness = 0; //current brightness level

void setup(){
  Serial.begin(9600);

  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);
  pinMode(redPin, OUTPUT);
}

void loop(){
  //if there's any serial data in the buffer, read a byte
  if( Serial.available() > 0 ){
    int inByte = Serial.read();

      //respond only to the values 'r', 'g', 'b', or '0' through '9'
      if(inByte == 'r')
        currentPin = redPin;

      if(inByte == 'g')
        currentPin = greenPin;

      if(inByte == 'b')
        currentPin = bluePin;

      if(inByte >= '0' && inByte <= '9'){
        //map the incoming byte value to the range of the analogRead() command
        brightness = map(inByte, '0', '9', 0, 255);
        //set the current pin to the current brightness:
        analogWrite(currentPin, brightness);
      }

      Serial.print("Current Pin : ");
      Serial.println(currentPin);

      Serial.print("Brightness : ");
      Serial.println(brightness);

  }//close serial check

}

PHP/HTML:

->

PHP/HTML:

<?php
    require("php_serial.class.php");
// include("php_serial.class.php");

    // Let's start the class
    $serial = new phpSerial();

    // First we must specify the device. This works on both Linux and Windows (if
    // your Linux serial device is /dev/ttyS0 for COM1, etc.)
    $serial->deviceSet("/dev/ttyACM0");

    // Set for 9600-8-N-1 (no flow control)
    $serial->confBaudRate(9600); //Baud rate: 9600
    $serial->confParity("none");  //Parity (this is the "N" in "8-N-1")
    $serial->confCharacterLength(8); //Character length     (this is the "8" in "8-N-1")
    $serial->confStopBits(1);  //Stop bits (this is the "1" in "8-N-1")
    $serial->confFlowControl("none");

    // Then we need to open it
    $serial->deviceOpen();

    // Read data
    $read = $serial->readPort();
print "<pre>";
print_r($read);
print "</pre>";

    // Print out the data
    echo $read;
        // print exec("echo 'r9g9b9' > /dev/ttyACM0");
    print "RESPONSE(1): {$read}<br><br>";

    // If you want to change the configuration, the device must be closed.
    $serial->deviceClose();
?>

<?php
    if( isset($_REQUEST['LED']) )
        response();
?>

<form action='index.php' method='POST'>
    <select id='led' name='LED'>
        <option id='nil'>-</option>
        <option id='red'>RED</option>
        <option id='green'>GREEN</option>
        <option id='blue'>BLUE</option>
        <option id='all'>ALL</option>
    </select>
    <input type='submit' value='SET'>
</form>

<?php
    print "Hi, Earthlings!";

    function response(){
        $CMDString = "";
        $execute   = false;

        if( isset($_REQUEST['LED']) ){
                switch ($_REQUEST['LED']) {
                    case 'RED':
                        $CMDString = 'r9';
                        $execute = true;

        exec("echo 'r9g0b0' > /dev/ttyACM0");

                print "<br>FOUND: {$_REQUEST['LED']}";
                        break;
                    case 'GREEN':
                        $CMDString = 'g9';
                        $execute = true;
                print "<br>FOUND: {$_REQUEST['LED']}";
                        break;
                    case 'BLUE':
                        $CMDString = 'b9';
                        $execute = true;
                print "<br>FOUND: {$_REQUEST['LED']}";
                        break;
                    case 'ALL':
                        $CMDString = 'r9g9b9';
                        $execute = true;
                print "<br>FOUND: {$_REQUEST['LED']}";
                        break;
                    default:
                        print exec("echo 'r0g0b0' > /dev/ttyACM0");
                        $execute = false;
                        break;
                }

                if($execute){
                    print exec("echo '{$CMDString}' > /dev/ttyACM0");
                    print "<br><br>executing: {$CMDString}";
                }
        }
    }
?>
3个回答

14

我假设你正在使用Linux操作系统。

首先设置你的串口:

stty -F /dev/ttyACM0 cs8 9600 ignbrk -brkint -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts

然后你可以使用传统的 fread/fwrite 函数。

$fp =fopen("/dev/ttyACM0", "w+");
if( !$fp) {
        echo "Error";die();
}

fwrite($fp, $_SERVER['argv'][1] . 0x00);
echo fread($fp, 10);

fclose($fp);

你只需要记住一件事情:Arduino会在每次连接时重新启动。如果你不知道这点,它会让你感到困惑。例如,如果你连接(fopen)并立即发送数据,Arduino会错过它,因为它正在启动(这需要一两秒钟的时间)。尝试通过休眠来给它一些时间。如果你想要禁用重新启动,使用10uF电容器将GRD与RST相连。

祝好运!

附注:你可以使用“screen”进行故障排除。

screen /dev/ttyACM0 9600

发布设置PHP与Arduino的文章 http://systemsarchitect.net/connecting-php-with-arduino-via-serial-port-on-linux/ 还有一个在这里 http://systemsarchitect.net/arduino-and-php-serial-communication-with-a-protocol/


感谢您非常有帮助的评论。我已经成功地将一个10uF电容应用到我的设置中。因此,我不再需要打开Arduino串行监视器。现在我可以使用Web界面来控制我的RGB-LED实验。唯一的问题是,我仍然没有从我的Aduino代码中获得任何返回语句,例如在串行监视器中,我有“RED ON”等确认语句。在我的Web界面中,我没有得到这个非常重要的数据。我成功执行了您的stty命令,但没有任何改变。请问您能否给我更多的帮助? - sisko
你能把你的Arduino和PHP代码粘贴过来吗?没有代码很难判断。 - Lukasz Kujawa
嗨Lukasz,你一直以来的帮助非常宝贵,我非常感激。我将标记你的答案为正确,但我会更加感激你对我正在经历的更多复杂情况提供更多帮助。你打开和读取端口的策略有效,但只是间歇性的,即:有时候它有效,但大部分时间我没有输出。当我确实得到输出时,它是串行端口中的所有内容而不是最新的内容。请问你能否提供更多建议?此外,你能解释一下“stty…”命令代码是做什么的吗?它似乎并没有帮助我的情况。 - sisko
stty命令只是确保设备与Arduino兼容(例如将传输速度设置为9600bps)。 /dev/ttyACM0只是一个管道。它没有任何智能来以便捷的方式提供数据。您读取N个字节,如果有内容,则获取它。了解要读取多少数据很重要。请查看我为进程间通信创建的示例(https://github.com/lukaszkujawa/php-multithreaded-socket-server/blob/master/sock/SocketServerBroadcast.php)handleProcess()和broadcast()。 - Lukasz Kujawa
我发送到管道的数据的前4个字节是一个整数,所以后来当我从管道读取时,我只需要读取4个字节就可以知道我需要读取多少字节。在Arduino之外尝试使用管道,以更好地理解您正在做什么。 - Lukasz Kujawa
显示剩余3条评论

3

/dev/ttyUSB0 正在以 root 用户身份运行,如果您正在使用 Apache,请尝试将 /dev/ttyUSB0 的所有权更改为 apache 或当前登录用户。

$ sudo chown apache2:apache2 /dev/ttyACM0
OR
$ sudo chown yourusername:yourusername /dev/ttyACM0

然后再尝试一次,或者尝试从Ubuntu登出并以root用户的身份登录。


https://symfony.com/doc/current/reference/constraints/LessThanOrEqual.html#basic-usage - mblaettermann
你应该将Apache用户添加到“dialout”组,而不是更改设备的所有者或权限。 - jww

2
您可能是在串口上没有数据时尝试阅读。您需要实现 JavaScript 代码来调用可以定期读取的 PHP 代码。
当您获取到数据后,应该对其进行处理。 readPort() 对我很有效。如果波特率、奇偶校验等已经调整好,那么您应该不会有任何问题读取串口。
以下是使用Arduino库的示例,一段时间前这对我很有效:
<?php
    include "php_serial.class.php";

    // Let's start the class
    $serial = new phpSerial();

    // First we must specify the device. This works on both Linux and Windows (if
    // your Linux serial device is /dev/ttyS0 for COM1, etc.)
    $serial->deviceSet("/dev/ttyUSB0");

    // Set for 9600-8-N-1 (no flow control)
    $serial->confBaudRate(9600); //Baud rate: 9600
    $serial->confParity("none");  //Parity (this is the "N" in "8-N-1")
    $serial->confCharacterLength(8); //Character length     (this is the "8" in "8-N-1")
    $serial->confStopBits(1);  //Stop bits (this is the "1" in "8-N-1")
    $serial->confFlowControl("none");

    // Then we need to open it
    $serial->deviceOpen();

    // Read data
    $read = $serial->readPort();

    // Print out the data
    echo $read;

    // If you want to change the configuration, the device must be closed.
    $serial->deviceClose();
?>

我知道波特率是什么,但你介意告诉我奇偶校验是什么以及如何在这种情况下正确配置它吗? - sisko
感谢您的答案和代码示例。我使用了您的代码片段更新了我的代码,但仍然没有收到任何反馈。我在我的PHP/HTML脚本中更新了原始问题。我应该在3个地方得到一些反馈,但是没有任何反馈。我应该指出,我的端口(/dev/ttyACM0)设置为chmod 777,并且我实际上在我的Arduino草图中调用Serial.println,这就是为什么我期望在PHP中返回一些数据。事实上,每次我使用我的Web界面时,我的LED都成功响应,我的Arduino串行监视器打印我的消息。 - sisko
你使用的操作系统是什么?你使用的Apache版本和PHP版本分别是多少? - opc0de
操作系统是Linux Ubuntu-12,PHP版本为5.3.10,Apache版本为Apache/2.2.22。 - sisko
@sisko,你能在Arduino IDE(SerialMon)中看到串行输出吗? - opc0de
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接