Go Down

Topic: Serial communication with Web Server (PHP) (Read 3013 times) previous topic - next topic

Nicknml

May 07, 2015, 03:06 am Last Edit: May 07, 2015, 03:08 am by Nicknml
I've been playing around with controlling an Atmega1284P (yea a bit overkill, but I had it laying around) over the web using PHP.  It "kinda" works. by "kinda" I mean it's stable under certain environments and totally unstable under others.


Environment 1:
OS CentOS 6.6 (running as a VirtualBox guest)
Apache version: 2.2.15
PHP version: 5.3.3
Result: fairly stable, very rarely do I not get a sensor reading

Environment 2:

OS: CentOS7.1 (tried both a dedicated physical machine and a VirtualBox guest)
Apache version: 2.4.6
PHP version: 5.4.16
Result: When I take a reading of my photoresistor, one or both of my two LED's turns off/on. Sometimes I do not get a sensor reading.

Environment 3:

OS:Raspbian
Apache version:2.2.22
PHP version:5.4.39
Result: When I take a reading of my photoresistor, one or both of my two LED's turns off/on. Sometimes I do not get a sensor reading.


Hardware configuration (Arduino side of things)
Atmega 1284p
FTDI USB-Serial
Two LED's
photoresistor
DS1631 I2C temp sensor


My Arduino code:

Code: [Select]
//temp sensor vars
boolean neg=0;
byte temp=0;
float tempb=0;
// end

byte hybyte=0;
int result=0;
void setup() {
  // put your setup code here, to run once:
DDRD|=B11000000; //setting pins 20 and 21 as outputs
ADMUX=B01000111;//set adc reference and select channel
ADCSRA=B10000110;//enable adc and set prescaler to divide by 64
//temp sensor pins
PORTC |=B11000000;
DDRC |=B11000000;// pc7 as ada and pc6 as sck
//end
Serial.begin(9600);
DS1631startconvert();
}

void loop() {
  // put your main code here, to run repeatedly:
//cal = OSCCAL;
if (Serial.available()){
     int ser = Serial.read();
    
     if (ser == 52){//keyboard key 4 to read the temp sensor
      DS1631readtemp();
      delay(50);
      tempb=(tempb*(9.0/5.0))+32;
      Serial.println(tempb,4);//4 decimal places
      neg=0;
      temp=0;
     tempb=0;
       }
     else if (ser == 53){//keyboard key 5 to turn on led1
      PORTD |=B01000000;
      delay(50);
    Serial.println("Object1 enabled");
       }
     else if(ser == 54){//keyboard key 6 to turn off led1
      PORTD &=~B01000000;
            delay(50);
      Serial.println("Object1 disabled");
       }
     else if(ser == 55){//keyboard key 7 to turn led2 on
      PORTD |=B10000000;
            delay(50);
       Serial.println("Object2 enabled");
       }
      else if(ser == 56){//keyboard key 8 to tourn led2 off
      PORTD &=~B10000000;
            delay(50);
     Serial.println("Object2 disabled");
       }
       else if(ser == 57){//keyboard key 9 to read the photoresistor
            delay(50);
            adcread();
     Serial.println(result);
       }
}

}

void adcread(){
ADCSRA |= (1 << ADSC);         // start ADC measurement
    while (ADCSRA & (1<<ADSC)); // wait till conversion complete
result=ADCW;

}
//temp sensor reading
void start(){
DDRC|=_BV(DDC7);
PORTC|=_BV(DDC7);
PORTC|=_BV(DDC6);
PORTC&=~_BV(DDC7);
PORTC&=~_BV(DDC6);
}

void stop1(){
DDRC|=_BV(DDC7);
PORTC&=~_BV(DDC6);
PORTC&=~_BV(DDC7);
PORTC|=_BV(DDC6);
PORTC|=_BV(DDC7);
  }
void clk(){
PORTC|=_BV(DDC6);
PORTC&=~_BV(DDC6);
//delay(1);
  }
void DS1631startconvert(){
start();
//send address
//digitalWrite(sda,HIGH);
PORTC|=_BV(DDC7);
clk();
//digitalWrite(sda,LOW);
PORTC&=~_BV(DDC7);
clk();
//digitalWrite(sda,LOW);
PORTC&=~_BV(DDC7);
clk();
//digitalWrite(sda,HIGH);
PORTC|=_BV(DDC7);
clk();
//digitalWrite(sda,LOW);
PORTC&=~_BV(DDC7);
clk();
//digitalWrite(sda,LOW);
PORTC&=~_BV(DDC7);
clk();
//digitalWrite(sda,HIGH);
PORTC&=~_BV(DDC7);
clk();
//digitalWrite(sda,LOW);//write
PORTC&=~_BV(DDC7);
clk();
//ignore ack
clk();
//start t convert command
//digitalWrite(sda,LOW);
PORTC&=~_BV(DDC7);
clk();
//digitalWrite(sda,HIGH);
PORTC|=_BV(DDC7);
clk();
//digitalWrite(sda,LOW);
PORTC&=~_BV(DDC7);
clk();
//digitalWrite(sda,HIGH);
PORTC|=_BV(DDC7);
clk();
//digitalWrite(sda,LOW);
PORTC&=~_BV(DDC7);
clk();
//digitalWrite(sda,LOW);
PORTC&=~_BV(DDC7);
clk();
//digitalWrite(sda,LOW);
PORTC&=~_BV(DDC7);
clk();
//digitalWrite(sda,HIGH);
PORTC|=_BV(DDC7);
clk();
clk();//ignoring ack
stop1();
}
void DS1631readtemp(){
start();
//send device address
//send address
//digitalWrite(sda,HIGH);
PORTC|=_BV(DDC7);
clk();
//digitalWrite(sda,LOW);
PORTC&=~_BV(DDC7);
clk();
//digitalWrite(sda,LOW);
PORTC&=~_BV(DDC7);
clk();
//digitalWrite(sda,HIGH);
PORTC|=_BV(DDC7);
clk();
//digitalWrite(sda,LOW);
PORTC&=~_BV(DDC7);
clk();
//digitalWrite(sda,LOW);
PORTC&=~_BV(DDC7);
clk();
//digitalWrite(sda,HIGH);
PORTC&=~_BV(DDC7);
clk();
//digitalWrite(sda,LOW);//write
PORTC&=~_BV(DDC7);
clk();
//ignore ack
clk();
//send read temp command AAh
//digitalWrite(sda,HIGH);
PORTC|=_BV(DDC7);
 clk();
 //digitalWrite(sda,LOW);
 PORTC&=~_BV(DDC7);
 clk();
 //digitalWrite(sda,HIGH);
 PORTC|=_BV(DDC7);
 clk();
 //digitalWrite(sda,LOW);
 PORTC&=~_BV(DDC7);
 clk();
 //digitalWrite(sda,HIGH);
 PORTC|=_BV(DDC7);
 clk();
 //digitalWrite(sda,LOW);
 PORTC&=~_BV(DDC7);
 clk();
 //digitalWrite(sda,HIGH);
 PORTC|=_BV(DDC7);
 clk();
 //digitalWrite(sda,LOW);
 PORTC&=~_BV(DDC7);
 clk();
 clk(); //ignoring ack again
 stop1();
 start();
 //send device address
//digitalWrite(sda,HIGH);
PORTC|=_BV(DDC7);
clk();
//digitalWrite(sda,LOW);
PORTC&=~_BV(DDC7);
clk();
//digitalWrite(sda,LOW);
PORTC&=~_BV(DDC7);
clk();
//digitalWrite(sda,HIGH);
PORTC|=_BV(DDC7);
clk();
//digitalWrite(sda,LOW);
PORTC&=~_BV(DDC7);
clk();
//digitalWrite(sda,LOW);
PORTC&=~_BV(DDC7);
clk();
//digitalWrite(sda,HIGH);
PORTC&=~_BV(DDC7);
clk();
//digitalWrite(sda,HIGH);//read
PORTC|=_BV(DDC7);
clk();
//pinMode(sda,INPUT);//change pin from output to input for readin
DDRC&=~_BV(DDC7);
byte raw=0;
clk();
//read the temp
 //raw=digitalRead(sda);
 raw=PINC & _BV(PC7);
 if(raw==128){
  temp=temp+128;
 neg=1;
 }
 clk();
 //raw=digitalRead(sda);
 raw=PINC & _BV(PC7);
 if(raw==128){
   temp=temp+64;
 }
 clk();
 //raw=digitalRead(sda);
 raw=PINC & _BV(PC7);
 if(raw==128){
  temp=temp+32;
 }
 clk();
 //raw=digitalRead(sda);
 raw=PINC & _BV(PC7);
 if(raw==128){
   temp=temp+16;
 }
 clk();
 //raw=digitalRead(sda);
 raw=PINC & _BV(PC7);
 if(raw==128){
  temp=temp+8;
 }
 clk();
 //raw=digitalRead(sda);
 raw=PINC & _BV(PC7);
 if(raw==128){
   temp=temp+4;
 }
 clk();
 //raw=digitalRead(sda);
 raw=PINC & _BV(PC7);
 if(raw==128){
  temp=temp+2;
 }
 clk();
 //raw=digitalRead(sda);
 raw=PINC & _BV(PC7);
 if(raw==128){
   temp=temp+1;
 }
 clk();
 
//doing more significant read
/*
0000
.5 1
.25 2
.125 3
.0625 4


*/
//pinMode(sda,OUTPUT);
DDRC|=_BV(DDC7);
//digitalWrite(sda,LOW);
PORTC&=~_BV(DDC7);
clk();
//pinMode(sda,INPUT);
DDRC&=~_BV(DDC7);
//raw=digitalRead(sda);
raw=PINC & _BV(PC7);
if(raw==128){
   tempb=tempb+.5;
 }
clk();
//raw=digitalRead(sda);
raw=PINC & _BV(PC7);
if(raw==128){
   tempb=tempb+.25;
 }
clk();
//raw=digitalRead(sda);
raw=PINC & _BV(PC7);
if(raw==128){
   tempb=tempb+.125;
 }
clk();
//raw=digitalRead(sda);
raw=PINC & _BV(PC7);
if(raw==128){
   tempb=tempb+.0625;
 }
clk();
clk();
clk();
clk();
clk();
clk();
stop1();

if (neg==1){
temp=temp-1;
temp=~(temp);
tempb=(tempb+temp)*-1;
}
else{
tempb=tempb+temp;
}

}

Nicknml

#1
May 07, 2015, 03:09 am Last Edit: May 07, 2015, 03:12 am by Nicknml
On the webserver side using this code(as well as this person's code for the serial comms: http://www.phpclasses.org/browse/file/17926.html):

Code: [Select]
<!DOCTYPE html>
<head>
<link rel="stylesheet" type="text/css" href="main.css">
<title>Cpannel</title></head>
<body>
<div id="title">Control Panel</div>
<div id="panel">
<form  method='post'>
<input type='submit' name='button1' value='Read Photo' id="buttona" class="button"/>
<input type='submit' name='button2' value='Turn off' id="buttonb" class="button"/>
<input type='submit' name="button3" value='Read Temp' id="buttonc" class="button"/>
<input type='submit' name="button4" value='Clear' id="buttond" class="button"/>
</form>
<form  method='post'>
<input type='submit' name='button5' value='Ob1 on' id="buttone" class="button"/>
<input type='submit' name='button6' value='Ob1 off' id="buttonf" class="button"/>
<input type='submit' name="button7" value='Ob2 on' id="buttong" class="button"/>
<input type='submit' name="button8" value='Ob2 off' id="buttonh" class="button"/>
</form>
</div>
<div class="status">
<br />Status:<br />
</div>
<?php
include "php_serial.class.php"
$serial = new phpSerial;
$serial->deviceSet("/dev/ttyUSB0");
$serial->confBaudRate(9600);

date_default_timezone_set("UTC");
if (isset(
$_POST['button1']))
{
$serial->deviceOpen();
$serial->sendMessage("9");
$read $serial->readPort();
echo 
"<div class='status'>" $read "</div>";
$serial->deviceClose();
echo 
"<div class='status'>" date("h:i:sa") . "</div>";
}
if (isset(
$_POST['button2']))
{
echo 
"button2 has been pressed";
}
if (isset(
$_POST['button3']))
{
$serial->deviceOpen();
$serial->sendMessage("4");
$read $serial->readPort();
echo 
"<div class='status'>" $read "</div>";
$serial->deviceClose();
echo 
"<div class='status'>" date("h:i:sa") . "</div>";
}
if (isset(
$_POST['button4']))
{
echo 
"";
}


if (isset(
$_POST['button5']))
{
$serial->deviceOpen();
$serial->sendMessage("5");
$read $serial->readPort();
echo 
"<div class='status'>" $read "</div>";
$serial->deviceClose();
echo 
"<div class='status'>" date("h:i:sa") . "</div>";
}
if (isset(
$_POST['button6']))
{
$serial->deviceOpen();
$serial->sendMessage("6");
$read $serial->readPort();
echo 
"<div class='status'>" $read "</div>";
$serial->deviceClose();
echo 
"<div class='status'>" date("h:i:sa") . "</div>";
}
if (isset(
$_POST['button7']))
{

$serial->deviceOpen();
$serial->sendMessage("7");
$read $serial->readPort();
echo 
"<div class='status'>" $read "</div>";
$serial->deviceClose();
echo 
"<div class='status'>" date("h:i:sa") . "</div>";
}
if (isset(
$_POST['button8']))
{
$serial->deviceOpen();
$serial->sendMessage("8");
$read $serial->readPort();
echo 
"<div class='status'>" $read "</div>";
$serial->deviceClose();
echo 
"<div class='status'>" date("h:i:sa") . "</div>";
}
?>

</body>

</html>


The webpage side of things is a bit on the messy side (was experimenting with other aspects of PHP).  If anyone could give me some tips on improving reliability, that would be great!

The current goal is to be able to run it off of of my Raspberry Pi without the current stability issues.

rw950431

Have you interrogating the arduino from a serial terminal (eg minicom or screen) on your linux host?  Doing that will ensure your serial link is working correctly

See also http://www.fritz-hut.com/2012/08/30/php-serialclass-with-arduino-raspberrypi/ for some additional steps you may need to take to get php serial working.

Nicknml

#3
May 07, 2015, 03:21 pm Last Edit: May 07, 2015, 04:41 pm by Nicknml
I did just use minicom on the Linux host, and it behaves just fine.

I did add the following lines, but it didn't help at all:
Code: [Select]
$serial->confParity("none");
$serial->confCharacterLength(8);
$serial->confStopBits(1);
$serial->confFlowControl("none");

rw950431

So it seems the problem is with the phpserial module- I'm not a PHP person so cant really help too much.

I've not used any of them but this page https://serverfault.com/questions/112957/sniff-serial-port-on-linux gives some utilities to monitor serial comms

Just based on the write up I'd try http://sourceforge.net/projects/slsnif/ to try and understand what is going wrong between your PHP module and the arduino.

Nicknml

I'm just learning PHP myself.  Making an educated guess, it appears that the more recent versions of php don't like to play nicely with php_serial.class.php.  I also noticed that I don't have any problems when I hit a button that triggers something simple like an LED but if I select something such as take a reading of my photo resistor things go a bit nuts with my LED randomly getting turned on/off (but again everything is perfectly stable when I tried it under minicom.)

Will have to sniff the serial port to see exactly what's happening :)

Nicknml

#6
May 13, 2015, 05:59 pm Last Edit: May 13, 2015, 09:37 pm by Nicknml
Well I did find a work-around to the issue by adding the following lines after the results of the photoresistor and temperature are sent to clear the incoming serial buffer (a delay was also needed):

Code: [Select]

delay(250);
while(Serial.available())
  Serial.read();


I did try slsnif but got "Failed to open a pty: No such file or directory" Googled it and read that is only supports "legacy" pseudo-terminals.  Tried a few others with no luck.

Update: I've tried it on my RaspberryPi.  For some reason, a response isn't always displayed such as the reading of my photoresistor. Everything else works ok on it.
Udate2:I did a work-around on that on the php side with a while loop.

Go Up