Archivo

Entradas Etiquetadas ‘envio’

Arduino: Usando el serial para comunicarnos con el ordenador

Viernes, 5 de Agosto de 2011 Gaspar Fernández Sin comentarios

Es interesante ver cómo los programas que corren con Arduino pueden hacer uso del puerto serie para comunicarnos con el ordenador. No sólo vale para hacer la programación del chip, sino que podemos intercambiar información, variar el comportamiento del programa… o simplemente tener un canal para depurar nuestro programa mostrando el estado de las variables en cualquier momento.

La configuración es muy sencilla, sólo necesitamos especificar la velocidad del puerto serie cuando queramos iniciar la comunicación. La velocidad más alta que he podido alcanzar es de 230400bps, lo que vienen a ser unos 28Kb/s; aunque, mejor no subir de 115200bps, o unos 14Kb (porque a 230400 la transmisión empieza a ser inestable y a veces se pierden bits).

Lo más normal es querer iniciar la comunicación al principio y cesarla al final del programa por lo que nuestro Serial empezará en el setup. Vamos a hacer un pequeño ejemplo de comunicación a través del USB del Arduino:
serial.h:

1
2
3
4
5
6
/* En este archivo veremos la configuración de nuestro proyecto */

/* Velocidad del puerto serie */
/* #define SERIAL_SPEED 230400 */
/* Es una buena velocidad para el serial del Arduino Diecimila */
#define SERIAL_SPEED 115200

serial1.pde:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// serial1
// Hace un eco con el puerto serie del Arduino
#include "serial.h"

void setup()
{
Serial.begin(SERIAL_SPEED);
}

void loop ()
{
int recibe;
if(Serial.available())
{
recibe=Serial.read();
// Escribimos byte a byte
Serial.print(recibe, BYTE);
}

}

Si compilamos/programamos y ejecutamos un terminal serie, a mí me gusta cutecom, es simple y tiene entorno gráfico. Si nosotros escribimos por la entrada, el programa símplemente repite lo que decimos:
Cutecom

Por otra parte, el uso del Serial no es bloqueante, es decir, podemos realizar otras tareas mientras esperamos que lleguen datos por el puerto. Esto puede ser muy útil ya que nos permite poder modificar el comportamiento del circuito mientras estemos conectados al serial, o la interacción con otros aparatos que también se conecten al puerto serie mientras tenemos tiempo de CPU para otros cálculos.

Podemos comprobarlo aquí:
serial.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* En este archivo veremos la configuración de nuestro proyecto */

/* Velocidad del puerto serie */
/* #define SERIAL_SPEED 230400 */
/* Es una buena velocidad para el serial del Arduino Diecimila */
/* #define SERIAL_SPEED 115200 */
/* Para ver cómo el led de transmisión parpadea, transmitimos más lento */
#define SERIAL_SPEED 1200
/* Led que queremos que parpadee mientras se ejecuta el programa */
#define STATUS_LED   11
/* Led que indica transferencia de datos */
#define TRANSF_LED   10
/* Retardo introducido para ver el estado del led */
#define BLINK_DELAY  500
/* Bytes que tenemos que recibir antes de que el led de transferencia parpadee */
#define BLINK_RECEPTION 50

serial1.pde:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// serial1
// Hace un eco con el puerto serie del Arduino

#include "serial.h"

// Almacenamos el estado como variable global
int estado=LOW;
int estado_transf=LOW;
// Almacenamos también el número de milisegundos anterior
unsigned long momento_anterior=0;
unsigned long bytes_recibidos=0;
void setup()
{
Serial.begin(SERIAL_SPEED);
// Queremos que un led parpadee mientras trabajamos
pinMode(STATUS_LED, OUTPUT);
// Queremos salida por el led de transferencia
pinMode(TRANSF_LED, OUTPUT);
}
<p style="text-align: center;">void loop ()
{
int recibe;
unsigned long momento_actual=millis();
// No bloqueante, si hay algo para leer entramos, si no, no.
if(Serial.available())
{
recibe=Serial.read();
// Escribimos byte a byte
Serial.print(recibe, BYTE);
++bytes_recibidos;
if (bytes_recibidos%BLINK_RECEPTION==0)
{
estado_transf=!estado_transf;
digitalWrite(TRANSF_LED, estado_transf);
}
}
// No usamos delay para el parpadeo porque nos entorpece la comunicación con el serial
if (momento_actual-momento_anterior&gt;=BLINK_DELAY)
{
// Cambiamos el estado siguiente. Si era HIGH (1) ahora será
// LOW (0). He leído en algún lado que el valor de HIGH no
// siempre es 1; pero en este caso sí es así.
estado=!estado;
// Escribimos el estado actual del led
digitalWrite(STATUS_LED, estado);
// Establecemos el momento anterior como actual.
momento_anterior=momento_actual;
}
}

Comunicación por puerto serie y led

Enviando posts a twitter

Viernes, 28 de Mayo de 2010 Gaspar Fernández Sin comentarios

twitter-bird-6

Hace mucho tiempo leí en anieto2k una función muy interesante para twittear sin necesidad de incluir APIs tremendas. Es decir, si en mi aplicación, sólo quiero enviar twits, ¿para qué incluir algo demasiado grande? Con una pequeña función estaría todo resuelto.

El tema es que hace poco inicié un proyecto que periódicamente envía twits y necesité echar mano de esa función. Descubrí que Twitter había cambiado un poco su forma de interactuar.

Antes, podíamos enviar por GET (en la URL) el parámetro del mensaje que íbamos a postear, aunque ahora devuelve un error extraño: 413 Request Entity Too Large, más o menos es cuando la consulta que enviamos al servidor es muy grande; aunque el error nos lo da porque no encuentra el post que queremos publicar.

Para solucionarlo, tenemos que enviarlo con el método post, de la siguiente forma:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function postToTwitter($username,$password,$message)
{
// Esta línea está modificada
    $host = "http://twitter.com/statuses/update.xml";

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $host);
    curl_setopt($ch, CURLOPT_VERBOSE, 1);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
    curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    curl_setopt($ch, CURLOPT_POST, 1);
// Esta línea es nueva
   curl_setopt($ch, CURLOPT_POSTFIELDS, 'status='.urlencode(stripslashes(urldecode($message))));
    $result = curl_exec($ch);
    $resultArray = curl_getinfo($ch);
    curl_close($ch);
    if($resultArray['http_code'] == "200")
    {
        echo "<br />OK! postedo en http://twitter.com/".$username."/<br />";
    }
    else
    {
        // Esto lo podemos quitar, es sólo para analizar la salida.
        print_r($resultArray);
        echo "<br />Error! ha ocurrido un problema<br />";
    }
}

Con esta versión modificada del script ya podemos twitear :)

Y para llamar a esta función:

postToTwitter(’usuario’, ‘contraseña’, ‘140 letras de lo que queremos twitear’);

Foto: Free Twitter Bird Icon Set

Club2020 de Vodafone… enviar SMS desde la consola

Miércoles, 16 de Diciembre de 2009 Gaspar Fernández Sin comentarios

club2020No vengo a hablaros de la empresa Vodafone, ni del concurso (que podéis entrar desde este enlace y no tenéis que ser de Vodafone). Es un concurso rasca y gana (aunque cada cierto tiempo hay concursos parecidos; en el que uno de los premios son SMS gratis.

Hasta ahí bien, el problema viene a la hora de gastar los SMS, y es que mientras entro en la web (todo hecho en flash), se carga la intro, me la salto, se carga la web, me identifico, pulso en enviar mensajes, escribo el número, el mensaje y envío echo unos 3 minutos, y para el SMS tardo menos desde el móvil.

He hecho un pequeño script para consola que lo hace todo solo, y además en unos 10 segundos (como mucho) está mandado el mensaje… esto también nos permitirá enviar muchos mensajes seguidos (y si queremos usarlo para felicitar las fiestas, nos vendrá genial).

Nota: Antes de postear el código, quiero decir una cosa (NO hago comprobación de las letras de los mensajes, que son algo menos de 160 caracteres), ni de los parámetros (explicados al final) devuelvo el texto de enviado y no enviado, aunque eso no significa que se haga de verdad (ya sabéis cómo andan los SMS incluso en este 2009); por otra parte, si Vodafone corta el servicio o introduce alguna modificación en la página… ¡mala suerte! se nos acabó esto, pero quise compartir este código (y tal vez podamos hacer más cosa en el futuro con él).

Nota 2: Requiere cURL (sin él habría sido una matanza de código)

Nota 3: No está muy comentado, pero si hay alguna duda, siempre tendremos los manuales de cURL, de bash, y los comentarios en este post :)

Ahí va:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#!/bin/bash

MOVIL_USR={mi movil}
CLAVE_USR={mi clave club2020}

function strpos()
{
str=${1/$2*/}
if [[ -z "$1" ]]; then
cad1l=0
else
cad1l=`expr length "$1"`
fi

if [[ -z "$str" ]]; then
donde=0;
else
donde=`expr length "$str"`
fi
if (( $donde &lt; $cad1l )); then
echo $donde
else
echo -1
fi
}

echo "Identificándonse en el sistema..."
#Envio de datos
login="accion=login&amp;clave%5Fusr="$CLAVE_USR"&amp;movil%5Fusr="$MOVIL_USR
data=`curl -s -L -b cookies.txt -c cookies.txt "http://club2020.mi.vodafone.es/rascaygana/actuar.php?"$login`

# Usé esto para obtener los datos a mano hace un rato
#echo $data&gt;tmp
#data=`cat tmp`

# Almacenamos en un array  los datos que nos ha mandado la web
i=1
datos[${i}]=`echo $data | cut -d"&amp;" -f $i`;

while [[ -n ${datos[${i}]} ]]; do let i=$i+1; datos[$i]=`echo $data | cut -d"&amp;" -f $i`; done
#Recorremos el array para mirar las opciones recibidas
datosrecibidos=${#datos[*]}

for ((i=0;i&lt;$datosrecibidos;i++)); do
if (( `strpos ${datos[${i}]} =` &gt; -1 )); then
combo=${datos[${i}]}
clave=`echo $combo | cut -d"=" -f1`
valor=`echo $combo | cut -d"=" -f2`
if [[ $clave == "usuario" ]]; then
usuario=$valor;
elif [[ $clave == "nombre" ]]; then
nombre=$valor;
elif [[ $clave == "tarjetas" ]]; then
tarjetas=$valor;
elif [[ $clave == "mensajes" ]]; then
mensajes=$valor;
fi
fi
done

echo "Hola "$nombre" te quedan "$mensajes" mensajes y tienes "$tarjetas" por rascar"
mensaje=$2
destinatario=$1
echo "Enviando mensaje: "$mensaje" a "$destinatario"..."
postdata="accion=mandarSms&amp;mensaje="$mensaje"&amp;destinatario="$destinatario"&amp;firma="$usuario

#Envio de datos
result=`curl -s -L -b cookies.txt -c cookies.txt -d "$postdata" 'http://club2020.mi.vodafone.es/rascaygana/actuar.php'`

#echo $result &gt; tmp2
result="retorno"`cat tmp2`
i=1
resdata[${i}]=`echo $result | cut -d"&amp;" -f $i`;

while [[ -n ${resdata[${i}]} ]]; do let i=$i+1; resdata[$i]=`echo $result | cut -d"&amp;" -f $i`; done
#Recorremos el array para mirar las opciones recibidas
resdatarecibidos=${#resdata[*]}

for ((i=0;i&lt;$resdatarecibidos;i++)); do
if (( `strpos "${resdata[${i}]}" =` &gt; -1 )); then
combo=${resdata[${i}]}
clave=`echo $combo | cut -d"=" -f1`
valor=`echo $combo | cut -d"=" -f2`
if [[ $clave == "error" ]]; then
error=$valor;
elif [[ $clave == "mensajes" ]]; then
mensajes=$valor;
fi

fi

done

echo "Resultado de la operación: "$error" Quedan "$mensajes" mensajes"
echo "Cerrando sesión..."

#Envio de datos
curl -s -L -b cookies.txt -c cookies.txt 'http://club2020.mi.vodafone.es/rascaygana/actuar.php?accion=logout' &gt;/dev/null

Si guardamos este archivo como sms2020 y le damos permiso de ejecución, el primer parámetro es el móvil del destinatario, y el segundo el mensaje (entrecomilladlo si tiene espacios). Además, en la parte de arriba del archivo encontramos MOVIL_USR y CLAVE_USR, tendréis que poner vuestro número de móvil y vuestra clave del club2020 (para poder identificaros en el sistema).
Nota 4: Pude optimizar un poco el código, pero como había prisa y no sé lo que durará esto, no quise calentarme mucho el coco.
Nota 5: Para registrase: seguid este link (así me dais sms gratis a mí también, porque los demás premios nunca tocan).

Visita otras webs de la red