简体   繁体   中英

Reading data from serial port from Arduino on Windows via PHP. Data not matching serial monitor output

Data I send to the serial port from the Arduino Uno can be viewed exactly as expected in the Arduino serial monitor, but when reading the data from PHP through serproxy in my WAMP environment I am getting some missing or extra characters (often a character that looks like a question mark inside of a black diamond, for example).

I've found similar questions posted, but all of the answers fell short. Often solutions were given for Linux only, or solved only part of the many challenges it takes to even get Windows to read (not write) from a serial port.

I tried the following to get PHP to simply read any serial data:

  • I first tried the php_serial class suggested, but quickly found out it only allows writing on Windows, and the answer for one of the other stack overflow questions ( Serial Communication Arduino to PHP ) suggested replacement code only for the Linux portion of the code, not Windows.

  • The article at Serial comm with PHP on Windows also mentions limited capacity on Windows for php_serial class and suggests an alternative serial extension (also mentioned here and here ), but this would not load on my WAMP environment with PHP 5.4.12 VC9 build when I used the correct matching extension version, added the extension to the correct php.ini, and restarted the server. I received a "Module win_serial is not compiled into PHP" after following all of the steps. If anyone else has had this issue please let me know as I would be willing to look into this again.

  • Finally, I tried using a program called serproxy which redirects network sockets to and from serial ports. This does work with the caveat that I added a 10uF capacitor on the Arduino's GND and RESET pins to prevent reseting on new serial connections as mentioned at PHP serial port data return from Arduino .

So now, I have my Arduino sending data to my computer via the USB cable, and so long as I am monitoring the data in Arduino's serial monitor, everything looks as it should. The moment I echo out that same data in PHP I begin to see extra or missing data along with the stream. So sending the text "AOK AOK AOK" sometimes becomes "OK?Pz[R" or something similar when echoed out of my PHP script.

Things I've tried to get clean serial data from PHP socket_read():

  • Messed around with various mb_convert_encoding (like 'ASCII' or 'utf-8')

  • Setting parity of serial data. I tried setting it to "EVEN" in serproxy config and DOS (ran command of "mode COM4: BAUD=9600 PARITY=E data=8 stop=1 XON=off TO=on" and recieved a valid response/output that command worked as expected)

  • Verified baud rate is set to 9600 in PHP code and serproxy config

  • Attempted simple trimming and/or regular expressions to filter out noise, but it doesn't help as some normal alphanumeric characters are randomly mixed in the output as well

Having modified some example socket code for TCP/IP from php.net , I have a PHP script that writes 2048 bits of data from the serial port via serproxy. This page is called via jQuery from another page every 10th of a second and the echoed content is loaded into the contents of a on my main page.

My end goal is to send a stream of either 1's or 0's to be sent to my PHP script to indicate that a should toggle it's background color. I would prefer to be certain those 1's or 0's were not just randomly echoed among the extra characters and truly came from the serial stream itself.

Does anyone know if serproxy is the cause of the adding or removing the unwanted data that I'm seeing in PHP?

The fact that the serial monitor is showing the correct data indicates to me that it's something in the way PHP is receiving or parsing the data.

I'm running out of ideas on what else I could check. Maybe another pair of eyes on this will bring to light something I've overlooked or did incorrectly.

Please see my code below for specific examples below:

serial.html

<!DOCTYPE html>
<head>
</head>
<body>
    <div id="serial" name="serial" class="serial"></div>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
    <script src="js/main.js"></script>
</body>
</html>

serial_output.php

<?php

// Set service port to 5334 for serproxy
$service_port = 5334;

// Using localhost address
$address = '127.0.0.1';

/* Create a TCP/IP socket. */
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

if ($socket === false) {
    echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
} 

// Attempting to connect to '$address' on port '$service_port'...";
$result = socket_connect($socket, $address, $service_port);

if ($result === false) {
    echo "socket_connect() failed.\nReason: ($result) " .     socket_strerror(socket_last_error($socket)) . "\n";
}

// Read 2048 bits of data from socket and convert encoding to ASCII
$out = mb_convert_encoding(socket_read($socket, 2048), 'ASCII'); 

// Filter out anything that is not "AOK"
if(preg_match("/AOK/", $out)){
    echo 1;
} else {
    // Else output raw data so we can see what was actaully sent
    echo $out;
}

// Closing socket...
socket_close($socket);

?>

main.js

// Set #serial background color to red when receiving a "1" 
function setBgColor(){
    var serial = $('#serial');  

    // Set #serial background color to red when receiving a "1"
    if($('#serial').html() == "1") {
        serial.css('background-color','red');
    } else {
        // Set #serial background to white if we did not receive a "1"
        serial.css('background-color', 'white');
    }
}

var intervalId = window.setInterval(function(){
    $('#serial').load('serial_output.php');

    setBgColor();
}, 100);

arduino_serial.ino

#include <avr/pgmspace.h>

void setup() {
  // Initialize serial and wait for port to open:
  // Currently I have parity on my serial port set to "EVEN" hence SERIAL_8E1
  Serial.begin(9600, SERIAL_8E1);
} 

void loop() {
   Serial.println("AOK");
}

So I ran your code and had the same issues with my Arduino and an accelerometer. I found three ways to alleviate the issue.

First is just to error check your data in terms of what you expected. If the data doesn't match what you expected, just discard it. If you are getting data 10x a second, I suppose you can afford to lose some. [BTW: serproxy crashes on me in under 10 minutes, so it's of limited use to me].

Second, just delay the data on the Arduino side. Apparently the data loss is a "known issue" regarding Arduinos and serial ports. This person's site at martinmelchior.be has some code to delay the data stream being sent from the Ardunio;

`void slowSerialPrint(char text[]) {
  for ( int i ; i < strlen(text) ; i ++ ) {
    Serial.print(text[i]);
    delay(5);
  }
} `

Scroll down to "But not so fast..." to find that snippet.

Finally, you could just try what many others are doing and buy a cheap wireless router and use that as your owninexpensive wi-fi shield . Which, oddly enough is what the site linked above does!

It is also good to note that that router's maximum current draw at 5V is 185mA (OpenWrt boot), average current draw with WiFi at 18dBm is 100mA, without WiFi 80mA. Hence the average router power consumption is 0.5W, which is incredibly low.

Also, thank you for the code you posted, I was searching for a way to do exactly what you were doing, so I implemented your code, hit the same wall, solved my issue by slowing down the Arduino's output in javascript and discarding dirty data, then branched out into other options.

tl;dr: I don't think there is a simple solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM