Enviar datos de PHP a arduino

Buenas tardes!

Estoy haciendo en el proyecto de sintesi una simulacion de una casa domotica. Para ello he creado una Web que me crea una base de datos con unas tablas que seran las habitaciones.

Estas contienen los siguientes datos:

  • maxtemp
  • mintemp
  • alarma
  • luz

Maxtemp i mintemp son las temperaturas entre las que quiero que esté la habitacion. Los dos son enteros. Estará controlado con un sensor LM35. Yo le tengo que enviar la temperatura maxima y minima y que si esta por encima encienda un led azul, si esta por debajo un led rojo, y si esta en el intervalo que no haga nada.

Alarma sera booleano ON/OFF. Compre un emisor y receptor de IR similar a unos leds. Si la alarma esta en OFF, que no haga nada, pero si esta en ON el emisor no debe dejar de enviar señal, y a la que se corte que encienda y apague un led. (esto directamente no se ni como hacer ke envie la señal ni que reciba)

Luz. Le he de enviar el valor recogido (ON/OFF) o asignarle valor 1 al ON y 0 al OFF. Y encender el led o no en funcion a lo recibido.

Mis problemas...

  • no consigo enviarle esa variable 1 o 0 al led para encenderlo.
  • no encuentro como enviar todo el rato y cuando deje de enviar active un led
  • no consigo enviar la temperatura max i min para que el sensor trabaje o no.

He puesto un post algo excesivo, pero llevo tiempo peleandome, sin conseguir nada, y tengo que entregarlo el 20 de mayo...
Si alguien puede ayudarme me hará un favor grandisimo

Hola,

No entiendo muy bien la acotación de tu problema: es de PHP ó de Arduino?

Entiendo que lo que tienes que hacer es bajarte de internet la extensión para PHP que te deja manejar un puerto serie (no sé si estas en linux ó windows). Google !!

Una vez que tienes controlado como manejar el puerto serie, si no he entendido mal:

  • Conectas a la BBDD y haces la petición de tu tabla de Temp Max y Tem Min (típicas expresiones en PHP de mysql_connect,mysql_select_db y msql_query). Esos dos datos los tienes que enviar por el puerto serie y en tu arduino estar monitorizando lo que recibes. Tienes que crearte un mini-protocolo serie. Por ejemplo, que envies:
    TMax [dato] CR
    TMin [dato] CR
    Una vez que tienes el dato en Arduino, pues haces tu control ON-OFF ó PID,.. con la correspondiente activacion/desactivacion de un pin digital y lectura por pin analógico de la temperatura actual de la habitacion.

  • En caso de Alarma, es al revés, es el arduino el que manda por puerto serie los datos, por ejemplo,
    Alarma ON/OFF CR
    Según si tu led infrarrojo esta activado ó no.
    Con el dato recibido tienes que actualizar tu tabla.

  • La luz similar a anteriores.

Espero haber entendido bien tu problema.... :wink:

Salu2

Igor R.

Link para ir entrando en materia:

http://www.punksolid.com/conectar-la-placa-arduino-con-php-a-travez-de-php-serial/2008/

:wink:

Si, has entendido bien mi problema, viene a la hora de saber como enviar el valor a arduino.
Yo necesito enviarle los valores de tempmax, tempmin, alarma y luz por el puerto serie.

Se me habia olvidado comentar que trabajo desde windows :-[
La extension ya la tngo instalada, antes de venir aqui a preguntar me he informado, para no aprovecharme de alguien que sepa sin buscarme la vida, simplemente porque no me "gusta", pero igualmente gracias por decirmelo, porque en verdad lo averigué en un foro.
Si tubiera mas tiempo seguiria peleandome yo solo, pero el problema es que tengo que presentar el proyecto el 20 de mayo, y sigo sin haberlo conseguido, han ido pasando los dias... y hoy ya es 9 con la tonteria.

Yo seguí este link --> Gamut Industries – Internet Investment and Development
Y consegui encender un LED.

En ningun momento sabia que valor estaba recibiendo el arduino porque lo envia con una funcion chr() que aun no he entendido lo que hace.
Intente enviarle un 0 o 1 modificando el programa del arduino, pero no habia forma de conseguirlo.
Tenia algo similar a:

if (ValorRecibido==1)
encender el led
else if (ValorRecibido==0)
apagar el led
else
hacer que parpadee el led (para poder comprobar si no recibia 0 ni 1)

Y en php:

$fp =fopen("com3", "w");
fwrite($fp, 1);
flose($fp);

$fp =fopen("com3", "w");
fwrite($fp, '1');
flose($fp);

Una cosa que no entiendo es como enviarle maxtemp, mintemp, alarma, luz1 y luz2. Ahi es donde viene mi problema.

El caso de la alarma si que no he entendido nada. Segun me comentas dependo del arduino para decidir si esta ON/OFF?
Tampoco se como ponerle que el emisor y receptor han de tener señal continua y que en el momento en que se corte, encienda un LED avisando...

Gracias por la ayuda :wink:

Hola,

La función chr() te convierte a carácter ASCII. Aquí puedes ver un listado de caráteres ASCII:

Si haces chr(52) tendrás si te fijas en la lista es un "4".

Lo que te tienes que hacer es un miniprotocolo para intercambiar datos entre PHP y Arduino via serie. Entonces en ambos sitios, tienes que estar monitorizando lo que recibes por el puerto serie, y según la orden recibida, haces una cosa u otra.

Por ejemplo, puedes hacerte un miniprotocolo que mandes las ordenes en ASCII de esta forma:
M [dato] chr(13)
n [dato] chr(13)
A [on/off] chr(13)
L [on/off] chr(13)

Entonces tienes que analizar lo que te llega por el puerto serie (tanto por Arduino, como por PHP) y ver que si lo primero es una M, significa que lo que viene posteriormente es la temperatura máxima, y el valor se acaba cuando llegue un intro (carácter 13)

Entiendo que hay información que mandas PHP --> Arduino, como son Temp Maxima, Temp Minima y Luz. Y hay otra que es al revés, como es alarma, ya que es el arduino quien lo detecta y se lo manda a PHP.

En Pseudocodigo:

  1. Leo el valor recibido en puerto serie
  2. En caso que sea una "M", sigo leyendo hasta recibir un intro. Será mi temp maxima
    En caso que sea una "N",sigo leyendo hasta recibir un intro. Será mi temp mínima.
  3. Con esos datos en mis variables de arduino, hago mi control de caldera. Es decir, leo mi sensor de temperatura actual, y enciendo/apago mi salida convenientemente.

Lo he contado un poco por encima, como idea general. Pero antes de empezar con el proyecto, deberías dominar como mandar/recibir por el puerto serie, como manejar entradas/salidas digitales con arduino, como manejar entradas analógicas con arduino,....

Hazte un programita en Arduino básico, y para probar si funciona, te conectas usando el hyperterminal de windows, y le mandas la orden de encender/apagar led. Una vez que lo tengas funcionando, pues haces que la orden la mande tu página en PHP..... Poco a poco :wink:

Salu2

Igor R

No acabo de entender de todo lo de el miniprotocolo, pero me pondre a probar para entenderlo :wink:

Bueno, poco a poco tiene que ser en menos de 10 dias... :-/

Pero aver si con lo que me has explicado lo consigo.

Parece "facil". Ahora me falta entender lo de como hacer que cuando se corte la señal del IR me de un aviso.

Ya comentaré cuando consiga enviar los datos bien.

Por cierto, lo de la alarma, a lo mejor te entendí mal.

Yo entendí que tenias que hacer un montaje con el diodo simulando una barrera, y que cuando haya un obstáculo, que corte dicha barrera, te mande a tu hoja de PHP que la alarma ha sido activada.

Pero leyendo de nuevo, parece algo más fácil lo que dices, simplemente que cuando le mandes a ON, active una salida dígital (donde tendrás conectado tu diodo emisor mediante una resistencia).

Necesitas tener una especia de "lenguaje" para poder "entenderte" entre tu hoja web en php y tu arduino.

Este lenguaje se llama protocolo. Dicho protocolo puede ser más o menos elaborado según tus necesidades. Yo te he puesto un ejemplo básico. Necesitas mandar/recibir diferentes datos. Entonces el emisor y el receptor necesitan conocer qué es lo que estan recibiendo, para poder interpretarlo.

Imaginate que sólo le envias por el puerto serie un valor , pongamos que es un 43 y el receptor lo recibe. ¿Como sabe que lo que le envias es la temperatura máxima ó la temperatura mínima?

Entonces como parece que en tu ejercicio, lo que te piden es que siempre sea tu hoja PHP la que mande datos a Arduino (Temp Maxima, Tem Min, Led On-Off, Alarma On-Off), puedes poner eso en una sóla trama. Por ejemplo, separados por comas:
S,38,33,1,0 y el caracter retorno de carro (intro)

Le envias un caracter de inicio, para saber que estas recibiendo un nuevo dato (siempre sabes que te llegará una S, luego temperatura máxima, luego temperatura minima, luego orden para el led y la orden para la alarma)

Tu programa de Arduino tiene que ir monitorizando el puerto serie en el bucle loop:

void loop() {

if (Serial.available() > 0) {
//Significa que has recibido algo y lees el primer byte
dato_recibido=Serial.read();
if dato_recibido=='S' dato_recibido=Serial.read();
//Si recibes una S, lees de nuevo para capturar el siguiente dato
while (dato_recibido != ","){
//mientras dato recibido sea diferente de una coma, tengo que capturar el valor de mi temperatura máxima)

...

Ahora el seguir es cosa tuya... En menos de 10 días te da tiempo.... ánimo!! ¿Donde te han mandado esto? ¿Instituto, universidad, colegio?

Igor R.

Parece que lo voy entendiendo mejor... (mas que entendiendo me estas orientando muy bien)

No es que me lo hayan pedido, me lo he buscado yo solo este "problema" ;D

Estoy estudiando un ciclo de grado superior de Informatica, y en el proyecto he decidido hacer una simulacion de una casa domotica

Es muy bueno tener inquietudes y buscarse "problemas" ... :wink:

Si, pero llega un momento que ves que el tiempo se te hecha encima sin darte cuenta, y almenos para mi, empieza a no gustarme tanto lo que tengo que hacer.

Pero bueno, despues de esto me pondre a hacer proyectos con leds, que vayan cambiando y tal, para hacer efectos detras del monitor o algo asi.

Pero de momento hay que centrarse ne lo que urge. No la liemos! jajaja

Hola! He estado ya probando con lo que me comentaste.

Ya tengo este codigo arduino, bastante simple, pero que me permitirá probar lo del envio de las variables

int luz1= 13;
int luz2 = 12;
int el1;
int el2;
char dato_recibido;

void setup() {
pinMode(luz1, OUTPUT);
pinMode(luz2, OUTPUT);
Serial.begin(9600);
}

void loop()
{
//enviar --> S,L1,l0,F
//S inicio
//F fin
if (Serial.available() > 0)
{
//Significa que has recibido algo y lees el primer byte
dato_recibido=Serial.read();
if (dato_recibido=='S')
{
dato_recibido=Serial.read();
//Si recibes una S, lees de nuevo para capturar el siguiente dato
while (dato_recibido != 'F')
{
if (dato_recibido=='L')
{
el1=Serial.read();
if(el1=='1') el1=HIGH;
else el1=LOW;

digitalWrite(luz1,el1);
}
else if (dato_recibido=='l')
{
el2=Serial.read();
if(el2=='1') el2=HIGH;
else el2=LOW;

digitalWrite(luz2,el2);
}
dato_recibido=Serial.read();
Serial.print(dato_recibido);
}
}
}
}

Si le envio esos datos por el programa de arduino funciona OK enviando 'S,L1,l0,F'.

He probado desde hyperterminal, intentando enviarle un archivo de texto que contenia lo mismo, a la misma velocidad y no lo he conseguido.

He probado a enviarle desde PHP una variable $envio, que contenia 'S,L1,l0,F'. Pero no consigo encender la luz.

<?php $envio='S,L1,l0,F'; $fp=fopen("com3", "w"); fwrite($fp,$envio); sleep(3); fclose($fp); ?>
<?php $fp=fopen("com3", "w"); fwrite($fp,'S,L1,l0,F'); sleep(3); fclose($fp); ?>
<?php $envio='chr(83)'+'chr(44)'+'chr(76)'+'chr(49)'+'chr(44)'+'chr(108)'+'chr(48)'+'chr(44)'+'chr(70)'; $fp=fopen("com3", "w"); fwrite($fp,$envio); sleep(3); fclose($fp); ?>

La pagina no muestra ningun error. Pero tampoco enciende el primer LED (que es lo que deberia hacer)

[edit]Otro problema es que no se como seleccionar la temperatura que tiene dos caracteres. He probado con poner que mientras no sea una ',' el valor recibido, valor=valor+Serial.read(), pero no es esta la estructura correcta :-/[/edit]

Bueno, sin que sirva de precedente, hago un ejemplo básico.
Esta programado pensado en ESTADOS.
¿Qué significa esto? La respuesta es sencilla, empezamos en estado=0.
-> Si estoy en estado=0 Y recibo=S,entonces voy a estado 1, porque estoy siguiendo la secuencia correcta.
-> Si estoy en estado=1 Y recibo=1ó0,entonces voy a estado 2, porque estoy siguiendo la secuencia correcta. Me guardo en una variable la orden recibida.
-> Si estoy en estado=2 Y recibo=F,entonces voy a estado 0,y significa que la trama ha ido bien y enciendo/apago segun la orden.

Es una forma sencilla para programar cosas secuenciales. Es decir, para poder pasar a la siguiente acción, tengo que estar en el estado anterior y se tiene que cumplir la condición para ir al siguiente.

Lo único que no contempla el código, es que si envias S, y luego lo que quieras no valido, pero luego un 1ó0, luego lo que quieras no valido, y luego una F, pues tambien funcionará. En tus manos esta cambiarlo.

int luz1= 13;
int el1;
int estado=0;
byte dato_recibido;

void setup() {
   pinMode(luz1, OUTPUT);
   Serial.begin(9600);
}

void loop() 
{
  //trama a recibir --> S1F ó S0F
  //S inicio
  //1 ENCENDIDO Y 0 APAGADO
  //F fin
  while (Serial.available() > 0) 
  {
    //Significa que has recibido algo y lees el primer byte
    dato_recibido=Serial.read();
    if (dato_recibido=='S' && estado==0){
      estado=1;
      Serial.println("ESTADO 1");
    }
    if (((dato_recibido=='1')||(dato_recibido=='0')) && estado==1){
      estado=2;
      if (dato_recibido=='1')  el1=1;
      if (dato_recibido=='0')  el1=0;
      Serial.println("ESTADO 2");
    }
    if (dato_recibido=='F' && estado==2){
      estado=0;
      digitalWrite(luz1,el1);
      Serial.println("ESTADO 3");
    }
    
  }
}

Asegurate qué puerto COM tienes en el Arduino (FTDI).

Una vez que lo sepas, vas a Hyperterminal y haces una conexion nueva. En Conectar a.... Ahi eliges tu puerto COM.
En configuración del puerto pones 9600,8,Ninguno,1,Ninguno.

No tienes que enviar ningun archivo de texto, simplemente ir escribiendo lo que quieres enviar. EN MAYUSCULAS, vete probando S y leeras ESTADO 1, luego pulsas 1ó0, y verás ESTADO 2 y escribe una F y verás ESTADO 3 y tu led del arduino se encenderá o apagará según si has mandado un 1 ó 0.

:wink:

Igor R

Es algo básico, tendrás que mejorarlo, como añadir si pasa cierto tiempo sin recibir el siguiente cáracter, pues que vuelva al estado=0 (inicial) porque imaginate que le mandas S1F, y por lo que sea, no recibe bien el cáracter F, pues hasta que no le llegue una F, tu programa no hará nada....
A parte que no esta contemplado el caso de que estando en estado 1, es decir, a la espera de recibir la orden de encendido ó apagado, le llegue otra cosa.... La ignora y se queda esperando hasta que llegue un "1" ó un "0".

Programar pensando como DIAGRAMAS DE ESTADOS es algo que cuando se trata de acciones secuenciales, te ayuda muchisimo y tienes muchísima potencia. A parte de ser sencillo de pensar.

Pues mi hyperterminal debe tener algun problema. Pone conected, el contador va subiendo, pero no deja escribir nada.

Yo intentaba enviar archivos de texto porque no me deja escribir. Me he descargado otra http://www.pcworld.com/downloads/file/fid,3376-order,4-c,faxmodemutilities/description.html y sigo sin poder escribir nada.

He puesto las preferencias que me has dicho, y el puerto COM3, que es el de la placa.

Se me queda el hyperterminal con el "_" parpadeando y de ahí no pasa. No se como "solucionar" esto.

Con el codigo que me acabas de poner me parece que me he liado mas aunque deberia ser mas sencillo, aver si lo he entendido bien:

  • En el estado 0 está en espera de que le llegue la trama.
  • En el estado 1 le ha llegado la S inicial, lo cual implica que detrás le vendran los estados. Si se trata de una sola luz bien, pero en el caso de que sean dos luces, temperatura y alarma, debería ser algo del estilo S1130201F ( o SL1l1M30m20a1F). Pero entonces estaré con el mismo problema de antes, como hacer que una variable recoja el 30.
  • En el estado 2 ya ha recibido el valor de esa luz y lo asigna a una variable el1.
  • Por ultimo,en el estado 3, realiza las acciones de encender/apagar, etc. Y devuelve al estado 0, para que tenga que volver a recibir la S para volver a iniciar.

Me mirare el diagrama de estados que creo que lo remarcas por algo. jajaja

Siento ser tan pesado, pero me fastidia mucho que no me funcione y trabajar con tan poco tiempo.

Gracias por todo.

[edit]Lo del hyperterminal lo he solucionado, era una opcion que estaba desmarcada...
Escribo S y no hace nada. S1 nada. S1F y tampoco
Esta noche probaré mas, que ahora me tengo que ir.[/edit]

Mira bien lo del hyperterminal, porque funciona seguro.....

Una cosa es que no tengas tiempo, cosa que no estoy de acuerdo... y otra cosa que tampoco estes cinco minutillos pensando....ja,ja,ja

Puedes hacer que tu trama sea:
SMNL<1 ó 0>A<1 ó 0>F

  • Todo lo que llegue entre M y N, será la temperatura máxima.
  • Todo lo que llegue entre N y L, será tu temperatura mínima.
  • Despues de L, orden para encender Luz, será ON =1 u OFF=0.
  • Despues de A, orden para encender Alarma,será ON=1 u OFF=0.

Recuerda, que recibes carácteres, tendrás que convertirlo a número...

Esto es una idea, pero puedes hacerlo como quieras....

Bueno, ya has gastado los comodines del público.... Te toca currartelo un poco.... ;D

Buenas! He vuelto, pero esta vez no para preguntarte cosas ;D

Mas que nada para que veas lo que llevo hecho hasta ahora (y que funciona como necesito)

int luz1= 13;
int luz2 = 12;
int aCal = 7;
int aFrio = 8;
int el1;
int el2;
int M[2];
int m[2];
int maxtemp=99;
int mintemp=0;
char dato_recibido;
int analogPin = 3;
int val = 0;
float temp = 0;
int i;

void setup() {
pinMode(luz1, OUTPUT);
pinMode(luz2, OUTPUT);
pinMode(aCal, OUTPUT);
pinMode(aFrio, OUTPUT);
Serial.begin(9600);
}

void loop()
{
//enviar --> S,L1,l1,M30,m20,F
val = analogRead(analogPin);r
temp = val*500/1024;
val = byte(temp);
Serial.print("Temperatura:\t");
Serial.print(val);
Serial.println();
delay(500);

if (val>maxtemp)
{
digitalWrite(aFrio,HIGH);
digitalWrite(aCal,LOW);
}
else if (val<mintemp)
{
digitalWrite(aCal,HIGH);
digitalWrite(aFrio,LOW);
}
else
{
digitalWrite(aCal,LOW);
digitalWrite(aFrio,LOW);
}

if (Serial.available() > 0)
{
dato_recibido=Serial.read();
if (dato_recibido=='S')
{
dato_recibido=Serial.read();
while (dato_recibido != 'F')
{
dato_recibido=Serial.read();
if (dato_recibido=='L')
{
el1=Serial.read();
if(el1=='1') el1=HIGH;
else el1=LOW;

digitalWrite(luz1,el1);
}
else if (dato_recibido=='l')
{
el2=Serial.read();
if(el2=='1') el2=HIGH;
else el2=LOW;

digitalWrite(luz2,el2);
}
else if (dato_recibido=='M')
{
dato_recibido=Serial.read();
i=0;
while(dato_recibido!='m')
{
M*=dato_recibido;*

  • i++;*
  • dato_recibido=Serial.read();*
  • }*
  • M[0]=M[0]-48;*
  • M[1]=M[1]-48;*
    _ maxtemp=10*M[0]+M[1];_
  • }*
  • if (dato_recibido=='m')*
  • {*
  • dato_recibido=Serial.read();*
  • i=0;*
  • while(dato_recibido!='F')*
  • {*
    m*=dato_recibido;
    _
    i++;_
    dato_recibido=Serial.read();
    _
    }_
    _
    m[0]=m[0]-48;_
    _
    m[1]=m[1]-48;_
    _ mintemp=10m[0]+m[1];
    * }*
    * Serial.print(dato_recibido);
    _
    }*

    * }*
    * }*
    } [/quote]
    Ahora solo me queda aprender a enviar y recibir una señal de IR. Que tengo un emisor y receptor que son similares a un led, uno oscuro y otro claro.
    De momento lo que he encontrado son los que tienen 3 pins y son analogicos, pero nose donde leí que este tipo eran digitales.
    Aver donde encuentro mas info de esto :slight_smile:
    Gracias de nuevo Igor R :wink:

Ahora ya si quieres "profesionalizarlo", añade a tu trama un par de bytes con un "cheksum" para estar seguro que no ha habido ningun problema durante el envio de la misma.

Cuando creas la trama, añades por ejemplo un campo con el cheksum, asi al recibirla compruebas que todo ha ido "OK".

Un forma de hacerlo es hacer el complemento a dos de la suma de todos los bytes enviados anteriormente. Por ejemplo, si usas 2 bytes, la cuenta sería 65535-suma_bytes+1

Esto ya es para hacerlo PRO!! Para sacar nota!! ja,ja,ja

Una forma sencilla, para no meter tanta "paja" en medio de la trama, es hacer cosas asi:
Start Byte= FFh=255 decimal (todo a "1")
Datos enviados (algo fijo), por ejemplo=6 bytes
Checksum(2 bytes)= Complemento a dos de la suma de los datos anteriores incluido el start byte

Entonces, tu ya sabes que:

  • 1 byte=Start=FFh
  • 2 y 3 bytes=Temp Máxima (valor entre 0-65535)
  • 4 y 5 bytes=Temp Mínima (valor entre 0-65535)
  • 6 byte=Orden para luz
  • 7 byte =Orden para alarma
  • 8 y 9 byte= Checksum

Para las temperaturas, puedes enviarlas con un decimal, para ello multiplicas por 10 y al recibir divides. Ejemplo: Si quieres enviar 45,5 grados, pues en realidad envias un 455, y tu en la recepción, divides entre 10 y tendrías 45'5. Ya que tu sabes que todo el dato que recibas, vedrá con un decimal, por lo que tienes que dividir el valor entre 10...

Espero no haberte liado, simplemente te cuento que es lo que sueles encontrarte por ahi.....esto quizas para la evo2 de tu programa.... je,je,je

:wink:

Ui, deja las "profesionalizaciones" para mas adelante ;D

De momento me quiero seguir peleando con enviarle la cadena desde PHP, que solo consigo que me reciba la S >:(
Yo le envio S,L1,l1,M30,m20,F --> recibe S y nada mas.
Asi que debo ver como lo soluciono, porque eso es mas importante que "profesionalizarlo"

Aparte que también tengo que pelearme aun con el emisor y receptor de IR. Creo que simplemente poniendo uno como emisor y otro como receptor solo me quedará saber interpretar la señal que envia y tal. Son similares a un LED, y de este tipo no he encontrado buena información.