tag:blogger.com,1999:blog-52298998560625847122024-03-18T20:58:06.768-07:00Tinkering with Electronics...Physical Computing - Rapid prototyping hardwareIgorhttp://www.blogger.com/profile/07332255486737492708noreply@blogger.comBlogger23125tag:blogger.com,1999:blog-5229899856062584712.post-77100396611041385892030-01-01T14:58:00.000-08:002011-07-18T11:25:03.386-07:00Bienvenido! - Welcome!<div dir="ltr" style="text-align: left;" trbidi="on"><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Verdana,sans-serif; font-size: large;"><b>Blog News:</b></span></div><div class="separator" style="clear: both; font-family: Verdana,sans-serif; text-align: left;"><br />
</div><b><span style="color: red;">NEW</span> </b><b><a href="http://real2electronics.blogspot.com/2011/07/maqueta-de-control-pid-con-arduino.html">Maqueta de Control Didáctica (VirtualCamp Jul 2011)</a></b><br />
<b><span style="color: red;">NEW</span> </b><b><a href="http://real2electronics.blogspot.com/2011/01/timer-2.html"> Introducción al Timer 2</a></b><br />
<b><span style="color: red;">NEW</span> </b><b> <a href="http://real2electronics.blogspot.com/2010/11/libreria-tvout.html">TVout= Arduino + TV</a></b><br />
<b><span style="color: red;">NEW</span> </b><b> <a href="http://secuduino.blogspot.com/">CAN BUS CON ARDUINO!!</a><br />
<span style="color: red;"> </span></b><br />
<br />
<div style="color: blue;"><br />
<div style="color: blue;"><br />
</div></div><hr style="color: blue;" /><div style="color: blue;"><span style="font-size: large;">Puedes encontrar algunos artículos sobre microcontroladores, y en concreto sobre <a href="http://en.wikipedia.org/wiki/Arduino">Arduino</a> y Atmel en general.</span></div><div style="color: blue;"><span style="font-size: large;">Nos enfocaremos en hardware libre y creación de sistemas low cost.</span></div><hr style="color: blue;" /><div style="color: blue;"><span style="font-size: large;">You can find some posts about <a href="http://en.wikipedia.org/wiki/Arduino">Arduino</a> and Atmel. </span></div><div style="color: blue;"><span style="font-size: large;">We´ll focus in open-source hardware and the design of low cost products. </span></div><hr style="color: blue;" /><div style="color: blue;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><a href="http://www.arduino.cc/" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"> </a></div><div class="separator" style="clear: both; text-align: center;"><a href="http://www.arduino.cc/" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><br />
</a></div><div class="separator" style="clear: both; text-align: center;"><a href="http://www.arduino.cc/" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><br />
</a></div><div class="separator" style="clear: both; text-align: center;"><a href="http://www.arduino.cc/" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><br />
</a><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2cv_8qlo-BsbhycOwyC_nZH7_nV6H97RmXkkCf2ZCP1CuJ_lkeNFymAHjZEZfi-Ul1xBCHJIennwVuGzCwFgmoCIcaPIVYZJdeE2fn0CFI5Jo4Ra2Nzm6rPdWkcuCsW35A6XqBTbosruZ/s640/Real2Ekectronics_Arduino.JPG" /></div><span style="font-size: large;"><br />
</span><br />
<div style="color: red; text-align: left;"><br />
<span style="font-size: large;">Añadido Twitter al blog!! Últimos comentarios en la barra lateral ó enlaza a:</span><br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://twitter.com/real2electronic" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjF99R2GrMLx1bQ5BOdwacsoRMCYaQ-v-hUBoof6SsIv63jBCA6wGF-eKaHODb_PN1zaHr0CDqMramNtG-todcxuCb3fZJWiWvDlX7JLed3iroFEj7OtDSro43WG5-NFF8HIFabRixVQiL0/s320/twitter.JPG" /></a></div><br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://real2electronics.blogspot.com/atom.xml" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqRd5cE9gBtoyR7bV00QS9A-z9JxX1exkBtXtqaLLyQIa8ImZ-FDeoW_w0INInR9jh6zfHfMODvrKI0H5Sb9GxYPAoh3_wtD3nPL2dzl0wUOhBRWpRUiW_8-mpwuysaUR8qL2CnSvec8WH/s640/RSS_person_leaning.jpg" /></a></div><div style="text-align: center;"><a href="http://real2electronics.blogspot.com/atom.xml"><b>SUBSCRIBE</b></a></div><br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
.<br />
<br />
</div></div>Igorhttp://www.blogger.com/profile/07332255486737492708noreply@blogger.comtag:blogger.com,1999:blog-5229899856062584712.post-62409817558671140172011-09-03T11:36:00.000-07:002011-09-06T14:15:19.064-07:00Arduino ADC: Muestreo alta velocidad<div dir="ltr" style="text-align: left;" trbidi="on"><span style="color: white;">.</span><code><br />
<script src="http://www.gmodules.com/ig/ifr?url=http://www.google.com/ig/modules/translatemypage.xml&up_source_language=es&w=160&h=60&title=&border=&output=js">
</script> </code><br />
<br />
<div dir="ltr" style="text-align: left;" trbidi="on"><br />
El objetivo de este mini tutorial es configurar el módulo del convertidor analógico-digital a mayor velocidad que la que viene por defecto configurada en Arduino, tras las diferentes pruebas que se fueron haciendo en este <a href="http://arduino.cc/forum/index.php/topic,68855.0.html">post de foro Arduino</a> entre aero_yo, CesarCarlos y un servidor. A su vez, amplia el anterior tutorial sobre mostrar gráficamente datos recibidos de Arduino a tiempo real usando el software libre <a href="http://kst-plot.kde.org/">KST </a>publicado anteriormente <a href="http://real2electronics.blogspot.com/2009/11/graficar-con-kst.html">aquí</a>.<br />
<br />
El programa de Arduino, usa mayoritariamente C y diréctamente registros del microcontrolador, intentando conseguir el máximo rendimiento.<br />
<br />
Como se puede observar en el datasheet, Atmel recomienda que la velocidad de reloj del ADC esté entre 50-200 kHz, para una resolución de 10 bits. El oscilador de nuestro Arduino (16 MHz) alimenta también el módulo del conversor, pasando a través de un divisor de frecuencia (prescaler).<br />
Dicho prescaler se configura mediante tres bits del registro ADCSRA. Las combinaciones nos permiten dividir entre 2, 4,8,16,32,64 y 128.<br />
Por ejemplo, un prescaler de 64 nos daría una frecuencia de alimentación al ADC de 250 kHz (16 Mhz/64=250 kHz), lo cual esta un poco por encima de la recomendación.<br />
<br />
Se puede trabajar a mayores frecuencias, pero perdiendo resolución, que es lo que haremos aquí. Se trabajará con una resolución de 8 bits, para poder tener mayores velocidades de conversión y a su vez, minimizar el tiempo necesario para enviar el dato convertido mediante serie para poder disponerlo a la mayor frecuencia posible (sin tener que bajar a ensamblador).<br />
<br />
Una conversión normal cuesta 13 ciclos de reloj, y usaremos una sóla entrada analógica (5). El resultado generado tras la conversión es almacenado en los regitros ADCH y ADCL, pero si sólamente se desea 8 bits, bastará con leer el registro ADCH (justificación a la izquierda).<br />
<br />
Dicho resultado de la conversión (ADC) será enviado mediante serie (UART),sin convertir el dato a ASCII, para minimizar al máximo los tiempos de programa.<br />
<br />
Un script en phyton (soft libre y multiplataforma) será el encargado de recoger dicho byte, convertirlo en milivoltios y guardarlo en un fichero. En concreto, el script utilizado es el siguiente:<br />
<br />
<b>Código:</b><br />
<br />
<pre class="code" style="height: 300px; margin: 0px; overflow: auto; width: auto;">#! /usr/bin/env python
import serial
import sys
ser = serial.Serial('/dev/ttyUSB0', 1000000);
while 1:
try:
n=ser.read();
n=ord(n)*5000/255; #Convierto en mV
print n;
except KeyboardInterrupt:
ser.close();
sys.exit(0)
</pre>Para poder usar este código, se necesita tener instalado python y la librería pySerial. Como se puede observar, estamos trabajando a 1 Mbps. Se ha de cambiar el nombre del puerto serie en el que tenemos nuestro Arduino conectado, por ejemplo en caso Windows, 'COM3', 'COM4', etc.<br />
Es decir, cambiar la línea de la forma <b><span style="color: red;">ser = serial.Serial('COM2', 1000000);</span></b><br />
Si disponemos dicho script en un fichero, por ejemplo llamado adquisicion.py, ejecutaremos desde el terminal:<br />
<div style="color: blue;"><b></b><br />
<pre><span style="font-size: large;"><b>./adquisicion.py >> mifichero.csv</b></span></pre></div>El fichero que contiene el script, debe tener permisos de ejecución (linux).<br />
Cuando deseemos terminar la ejecución del script, en el terminal pulsamos CRTL+C.<br />
<u><i><b>Este script ha sido probado en Ubuntu y Windows, funcionando en ambos perfectamente.</b></i></u><br />
<br />
En la parte Arduino, el programa necesario es el siguiente:<br />
<br />
<pre class="code" style="height: 300px; margin: 0px; overflow: auto; width: auto;"><pre><span style="color: #7e7e7e;">//------------------------------------------------</span>
<span style="color: #7e7e7e;">// Fast Acquisition</span>
<span style="color: #7e7e7e;">// By: Igor R.</span>
<span style="color: #7e7e7e;">// 03/09/2011</span>
<span style="color: #7e7e7e;">//------------------------------------------------</span>
#define CHRONO 0
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><b>setup</b></span>()
{
<span style="color: #cc6600;"><b>Serial</b></span>.<span style="color: #cc6600;">begin</span>(1000000); <span style="color: #7e7e7e;">//1 Mbps</span>
<span style="color: #7e7e7e;">//Prescaler</span>
<span style="color: #7e7e7e;">//ADPS2 - ADPS1 - ADPS0 - Division Factor</span>
<span style="color: #7e7e7e;">//0 - 0 - 0 ->2</span>
<span style="color: #7e7e7e;">//0 - 0 - 1 ->2</span>
<span style="color: #7e7e7e;">//0 - 1 - 0 ->4</span>
<span style="color: #7e7e7e;">//0 - 1 - 1 ->8</span>
<span style="color: #7e7e7e;">//1 - 0 - 0 ->16</span>
<span style="color: #7e7e7e;">//1 - 0 - 1 ->32</span>
<span style="color: #7e7e7e;">//1 - 1 - 0 ->64</span>
<span style="color: #7e7e7e;">//1 - 1 - 1 ->128</span>
<span style="color: #7e7e7e;">//Configure to Prescaler=16 (11793.57 Hz a 115200)</span>
<span style="color: #7e7e7e;">//Configure to Prescaler=16 (66418.71 Hz a 1000000)</span>
<span style="color: #cc6600;">bitWrite</span>(ADCSRA,ADPS2,1);
<span style="color: #cc6600;">bitWrite</span>(ADCSRA,ADPS1,0);
<span style="color: #cc6600;">bitWrite</span>(ADCSRA,ADPS0,0);
<span style="color: #7e7e7e;">//Analog Input A5</span>
ADMUX=(1<<ADLAR)|(0<<REFS1)|(1<<REFS0)|(0<<MUX3)|(1<<MUX2)|(0<<MUX1)|(1<<MUX0);
}
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><b>loop</b></span>()
{
#if CHRONO==1
MeasureTime();
<span style="color: #cc6600;">for</span> (;;)
{
}
#else
<span style="color: #cc6600;">int</span> i;
<span style="color: #cc6600;">for</span> (;;)
{
<span style="color: #cc6600;">while</span> (!(UCSR0A & (1 << UDRE0)));
UDR0 = analogReadFast();
i++;
<span style="color: #cc6600;">if</span> (i==-1);
}
#endif
}
<span style="color: #7e7e7e;">//Read ADC</span>
<span style="color: #cc6600;">int</span> analogReadFast()
{
ADCSRA|=(1<<ADSC);
<span style="color: #7e7e7e;">// ADSC is cleared when the conversion finishes</span>
<span style="color: #cc6600;">while</span> (bit_is_set(ADCSRA, ADSC));
<span style="color: #cc6600;">return</span> ADCH;
}
<span style="color: #7e7e7e;">//Chrono function</span>
<span style="color: #cc6600;">void</span> MeasureTime()
{
<span style="color: #cc6600;">unsigned</span> <span style="color: #cc6600;">int</span> i=1;
<span style="color: #cc6600;">unsigned</span> <span style="color: #cc6600;">long</span> tStart;
<span style="color: #cc6600;">unsigned</span> <span style="color: #cc6600;">long</span> tEnd;
<span style="color: #7e7e7e;">//--------------------------------------------</span>
<span style="color: #7e7e7e;">//CHRONO</span>
tStart=<span style="color: #cc6600;">micros</span>();
<span style="color: #cc6600;">for</span> (;;)
{
<span style="color: #cc6600;">while</span> (!(UCSR0A & (1 << UDRE0)));
UDR0 = analogReadFast();
i++;
<span style="color: #cc6600;">if</span> (i== 1000) <span style="color: #cc6600;">break</span>;
}
tEnd=<span style="color: #cc6600;">micros</span>();
<span style="color: #7e7e7e;">// END CHRONO</span>
<span style="color: #7e7e7e;">//--------------------------------------------</span>
<span style="color: #cc6600;"><b>Serial</b></span>.<span style="color: #cc6600;">begin</span>(115200);
<span style="color: #cc6600;">delay</span>(100);
<span style="color: #cc6600;"><b>Serial</b></span>.<span style="color: #cc6600;">println</span>(<span style="color: #006699;">""</span>);
<span style="color: #cc6600;"><b>Serial</b></span>.<span style="color: #cc6600;">print</span>(<span style="color: #006699;">"tStart="</span>);
<span style="color: #cc6600;"><b>Serial</b></span>.<span style="color: #cc6600;">println</span>(tStart);
<span style="color: #cc6600;"><b>Serial</b></span>.<span style="color: #cc6600;">print</span>(<span style="color: #006699;">"tEnd="</span>);
<span style="color: #cc6600;"><b>Serial</b></span>.<span style="color: #cc6600;">println</span>(tEnd);
<span style="color: #cc6600;"><b>Serial</b></span>.<span style="color: #cc6600;">print</span>(<span style="color: #006699;">"Puntos="</span>);
<span style="color: #cc6600;"><b>Serial</b></span>.<span style="color: #cc6600;">println</span>(i);
<span style="color: #cc6600;"><b>Serial</b></span>.<span style="color: #cc6600;">print</span>(<span style="color: #006699;">"Frecuecy="</span>);
<span style="color: #cc6600;"><b>Serial</b></span>.<span style="color: #cc6600;">print</span>((<span style="color: #cc6600;">float</span>)1000000000.0/((<span style="color: #cc6600;">float</span>)tEnd-(<span style="color: #cc6600;">float</span>)tStart));
<span style="color: #cc6600;"><b>Serial</b></span>.<span style="color: #cc6600;">println</span>(<span style="color: #006699;">" Hz"</span>);
}
</pre></pre><br />
Se observa que el programa dispone de la variable CHRONO. Para un funcionamiento normal, enviando constantemente el valor adquirido, debe valer cero (0). Cuando vale uno (1), lo que hace es ejectuar el código utilizado para adquirir y enviar por serie, durante 1000 veces y cronometrar el resultado. Dicho resultado lo podemos leer mediante la consola serie del IDE de Arduino, ya que aunque tengamos configurado el puerto a 1 Mbps, cuando termina el cronometraje, el resultado lo envia a 115200 bps.<br />
<br />
Transmitiendo a 1Mbps, y con un prescaler de 16 para el ADC, me sale una frecuencia de <u><b><span style="color: red;">66417.71 Hz </span></b></u>(aprox 66.5 kHz). Es importante disponer este valor para cálculos frecuenciales o tener las unidades en tiempo.<br />
<br />
Resumiendo, necesitamos disponer cargado en Arduino el programa expuesto anteriormente, ejecutar el script python grabando la salida en el fichero deseado, lanzar el KST y abrir dicho fichero. Los datos se irán actualizando a "tiempo real".<br />
<br />
<br />
A continuación, unas capturas de pantalla resumiendo los pasos usando Ubuntu (click para agrandar las imagenes):<br />
<br />
<u><b>Paso 1:</b></u><br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj50ANzPkVEENT6GQ0Pofi3wFjPR5N0aphyphenhyphen65qGpZ3pjruvhuPpvQQuG1jYJwiA6qiT8hK4vGjqOm-imdA9PnO-3YM340dNCZ7n3OgOCciQktClsfsR58DOJJCFECI6Ai2C1-23wds29qQg/s1600/Tutorial1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="182" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj50ANzPkVEENT6GQ0Pofi3wFjPR5N0aphyphenhyphen65qGpZ3pjruvhuPpvQQuG1jYJwiA6qiT8hK4vGjqOm-imdA9PnO-3YM340dNCZ7n3OgOCciQktClsfsR58DOJJCFECI6Ai2C1-23wds29qQg/s400/Tutorial1.jpg" width="400" /></a></div><br />
<br />
<u><b>Paso 2:</b></u><br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZ33Q5tA1Yo0HHqm597S3c_plZG6YFOsFrQzIBkQ5jHR6VcsZvajuXlpVmEyLpQxwvGoY4NHrYV_52HrIPY6RzXW0kEr8TM9JWeH6p6uddXeGwN06528tQrolRmEcrCnPjHSFnxc0_W8iZ/s1600/Tutorial2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="248" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZ33Q5tA1Yo0HHqm597S3c_plZG6YFOsFrQzIBkQ5jHR6VcsZvajuXlpVmEyLpQxwvGoY4NHrYV_52HrIPY6RzXW0kEr8TM9JWeH6p6uddXeGwN06528tQrolRmEcrCnPjHSFnxc0_W8iZ/s400/Tutorial2.jpg" width="400" /></a></div><br />
<br />
<u><b>Paso 3:</b></u><br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4Am05CJZmBUiEApSK2moMUXhi5AQt8IIaMPhqZPIlSTyE-ixnxtrMeTsTOCmSSdQRSBjiPMGFxy5HNCE9Y8Q_Kn-e6B39rTVq-eDYOWNBFRTnyyK5Yzgh15qZs2E7HFl0i81meRylUFJU/s1600/Tutorial3.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="250" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4Am05CJZmBUiEApSK2moMUXhi5AQt8IIaMPhqZPIlSTyE-ixnxtrMeTsTOCmSSdQRSBjiPMGFxy5HNCE9Y8Q_Kn-e6B39rTVq-eDYOWNBFRTnyyK5Yzgh15qZs2E7HFl0i81meRylUFJU/s400/Tutorial3.jpg" width="400" /></a></div><br />
<br />
<u><b>Paso 4:</b></u><br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeabgk7McdgD7hK320Ulm7EpLX-RdDXBznANGoiS5qisEQfglDPYvgheqR9m_L5jH4IBXNhM2FZlSkuiQjoeEFGE1lDUgsHMUNaUcMQZeZxjZ9aMaT5cr58cm2NVtBz-AgTR-Ewvywq73F/s1600/Tutorial4.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="250" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeabgk7McdgD7hK320Ulm7EpLX-RdDXBznANGoiS5qisEQfglDPYvgheqR9m_L5jH4IBXNhM2FZlSkuiQjoeEFGE1lDUgsHMUNaUcMQZeZxjZ9aMaT5cr58cm2NVtBz-AgTR-Ewvywq73F/s400/Tutorial4.jpg" width="400" /></a></div><br />
<br />
<u><b>Paso 5:</b></u><br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBb2oRZpCqKwEa1rKECifyrU3JSEIHwBt0Gyl6mFVjwwbdVJFgHe1bk1qopiMzBIHkxAIy2BmxJ6-BWsJCmAITyArXL_OCAMTffJbUTBRyILQDkCJ4PUrhavF8fl2k-iNVY7NI4KswUvaq/s1600/Tutorial5.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="250" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBb2oRZpCqKwEa1rKECifyrU3JSEIHwBt0Gyl6mFVjwwbdVJFgHe1bk1qopiMzBIHkxAIy2BmxJ6-BWsJCmAITyArXL_OCAMTffJbUTBRyILQDkCJ4PUrhavF8fl2k-iNVY7NI4KswUvaq/s400/Tutorial5.jpg" width="400" /></a></div><br />
<br />
<br />
Y ahora solo esperar a ver como las gráficas se van actualizando con los datos recibidos de nuestro Arduino. En ejemplo de a continuación, los datos obtenidos de la captura de la onda senoidal de la red eléctrica (proveniente de un transformador), en los que se pueden ver el resultado de la PSD (Power Spectral Density):<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSts-EY8K6MJGo_VEgqcFexziiFMfKqmF9PFlnUAQhCy6Sbj0ccYA6DWcXanlw6pAYcjkzbQHqc-UKUGFVOaX0V6jw8IIlj6U4eGhWhr_AoMGVETyE7znZ5Vn6Tvx2DYJhdGxKCPGD2IkE/s1600/Tutorial6.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="356" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSts-EY8K6MJGo_VEgqcFexziiFMfKqmF9PFlnUAQhCy6Sbj0ccYA6DWcXanlw6pAYcjkzbQHqc-UKUGFVOaX0V6jw8IIlj6U4eGhWhr_AoMGVETyE7znZ5Vn6Tvx2DYJhdGxKCPGD2IkE/s640/Tutorial6.jpeg" width="640" /></a></div><br />
A continuación el esquema de conexión entre la red eléctrica y el Arduino mediante un trafo:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1PAIiU9SIw4o3WbI9eoX-NvekUVu8AqUycG_NXhSwkcGV6xLxETGEQZwfotJmuNT-82U5pYrc-S1UwYQVPxZ_e5SmNWH80Gp4P2I1M9Jahv4NLnOQEJjl_QyRGc1qOBqfxIrC1-Wjx8PC/s1600/Tutorial7.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="386" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1PAIiU9SIw4o3WbI9eoX-NvekUVu8AqUycG_NXhSwkcGV6xLxETGEQZwfotJmuNT-82U5pYrc-S1UwYQVPxZ_e5SmNWH80Gp4P2I1M9Jahv4NLnOQEJjl_QyRGc1qOBqfxIrC1-Wjx8PC/s640/Tutorial7.jpg" width="640" /></a></div><br />
El divisor de tensión creado con las resistencias de 1K, añaden un offset de 2.5v sobre la señal senoidal proveniente del trafo. La salida del trafo es una senoidal de 12v AC, por lo que añadimos este offset para poder entrar la señal a nuestro Arduino.<br />
Con el segundo divisor, creado utilizando un potenciometro, ajustamos para tener la amplitud de la señal entre 0 y 5 voltios (centrada sobre 2.5v).<br />
Cuidado con este montaje, que puede ser peligroso.<br />
<br />
<br />
<br />
Veamos otro ejemplo: un tono de <b>4 kHz</b> generado con la tarjeta de sonido, gracias al <a href="http://audacity.sourceforge.net/">Audacity</a>. Es decir, he usado la tarjeta de sonido, como un generador de ondas (conectándolo al ADC del microcontrolador). El propio Audacity dispone de una herramienta de análisis frecuencial, por lo que fácilmente se puede ver cómo deberían ser los resultados obtenidos de Arduino en KST.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBthNhlBBuXNF75EikWbQyEcm7CkHtAjxoUo25AkiPpRxjENKyZxA5yZsArXTp19J9uZpAJQJ2RcCT9SFJDsDUJPiJgUOfyxQ88EGxiNro5FA6_lHTUt1hEEGAcfu1cYkGw2NTPEIcvrkm/s1600/Test_sound_card2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBthNhlBBuXNF75EikWbQyEcm7CkHtAjxoUo25AkiPpRxjENKyZxA5yZsArXTp19J9uZpAJQJ2RcCT9SFJDsDUJPiJgUOfyxQ88EGxiNro5FA6_lHTUt1hEEGAcfu1cYkGw2NTPEIcvrkm/s640/Test_sound_card2.png" width="640" /></a></div><br />
<br />
<br />
<u><i>Se debería disponer de una etapa de filtraje para evitar antialiasing.</i></u><br />
<br />
<br />
No dejes de visitar el <a href="http://arduino.cc/forum/index.php/topic,68855.0.html">post del foro</a> original así como este <a href="http://arduino.cc/forum/index.php/topic,69995.0.html">otro post</a>, en el cual encontrarás diversas pruebas creadas por aero_yo y CesarCarlos, como medidas de armónicos de una guitarra, captura luz de una lámpara incandescente mediante un ldr, medida de la frecuencia de aleteo de una abeja, adquisición con micrófono, etc.<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
</div></div>Igorhttp://www.blogger.com/profile/07332255486737492708noreply@blogger.com18tag:blogger.com,1999:blog-5229899856062584712.post-18088292353850364422011-07-17T11:23:00.000-07:002011-08-10T09:47:22.146-07:00Maqueta de control PID con Arduino<div dir="ltr" style="text-align: left;" trbidi="on"><div style="color: white;">.</div><script src="http://www.gmodules.com/ig/ifr?url=http://www.google.com/ig/modules/translatemypage.xml&up_source_language=es&w=160&h=60&title=&border=&output=js">
</script><br />
<br />
<div dir="ltr" style="text-align: left;" trbidi="on"><div style="color: white;">.</div><span style="color: white;"> .</span><br />
<div style="font-family: inherit;">Con el motivo de la primera VirtualCamp (Julio 2011), el proyecto ha sido crear una maqueta de control didáctica con un presupuesto de menos de 10 euros (Arduino no incluido). La idea fue hacer un proyecto en 48h durante el fin de semana del 16-17 de Julio.</div><div style="font-family: inherit;">El proceso elegido es el control de temperatura. Para ello dos resistencias de potencia generan el calor y un ventilador actua como control para la refrigeración. Un sensor resistivo de tipo NTC se encarga de registrar la temperatura del habitáculo.</div><div style="font-family: inherit;">Se ha instalado el sensor de temperatura en medio de las resistencias de potencia para que el proceso disponga de la menor inercia posible, y así se comporte más rápido ante cambios de la entrada.</div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;">Los participantes del proyecto:</div><ul style="font-family: inherit;"><li>Igor R. -> Creación de la maqueta física, software Arduino y documentación.</li>
<li>Alberto Yebra -> Interfaz gráfica en python para la visualización del proceso. [<i><u><b>se ampliará este proyecto con su trabajo</b></u></i>].</li>
<li>LeoBot (Manuel) -> Introducción al control PID y teoría PWM.</li>
</ul><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;"><br />
</div><div class="separator" style="clear: both; font-family: inherit; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_pKFkVyXy6Fixd9jdSO6sgGxCrU13UksBvwFQRwNwYWRCfxiS72m-novtZzIkFlWE1gtYnsYeg4WmbPW130C6nhS_hCcLGhh82873hlqGbd3Ex5hcJb0ffFETiEHvGyf8FdQfUWQ99WTS/s1600/Maqueta_despues.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><br />
</a></div><div class="separator" style="clear: both; font-family: inherit; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJGdU5UjciBHhrpXgJMmPxz09CL0iTQYMZYnjUiu9d_V1-ZFjjL_noSZV6TcX6DPcFSHEcndry8JsIDZO794RaEWQEIGcywPr5Z8nFs0vjwG8dum702MomQOYpp87GhM1Tc8x46KpEnhIB/s1600/Maqueta_despues.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="440" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJGdU5UjciBHhrpXgJMmPxz09CL0iTQYMZYnjUiu9d_V1-ZFjjL_noSZV6TcX6DPcFSHEcndry8JsIDZO794RaEWQEIGcywPr5Z8nFs0vjwG8dum702MomQOYpp87GhM1Tc8x46KpEnhIB/s640/Maqueta_despues.jpg" width="640" /></a></div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;">Componentes necesarios:</div><ul style="font-family: inherit;"><li>Ventilador 12v usado para refrigeración de componentes en ordenadores.</li>
<li>Resistencias de potencia (47ohm) --> 2 unidades</li>
<li>Un sensor temperatura resistivo (NTC) + resistencia 3k pull up</li>
<li>Transistor Mosfet.</li>
<li>Diodo 1N4148. </li>
<li>Un recipiente (habitáculo). </li>
<li>Transformador externo para alimentación a 12v. </li>
</ul><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;">Los objetivos del proyecto usando Arduino han sido:</div><ol style="font-family: inherit;"><li>Creación física de la maqueta. </li>
<li>Control de un proceso usando un PID.</li>
<li>Captura de señal analógica.</li>
<li>Convertir la señal eléctrica a física mediante una tabla guardada en memoria de programa (flash) para evitar uso de RAM del microcontrolador.</li>
<li>Control carga de potencia mediante PWM.</li>
<li>Monitorización en el PC de resultados.</li>
</ol><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;">Veámos una foto de como ha quedado la maqueta (se ha usado una dremel para modificar el recipiente de plástico):</div><div class="separator" style="clear: both; font-family: inherit; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEituyzMEwsc2VZ6-Gix0jVYguxEQ-vZATOY3tvOYjkBY2Qi66OgSgz-WH-CE8xLqDs5CEN3q0Z3317hzfK_lL_9_0z8Rz17O9GRVnmFa6hMqSjoyucIo-H2MIgKXdLcGkDxCSyJq4kNTRjB/s1600/Maqueta_despues2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="284" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEituyzMEwsc2VZ6-Gix0jVYguxEQ-vZATOY3tvOYjkBY2Qi66OgSgz-WH-CE8xLqDs5CEN3q0Z3317hzfK_lL_9_0z8Rz17O9GRVnmFa6hMqSjoyucIo-H2MIgKXdLcGkDxCSyJq4kNTRjB/s320/Maqueta_despues2.jpg" width="320" /></a></div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;">Otra foto de la instalación del ventilador:</div><div style="font-family: inherit;"><br />
</div><div class="separator" style="clear: both; font-family: inherit; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizRj1xj8FwIMgu2z5X_Dex_D_IP2u_v-JQ-KKMnSyBc8uxuBi-6hAnBbKWgxHgxxcFbbWIhvsPU6l_LWuMnZEAQ_rB-B9dXNlU35AdSNhc2_sNq5sSbflkU_UNA_TY5eKqbUz0zgnsG2Vl/s1600/Maqueta_ventilador.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizRj1xj8FwIMgu2z5X_Dex_D_IP2u_v-JQ-KKMnSyBc8uxuBi-6hAnBbKWgxHgxxcFbbWIhvsPU6l_LWuMnZEAQ_rB-B9dXNlU35AdSNhc2_sNq5sSbflkU_UNA_TY5eKqbUz0zgnsG2Vl/s320/Maqueta_ventilador.jpg" width="320" /></a></div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;">La instalación eléctrica necesaria es bastante sencilla. La podemos dividir en dos partes: control del ventilador mediante transistor mosfet y adquisición de la temperatura mediante NTC.</div><div style="font-family: inherit;">A continuación, se puede observar un esquema de la conexión del ventilador. La salida utilizada en Arduino es el pin 9 (PWM).</div><div style="font-family: inherit;"><br />
</div><div class="separator" style="clear: both; font-family: inherit; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2bVPdmK8a0YFwYjgMacptysFOmSeOALgB8uuMfZ4JbFKV7iBQFhk4f_2_zaNcN6JsOKDMHVyXlWHtkxsolC7V9KsQWKCeBQ3-nmwW0y8cjs9dSdp0a00yzny8O7c8PCYxWFACpf-p-3Tg/s1600/Mosfet_control_PID_esquema.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="330" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2bVPdmK8a0YFwYjgMacptysFOmSeOALgB8uuMfZ4JbFKV7iBQFhk4f_2_zaNcN6JsOKDMHVyXlWHtkxsolC7V9KsQWKCeBQ3-nmwW0y8cjs9dSdp0a00yzny8O7c8PCYxWFACpf-p-3Tg/s400/Mosfet_control_PID_esquema.jpg" width="400" /></a></div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;"><style type="text/css">
<!--
@page { margin: 0.79in }
P { margin-bottom: 0.08in }
-->
</style> </div><div align="JUSTIFY" style="font-family: inherit; margin-bottom: 0in;"><span style="font-size: small;">En los sistemas de control en lazo cerrado la salida del controlador actúa sobre el actuador (en este caso motor eléctrico del ventilador) para corregir la magnitud física (temperatura) que se quiere controlar. </span></div><div align="JUSTIFY" style="font-family: inherit; margin-bottom: 0in;"><br />
</div><div align="JUSTIFY" style="font-family: inherit; line-height: 115%; margin-bottom: 0.14in;"><span style="font-size: small;">La técnica más habitual que se utiliza para el control de velocidad de motores de continua, es la modulación por anchura de pulso PWM (Pulse Width Modulation). Esta técnica consiste en una señal periódica cuadrada que cambia el tiempo de su estado activo (nivel alto) en el tiempo del período de la señal.</span></div><div align="JUSTIFY" style="font-family: inherit; line-height: 115%; margin-bottom: 0.14in;"><span style="font-size: small;">El tiempo que la señal periódica está activa con respecto a período de la señal se denomina </span><span style="font-size: small;"><i>Ciclo de Trabajo (Duty Cycle)</i></span> </div><div align="CENTER" style="font-family: inherit; line-height: 115%; margin-bottom: 0.14in;"><span style="font-size: x-small;"><span style="font-size: small;">D = (t</span><sub><span style="font-size: small;">on</span></sub><span style="font-size: small;">/ T) </span></span></div><div align="JUSTIFY" style="font-family: inherit; line-height: 115%; margin-bottom: 0.14in;"><span style="font-size: small;">Es decir, el duty cycle describe la proporción del tiempo a ON (encendido) sobre un período de tiempo fijo.</span></div><div align="JUSTIFY" style="font-family: inherit; line-height: 115%; margin-bottom: 0.14in;"><span style="font-size: small;">Crear este tipo de señal resulta muy sencillo en un microcontrolador, aunque cabe destacar que la corriente generada por el mismo es muy pequeña, por lo que hace necesario de una etapa de adaptación de potencia antes de unirlo al motor. Para ello se utiliza el transistor en conmutación (corte y saturación). </span><span style="font-size: small;"> Veámos como sería nuestro circuito conectado a la salida PWM del microcontrolador:</span></div><div style="font-family: inherit;"><br />
</div><div class="separator" style="clear: both; font-family: inherit; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1nMd-59ERV8Tw_gTTj7UJFhfl7tgaEETgF8apMmYl9HWlujyS5hBhEYqK9tAc78x4albpzpCnr4WP0T8pHTabE0MM2BsESM6BBjCF4g7EXS1DPPCryGMfbjyOhbDFrpHl4dpHLVUS5dWD/s1600/CircuitoActuador.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1nMd-59ERV8Tw_gTTj7UJFhfl7tgaEETgF8apMmYl9HWlujyS5hBhEYqK9tAc78x4albpzpCnr4WP0T8pHTabE0MM2BsESM6BBjCF4g7EXS1DPPCryGMfbjyOhbDFrpHl4dpHLVUS5dWD/s1600/CircuitoActuador.JPG" /></a></div><div align="JUSTIFY" style="font-family: inherit; line-height: 115%; margin-bottom: 0.14in;"><style type="text/css">
<!--
@page { margin: 0.79in }
P { margin-bottom: 0.08in }
-->
</style> </div><div align="JUSTIFY" style="font-family: inherit; margin-bottom: 0in;"><span style="font-size: small;">En el circuito, el transistor va a funcionar en corte-saturación, activando y desactivando el motor del ventilador mediante la señal PWM. Como el motor es un dispositivo inductivo (por las bobinas que tiene) se debe instalar un diodo (conocido como diodo de flyback ó freewheeling). Las bobinas se oponen al cambio de corriente, por lo que al "cortar" la alimentación se crea unos picos de voltaje muy altos que pueden dañar nuestra salida del microcontrolador. Gracias a este diodo, la corriente dispone de un camino de descarga.</span></div><div align="JUSTIFY" style="font-family: inherit; margin-bottom: 0in;"><span style="font-size: small;"><br />
</span></div><div align="JUSTIFY" style="font-family: inherit; line-height: 115%; margin-bottom: 0.14in;">El control de velocidad del motor se consigue variando la tensión que pasa por el motor y esta tarea la realiza la señal PWM que genera el microcontrolador. Al cambiar el tiempo a ON de la señal PWM (duty cycle), estamos cambiando efectivamente el valor medio (voltaje) sobre nuestro motor, lo que se traslada en un incremento/decremento de la velocidad del ventilador.<br />
Por lo que la salida de control PID es el duty cycle de la señal PWM aplicada al ventilador. Se ha modificado el registro del timer 1, que controla la frecuencia del pin 9, para que la frecuencia sea aproximadamente 32 kHz. La frecuencia de dicha señal, debe ser lo suficientemente rápida para que no afecte la inercia del sistema a controlar.<br />
Veámos una captura real de la señal que sale de nuestro control:</div><div class="separator" style="clear: both; font-family: inherit; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWP0auzB9XaajNoc34Q3xMQ7LEE8uUYu_SwZQNKjleZOxeON0qLS2wI-ewxxIphNxrqUEcs9WrEYDapTwy8vu4Teo3fqs_UzTM_LREmPUv088dxBWlbdSfrL_mDu_PlJZNkSl3Nam7wZw1/s1600/PWM_Analizador_Logico.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWP0auzB9XaajNoc34Q3xMQ7LEE8uUYu_SwZQNKjleZOxeON0qLS2wI-ewxxIphNxrqUEcs9WrEYDapTwy8vu4Teo3fqs_UzTM_LREmPUv088dxBWlbdSfrL_mDu_PlJZNkSl3Nam7wZw1/s640/PWM_Analizador_Logico.jpg" width="640" /></a></div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;">Se observa como el control va modificando adecuadamente el tiempo a ON del PWM para conseguir el SetPoint predefinido.</div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;">Para el caso del sensor NTC:</div><div class="separator" style="clear: both; font-family: inherit; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4YjgwTP3Bm_uTKuKfmOSRre2JYqN_8Wv3ygmsz6rS5bcE-_Q2aPB4LVvgE3TaWl7XzMdpKKNVBv6GW_rBDHU0sPoMX0Okax0A15J4MfK886FjV8ILlrPK56Q3NMVO6_8bI4hxb_qHLwwi/s1600/NTC_esquema.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="328" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4YjgwTP3Bm_uTKuKfmOSRre2JYqN_8Wv3ygmsz6rS5bcE-_Q2aPB4LVvgE3TaWl7XzMdpKKNVBv6GW_rBDHU0sPoMX0Okax0A15J4MfK886FjV8ILlrPK56Q3NMVO6_8bI4hxb_qHLwwi/s400/NTC_esquema.jpg" width="400" /></a></div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;">Para evitar resolver operaciones matemáticas en el microcontrolador, se ha creado una tabla de valores obtenidos del conversor ADC del Arduino versus temperatura en grados centígrados. Para ello se ha utilizado la hoja de cálculo LibreOffice Calc. Los datos de entrada son la Ro (resistencia a 25ºC) y el coeficiente beta del sensor [información proveniente del datasheet del fabricante]. Los pasos han sido crear la tabla de resistencia versus temperatura, e ir convirtiendo adecuadamente para obtener una tabla en forma lectura ADC versus temperatura en grados.</div><div style="font-family: inherit;"><br />
</div><div class="separator" style="clear: both; font-family: inherit; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJbU8iWREoYXkg8xRfwfoT5Z1oo599eEhdP-dKJshXSOIqciO6U-twDPDZ0VwsFdEiaTNf27pRMSMQerNAxspJkAGlgZNsc-XL6FxSyhI72jhSOY5WKTzyjpzJTs0pMqCswSyXzYaFuWl7/s1600/Linealizacion_NTC.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="329" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJbU8iWREoYXkg8xRfwfoT5Z1oo599eEhdP-dKJshXSOIqciO6U-twDPDZ0VwsFdEiaTNf27pRMSMQerNAxspJkAGlgZNsc-XL6FxSyhI72jhSOY5WKTzyjpzJTs0pMqCswSyXzYaFuWl7/s640/Linealizacion_NTC.jpg" width="640" /></a></div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;">Dicha tabla, será guardada en memoria de programa, evitando consumir memoria RAM innecesariamente de nuestro Arduino.</div><div style="font-family: inherit;">Se observa que la respuesta de un sensor NTC no es lineal.</div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;">La NTC se ha situado entre las dos resistencias calentadoras. De esta forma, se consigue que el sistema tenga menos inercia y su respuesta sea rápida.</div><div style="font-family: inherit;"><br />
</div><div class="separator" style="clear: both; font-family: inherit; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOMJkaAsnbXdfQp-4JFn9S3xaPFI2GqpnOrR_xd7OSJOL7WPRZDgDXiOfuH_mgMzrF2ddZpc09HWpViBBQwc3Hd0qMhjJaL226_jExgkBM91mbqVQu4cs-e9mISI740lZPTn_jJiUd40V5/s1600/Maqueta_calentador_ntc.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="351" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOMJkaAsnbXdfQp-4JFn9S3xaPFI2GqpnOrR_xd7OSJOL7WPRZDgDXiOfuH_mgMzrF2ddZpc09HWpViBBQwc3Hd0qMhjJaL226_jExgkBM91mbqVQu4cs-e9mISI740lZPTn_jJiUd40V5/s400/Maqueta_calentador_ntc.jpg" width="400" /></a></div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;"><u><span style="font-size: large;"><b>INTRODUCCIÓN</b></span></u><span style="font-size: large;"> </span><i><b><span style="color: blue;">Por LeoBot (Manuel)</span></b></i></div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;"><style type="text/css">
<!--
@page { margin: 0.79in }
P { margin-bottom: 0.08in }
-->
</style> </div><div align="JUSTIFY" style="font-family: inherit; margin-bottom: 0in; text-indent: 0.49in;"><span style="font-size: small;">La temperatura es una magnitud física que tanto en el ámbito doméstico e industrial es interesante controlar para tener un un mayor confort y eficiencia energética.</span></div><div align="JUSTIFY" style="font-family: inherit; margin-bottom: 0in; text-indent: 0.49in;"><span style="font-size: small;">El control se puede realizar tanto manual (control en lazo abierto) como automático (control en lazo cerrado).</span></div><div align="JUSTIFY" style="font-family: inherit; margin-bottom: 0in; text-indent: 0.49in;"><span style="font-size: small;">El </span><span style="font-size: small;"><u>control en lazo abierto</u></span><span style="font-size: small;"> es un control de encendido-apagado, en nuestro caso para calentar una habitación, un calentador se enciende o se apaga. En </span><span style="font-size: small;"><u>control en lazo cerrado</u></span><span style="font-size: small;"> se tiene un controlador que compara la variable (temperatura que se mide con un sensor) con la referencia, temperatura que se quiere tener en la habitación, y convertir el error que resulta en una acción de control para reducir el error.</span></div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;"><br />
</div><div class="separator" style="clear: both; font-family: inherit; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-MA5ArDs1k_5ISFPcqbCKQhWgEWFoKzKlr37s-G9HxcAQuhWtgQQAkhhSk-NN_SUMHKvYhACScPf13JM0KAGjdM_Rz-MNTE64OitqvYwCTjbvNJtSZGOUGVwWYlu_pEnnFscljnq4S0Bv/s1600/Lazo_Abierto.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="125" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-MA5ArDs1k_5ISFPcqbCKQhWgEWFoKzKlr37s-G9HxcAQuhWtgQQAkhhSk-NN_SUMHKvYhACScPf13JM0KAGjdM_Rz-MNTE64OitqvYwCTjbvNJtSZGOUGVwWYlu_pEnnFscljnq4S0Bv/s400/Lazo_Abierto.jpg" width="400" /></a></div><div style="font-family: inherit; text-align: center;"><i style="color: red;">a) SISTEMA EN LAZO ABIERTO</i></div><div style="font-family: inherit; text-align: center;"><br />
</div><div class="separator" style="clear: both; font-family: inherit; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgASnYndrFESoipRQwtKEuTxR0tFyvXkw4HOj9XDlVAaF4SjC63nqLosJ8RVtZQNV4ss0yRctZb2aC_5XMJrU48HZ8K5LN5RFXlxz0L1JEBmz6n30qrj805suD686nlpzy-Ew5-fZg4bpwO/s1600/Lazo_Cerrado.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="153" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgASnYndrFESoipRQwtKEuTxR0tFyvXkw4HOj9XDlVAaF4SjC63nqLosJ8RVtZQNV4ss0yRctZb2aC_5XMJrU48HZ8K5LN5RFXlxz0L1JEBmz6n30qrj805suD686nlpzy-Ew5-fZg4bpwO/s400/Lazo_Cerrado.jpg" width="400" /></a></div><div style="font-family: inherit; text-align: center;"><i style="color: red;">b) SISTEMA EN LAZO CERRADO</i></div><div style="font-family: inherit;"><style type="text/css">
<!--
@page { margin: 0.79in }
P { margin-bottom: 0.08in }
-->
</style> </div><div style="font-family: inherit; margin-bottom: 0in;"><br />
</div><div align="JUSTIFY" style="font-family: inherit; margin-bottom: 0in;"><span style="font-size: small;"> La unidad de control puede reaccionar de diferentes maneras ante la señal de error y proporcionar señales de salida para que actúen los elementos correctores.</span></div><div align="JUSTIFY" style="font-family: inherit; margin-bottom: 0in;"><span style="font-size: small;"><u>Tipos de control</u></span></div><div align="JUSTIFY" style="font-family: inherit; margin-bottom: 0in;"><span style="font-size: small;">1.- </span><span style="font-size: small;"><i>Control de dos posiciones</i></span><span style="font-size: small;">: el controlador es un interruptor activado por la señal de error y proporciona una señal correctora tipo encendido-apagado.</span></div><div align="JUSTIFY" style="font-family: inherit; margin-bottom: 0in;"><br />
</div><div class="separator" style="clear: both; font-family: inherit; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXWdri_6Uilzc_GtfbDrlPv3lFocBa5JBZQLEhmi8gWA7Bm9q4MQpmpqD4SmHZxd-YOWRFIPm96sLKaV358Hh5I5ddsVMasfSKC2FrUjr3ZVsQkjuCBMRhbcbtkkMWp_Y1gPrHS44MQlf7/s1600/Control_ON_OFF.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="212" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXWdri_6Uilzc_GtfbDrlPv3lFocBa5JBZQLEhmi8gWA7Bm9q4MQpmpqD4SmHZxd-YOWRFIPm96sLKaV358Hh5I5ddsVMasfSKC2FrUjr3ZVsQkjuCBMRhbcbtkkMWp_Y1gPrHS44MQlf7/s320/Control_ON_OFF.jpg" width="320" /></a></div><div align="JUSTIFY" style="font-family: inherit; margin-bottom: 0in;"><span style="font-size: small;">2.- </span><span style="font-size: small;"><i>Control proporcional (P)</i></span><span style="font-size: small;">: produce una acción de control que es proporcional al error. La señal de correctora aumenta al aumentar la señal de error.</span></div><div align="JUSTIFY" style="font-family: inherit; margin-bottom: 0in;"><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPWYl9G-y8x6uzExoVa-lrtuVeBqcODP-6vAcwlBzBfmEKtjk6hyQglkV67gNHbX1jyOk9qWRLr2Dx6XGkVjBg9kwf7grUzgc8bnaE1N8qYY2ye5WCs5iNBRdDwhoWK2Apzo0c7mM8IrcM/s1600/Respuesta_P.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPWYl9G-y8x6uzExoVa-lrtuVeBqcODP-6vAcwlBzBfmEKtjk6hyQglkV67gNHbX1jyOk9qWRLr2Dx6XGkVjBg9kwf7grUzgc8bnaE1N8qYY2ye5WCs5iNBRdDwhoWK2Apzo0c7mM8IrcM/s320/Respuesta_P.JPG" width="225" /></a></div></div><div align="JUSTIFY" style="font-family: inherit; margin-bottom: 0in;"><span style="font-size: small;">3.- </span><span style="font-size: small;"><i>Control derivativo (D)</i></span><span style="font-size: small;">: produce una señal de control que es proporcional a la rapidez con la que cambia el error. Ante un cambio rápido de la señal de error, el controlador produce una señal de corrección de gran valor; cuando el cambio es progresivo, sólo se produce una señal pequeña de corrección. El control derivativo se puede considerar un control anticipativo porque al medir la rapidez con que cambia el error se anticipa a la llegada de un error más grande y se aplica la corrección antes que llegue. El control derivativo no se usa solo, siempre va en combinación con el control proporcional y/o con el control integral.</span></div><div align="JUSTIFY" style="font-family: inherit; margin-bottom: 0in;"><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqqSc_zk47SeE-g9hn99NiRIxBFQORCusMGWfBos8DZ8ddTGDfVUFLhd0rqy8fJWGMT_ERuv4AuT-qm9Vuz86FLbPxJa53Wb5FCcx5kRB0o90Wx8USDZIdXr4SD_V8d1kJcRAM3zQrLyZq/s1600/Respuesta_PD.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="294" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqqSc_zk47SeE-g9hn99NiRIxBFQORCusMGWfBos8DZ8ddTGDfVUFLhd0rqy8fJWGMT_ERuv4AuT-qm9Vuz86FLbPxJa53Wb5FCcx5kRB0o90Wx8USDZIdXr4SD_V8d1kJcRAM3zQrLyZq/s320/Respuesta_PD.JPG" width="320" /></a></div></div><div align="JUSTIFY" style="font-family: inherit; margin-bottom: 0in;"><span style="font-size: small;">4.- </span><span style="font-size: small;"><i>Control integral (I)</i></span><span style="font-size: small;">: produce una acción de control que es proporcional a la integral del error en el tiempo. En consecuencia, una señal de error constante producirá una señal correctora creciente y aumentará si el error continua. El control integral se puede considerar que recuerda la situación anterior, suma todos los errores y responde a los cambios que ocurren.</span></div><div align="JUSTIFY" style="font-family: inherit; margin-bottom: 0in;"><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinro_7_UNqLyYDjxp6oYGHXG4zcFqzogsyQq4R_xeLT8M88sFaz65fzYNy-ZrX2Okasi7GKQ3jW2WOrz1T2kwzhfQage204HDPgR1Rf9ZFxkSf_yff-Xex_YyLywiyaEjX1ArnXuo3VPQM/s1600/Respuesta_I.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinro_7_UNqLyYDjxp6oYGHXG4zcFqzogsyQq4R_xeLT8M88sFaz65fzYNy-ZrX2Okasi7GKQ3jW2WOrz1T2kwzhfQage204HDPgR1Rf9ZFxkSf_yff-Xex_YyLywiyaEjX1ArnXuo3VPQM/s320/Respuesta_I.JPG" width="236" /></a></div></div><div align="JUSTIFY" style="font-family: inherit; margin-bottom: 0in;"><span style="font-size: small;">5.- </span><span style="font-size: small;"><i>Combinación de tipos de control</i></span><span style="font-size: small;">: proporcional derivativo (PD), proporcional integral (PI) y proporcional integral derivativo (PID). </span></div><div style="font-family: inherit;"> <span style="font-size: small;"><br />
</span></div><div class="separator" style="clear: both; font-family: inherit; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiM3eK5sln74UdSstQkHe5WKDqq9Cs2GHFNG2DhvaTsRyZWTkOWZz-9x9dapXG4_M4YWBNbOM_C6i0aclR0fXCdMVuU35gA36mR85GSwZWcMO0zkf5j5a_GyKjy9SK-04Q54BuaPPk7wCMo/s1600/Respuesta_PI.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiM3eK5sln74UdSstQkHe5WKDqq9Cs2GHFNG2DhvaTsRyZWTkOWZz-9x9dapXG4_M4YWBNbOM_C6i0aclR0fXCdMVuU35gA36mR85GSwZWcMO0zkf5j5a_GyKjy9SK-04Q54BuaPPk7wCMo/s640/Respuesta_PI.JPG" width="513" /></a></div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;"><style type="text/css">
<!--
@page { margin: 0.79in }
P { margin-bottom: 0.08in }
-->
</style> </div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;"><u><span style="font-size: large;"><b>CONTROL PID</b></span></u></div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;">El control Proporcional Integral Derivativo (PID) es mecanismo de control mediante realimentación negativa, el cual aplica una acción correctora al sistema para obtener el valor de consigna (Setpoint).</div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;">Existe multitud de recursos en internet acerca del mismo, por lo que aquí se verá desde el punto de vista práctico. Por ejemplo, <a href="http://es.wikipedia.org/wiki/Proporcional_integral_derivativo">wikipedia</a> dispone de una buena introducción.</div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;">El nuestro sistema:</div><ul style="font-family: inherit;"><li>Setpoint -> Temperatura de consigna del sistema. Se trata de la temperatura deseada a la cual el proceso tiene que mantenerse a través de la acción del control. El algoritmo oscila entre dos temperaturas, con el motivo de ver como se comporta ante cambios de la entrada. Es decir, es a la temperatura que queremos que se encuentre nuesto recipiente.</li>
<li>La realimentación o información de cómo se encuentra el sistema, es adquirida por la NTC. El objetivo es que el valor medido sea siempre igual al valor deseado (Setpoint).</li>
<li>El actuador es el ventilador, el cual regulamos su velocidad mediante modulación de ancho de pulsos (PWM).</li>
</ul><div style="font-family: inherit;">Para la visualización, se ha utilizado el software gratuito para Windows Stamp Plot Lite (<a href="http://www.selmaware.com/stampplotlite/index.htm">http://www.selmaware.com/stampplotlite/index.htm</a>).</div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;">Empezaremos por realizar sólo un control PROPORCIONAL. El programa de Arduino, cambia cada 120 segundos el Set Point entre 60 y 59 grados centígrados.</div><div style="font-family: inherit;">Se puede observar cómo el control proporcional no elimina el error permanente del sistema. </div><div style="font-family: inherit;"><br />
</div><div class="separator" style="clear: both; font-family: inherit; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFZQbmrXWDuv7iCEwKCpHoL3AA-46qxteAed_LXfukKD6EaNRlkI6Ye5xOnGFW_1GvCDGiftcW3qNcyaTo38TLg7BvEcAgLAmQnBYENrQm2aXNPeyWaNwUKOglAv9TA1bS1JkZKdoAE179/s1600/Control_P_StampPlot_ErrorPermanente.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="489" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFZQbmrXWDuv7iCEwKCpHoL3AA-46qxteAed_LXfukKD6EaNRlkI6Ye5xOnGFW_1GvCDGiftcW3qNcyaTo38TLg7BvEcAgLAmQnBYENrQm2aXNPeyWaNwUKOglAv9TA1bS1JkZKdoAE179/s640/Control_P_StampPlot_ErrorPermanente.jpg" width="640" /></a></div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;">Existe un límite en el valor de la constante proporcional, ya que nuestro sistema se vuelve oscilatorio, ya que un pequeño cambio en el error, hace que la salida de controlador sea muy grande. A continuación un ejemplo:</div><div style="font-family: inherit;"><br />
</div><div class="separator" style="clear: both; font-family: inherit; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWtu6cFGYCDPVsJfncC5qmRoCpTa-HYCJNk2-A3_IeVZrgdqOKAM1W__yJ88KDoe1jFVYym6etWmKm4P1P3Wyl_1IW3u4GzEyBdFnw0wqnhXJRpsMq3SYU7O90GiUkYXp0qrE3k1jy2xkN/s1600/Control_P_StampPlot_ControlProporcional_KpMuyGrande.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="490" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWtu6cFGYCDPVsJfncC5qmRoCpTa-HYCJNk2-A3_IeVZrgdqOKAM1W__yJ88KDoe1jFVYym6etWmKm4P1P3Wyl_1IW3u4GzEyBdFnw0wqnhXJRpsMq3SYU7O90GiUkYXp0qrE3k1jy2xkN/s640/Control_P_StampPlot_ControlProporcional_KpMuyGrande.jpg" width="640" /></a></div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;">Como se ha observado, la parte proporcional no tiene en cuenta el tiempo, por lo que para corregir el error permanente, necesitamos añadirle la parte INTEGRAL.</div><div style="font-family: inherit;">Para poder observar cómo se comporta, se ha introducido un retraso a la actuación de la misma.</div><div style="font-family: inherit;"><br />
</div><div class="separator" style="clear: both; font-family: inherit; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0wjachoRZ_aVfx-MN7kiHfvaB8n2xfvrYDXZ2bIaoW2K7UD5mR3M7RGiavZ_ADsd66ySLpDKQVCAUBpdYXsockpiWZOFk4BRJVcN9zGzabKU9CBEBzqOSsYTT3AqxmHX-AUNvmBpv21k_/s1600/Control_P_StampPlot_DelayAccionIntegral.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="490" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0wjachoRZ_aVfx-MN7kiHfvaB8n2xfvrYDXZ2bIaoW2K7UD5mR3M7RGiavZ_ADsd66ySLpDKQVCAUBpdYXsockpiWZOFk4BRJVcN9zGzabKU9CBEBzqOSsYTT3AqxmHX-AUNvmBpv21k_/s640/Control_P_StampPlot_DelayAccionIntegral.jpg" width="640" /></a></div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;">La parte integral consigue que nuestro sistema alcance los valores objetivo (Set Points de 60 y 58 grados), ya que corrige el error permanente del sistema.</div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;">La parte DERIVATIVA,sólo actua si hay un cambio en el valor absoluto del error. Es decir, si el error es constante, no actuará.</div><div style="font-family: inherit;"><br />
</div><div style="font-family: inherit;">El objetivo final de un sistema de control, es que el sistema siga lo más fielmente a su entrada ante perturbaciones externas y que responda ante cambios de consigna (SetPoint). Veámos un video, en el cual se altera el sistema (tapando la salida de aire-cables) y como al subir la temperatura, el sistema aumenta la velocidad del ventilador para tratar de contrarrestar la perturbación.</div><div style="text-align: center;"><br />
</div><div style="text-align: center;"><iframe allowfullscreen="" frameborder="0" height="510" src="http://www.youtube.com/embed/Jkcm1PAoYiw" width="640"></iframe></div><br />
<br />
<div style="text-align: center;"><br />
</div><div style="color: red; text-align: center;"><span style="font-size: large;"><b>DESCARGA EL SKETCH DE ARDUINO AQUÍ</b></span></div><br />
<br />
<center><iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="https://skydrive.live.com/embedicon.aspx/P%c3%bablico/VirtualCamp%20JUL%202011/PID%5E_2.pde?cid=d2ee689f353f15bc&sc=photos" style="background-color: #fcfcfc; height: 115px; padding: 0; width: 98px;" title="Preview"></iframe></center><br />
<br />
O puedes ojear el código a continuación:<br />
<br />
<center><iframe src="http://pastebin.com/embed_iframe.php?i=ajGPkv8s" style="border: none; height: 1000px; width: 100%;"></iframe></center><br />
<br />
.</div></div>Igorhttp://www.blogger.com/profile/07332255486737492708noreply@blogger.com56tag:blogger.com,1999:blog-5229899856062584712.post-49097873304873783322011-01-15T15:30:00.000-08:002011-01-18T06:22:17.936-08:00Timer 2: Introducción<span style="color: white;">.</span><br />
<code><br />
<script src="http://www.gmodules.com/ig/ifr?url=http://www.google.com/ig/modules/translatemypage.xml&up_source_language=es&w=160&h=60&title=&border=&output=js">
</script> </code><br />
<br />
El microcontrolador de las placas Arduino dispone de 3 módulos Contador/Timers (dos de 8 bits y uno de 16 bits). Se trata de hardware independiente al microprocesador que puede ejecutar tareas paralelas sin detener el flujo del programa. Algunas de éstas tareas son contador, medida precisa de tiempos, generador de ondas, .... Estos Timers son usados internamente por el core de Arduino para sus funciones internas, como pueden ser millis, delay, analogWrite,...<br />
<br />
Aquí vamos a ver cómo trabajar con el Timer 2, el cual es de 8 Bits. El Timer 2 es usado internamente en el core Arduino para generar el PWM por los pines 3 y 11, por lo que no se podrá usar dicha función en conjunto con el código propuesto más adelante.<br />
<br />
Para empezar vamos a ver el funcionamiento de dicho contador en modo Normal (Normal mode).<br />
Se trata del modo más sencillo, en el cual el el contador se incrementa a cada pulso de reloj hasta llegar a su máximo (8 bits=255) y se reinicia de nuevo desde 0. Es decir 0,1,2,...255 -> 0,1,...,255 -> 0,1,...<br />
En el momento que el contador vuelve a 0 (registro TCNT2), se activa el flag de "overflow" (TOV2). Se puede configurar una interrupción (overflow del timer) cuando ésto ocurre. Dicha interrupcion se encarga de resetear dicho el flag.<br />
<br />
<i><b><u>Notas</u>:</b> </i><br />
<i>El flag es un bit que cambia su estado, como si fuera una "alarma" para avisar al programador que un evento ha ocurrido. Dicho bit (TOV2) de overflow se encuentra en el registro TIFR2.</i><br />
<i>Una interrupción es una señal recibida por el microcontrolador, que interrumpe la ejecución del código actual y cambia a la rutina que atiende dicha interrupción.</i><br />
<br />
Normalmente el cristal usado en la mayoría de las placas Arduino es de 16 MHz (cuidado que algunas como LilyPad van a 8Mhz), lo que significa que la resolución máxima es de 1/16.000.000= 62.5 ns. Es decir, que el contador alimentado por la frecuencia reloj del micro, incrementa en uno su valor cada 62.5 ns, y tendría su overflow cada 256*1/16000000=0.016ms.<br />
<br />
Se puede observar que es un tiempo muy pequeño. Para poder tener más rangos, el timer dispone de PRESCALER. Ésto es simplemente un divisor de la frecuencia del reloj que le esta alimentando al timer. Los PRESCALER disponibles son 1,8,32,64,128,256 y 1024.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiN0bbb8iF7qLbekyPn6sYFAmM6dscfx6l7vNrf54HKH2ix0flDcYGOU6iSWawS4QI9mxd83amovrsNhIFyEpNeMQwOqJFM5En8lnjR-4vHcpYxcfLNyvW7fZGrLXQF5jSHZDCN8GwWdbN0/s1600/Timer2_capture3.jpg" /></div><br />
El lenguaje Arduino no dispone de funciones propias para configurar los timer. Los registros internos del microcontrolador para configurar el Timer2 son TCCR2A, TCCR2B, TNT2, OCR2A,OCR2B, TIMSK2,TIFR2,ASSR y GTCCR. Lo mejor para ampliar conocimientos acerca de todas las posibilidades que existen es el datasheet del propio microcontrolador.<br />
<br />
En el registro TCCT2B se disponen los bits CS22,CS21 y CS20 (bit 2,1 y 0). Dichos bits son los encargados de configurar el PRESCALER del timer.<br />
Veamos las combinaciones de CS22 - CS21 - CS20 respectivamente.<br />
<ul><li>0 - 0 - 0 => No Clock</li>
<li>0 - 0 - 1 => No Prescaling [0.016 ms]</li>
<li>0 - 1 - 0 => Prescaler=8 [0.128 ms]</li>
<li>0 - 1 - 1 => Prescaler=32 [0.512 ms]</li>
<li>1 - 0 - 0 => Prescaler=64 [1.024 ms]</li>
<li>1 - 0 - 1 => Prescaler=128 [2.048 ms]</li>
<li>1 - 1 - 0 => Prescaler=256 [4.096 ms]</li>
<li>1 - 1 - 1 => Prescaler=1024 [16.384 ms]</li>
</ul><br />
He preparado un programa, el cual conmuta el Pin 13 de Arduino cada vez que se produce la interrupción de Overflow. He recogido la salida de dicho pin con un Analizador Lógico. Lo que se observa, es una señal cuadrada, es decir el pin esta conmutando de estado ALTO="1" a estado BAJO="0" según la configuración de los bits CS22-CS21-CS20.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGcfnpm4kgxcpcpTPTvU5pqrR4BbVLBtpt2214mXneTrJzYEfiZrH6kWA_-GiWvlEGH0VO8WudxCHN7HmG1trrxaz3MLEVYZyT5Yy9xCVJC9Phq73lpE055DW2vjySQAxGQDVOd-KI8VY8/s1600/Timer2_capture1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="251" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGcfnpm4kgxcpcpTPTvU5pqrR4BbVLBtpt2214mXneTrJzYEfiZrH6kWA_-GiWvlEGH0VO8WudxCHN7HmG1trrxaz3MLEVYZyT5Yy9xCVJC9Phq73lpE055DW2vjySQAxGQDVOd-KI8VY8/s640/Timer2_capture1.jpg" width="640" /></a></div><br />
<div style="text-align: center;"><b style="color: red;"><i>(click para agrandar)</i></b></div><br />
Para lograr el máximo rendimiento del código, he usado control directo de los registros del microcontrolador para conmutar el pin 13 y así no meter "retrasos" debido a la ejecución de código. Para entendernos, la instrucción <b><span style="color: blue;">digitalWrite</span></b> es "lenta".<br />
Los tres registros internos usados por el microcontrolador para el control de los puertos son:<br />
<ul><li>DDR<b><span style="color: red;">x</span></b> => Configura los pines del puerto como entrada ("0") o salida ("1").</li>
<li>PORT<b><span style="color: red;">x</span></b> => Controla si el estado ALTO y BAJO de los pines de dicho puerto.</li>
<li>PIN<b style="color: red;">x</b> => Estado de los pines.</li>
</ul>siendo <b style="color: red;">x</b> alguno de los tres puertos disponibles en el micro: B,C ó D.<br />
Para saber la equivalencia entre los pines de Arduino con los del micro, visitar: <a href="http://www.arduino.cc/en/Reference/PortManipulation">http://www.arduino.cc/en/Reference/PortManipulation</a><br />
Cómo se puede ver, el pin 13 de Arduino equivale al PB5 (puerto B, bit 5). <br />
<br />
<i><u><b>Truco</b></u> => Si escribes sobre el registro PINx cuando esta declarado cómo salida, el pin conmutará.</i><br />
<br />
<br />
<b style="color: blue;">_BV()</b> usado en el código es un macro definido en<b> <span style="color: red;">avr/sfr_defs.h</span></b>, el cual se añade indirectamente al incluir <b><span style="color: red;">avr/io.h</span></b>. Para hacerlo fácil, lo puedes usar sin añadir dichos includes, ya que esta incluido en el core de Arduino.<br />
Dicho macro esta definido como: <b><span style="color: blue;">#define _BV( bit ) ( 1<<(bit) )</span></b><br />
Lo que hace es poner a "1" el bit definido dentro del paréntesis de la función.<br />
<br />
<i>No he usado dicho macro para la configuración de los registros del Timer 2 dentro del setup() para intentar ser más claro y entenderlo mejor mientras se esta leyendo el datasheet del micro.</i><br />
<br />
Queda de ver una cosa.... ¿Cómo configuro las interrupción de overflow del timer 2?<br />
Para "recoger" las interrupciones generadas por el microcontrolador, nuestro código debe disponer de la siguiente estructura:<br />
<br />
<br />
<span style="color: blue;">#include <avr/interrupt.h> </span><br />
<br />
<span style="color: blue;">ISR(TIMER2_OVF_vect)</span><br />
<span style="color: blue;">{</span><br />
<span style="color: blue;"> // código a ejecutar cuando se activa la interrupción</span><br />
<span style="color: blue;">}</span><br />
<br />
<b>ISR(<span style="color: red;">int</span>)</b> define la función que se ejecutará cuando se active la interrupción <b style="color: red;">int</b>, en este caso concreto, la interrupción de overflow del Timer 2 (<b style="color: red;">TIMER2_OV_vect</b>). Existen más interrupciones cómo por ejemplo: INT0_vect, USART_RX_vect, ...<br />
Para ampliar información, visitar <a href="http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html">http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html</a> .<br />
<br />
<br />
<br />
<br />
<b>Código del sketch:</b><br />
<br />
<pre class="code" style="color: #38761d; height: 300px; margin: 0px; overflow: auto;">#include <avr/interrupt.h>
//-----------------------------------------------------
// Rutina de Interrupcion [TIMER2_OVF_vect es la rutina que se ejecuta cuando el Timer2 ->Overflow]
// Arduino tiene un cristal de 16 Mhz
// Por lo que tenemos una interrupcion cada => 1/ ((16000000 / PRESCALER) / 256)
ISR(TIMER2_OVF_vect)
{
PINB |=_BV(PB5);
}
void setup()
{
DDRB=_BV(PB5); // Pin 13 Arduino equivale a PB5
// NORMAL MODE
TCCR2A = (1<<COM2A1) | (0<<COM2A0) | (0<<COM2B1)| (0<<COM2B0) | (0<<3) | (0<<2) | (0<<WGM21) | (0<<WGM20);
TCCR2B = (0<<FOC2A) | (0<<FOC2B) | (0<<5) | (0<<4) | (0<<WGM22) | (1<<CS22) | (0<<CS21) | (0<<CS20);
// Activo Timer2 Overflow Interrupt
TIMSK2 =(0<<7) | (0<<6) | (0<<5) | (0<<4) | (0<<3) | (0<<OCIE2B) | (0<<OCIE2A) | (1<<TOIE2);
// Oscilador interno
ASSR = (0<<7) | (0<<EXCLK) | (0<<AS2) | (0<<TCN2UB) | (0<<OCR2AUB) | (0<<OCR2BUB) | (0<<TCR2AUB) | (0<<TCR2BUB) ;
//Activo interrupciones globales.
sei();
}
void loop()
{
}
</pre><br />
<br />
<br />
<br />
<br />
<br />
Veámos ahora un ejemplo de cómo usar el <b>Timer2</b> para controlar diferentes tareas. En este ejemplo, conmutaremos el estado de dos pines (pin 13 y pin 1 de Arduino) a dos frecuencias diferentes. Es decir, haremos que el led conectado al pin 13 parpadee cada 10 ms y que el pin 1 cada 25 ms.<br />
Para ello configuramos nuestro Timer2 para que active la interrupción cada <b>1ms</b>. Dentro de la interrupción aumentará una variable llamada ticks. Dicha variable será la base para controlar la ejecución del resto de mi programa.<br />
Por lo que el flujo de mi programa vendrá controlado basado en unidades de 1ms (variable ticks). Esto es la base de cómo hacer "tareas multiples" con un microcontrolador.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG9XeNmxeLoPPGzGrGqb7evCJ7kp2BlErDwz6Cf8kphd4zfXVzKyLFDViMLwzQG5UNW_CRSo3ly4ISHgp5h0QeFgdvF1F-06UkkwP4j9hk7TJmYXy3vR-L_Ul14McPofsn2ILwYpvWz6fc/s1600/Timer2_capture2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="192" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG9XeNmxeLoPPGzGrGqb7evCJ7kp2BlErDwz6Cf8kphd4zfXVzKyLFDViMLwzQG5UNW_CRSo3ly4ISHgp5h0QeFgdvF1F-06UkkwP4j9hk7TJmYXy3vR-L_Ul14McPofsn2ILwYpvWz6fc/s640/Timer2_capture2.jpg" width="640" /></a></div><br />
<div style="text-align: center;"><b style="color: red;"><i>(click para agrandar)</i></b></div><br />
<br />
<br />
<b>Código del sketch 2:</b><br />
<br />
<pre class="code" style="color: #38761d; height: 300px; margin: 0px; overflow: auto;">#include <avr/interrupt.h>
//DECLARACION DE VARIABLES GLOBALES
volatile unsigned long ticks;
unsigned long Tarea1;
unsigned long Tarea2;
//-----------------------------------------------------
// Rutina de Interrupcion [TIMER2_OVF_vect es la rutina que se ejecuta cuando el Timer2 ->Overflow]
// Arduino tiene un cristal de 16 Mhz
// Por lo que tenemos una interrupcion cada => 1/ ((16000000 / PRESCALER) / 256)
ISR(TIMER2_OVF_vect)
{
ticks++;
}
void setup()
{
DDRB=_BV(PB5); // Pin 13 Arduino equivale a PB5
DDRD=_BV(PD1); // Pin 2 Arduino equivale a PD1
// NORMAL MODE
TCCR2A = (1<<COM2A1) | (0<<COM2A0) | (0<<COM2B1)| (0<<COM2B0) | (0<<3) | (0<<2) | (0<<WGM21) | (0<<WGM20);
TCCR2B = (0<<FOC2A) | (0<<FOC2B) | (0<<5) | (0<<4) | (0<<WGM22) | (1<<CS22) | (0<<CS21) | (0<<CS20);
//Configurado a 1.024 ms
// Activo Timer2 Overflow Interrupt
TIMSK2 =(0<<7) | (0<<6) | (0<<5) | (0<<4) | (0<<3) | (0<<OCIE2B) | (0<<OCIE2A) | (1<<TOIE2);
// Oscilador interno
ASSR = (0<<7) | (0<<EXCLK) | (0<<AS2) | (0<<TCN2UB) | (0<<OCR2AUB) | (0<<OCR2BUB) | (0<<TCR2AUB) | (0<<TCR2BUB) ;
// Inicializo variables
Tarea1=10;
Tarea2=25;
//Activo interrupciones globales.
sei();
}
void loop()
{
if (ticks>=Tarea1)
{
PINB |=_BV(PB5); //Conmuto pin 13
Tarea1+=10; //Configuro para que se ejecute de nuevo la Tarea1 dentro de 10 ticks
}
if (ticks>=Tarea2)
{
PIND |=_BV(PD1); //Conmuto pin 2
Tarea2+=25; //Configuro para que se ejecute de nuevo la Tarea2 dentro de 25 ticks
}
}
</pre><br />
<br />
<br />
Espero que ésto ayude y no dudes en contactar conmigo si encuentras algun error.<br />
<br />
<br />
<br />
<br />
<b>Links recomendados:</b><br />
<a href="http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=50106">http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=50106</a> [Newbie's Guide to AVR Timers]<br />
<a href="http://arduino.cc/en/Tutorial/SecretsOfArduinoPWM">http://arduino.cc/en/Tutorial/SecretsOfArduinoPWM</a> ó <a href="http://arduino.cc/es/Tutorial/SecretsOfArduinoPWM">http://arduino.cc/es/Tutorial/SecretsOfArduinoPWM</a> [castellano]<br />
<a href="http://www.nongnu.org/avr-libc">http://www.nongnu.org/avr-libc</a> [Libreria de C para AVR usada por el core de Arduino]<br />
<a href="http://www.tte-systems.com/books/pttes">http://www.tte-systems.com/books/pttes</a> [ Libro Patterns for Time-Triggered Embedded Systems ]<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
.Igorhttp://www.blogger.com/profile/07332255486737492708noreply@blogger.com16tag:blogger.com,1999:blog-5229899856062584712.post-60435871298808492672010-11-29T09:35:00.000-08:002011-01-18T06:22:17.938-08:00Libreria TVout<span style="color: white;">.</span><br />
<code><br />
<script src="http://www.gmodules.com/ig/ifr?url=http://www.google.com/ig/modules/translatemypage.xml&up_source_language=es&w=160&h=60&title=&border=&output=js">
</script> </code><br />
<span style="color: white;">. </span><br />
Se trata de una librería para crear video compuesto con Arduino. Su utilización es muy sencilla y directa.<br />
<div style="text-align: center;"><a href="http://code.google.com/p/arduino-tvout/">http://code.google.com/p/arduino-tvout/</a></div><div style="color: blue;"><br />
<br />
<span style="font-size: large;">Tan sólo necesitas un par de diodos y un par de resistencias!!!!</span></div><div style="color: blue;"><br />
</div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNP3rfuIfuHjU9wL_vVJv2VwIcvTSTUCCObBqcX2G5hBfzkeofhyphenhyphensbFUISJcSgQuaBsRXAiTcsABPw_k3n3bgUQF8x09gPUmhZ-wVHeSe28VuxHQVc0gvI-Bal_m6YpbO6I0jZIA7ZqJt-/s1600/Esquema.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="100" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNP3rfuIfuHjU9wL_vVJv2VwIcvTSTUCCObBqcX2G5hBfzkeofhyphenhyphensbFUISJcSgQuaBsRXAiTcsABPw_k3n3bgUQF8x09gPUmhZ-wVHeSe28VuxHQVc0gvI-Bal_m6YpbO6I0jZIA7ZqJt-/s320/Esquema.jpg" width="320" /></a></div><br />
Para un Diecimila (ATMega328P) los pines son:<br />
<ul><li>Sync = pin 9, Arduino</li>
<li>Video = pin 7, Arduino</li>
<li>GND = masa, Arduino</li>
</ul><br />
Veámos un ejemplo sencillo con dos simples pantallas. En la primera se muestra texto con la temperatura recogida con una NTC y adquirida por Arduino en su entrada 5. Después de un delay, se muestra un bitmap (ver el vídeo del resultado al final de esta entrada).<br />
<br />
He utilizado la última versión beta disponible en el momento de escribir esta entrada. Existe una función para mostrar imagenes almacenadas en memoria flash. Para crear imagenes, puedes utilizar el software Image2Code (<a href="http://sourceforge.net/projects/image2code/files/">http://sourceforge.net/projects/image2code/files/</a>).<br />
El software permite abrir directamente una imagen y convertirla a un array en C:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCE-QsNa4dFEfPaM_SabLulOjqF4m3U0HDXfpAYjB5BvFho1uUJk5tQb-snNkga14Bia1zIpJwjDcGa87rXgystkWZFLK8zxAAYemoJ9PbvMjzbq5exSFNl1YrH6lw-7R3T3inSbyIgZE6/s1600/Image2Code.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="375" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCE-QsNa4dFEfPaM_SabLulOjqF4m3U0HDXfpAYjB5BvFho1uUJk5tQb-snNkga14Bia1zIpJwjDcGa87rXgystkWZFLK8zxAAYemoJ9PbvMjzbq5exSFNl1YrH6lw-7R3T3inSbyIgZE6/s400/Image2Code.jpg" width="400" /></a></div><br />
Una vez hecho click sobre Convert, se te abrira el editor de textos con el código de la foto. Usa la función <br />
reemplazar para eliminar "{" y "}".<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvxHxUaBfg8JaEVVNYXrUT0Al4xHW3Z3j1VuMEna5NSV2ancE2agRGlUoG17LXsEzIOOYlABkYbau_Q8ddBiF_4ezighjNHYno_ZoRkrHkiQmmXoCCQFgC3SfjeqiLAg1ySHK8GhWWtDxf/s1600/reemplazar.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="207" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvxHxUaBfg8JaEVVNYXrUT0Al4xHW3Z3j1VuMEna5NSV2ancE2agRGlUoG17LXsEzIOOYlABkYbau_Q8ddBiF_4ezighjNHYno_ZoRkrHkiQmmXoCCQFgC3SfjeqiLAg1ySHK8GhWWtDxf/s400/reemplazar.jpg" width="400" /></a></div><br />
Ahora ya tienes tu imagen preparada para grabarla en tu Arduino. Lo único que falta es crear un array de char donde guardarás dicha imagen. Para ello hay que crear dos archivos, uno *.h donde estará la declaración de la variable y uno *.cpp donde se guardará el array obtenido con Image2Code.<br />
En mi ejemplo, guardaré la imagen creada en un array llamado <b><span style="color: red;">ok[]</span></b> .<br />
<br />
Empecemos con el *.h, en mi caso le he llamado <b><span style="color: red;">bitmap.h</span></b>.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwuuDHofbbXxeDIb09mkIhHxenWsdOYwWX5DKbaHeKcHSHTOg4UGtPyr97WlhzS4wFc6DFk1-vRasCne1dqRj6Zr6ktXuR9Svmykr40gv6xWFY3ac2LdmgvP-m3m9prqsnR3Pd4y9W2gW2/s1600/bitmap2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="253" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwuuDHofbbXxeDIb09mkIhHxenWsdOYwWX5DKbaHeKcHSHTOg4UGtPyr97WlhzS4wFc6DFk1-vRasCne1dqRj6Zr6ktXuR9Svmykr40gv6xWFY3ac2LdmgvP-m3m9prqsnR3Pd4y9W2gW2/s320/bitmap2.jpg" width="320" /></a></div>Para el *.cpp, en mi caso <b><span style="color: red;">bitmap.cpp</span></b>. (en la tercera línea, se pone el tamaño de la imagen (74x96).<br />
<div style="color: blue;">#include "bitmap.h"<br />
PROGMEM const unsigned char ok[] = {<br />
74,96,</div><span style="color: red;"> //pegar aquí el código obtenido con Image2Code</span><br />
<span style="color: blue;">}; </span><br />
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcmJZhCtC5E3i1jvsaFeSVUt__187pdIYXsfQPAC6eBvHjaJ4e6gkhg84ZQNThFgw5eZ3qiAAZTiV7tb7kNsWu4Nk8AymWi_IfrubNsfYdegHZNk7eftcsWgbR-FDCs-1mksPtvDRm-g2O/s1600/bitmap.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="288" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcmJZhCtC5E3i1jvsaFeSVUt__187pdIYXsfQPAC6eBvHjaJ4e6gkhg84ZQNThFgw5eZ3qiAAZTiV7tb7kNsWu4Nk8AymWi_IfrubNsfYdegHZNk7eftcsWgbR-FDCs-1mksPtvDRm-g2O/s400/bitmap.jpg" width="400" /></a></div><br />
<br />
<br />
<br />
<div style="color: blue;"><u><b>Librerías y código:</b></u></div><ul><li><a href="http://cid-d2ee689f353f15bc.photos.live.com/self.aspx/P%c3%bablico/TVout.zip">Librería TVout</a></li>
<li><a href="http://cid-d2ee689f353f15bc.photos.live.com/self.aspx/P%c3%bablico/TVoutfonts.zip">Fuentes de texto</a></li>
<li><a href="http://cid-d2ee689f353f15bc.photos.live.com/self.aspx/P%c3%bablico/DemoPAL%5E_igor%5E_1.rar">Ejemplo</a> </li>
</ul><br />
<br />
<b>Código del sketch:</b><br />
<br />
<pre class="code" style="color: #38761d; height: 300px; margin: 0px; overflow: auto;">#include <TVout.h>
#include <fontALL.h>
#include "bitmap.h"
TVout TV;
int final=8;
int mydelay=10;
double temperatura=0.0;
void setup()
{
TV.start_render(PAL);
TV.clear_screen();
}
void loop()
{
TV.select_font(font4x6);
TV.print_str(2,0*8,"Rumbeando con Arduino By IgOrR");
TV.select_font(font8x8);
temperatura=analogRead(5)*5.0/1023.0;
TV.set_cursor(2,5*8);
//Muestro voltage
TV.print("Analog 5= ");
TV.print(temperatura,2);
TV.print("V");
//Muestro grados
TV.set_cursor(2,6*8);
TV.print("Temp = ");
temperatura=-27.025*temperatura + 112.95;
TV.print(temperatura,2);
for (int i=0;i<3;i++)
{
for (int i=0;i<final;i++)
{
TV.print_str(0,9*8," ");
TV.print_str(i*6,9*8,"Toma ya!");
TV.delay_frame(mydelay);
}
for (int i=final;i>0;i--)
{
TV.print_str(0,9*8," ");
TV.print_str(i*6,9*8,"Toma ya!");
TV.delay_frame(mydelay);
}
}
TV.clear_screen();
TV.bitmap(30,0,ok,0,0,0);
TV.delay_frame(300);
TV.clear_screen();
}
</pre><br />
<br />
<br />
<br />
<br />
<div style="text-align: center;"><object height="344" width="425"><param name="movie" value="http://www.youtube.com/v/urNtuDe8ZBo?fs=1&hl=es_ES"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/urNtuDe8ZBo?fs=1&hl=es_ES" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object> </div><br />
<br />
<br />
Pongo unas fotos,para que se aprecie mejor la calidad:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNcow1Q31aoRlNIoWNwkykK7Qs-diuDi1mTWBGvU8eVOFf2iMIXUh8zQD5obJr2Gl7PE1ve6lBnoPicxmvuGTHFqRzQ7_lig0AcjB-nhnuyBn2FLDO52FYFZK9IaK37-NytWCExQ4OOD2F/s1600/TVout1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="252" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNcow1Q31aoRlNIoWNwkykK7Qs-diuDi1mTWBGvU8eVOFf2iMIXUh8zQD5obJr2Gl7PE1ve6lBnoPicxmvuGTHFqRzQ7_lig0AcjB-nhnuyBn2FLDO52FYFZK9IaK37-NytWCExQ4OOD2F/s320/TVout1.jpg" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaDknNjMVPQuTCRBPbFNT9zVBqwKd86YeUdBfRo8HxqsD2SHXr13OmDg6pTgecjHy0XU3iqUTDBqHFyodfjCg5yw_WWfGINeSUF_A9IevULOpRl6HgprEPQsiujpLFKPAMOeIJy45JYZcW/s1600/TVout2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="242" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaDknNjMVPQuTCRBPbFNT9zVBqwKd86YeUdBfRo8HxqsD2SHXr13OmDg6pTgecjHy0XU3iqUTDBqHFyodfjCg5yw_WWfGINeSUF_A9IevULOpRl6HgprEPQsiujpLFKPAMOeIJy45JYZcW/s320/TVout2.jpg" width="320" /></a></div><br />
<br />
<br />
<br />
<span style="font-size: large;"><b>Links:</b></span><br />
<ul><li><a href="http://www.rickard.gunee.com/projects/video/pic/howto.php">http://www.rickard.gunee.com/projects/video/pic/howto.php</a></li>
<li><a href="http://www.batsocks.co.uk/readme/video_timing.htm">http://www.batsocks.co.uk/readme/video_timing.htm</a></li>
</ul><br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
.<br />
<br />
<br />
<br />
<div style="color: white;">.</div>Igorhttp://www.blogger.com/profile/07332255486737492708noreply@blogger.com15tag:blogger.com,1999:blog-5229899856062584712.post-68893446147562915532010-01-10T05:26:00.000-08:002011-01-18T06:22:17.942-08:00LINKDUINO: DD-WRT + OPTWARE<div style="color: white; text-align: center;">.<br />
</div><script src="http://www.gmodules.com/ig/ifr?url=http://www.google.com/ig/modules/translatemypage.xml&up_source_language=es&w=160&h=60&title=&border=&output=js">
</script><br />
<br />
Para poder realizar este tutorial es necesario que dispongas de alguno de estos recursos:<br />
<ul><li>Router con gran memoria flash libre</li>
<li>SD/MMC mod.<br />
</li>
<li>Router con USB. </li>
</ul>(Ampliar información visitando el siguiente <a href="http://www.dd-wrt.com/wiki/index.php/Optware">link</a>.)<br />
<br />
Aqui vamos a explicar cómo hacerlo usando el SD/MMC mod. QUIERO DEJAR CLARO QUE TODA LA INFORMACIÓN ESTÁ EXTRAIDA DEL BLOG <a href="http://ahorcandoeltiempo.blogspot.com/2008/11/control-webcam-20.html">MATANDO EL TIEMPO</a> (gracias Edu por tan buen documento).<br />
<br />
<div style="color: red;"><span style="font-size: large;"><b>Primer paso:</b> <i>Instalar SD</i></span><br />
</div><br />
Puedes encontrar toda la información en: <a href="http://nuwiki.openwrt.org/oldwiki/OpenWrtDocs/Customizing/Hardware/MMC?highlight=%28mmc%29">http://nuwiki.openwrt.org/oldwiki/OpenWrtDocs/Customizing/Hardware/MMC?highlight=%28mmc%29</a><br />
<br />
<br />
Video explicativo de <a href="http://lampiweb.com/"><b>Lampi</b></a>:<br />
<br />
<object height="505" width="640"><param name="movie" value="http://www.youtube.com/v/TqktmXB_dww&hl=es_ES&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/TqktmXB_dww&hl=es_ES&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="505"></embed></object><br />
<br />
<br />
Y unas fotos (son las mejores que he encontrado. Extraidas de <a href="http://www.dd-wrt.com/wiki/index.php/Linksys_WRT54G-TM_SD/MMC_mod">aquí</a>):<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifYEXSXlI0plQRnH-1SvIO5rZU2j5__FUsJSf7eAunedV929HaTeLAyMNqYtXvMQein4OHiquAzg6z_IqHvQMXp2XnZFy-Qbs4Ze2UxbQBu62hWaBsZXbcUADOIs2fKJ7M8Stie1wv2Lhu/s320/gpiobt3.png" /><br />
</div><br />
<div class="separator" style="clear: both; text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2yUKyxj7XK8dUE37-uD0xiXySEfjezIVNWI4R3xOSGZ5kPRmHDBA65Qmw67PHEdeXFFcGJGOz4igSsV1TO0UC0Bpd7LeE7ZXvtijS2p44Nfz4MGQbBulKqsB34Zn1CvYyDB2rlI91ZWkC/s320/gpio2and3largeip3.jpg" /><br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"> <img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDL8XsH79zYyrw6sZz1oc1LvvU_FD13M8jx81rO6PDNydjVkQejeFSZjoBjlB91Y95vrEtNJKqrs7G6fXcQtwhC2svsNEJy9_vyytyxQuAyEkqGOxBReuXPFtqpMAwgA6LLENFyQnDhVLI/s320/gpio4and7largeje5.jpg" /><br />
</div><br />
<br />
<div style="color: red;"><span style="font-size: large;"><b>Segundo paso:</b> <i>Instalar Optware</i></span><br />
</div><br />
Como se detallada en <a href="http://ahorcandoeltiempo.blogspot.com/2008/11/control-webcam-20.html">Matando el Tiempo</a>:<br />
<br />
1) Firmware: DD-WRT v24 sp2 (10/10/09) con mod SD, una tarjeta reconocida (las modernas, por ejemplo HC, no las reconoce) y lista para usar.<br />
<i>Me ha reconocido una de 1 Gb (velocidad x66).</i><br />
<i> </i> <br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4wxvjBJufZp0SRJpZqc00ugTS1IEo5NzdJcpbc2B-hcILRQpMsH9Rw13kXS4oHHfSpDkg8Z2VCHnn6yol7QcYSihvlAP1IEd6J7HzA_e6g0BrjJ_KgTOO2QDGn2GoZrVC3ShYmfw5EpM3/s1600-h/dd-wrt_mmc_sd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4wxvjBJufZp0SRJpZqc00ugTS1IEo5NzdJcpbc2B-hcILRQpMsH9Rw13kXS4oHHfSpDkg8Z2VCHnn6yol7QcYSihvlAP1IEd6J7HzA_e6g0BrjJ_KgTOO2QDGn2GoZrVC3ShYmfw5EpM3/s640/dd-wrt_mmc_sd.jpg" /></a><br />
</div><br />
<br />
<br />
2) Montar la partición en la SD<br />
<br />
<div style="color: #274e13;"><b><code>mkdir /mmc/jffs</code><br />
<code>mount --bind /mmc/jffs /jffs</code></b><br />
</div><br />
3) Instalar Optware<br />
<br />
<div style="color: #274e13;"><b><code>mkdir /jffs/opt</code><br />
<code>mount -o bind /jffs/opt /opt</code><br />
<code>mkdir /jffs/tmp</code><br />
<code>cd /jffs/tmp</code><br />
<code>wget http://www.wlan-sat.com/boleo/optware/optware-install-ddwrt.sh</code><br />
<code>./optware-install-ddwrt.sh</code></b><br />
</div><br />
Adjunto el código de dicho script de instalación:<br />
<br />
<div style="color: #274e13;"><pre class="code" style="height: 300px; margin: 0px; overflow: auto; width: auto;">#!/bin/sh
# Optware pre-installation script, Leon Kos 2006, 2008
# added -verbose_wget to some lines, MrAlvin 2009
REPOSITORY=http://ipkg.nslu2-linux.org/feeds/optware/ddwrt/cross/stable
TMP=/tmp
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/opt/bin:/opt/sbin
unset LD_PRELOAD
unset LD_LIBRARY_PATH
_check_config()
{
echo "Checking system config ..."
GATEWAY=$(netstat -rn |
sed -n 's/^0.0.0.0[ \t]\{1,\}\([0-9.]\{8,\}\).*/\1/p' )
if [ -n "${GATEWAY}" ]; then
echo "Using ${GATEWAY} as default gateway."
else
echo "Error: No default gateway set!"
exit 2
fi
if [ -s /etc/resolv.conf ]; then
echo "Using the following nameserver(s):"
if grep nameserver /etc/resolv.conf ; then
GATEWAY_SUBNET=$(echo "${GATEWAY}" |
sed 's/\.[0-9]\{1,3\}\.[0-9]\{1,3\}$//')
if [ "${GATEWAY_SUBNET}" = "192.168" ]; then
if grep -q ${GATEWAY} /etc/resolv.conf ; then
echo "Gateway ${GATEWAY} is also nameserver."
else
echo "Warning: local nameserver is different than gateway!"
echo "Check config or enter:"
if test -L /etc/resolv.conf ; then
echo " sed -i s/192.168.*/${GATEWAY}/ /tmp/resolv.conf"
else
echo " sed -i s/192.168.*/${GATEWAY}/ /etc/resolv.conf"
fi
echo "and try again - or wait to see if your download continues anyway."
fi
fi
else
echo "Error: No nameserver specified in /etc/resolv.conf"
exit 5
fi
else
echo "Error: Empty or nonexistent /etc/resolv.conf"
exit 3
fi
if mount | grep -q /opt ; then
[ -d /opt/etc ] && echo "Warning: /opt partition not empty!"
else
echo "Error: /opt partition not mounted."
echo "for running Optware on JFFS (not recommended), Enter"
echo " mkdir /jffs/opt"
echo " mount -o bind /jffs/opt /opt"
echo "to correct this."
exit 4
fi
}
_install_package()
{
PACKAGE=$1
echo "Installing package ${PACKAGE} ..."
echo " Some newer versions of DD-WRT does not show download progress bar,"
echo " so just be patient - or check STATUS -> BANDWIDTH tab for download"
echo " activity in your routers Web-GUI, and then still wait a minute or two."
wget -O ${TMP}/${PACKAGE} ${REPOSITORY}/${PACKAGE}
cd ${TMP}
tar xzf ${TMP}/${PACKAGE}
tar xzf ${TMP}/control.tar.gz
cd /
if [ -f ${TMP}/preinst ] ; then
sh ${TMP}/preinst
rm -f ${TMP}/preints
fi
tar xzf ${TMP}/data.tar.gz
if [ -f ${TMP}/postinst ] ; then
sh ${TMP}/postinst
rm -f ${TMP}/postinst
fi
rm -f ${TMP}/data.tar.gz
rm -f ${TMP}/control.tar.gz
rm -f ${TMP}/control
rm -f ${TMP}/${PACKAGE}
}
_check_config
_install_package uclibc-opt_0.9.28-13_mipsel.ipk
_install_package ipkg-opt_0.99.163-10_mipsel.ipk
/opt/sbin/ldconfig
/opt/bin/ipkg -verbose_wget update
/opt/bin/ipkg -force-reinstall -verbose_wget install uclibc-opt
/opt/bin/ipkg -force-reinstall -verbose_wget install ipkg-opt
</pre></div><br />
<br />
<br />
¡ Ya podemos instalar paquetes de Optware en nuestro router! Puedes ver una lista resumen <a href="http://www.dd-wrt.com/wiki/index.php/Quick_list_of_Optware_packages">aquí</a> y directamente los paquetes <a href="http://ipkg.nslu2-linux.org/feeds/optware/ddwrt/cross/stable/">aquí</a>.<br />
<br />
Para ello, ahora dispones en <b><span style="color: red;">/opt/bin</span></b> de la utilidad <b style="color: red;">ipkg-opt</b> para poder instalar paquetes Optware. <br />
<br />
4) Tienes que asegurarte que cada vez que se inice el router, se ejecuten las ordenes:<br />
<br />
<div style="color: #274e13;"><b><code>mount --bind /mmc/jffs /jffs</code><br />
<code>mount -o bind /jffs/opt /opt</code></b><br />
</div><br />
Gracias a estos dos comandos, <b>/jffs</b> y <b>/opt</b> apuntan a directorios de la MMC. <br />
Para ello, en el menu ADMINISTRATION / COMANDS, puedes grabar un script con las ordenes a ejecutar (SAVE STARTUP).<br />
<code></code><br />
<br />
<b>Nota:</b> <i>Sólo he detallado lo mínimo para poder empezar a instalar paquetes. Se puede necesitar ampliar los comandos en el script de inicio, si se desea usar otros servicios, como por ejemplo servidor web con php u otros.</i><br />
<br />
Si quieres probar el ejemplo de <b><span style="color: #741b47;">CONTROLAR LCD A TRAVÉS DE WEB EMBEBIDA</span></b>, lo he adaptado a PHP (necesitas instalarte los paquetes php y php-thttpd):<br />
<br />
<div style="text-align: center;"><a href="http://cid-d2ee689f353f15bc.skydrive.live.com/self.aspx/P%c3%bablico/LCD%5E_Controlled%5E_with%5E_PHP.rar"><b><span style="font-size: large;"><span style="color: red;">PULSA AQUÍ PARA DESCARGARLO </span></span></b></a><br />
</div><br />
Dispones de 3 archivos:<br />
<ul><li>form_lcd.html => Principal. Contiene el formulario a enviar.<br />
</li>
<li>lcd.jpg => Foto que se muestra en la página principal.<br />
</li>
<li>script.php => Recoge los datos enviados por POST y los envia por puerto serie.<br />
</li>
</ul><br />
<br />
<br />
<div style="text-align: justify;">Ahora puedes dejar el servidor que viene con DD-WRT para servir las páginas de configuración del router escuchando en el puerto 80 y añadir nuevo/s servidor/es con mayor capacidad para tus páginas personales. (Por ejemplo, php-thttpd por el puerto 8080). ¡Puedes usar PHP 5!<br />
</div><br />
A continuación, pongo las fotos que he realizado del proceso:<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK7g5GX1vkPKIJcyOFi8mpn_-2mY8N_dMpB6skH6pfq3diC8lJhR-k1_YA1R8iS5iwKVhLNlTBXFgQZkOxhZAhK-UCl0tY6jFC4QSt_jJ1oJMH2h2rQZTe1au6qPeqAq1IhAg2hbKtnxZZ/s320/Mi_foto_final.jpg" /><br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"> <img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZt3MUXYio4GlbDWlEMqPOpBI1pbCc4HiGeZo1VTb3lPF-8ptwQz1ZT-_A4Wi4NMnvY6J8x_MxiueFn-GacizGvkXebopqrUl2grS_oYJ41gmW3A1mUi_OSEDMYNcWB1AHbBW6EP3f1Mrw/s320/Mi_foto_gpio2y3.jpg" /><br />
</div><br />
<div class="separator" style="clear: both; text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5CTtDQksb-rXoC1XPX7UKfL9Moo0gp_0CmMdBkJkydYhi2Ago8q4Ng8gMNpzJnxXRecVB1yTUwtclrKwFbT0k9635j_OCKT56y3HojgCbHJhiO4sPnetw7MxlqU8D1-ZC_vPF0NzXOCOz/s320/Mi_foto_gpio4y5y7.jpg" /><br />
</div><br />
<br />
<br />
<br />
<br />
<div style="color: blue; text-align: justify;"><span style="font-size: large;">Con esta mod al router, ya sólo queda en tu imaginación las aplicaciones que puedes realizar. Ya no perderás nada cuando tu router se reinicie. Repasa los paquetes Optware que puedes descargar, y seguro que se te van ocurriendo ideas.</span><br />
</div><br />
<br />
<br />
<br />
<b>Notas adicionales:</b><br />
Tomato dispone de una versión con drivers para manejar SDHC, la he probado con una tarjeta de 4 Gb y ha funcionado perfectamente. Tengo que ver si se pueden usar los paquetes Optware con dicho firmware, ya que el router parece ir más descargado con dicho firmware.<br />
<a href="http://gemini.net.pl/%7Eslodki/tomato-sdhc.html">Link: TOMATO firmware with SDHC mod</a><br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
.Igorhttp://www.blogger.com/profile/07332255486737492708noreply@blogger.com5tag:blogger.com,1999:blog-5229899856062584712.post-33612132622841925492010-01-03T11:44:00.000-08:002011-01-18T06:22:17.944-08:00LINKDUINO: Controlar LCD desde web embebida<div style="color: white; text-align: center;">.<br />
</div><script src="http://www.gmodules.com/ig/ifr?url=http://www.google.com/ig/modules/translatemypage.xml&up_source_language=es&w=160&h=60&title=&border=&output=js">
</script><br />
<br />
Siguiendo cómo realizar páginas embebidas, las cuales interactuen con Arduino, veremos un ejemplo de cómo usar formularios. (Se debe leer primero el siguiente <a href="http://real2electronics.blogspot.com/2009/12/linkduino-web-server.html">post</a>)<br />
<br />
Nuestro ejemplo se trata del envio de texto a un display lcd 4x20, a través de internet/local via página web embebida en el router.<br />
<br />
Para ello, crearemos una página web que contenga un formulario, al cual se enviará la información de 4 controles de tipo INPUT a un script, que sacará dicha información por el puerto serie hacia Arduino.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbbI4teUOqBmy3AMd35DHq4Kw_qnNs7nIRpBTUu0U3Hw763IlxdpgfhGaQZMxx5jAf9XuVdAOp84CclygCtT6LFsrB_FBKCMGvvQqRbxhc4LsCVMAFpNOgek0LrCgOE9VtijPuVOJScXJv/s640/captura_web.JPG" /><br />
</div><br />
El código html de dicha página es el siguiente:<br />
<br />
<b>form_lcd.html</b><br />
<div style="color: #38761d;"><br />
</div><pre class="code" style="color: #38761d; height: 300px; margin: 0px; overflow: auto; width: auto;"><html>
<head>
</head>
<div style="text-align:left;">
<img src="/user/lcd.jpg">
</div>
<div style="color:blue;text-align:left;">
<span style="font-size:x-large;">
<p>DATOS A ENVIAR: </p>
<p> </p>
</span></div>
<form action="/user/cgi-bin/lcd.sh" method="POST">
LCD line 1:
<input type= "text" name= "L0" size=25 maxlength=20 ><p>
LCD line 2:
<input type= "text" name= "L1" size=25 maxlength=20><p>
LCD line 3:
<input type= "text" name= "L2" size=25 maxlength=20><p>
LCD line 4:
<input type= "text" name= "L3" size=25 maxlength=20><p>
</br>
</br>
<INPUT type="submit" value="ENVIAR">
</form>
</body>
</html>
</pre><div style="color: #38761d;"><br />
</div><br />
<br />
Ahora veamos que hace nuestro script:<br />
<b>lcd.sh</b><br />
<div style="color: #38761d;"><br />
</div><pre class="code" style="color: #38761d; height: 300px; margin: 0px; overflow: auto;">#!/bin/sh
read QUERY_STRING
n_campos=$(echo $QUERY_STRING|awk 'BEGIN {FS="&"} {print NF}')
#------------------------------------------------------------------
echo "<HTML>"
echo "<HEAD>"
echo "Datos POST: "
echo $QUERY_STRING
echo "<br/>"
echo "<br/>"
echo "Has recibido:"
echo $n_campos
echo " campos"
echo "<br/>"
echo "<br/>"
i=1
while [ $i -le $n_campos ]
do
data=$(echo $QUERY_STRING|cut -f$i -d '&'|sed s/'+'/' '/g)
echo $data
echo $data|sed s/'='//g > /dev/cua/1
echo "<br/>"
i=`expr $i + 1`
done
# -----FIN ------
echo "<div style='color:blue;text-align:center;'>"
echo "<p><span style='font-size:50px;'>SE HAN ENVIADO LOS DATOS</span></p>"
echo "</div>"
echo "<META HTTP-EQUIV=Refresh CONTENT=3;URL=/user/form_lcd.html>"
echo "</HEAD><BODY>"
echo "</BODY></HTML>"
</pre><br />
<div style="text-align: justify;">En el script, recojo los datos recibidos por método POST (variable $QUERY_STRING). Para saber cuantos campos recibo, hago un awk separando campos por el caracter delimitador '<b>&</b>'.<br />
</div><div style="text-align: justify;">La variable $QUERY_STRING dispone los datos separados por '<b>&</b>' y los espacios con el carácter '<b>+</b>'.<br />
</div><div style="text-align: justify;">La variable NF es interna de awk, y son el número de campos de entradas (en nuestro caso, se ha especificado que el separador de campos es '<b>&</b>').<br />
</div><div style="text-align: justify;">Con la ayuda de cut y sed, se ha modificado la cadena recibida para obtener formato deseado.<br />
</div><br />
Un buen tutorial acerca "Linux Shell Scripting" :<br />
<div style="text-align: center;"><a href="http://www.freeos.com/guides/lsst/">http://www.freeos.com/guides/lsst/</a><br />
</div><br />
Recordad que dicho script tiene que tener permisos de ejecución (<b style="color: #38761d;">chmod +x lcd.sh</b>) <br />
<br />
Ahora nos toca el código de Arduino:<br />
<div style="color: #38761d;"><br />
</div><pre class="code" style="color: #38761d; height: 300px; margin: 0px; overflow: auto; width: auto;">// Linkduino: LCD controlado por serie
// By Igor Real
// 03-Enero-2010
// http://real2electronics.blogspot.com/
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 10, 11, 12, 13);
int byte_received;
void setup() {
lcd.begin(20, 4);
delay(100);
Serial.begin(9600);
Serial.println("Empezamos...");
}
void loop() {
while (Serial.available()>0){
byte_received=Serial.read();
if (byte_received=='L'){
Serial.println("Dentro de l");
byte_received=Serial.read();
switch (byte_received){
case '0':
{
byte cont1=0;
byte data[20];
while (Serial.available()>0){
byte_received=Serial.read();
if ( (byte_received>31) &&(byte_received<127) ){
data[cont1]=byte_received;
cont1=cont1+1;
delay(1);
if (cont1==20) break;
}
}
lcd.setCursor(0,0);
for (int i=0;i<cont1;i++) lcd.print(data[i]);
for (int i=cont1;i<20;i++) lcd.print(" ");
break;
}
case '1':
{
byte cont1=0;
byte data[20];
while (Serial.available()>0){
byte_received=Serial.read();
if ( (byte_received>31) &&(byte_received<127) ){
data[cont1]=byte_received;
cont1=cont1+1;
delay(1);
if (cont1==20) break;
}
}
lcd.setCursor(0,1);
for (int i=0;i<cont1;i++) lcd.print(data[i]);
for (int i=cont1;i<20;i++) lcd.print(" ");
break;
}
case '2':
{
byte cont1=0;
byte data[20];
while (Serial.available()>0){
byte_received=Serial.read();
if ( (byte_received>31) &&(byte_received<127) ){
data[cont1]=byte_received;
cont1=cont1+1;
delay(1);
if (cont1==20) break;
}
}
lcd.setCursor(0,2);
for (int i=0;i<cont1;i++) lcd.print(data[i]);
for (int i=cont1;i<20;i++) lcd.print(" ");
break;
}
case '3':
{
byte cont1=0;
byte data[20];
while (Serial.available()>0){
byte_received=Serial.read();
if ( (byte_received>31) &&(byte_received<127) ){
data[cont1]=byte_received;
cont1=cont1+1;
delay(1);
if (cont1==20) break;
}
}
lcd.setCursor(0,3);
for (int i=0;i<cont1;i++) lcd.print(data[i]);
for (int i=cont1;i<20;i++) lcd.print(" ");
break;
}
}
}
}
}
</pre><br />
<br />
El programa es sencillo,utiliza la libreria <a href="http://arduino.cc/en/Reference/LiquidCrystal">LiquidCrsytal</a> para el control del lcd basado en HD44780 y se debe recibir las siguientes "tramas" para escribir en cada línea:<br />
<div style="text-align: left;"><b>L0</b><i><span style="color: blue;">lo_que_quiero_escribir_en_la_primera_linea</span></i><br />
</div><div style="text-align: left;"><b>L1</b><span style="color: blue;"></span><i><span style="color: blue;">lo_que_quiero_escribir_en_la_segunda_linea</span></i><br />
</div><div style="text-align: left;"><b>L2</b><i><span style="color: blue;">lo_que_quiero_escribir_en_la_tercera_linea</span></i><br />
</div><div style="text-align: left;"><b>L3</b><i><span style="color: blue;">lo_que_quiero_escribir_en_la_cuarta_linea</span></i><br />
</div><br />
El conexionado de mi LCD (comprado en <a href="http://stores.ebay.com/Sure-Electronics">Sure Electronics</a> por ebay) ha sido:<br />
<ul><li>pin 1 Vss => Unido a masa<br />
</li>
<li>pin 2 Vdd => Unido a +5 voltios</li>
<li>pin 3 Vo => Poti de 10 Kohm (los otros dos extremos del poti a +5V y GND respectivamente)<br />
</li>
<li>pin 4 RS => Unido a pin 8 Arduino</li>
<li>pin 5 R/W => Unido a masa (no uso la opción de crear carácter)</li>
<li>pin 6 E => Unido a pin 9 Arduino</li>
<li>pin 7 DB0 => No conectado (control 4 bits)</li>
<li>pin 8 DB1 => No conectado (control 4 bits)</li>
<li>pin 9 DB2 => No conectado (control 4 bits)</li>
<li>pin 10 DB3 => No conectado (control 4 bits) </li>
<li>pin 11 DB4 => Unido a pin 10 Arduino</li>
<li>pin 12 DB5 => Unido a pin 11 Arduino</li>
<li>pin 13 DB6 => Unido a pin 12 Arduino</li>
<li>pin 14 DB7 => Unido a pin 13 Arduino</li>
<li>pin 15 A => Unido +5V a través de R=120 ohm <br />
</li>
<li> pin 16 K => Unido GND</li>
</ul><br />
<br />
<br />
<br />
<span style="color: blue;"><span style="color: black;">Lo mejor es ver un video de funcionamiento:</span></span><br />
<span style="color: blue;"><br />
</span><br />
<span style="color: blue;"><object height="505" width="640"><param name="movie" value="http://www.youtube.com/v/wb2vKsKqqWo&hl=es_ES&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/wb2vKsKqqWo&hl=es_ES&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="505"></embed></object></span><br />
<span style="color: blue;"><br />
</span><br />
<span style="color: blue;"><br />
</span><br />
<span style="color: blue;"><br />
</span><br />
<div style="text-align: justify;"><span style="color: blue;"><span style="color: black;">Con este ejemplo, se ha visto cómo funcionan los formularios y cómo tratar los datos recibidos mediante POST al script para su posterior tratamiento. En html, los formularios disponen de diversos tipos de controles: text, radio, textarea, select , ... En este ejemplo, para no introducir demasiados conceptos, se han usado los controles de tipo texto, pero el funcionamiento es similar para el resto.</span></span><br />
<span style="color: blue;"><span style="color: black;">Gracias al programa de Arduino, ahora es sencillo pasar al display información de Twitter, páginas web,...<br />
</span></span><br />
</div><br />
<br />
<div style="color: red; text-align: center;"><span style="font-size: large;"><b><br />
</b></span><br />
</div><div style="color: red; text-align: center;"><a href="http://cid-d2ee689f353f15bc.skydrive.live.com/self.aspx/P%c3%bablico/LCD%5E_web%5E_control%5E_example.rar"><span style="font-size: large;"><b>PULSA AQUÍ PARA DESCARGAR EL EJEMPLO</b></span></a></div><div style="color: red;"><br />
</div><br />
<br />
<span style="color: blue;"><span style="color: black;"> </span><br />
</span><br />
<span style="color: blue;"><br />
</span><br />
<span style="color: blue;"><br />
</span><br />
<span style="color: blue;"><br />
</span><br />
<span style="color: blue;"><br />
</span><br />
<span style="color: blue;"><br />
</span><br />
<br />
<span style="color: blue;"><span style="color: black;"> </span></span><i><span style="color: blue;"> </span></i>Igorhttp://www.blogger.com/profile/07332255486737492708noreply@blogger.com2tag:blogger.com,1999:blog-5229899856062584712.post-12427961531866136692009-12-29T03:05:00.000-08:002011-01-18T06:22:17.946-08:00LINKDUINO: SOFTWARE PARA TELEMETRIA<div style="color: white; text-align: center;">.<br />
</div><script src="http://www.gmodules.com/ig/ifr?url=http://www.google.com/ig/modules/translatemypage.xml&up_source_language=es&w=160&h=60&title=&border=&output=js">
</script><br />
<br />
<br />
<span style="color: black; font-size: small;">Veamos una nueva aplicación, desarrollada en Real2Electronics, para la adquisición de datos en "tiempo real" creada para la plataforma <b style="color: red;">LINKDUINO</b>. Gracias a este software, el usuario dispone de una herramienta sencilla y básica para la adquisición y visualización de datos via serie ó ethernet, pudiendo usar conectividad WIFI para disponer de <b>TELEMETRÍA</b>.</span><br />
<span style="color: black; font-size: small;">Nunca fueron tan fáciles y baratas tus pruebas "<a href="http://es.wikipedia.org/wiki/Hardware-in-the-loop">Hardware-in-the-loop</a>" gracias a <b style="color: red;">LINKDUINO</b>.<br />
</span><br />
<div class="MsoNormal" style="text-align: justify;"><br />
<span style="color: black; font-size: small;">Se han utilizado los siguientes controles para la realización de esta aplicación: <br />
</span><br />
</div><ul><li><span style="color: black; font-size: small;"> </span><span lang="EN-GB" style="color: black; font-size: small;"><b>Minimalistic Telnet:</b> <span style="color: black;"><span lang="EN-GB"><a href="http://www.codeproject.com/KB/IP/MinimalisticTelnet.aspx" style="text-decoration: none;"><span style="text-decoration: underline;">http://www.codeproject.com/KB/IP/MinimalisticTelnet.aspx</span></a></span></span></span><span style="font-size: small;"> </span></li>
<li><span style="font-size: small;"><b>ZedGraph:</b> <a href="http://zedgraph.org/wiki/index.php?title=Main_Page">http://zedgraph.org/wiki/index.php?title=Main_Page</a></span></li>
</ul><span style="font-size: small;"> <br />
</span><br />
<span style="font-size: small;">Veamos una captura de pantalla para ver el aspecto final de la aplicación:</span><br />
<br />
<div class="separator" style="clear: both; text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg25vVi0_qCbFS_wdsMGoIznLd-5D0zxkUK4WFQY_OXqClxZkjZFrwtEdFq-scdKoMieSLrks6q4_ex9Hz0q7PyGMF8wMXafpnMzSGWwJdxSua6Cqg_e8xkPZG5HunD0gw5YKl-plJbFRly/s640/Funcionando+Linkuduino+Interface.JPG" /><br />
</div><br />
<br />
Gracias a éste programa podremos:<br />
<div class="Section1" style="font-family: inherit;"><span style="font-size: small;"> </span><br />
<ul><li>Salvar datos a CSV (para poder exportar datos a Excel, Matlab, ...)<br />
</li>
<li>Salvar gráfico como *.jpg, *.gif, ...</li>
<li>Copiar <br />
</li>
<li>Imprimir</li>
<li>Ver valores de los puntos</li>
<li>Zoom</li>
<li>Moverse por la gráfica </li>
<li>Autoescala según se reciben datos<br />
</li>
</ul><br />
<div style="color: red; text-align: center;"><span style="color: red; font-size: x-large;"><b><span style="color: red;"><a href="http://cid-d2ee689f353f15bc.skydrive.live.com/self.aspx/P%c3%bablico/LINKDUINO%20INTERFACE%20v1.rar">PULSA AQUI PARA DESCARGAR</a></span></b></span><br />
</div><div style="color: red;"><br />
</div><div style="color: red;"><br />
</div><br />
<div class="MsoNormal"><span style="color: black; font-size: small;">Por la parte Arduino, se debe enviar la información al puerto serie de la siguiente manera:<o:p></o:p></span><br />
</div><div class="MsoNormal" style="text-align: center;"><span style="color: black; font-size: small;"> </span><span style="font-size: large;"><b><span style="color: red;">E</span></b></span><span style="color: black; font-size: large;">ValorX</span><span style="font-size: large;"><b><span style="color: red;">;</span></b></span><span style="color: black; font-size: large;">ValorY</span><span style="font-size: large;"><b><span style="color: red;">F</span></b></span><span style="color: black; font-size: small;"><o:p></o:p></span><br />
</div><span style="font-size: small;"><br />
siendo:</span><span style="font-size: small;"><br />
<span style="color: black;"> </span></span><br />
<ul><li><span style="font-size: small;"><b><span style="color: red;">E:</span></b><span style="color: black;"> Caracter E (empiece) <span style="color: blue;">char(0x45)</span></span></span></li>
<li><span style="font-size: small;"><span style="color: black;"> Valor X del punto enviado. (float i.e. 3,5)</span></span></li>
<li><span style="font-size: small;"><span style="color: black;"><span style="color: black;"> </span><b><span style="color: red;">;</span></b><span style="color: black;"> (Punto y coma) Usado como delimitador entre X e Y. <span style="color: blue;">char(0x3B</span>)</span></span></span></li>
<li><span style="font-size: small;"><span style="color: black;"><span style="color: black;"> Valor Y del punto <span style="color: black;">enviado. </span><span lang="EN-GB" style="color: black;">(float i.e 4509,334)</span></span></span></span></li>
<li><span style="font-size: small;"><span style="color: black;"><span style="color: black;"><span lang="EN-GB" style="color: black;"><span lang="EN-GB" style="color: black;"> </span><b><span lang="EN-GB" style="color: red;">F:</span></b><span lang="EN-GB" style="color: black;"> Caracter F (fin) <span style="color: blue;">char(0x46)</span></span></span></span></span></span></li>
</ul></div><div class="Section1" style="font-family: inherit;"><span style="font-size: small;"><span style="color: black;"><span style="color: black;"><span lang="EN-GB" style="color: black;"> </span></span></span></span><span style="font-size: small;"><br />
Ejemplos de tramas validas.</span><span style="font-size: small;"><br />
</span><br />
<div class="MsoNormal"><span style="color: black; font-size: small;"> <i><span style="color: blue;">E45,67;</span><st1:metricconverter productid="32,67F" st="on" style="color: blue;">32,67F</st1:metricconverter></i></span><br />
</div><div class="MsoNormal" style="color: blue;"><i><span style="font-size: small;"><st1:metricconverter productid="32,67F" st="on"> E65.56;<st1:metricconverter productid="89009.56F" st="on">89009.56F</st1:metricconverter></st1:metricconverter></span></i><br />
</div><div class="MsoNormal"><div style="color: blue;"><i><span style="font-size: small;"><st1:metricconverter productid="32,67F" st="on"><st1:metricconverter productid="89009.56F" st="on"> ...</st1:metricconverter></st1:metricconverter></span></i><br />
</div><br />
<br />
</div><div class="MsoNormal" style="text-align: justify;"><span style="color: black; font-size: small;">Tanto '<b><span style="color: red;">.</span></b>' como '<b style="color: red;">,</b>' son admitidos como carácter de delimitador decimal.<o:p></o:p></span><br />
</div><div class="MsoNormal" style="text-align: justify;"><span style="font-size: small;"><br />
</span><br />
</div><div class="MsoNormal"><div style="color: #38761d; text-align: justify;"><span style="font-size: large;"><i><b>Quick Start Guide</b></i></span><br />
</div><span style="color: black; font-size: small;"><span style="font-size-adjust: none; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;">1) D</span></span><span style="color: black; font-size: small;">escargar aplicación<o:p></o:p> </span><br />
<span style="color: black; font-size: small;">2) Descargar e instalar <a href="http://www.microsoft.com/downloads/details.aspx?familyid=333325FD-AE52-4E35-B531-508D977D32A6&displaylang=es">.NET Framework 3.5</a>. (normalmente ya lo tendrás instalado).</span><br />
<span style="color: black; font-size: small;">3) Descomprimir el fichero .rar donde quieras que resida. Ej. C:\Real2Electronics\LINKDUINO<o:p></o:p> </span><br />
<span style="font-size: small;">4) Ejecuta LINKDUINO INTERFACE</span><br />
<span style="font-size: small;">5) Elegir método de adquisición de la información mediante las pestañas del tabControl: </span><br />
<div style="text-align: justify;"><span style="font-size: small;"><b> -Serial Port </b><b>Config</b><b>: </b>Te permitirá visualizar la configuración existente del puerto serie, además de comenzar la comunicación, cerrarla y limpiar el buffer de los datos recibidos hasta el momento.<br />
Si se desea configurar los parámetros del puerto serie, vaya al menú superior y haga click sobre Config Serial Port. Esto abrirá una nueva ventana de configuración.</span><br />
</div><div style="text-align: justify;"><span style="font-size: small;"><b> -TC</b><b>P/</b><b>IP</b><b>:</b> Te permite configurar fácilmente la direccion IP del servidor Telnet (en nuestro caso el router Linksys, ej. 192.168.0.1), el nombre de usuario, contraseña y puerto. Además proporciona el control de conexión/desconexión y limpieza del buffer.</span><br />
<span style="font-size: small;">6) Una vez elegido el método de conexión, deberemos de pulsar Connect/Open Port, y automáticamente, la aplicación comenzará a plottear sobre el gráfico los datos adquiridos.<span style="font-style: italic;">(Cuando se realiza la conexión mediante Telnet, ésta tarda unos segundos en estar activa)</span></span><br />
</div></div></div><div class="Section1" style="font-family: inherit;"><br />
<span style="font-size: small;">Veamos ahora un programa de ejemplo para el Arduino:</span><br />
<div style="color: #38761d;"><br />
</div><pre class="code" style="color: #38761d; margin: 0px; overflow: auto;">void setup()
{
Serial.begin(9600);
}
void loop()
{
static float i = 0;
static float result =0;
result = analogRead(0);
result = (result * 100.0) / 1023.0;
Serial.print("E");
Serial.print(i);
Serial.print(";");
Serial.print(result);
Serial.println("F");
i = i + 1;
}
</pre><span style="font-size: small;"> </span><br />
<span style="font-size: small;">Este programa simplemente lee el valor de la entrada ADC0 y nos envía mediante serie la trama:</span><br />
<div class="MsoNormal" style="text-align: center;"><span style="font-size: small;"> <b><span style="color: red;">E</span></b><span style="color: blue;">indiceMuestra</span><b><span style="color: red;">;</span></b><span style="color: blue;">ValorMuestra</span><b><span style="color: red;">F</span></b> </span><br />
<div style="text-align: justify;"><span style="font-size: small;">siendo ValorMuestra, el valor en tanto por cien. Si quieres enviar tiempo, recuerda la función <a href="http://arduino.cc/en/Reference/Millis">millis</a> de Arduino.</span><br />
<span style="font-size: small;"><br />
</span><br />
<span style="font-size: small;">Veamos un video de ejemplo:</span><br />
<div style="text-align: center;"><br />
</div><div style="text-align: center;"><span style="font-size: small;"><object height="505" width="853"><param name="movie" value="http://www.youtube.com/v/YjPuDD_AK4A&hl=es_ES&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/YjPuDD_AK4A&hl=es_ES&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="853" height="505"></embed></object><br />
</span><br />
</div><div style="text-align: center;"><span style="font-size: small;"><br />
</span><br />
</div><div style="text-align: center;"><span style="font-size: small;"><br />
</span><br />
</div><span style="font-size: small;"> </span><br />
<span style="font-size: small;"><br />
</span><br />
<span style="font-size: small;"><br />
</span><br />
</div></div><br />
<div style="text-align: center;"><br />
</div><div style="text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div style="text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi62nLdm5ZNmm-9E-vwwTB6XDdv3LBBQ9CUaXS6sPEBz-9o4TOWN6FdW1nb2kqTv_8tu-2ZdP_B9_7mj2n9iqDZYeOrDGwbArJ_uesVtDYW1hXj_NKkNDKI7f4_nBOiNU9gtQEIRTrGHRDM/s640/Linkduino.jpg" /><br />
</div><div style="text-align: center;"><br />
</div><br />
<br />
<div class="MsoNormal"><span style="font-size: small;"></span><br />
</div><div class="MsoNormal"><span style="font-size: small;"><br />
<o:p></o:p></span><br />
</div><div class="MsoNormal"><div style="color: red;"><i><span style="font-size: large;"><b>¿Necesitas un software a medida para tu aplicación? Ponte en contacto.</b></span></i><br />
</div><br />
<br />
<br />
<br />
<br />
<span style="font-size: small;"><b>Aritz R</b><br />
</span><br />
</div><span style="font-size: small;"> </span><br />
</div><div class="Section1" style="font-family: inherit;"><span style="font-size: small;"><br />
</span><br />
<span style="font-size: small;"><br />
</span><br />
</div><span style="font-size: medium;"><br />
</span><br />
<span style="font-size: medium;"><br />
</span><br />
<span style="font-size: medium;"><br />
</span><br />
<span style="font-size: medium;">.<br />
</span>Aritz Rhttp://www.blogger.com/profile/01175349926423359912noreply@blogger.com7tag:blogger.com,1999:blog-5229899856062584712.post-64856834028075487252009-12-20T06:55:00.000-08:002011-01-18T06:22:17.948-08:00LINKDUINO: Embedded Web Server<div style="color: white;">.</div><script src="http://www.gmodules.com/ig/ifr?url=http://www.google.com/ig/modules/translatemypage.xml&up_source_language=es&w=160&h=60&title=&border=&output=js">
</script><br />
<br />
<br />
Vamos a ver cómo aprovecharnos del pequeño httpd server que trae el router para nuestras propias páginas web. (Este server es el utilizado para alojar las páginas de configuración del router).<br />
<br />
Las rutas para guardar las páginas web dentro de nuestro router són:<br />
<ul><li>Estáticas => /tmp/www/</li>
<li>Dinámicas => /tmp/www/cgi-bin/</li>
</ul>(Recordad que el script debe tener los permisos adecuados <b><span style="color: #38761d;">chmod +x /tmp/www/cgi-bin/yourscript.sh</span></b>)<br />
<div style="color: red; text-align: justify;"><b>PARA PODER USAR CGI SCRIPTS, DEBES TENER UNA VERSIÓN DE DD-WRT ANTERIOR A DD-WRT V24 pre SP2 (svn 12533+), YA QUE HA SIDO INHABILITADO POR MOTIVO DE FALLO DE VULNERABILIDAD. TEN CUIDADO SI VAS A DAR CONECTIVIDAD AL EXTERIOR.</b></div><br />
<div style="color: red;"><b>He subido las versiones de firmware que he utilizado:</b></div><ul style="color: red;"><li><b>DD-WRT v23 mini => <a href="http://cid-d2ee689f353f15bc.skydrive.live.com/self.aspx/P%c3%bablico/dd-wrt.v23%5E_mini%5E_generic.bin">PULSA AQUI</a></b> </li>
<li><b>DD-WRT v23 SP2 std => <a href="http://cid-d2ee689f353f15bc.skydrive.live.com/self.aspx/P%c3%bablico/dd-wrt.v23%5E_generic.bin">PULSA AQUI</a></b></li>
</ul><div style="color: red;"><script type="text/javascript">
document.write("<a title=\"" + share.about + "\" href=\"javascript:openAboutWindow()\">DD-WRT v23 SP2 (09/15/06) std</a>");
</script></div><div style="color: red;"><b>Recuerda que si no tienes una versión DD-WRT en el router, primero se debe enviar el firmware de la versión mini y posteriormente cualquiera de las versiones mayores.</b></div><br />
<br />
<br />
<span style="color: magenta;">Linksys dispone de la siguiente utilidad soft para flashear el equipo </span><a href="http://cid-d2ee689f353f15bc.photos.live.com/self.aspx/P%c3%bablico/Tftp%5EJ0.exe"><span style="color: magenta;">LINKSYS TFTP</span></a><br />
<br />
<br />
<br />
<i><span style="color: blue;">Todas las páginas alojadas en /tmp/ se encuentrar en la SDRAM , por lo que se perderán ante un reboot ó perdida de corriente del router. Para tenerlo de forma permanente, tendrás que tener el mod de SD ó tener un router con USB.</span></i><br />
<br />
<br />
<div style="text-align: justify;">El CGI (Common Gateway Interface) define una manera para que un servidor web pueda delegar la generación de páginas web a una aplicación de consola. Es el método más simple de disponer contenido dinámico en un sitio web. Es decir, si ingresamos la URL <b><span style="color: #38761d;">http://ip_router/user/cgi-bin/test.sh</span></b>, el servidor de nuestro router intentará ejecutar el archivo<span style="color: #38761d;"> <b>/tmp/www/cgi-bin/test.sh</b></span> y retornará la salida de dicho script.<br />
<br />
Veamos un ejemplo sencillo que muestra Hola Mundo!! y la fecha (obtenida del router). Creamos nuesto script en <span style="color: #38761d;"><b>/tmp/www/cgi-bin/test.sh</b></span></div><br />
<pre class="code" style="color: #38761d; margin: 0px; overflow: auto;">#!/bin/sh
echo "<html><head><title>Test CGI"
echo "</title></head><body>"
echo "<h1>Hola Mundo</h1>"
echo "Hoy es $(date)"
echo "</body></html>"
</pre><br />
Otorgamos permiso de ejecución <b style="color: red;">/tmp/www/cgi-bin # chmod +x test.sh</b><span style="color: #38761d;"><b></b></span><br />
Abrimos nuestro Navegador <b><span style="color: red;">http://<i style="color: orange;">ip_router</i>/user/cgi-bin/test.sh</span></b><br />
<br />
<i>(Lo más rápido y sencillo es trabajar con <a href="http://winscp.net/eng/download.php">WinSCP</a>)</i><br />
<br />
<br />
<br />
<br />
<br />
<br />
Ahora, veamos el ejemplo que siempre ponemos de encender/apagar un led, ya visto anteriormente <a href="http://real2electronics.blogspot.com/2009/10/linksys-arduino.html">aqui</a>.<br />
<b>1)</b> Crearemos una página web (html) <br />
<br />
<div class="separator" style="clear: both; text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2QOAyQqw7dAC8FujWVyEnkV3-JRSKDthKVpVKS-bbMlGx_aAvn4D232HK7PZli0jc9KiyPJuDTgJno7UyDECIwwUL1_qmQG-ppTn_Hj-bBtS65XGM1YUnXpqps8_YZzm31O886zQ4Br6x/s640/web_capture_led_control.JPG" /></div><br />
<b>Código</b><br />
<br />
<pre class="code" style="color: #38761d; height: 300px; margin: 0px; overflow: auto;"><html>
<head>
</head>
<body link=red vlink=red alink=red>
<div style="text-align:center;">
<img src="/user/logo.jpg">
</div>
<br/>
<div style="text-align:center;">
<span style="font-size:x-large;">
<a href="/user/cgi-bin/led_on.sh">LED ON</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<a href="/user/cgi-bin/led_off.sh">LED OFF</a>
</span>
</div>
<br/><br/><br/><br/>
<div style="color:blue;text-align:center;">
<span style="font-size:x-large;">
http://real2electronics.blogspot.com
</span></div>
</body>
</html>
</pre><br />
Contiene una foto del logo y un par de links que apuntan a los scripts led_on.sh y led_off.sh<br />
<br />
<br />
<b>2)</b> Crear el script: <b style="color: red;">led_on.sh</b><br />
<pre class="code" style="color: #38761d; margin: 0px; overflow: auto;">#!/bin/sh
echo "S1F" > /dev/cua/1
echo "<HTML>"
echo "<HEAD>"
echo "<META HTTP-EQUIV=Refresh CONTENT=0;URL=/user/control.html>"
echo "</HEAD><BODY>"
echo "</BODY></HTML>"
</pre><br />
El script envia la orden de encender por el puerto serie y redirecciona a la página principal (control.html).<br />
<br />
<b>3)</b> Crear el script: <b style="color: red;">led_off.sh</b><br />
<pre class="code" style="color: #38761d; margin: 0px; overflow: auto;">#!/bin/sh
echo "S0F" > /dev/cua/1
echo "<HTML>"
echo "<HEAD>"
echo "<META HTTP-EQUIV=Refresh CONTENT=0;URL=/user/control.html>"
echo "</HEAD><BODY>"
echo "</BODY></HTML>"
</pre><br />
El script envia la orden de apagar por el puerto serie y redirecciona a la página principal (control.html).<br />
<br />
<b>4) </b>Otorgamos permisos de ejecución a dichos scripts.<br />
<br />
<b>5)</b> Deberíamos tener una estructura asi:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyxJXadNSubQo5OUd3fwzMHw5RYPQzb83cU4obJzH97iFFNnOQjyJEa1cqqYWkHfwOvYJ9739eXZ860ieREcVJW8xVPkJQYAhoQntDHbO6Qm_3k9A1VXeQpkitRIOe2NUgQtV5_qjeXYDn/s1600-h/estructura_www.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyxJXadNSubQo5OUd3fwzMHw5RYPQzb83cU4obJzH97iFFNnOQjyJEa1cqqYWkHfwOvYJ9739eXZ860ieREcVJW8xVPkJQYAhoQntDHbO6Qm_3k9A1VXeQpkitRIOe2NUgQtV5_qjeXYDn/s640/estructura_www.JPG" /></a></div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqVrulvwbpRZdEIUDuEe6D6XMtPqO7xh_Pt8on5PvckXBlsm0W3EVCgkIDDIAEVJxvEFj7q_fl2S0SgVS5ryDUrPDndunlHh1-5crf0HfY4VlFGlwiby5P_lRpNHB2c_ymLJhQcKCxrdw7/s1600-h/estructura_www2.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqVrulvwbpRZdEIUDuEe6D6XMtPqO7xh_Pt8on5PvckXBlsm0W3EVCgkIDDIAEVJxvEFj7q_fl2S0SgVS5ryDUrPDndunlHh1-5crf0HfY4VlFGlwiby5P_lRpNHB2c_ymLJhQcKCxrdw7/s640/estructura_www2.JPG" /></a></div><br />
<b>Veamos el resultado final con un video:</b><br />
<br />
<object height="505" width="640"><param name="movie" value="http://www.youtube.com/v/IxavvRaCOKM&hl=es_ES&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/IxavvRaCOKM&hl=es_ES&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="505"></embed></object><br />
<br />
<a href="http://www.blogger.com/goog_1261322289743"><br />
</a><br />
<div style="text-align: center;"><a href="http://cid-d2ee689f353f15bc.skydrive.live.com/self.aspx/P%c3%bablico/Web%5E_Server%5E_Example.rar"><span style="font-size: large;"><b style="color: red;">PARA DESCARGA EL RAR CON TODOS LOS ARCHIVOS DE EJEMPLO, PULSA AQUI.</b></span></a></div><br />
<br />
<br />
<br />
<span style="font-size: large;">Ahora ya sólo imaginación.... ¿qué tal subir/bajar la puerta del garage mediante Wifi y un móvil? Ya he probado a conectarme con mi nokia n85 y va perfecto!! ...je,je,je</span><br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi62nLdm5ZNmm-9E-vwwTB6XDdv3LBBQ9CUaXS6sPEBz-9o4TOWN6FdW1nb2kqTv_8tu-2ZdP_B9_7mj2n9iqDZYeOrDGwbArJ_uesVtDYW1hXj_NKkNDKI7f4_nBOiNU9gtQEIRTrGHRDM/s640/Linkduino.jpg" /></div><br />
<br />
<br />
<br />
<br />
<br />
.Igorhttp://www.blogger.com/profile/07332255486737492708noreply@blogger.com13tag:blogger.com,1999:blog-5229899856062584712.post-33325586156461982682009-12-09T11:43:00.000-08:002011-01-18T06:22:17.949-08:00LINKDUINO: Twitter<div style="color: white;">.<br />
</div><script src="http://www.gmodules.com/ig/ifr?url=http://www.google.com/ig/modules/translatemypage.xml&up_source_language=es&w=160&h=60&title=&border=&output=js">
</script><br />
<br />
<br />
Primero, poner el link de mi fuente de inspiración<a href="http://www.themagicclock.com/"> http://www.themagicclock.com/</a><br />
<br />
Veamos un sencillo ejemplo de cómo sacarle más partido a éste hardware. (Asumimos que tienes instalado <a href="http://www.dd-wrt.com/">DD-WRT</a>, con el hack del puerto serie e interfaz apropiada para cambiar niveles 3v3 a 5 voltios y tu router tiene conexión a internet).<br />
<br />
Crearemos un script sencillo en el <a href="http://es.wikipedia.org/wiki/Bash">bash</a> del router, el cual se conecta a la página <a href="http://es.wikipedia.org/wiki/Extensible_Markup_Language">xml</a> de una cuenta <a href="http://twitter.com/">Twitter</a> y obtiene el "status" actual de dicho usuario. Una vez obtenido, enviará dicho status a nuestro Arduino por puerto serie.<br />
Para ello, nuestro Arduino contendrá el programa de ejemplo explicado anteriormente <a href="http://real2electronics.blogspot.com/2009/10/linksys-arduino.html">aqui</a> (mini protocolo serie).<br />
<br />
En este caso concreto, según el status del usuario:<br />
<ul><li>Si status = S1F, entonces activará el pin 13.</li>
<li>Si status = S0F, entonces desactivará el pin 13.</li>
</ul>En el ejemplo, uso la cuenta Twitter de éste blog => <a href="http://twitter.com/users/show/real2electronic.xml">http://twitter.com/users/show/real2electronic.xml</a><br />
Podemos ver, que el status actual se encuentra entre <b style="color: red;"><text></text></b>las etiquetas <b style="color: red;">text</b>. <br />
<br />
El código de nuestro script es:<br />
<br />
<pre class="code" style="height: 300px; margin: 0px; overflow: auto; width: auto;">#!/bin/sh
while true
do
ping www.google.es -c 4
URL="http://twitter.com/users/show/real2electronic.xml"
contenido=`wget -q -O - $URL|grep \<text|sed -e s/\<text\>//g -e s:\</text\>::g`
echo $contenido
echo $contenido > /dev/cua/1
for i in 1 2 3 4 5
do
gpio disable 7
sleep 1
gpio enable 7
sleep 1
done
done
</pre><div style="text-align: center;"><br />
</div><div style="text-align: center;"><br />
</div><div style="text-align: center;"><b><a href="http://cid-d2ee689f353f15bc.skydrive.live.com/self.aspx/P%c3%bablico/twitter.sh"><span style="color: red;">PULSA AQUÍ PARA DESCARGAR EL SCRIPT</span></a></b><br />
</div><br />
<br />
<b>1)</b> Es script realiza un ping para forzar conexión con internet.<br />
<b>2)</b> Obtiene la página, y extrae la linea que se encuentra entre <b style="color: red;"><text></b> y <b style="color: red;"></text></b><br />
<b>3)</b> Muestra y envia por puerto serie dicha cadena<br />
<b>4)</b> Realiza un bucle de encendido/apagado del led de DMZ del router.<br />
<br />
Para escribir dicho script, puedes hacerlo mediante <a href="http://es.wikipedia.org/wiki/Vi">vi</a> (conectandote por telnet al router), o bien enviarlo usando <a href="http://www.winscp.net/">WinSCP</a>. Para usar este último,sigue instrucciones de <a href="http://www.dd-wrt.com/wiki/index.php/WinSCP">http://www.dd-wrt.com/wiki/index.php/WinSCP</a><br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgJ_QTE332B_7jb7EI2MoGKRUrrzgrCq54QU1WpsJjoHom-5WRYhpbYDrUPVB1JKjOxVNJLjeriii_ElXW73ms_ikzVD5UN6ZWCdyrU2u5aeuvqTThL6FkF22Q-H_YytI4H6jfeDfa-F8F/s1600-h/WinSCP.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgJ_QTE332B_7jb7EI2MoGKRUrrzgrCq54QU1WpsJjoHom-5WRYhpbYDrUPVB1JKjOxVNJLjeriii_ElXW73ms_ikzVD5UN6ZWCdyrU2u5aeuvqTThL6FkF22Q-H_YytI4H6jfeDfa-F8F/s640/WinSCP.JPG" /></a><br />
</div><br />
<br />
<div style="color: red;"><b>Algo curioso que he descubierto haciendo el script, es que no se pueden realizar más de 150 peticiones a la hora a la página xml de Twitter, asi que se debe modificar dicho script con un sleep de mayor duración. No lo he modificado, para que no sea pesado a la hora de probarlo.<br />
</b><br />
</div><br />
Copia ó crealo con <b>vi</b> dicho script en el directorio /tmp/, el cual tiene permisos de escritura.<br />
Dale permisos de ejecución al archivo: <b><span style="color: #38761d;">chmod 755 script_name</span></b>, por ejemplo chmod 755 twitter.sh.<br />
Para ejecutar en segundo plano: <b><span style="color: #38761d;">root@DD-WRT:/tmp# ./twitter.sh &</span></b><br />
<b><span style="color: #38761d;"> </span></b> <br />
Recuerda, que dicha estructura de carpetas es RAM y perderás el script cuando reinicie el router.<br />
Si quieres que permanezca en memoria =><a href="http://www.dd-wrt.com/wiki/index.php/Startup_Scripts#NVRAM_Method"> http://www.dd-wrt.com/wiki/index.php/Startup_Scripts#NVRAM_Method </a><br />
<br />
<b><span style="color: #38761d;"></span></b><br />
<br />
<b>A continuación, un video tutorial de todo el proceso:</b><br />
<br />
<b><object height="505" width="640"><param name="movie" value="http://www.youtube.com/v/L1P_MnL3884&hl=es_ES&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/L1P_MnL3884&hl=es_ES&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="505"></embed></object> </b><br />
<br />
<br />
<br />
<br />
<br />
<div style="color: red;"><b>Ahora ya puedes abrir/cerrar una puerta, encender/apagar una caldera, activar una bocina para asustar a tu pareja ... lo que se te ocurra desde Twitter !!!</b><br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi62nLdm5ZNmm-9E-vwwTB6XDdv3LBBQ9CUaXS6sPEBz-9o4TOWN6FdW1nb2kqTv_8tu-2ZdP_B9_7mj2n9iqDZYeOrDGwbArJ_uesVtDYW1hXj_NKkNDKI7f4_nBOiNU9gtQEIRTrGHRDM/s640/Linkduino.jpg" /><br />
</div><br />
<br />
<br />
<br />
<br />
<br />
<b>. <br />
</b><br />
</div>Igorhttp://www.blogger.com/profile/07332255486737492708noreply@blogger.com0tag:blogger.com,1999:blog-5229899856062584712.post-2034717824532198252009-11-30T15:44:00.000-08:002011-01-18T06:22:17.951-08:00Graficar con Kst<div style="color: white;">.<br />
</div><script src="http://www.gmodules.com/ig/ifr?url=http://www.google.com/ig/modules/translatemypage.xml&up_source_language=es&w=160&h=60&title=&border=&output=js">
</script><br />
<br />
<br />
<br />
<br />
Veamos la forma más sencilla (que he encontrado hasta ahora) de graficar datos recibidos de nuestro Arduino en "real time". Tiene la ventaja sobre excel, que está preparado para trabajar con gran cantidad de datos, ya que excel está limitado a 32.000 puntos en gráficos 2D.<br />
Otra gran ventaja... es gratuito!! Se encuentra disponible para entorno Windows y Linux.<br />
<br />
Para ello nos ayudaremos de dos softwares gratuitos:<br />
<ul><li><b>Realterm</b> => <a href="http://realterm.sourceforge.net/">http://realterm.sourceforge.net/</a><br />
</li>
<li><b>KST </b> => <a href="http://kst.kde.org/">http://kst.kde.org/</a> (Linux y Windows)<br />
</li>
</ul><i>Si se trabaja con linux, no se necesita Realterm, ya que se puede capturar directamente todo lo recibido por el puerto serie a un archivo.</i><br />
<i></i><br />
<br />
Según la propia web: "<b style="color: red;"> Kst</b><span style="color: red;"> es la herramienta más rápida para graficar gran volumen de datos en real-time y con funcionalidades básicas para el análisis.</span>"<br />
Gracias a KST, dispondremos de posibilidad de disponer varias vetanas, múltiples gráficas, <a href="http://en.wikipedia.org/wiki/Spectral_density"><b style="color: blue;">PSD</b></a>, zoom, histogramas, ...<br />
Ejemplo demo de pantalla (extraido de la web de Kst):<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhs1P5bCbpfaAjg-5UNEWybOTPTX5sVE7OwPOrGPbmmJcFetvUEU2_SsqZZ1oUTyx0_9kN-qJIXKHiLYuRDOHUw6zRlA6EQ1bs2aEgaIqgtU-i1a9_T2ZcA-7KfzIQ1LKoxz3r7TOBskZf6/s1600/kstdemo.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhs1P5bCbpfaAjg-5UNEWybOTPTX5sVE7OwPOrGPbmmJcFetvUEU2_SsqZZ1oUTyx0_9kN-qJIXKHiLYuRDOHUw6zRlA6EQ1bs2aEgaIqgtU-i1a9_T2ZcA-7KfzIQ1LKoxz3r7TOBskZf6/s640/kstdemo.JPG" /></a><br />
</div><br />
<br />
<br />
La idea es:<br />
<div style="color: blue;"><b>1) Usar Realterm para capturar todo lo recibido por el puerto serie a un archivo de texto.</b><br />
</div><div style="color: blue;"><b>2) Plotear dicho archivo de texto con la ayuda de KST.</b><br />
</div><br />
En Realterm sólo tenemos que abrir el puerto serie correnspondiente a nuestro Arduino.<br />
Mi programa de ejemplo de Arduino, esta preparado para enviar datos de forma continua, cuando se recibe una "C" y detener el envio, cuando se recibe una "F".<br />
<pre> </pre><pre> </pre><b><span style="color: #6aa84f;">--------- CÓDIGO ARDUINO ---------</span> <br />
</b><br />
<pre>extern volatile <span style="color: #cc6600;">unsigned</span> <span style="color: #cc6600;">long</span> timer0_overflow_count;
<span style="color: #cc6600;">float</span> fanalog0;
<span style="color: #cc6600;">int</span> analog0;
<span style="color: #cc6600;">unsigned</span> <span style="color: #cc6600;">long</span> tiempo;
<span style="color: #cc6600;">byte</span> serialByte;
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><b>setup</b></span>() {
<span style="color: #cc6600;">Serial</span>.<span style="color: #cc6600;">begin</span>(9600);
<span style="color: #cc6600;">Serial</span>.<span style="color: #cc6600;">println</span>(<span style="color: #006699;">"Empezamos..."</span>);
}
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><b>loop</b></span>()
{
<span style="color: #cc6600;">while</span> (<span style="color: #cc6600;">Serial</span>.<span style="color: #cc6600;">available</span>()>0){
serialByte=<span style="color: #cc6600;">Serial</span>.<span style="color: #cc6600;">read</span>();
<span style="color: #cc6600;">if</span> (serialByte==<span style="color: #006699;">'C'</span>){
<span style="color: #cc6600;">while</span>(1){
analog0=<span style="color: #cc6600;">analogRead</span>(0);
<span style="color: #7e7e7e;">// Convierto a milivoltios</span>
fanalog0=(analog0)*(5000.0/1023);
<span style="color: #7e7e7e;">// Recojo ticks del timer0 => 1 tick cada 4 us (usado en millis )</span>
tiempo=(timer0_overflow_count << 8) + TCNT0;
<span style="color: #7e7e7e;">// Convierto a us</span>
tiempo=tiempo*4;
<span style="color: #7e7e7e;">//Lo envio para simular archivo tipo *.csv</span>
<span style="color: #cc6600;">Serial</span>.<span style="color: #cc6600;">print</span>(tiempo);
<span style="color: #cc6600;">Serial</span>.<span style="color: #cc6600;">print</span>(<span style="color: #006699;">';'</span>,<span style="color: #006699;">BYTE</span>);
<span style="color: #cc6600;">Serial</span>.<span style="color: #cc6600;">println</span>(fanalog0,<span style="color: #006699;">DEC</span>);
<span style="color: #cc6600;">if</span> (<span style="color: #cc6600;">Serial</span>.<span style="color: #cc6600;">available</span>()>0){
serialByte=<span style="color: #cc6600;">Serial</span>.<span style="color: #cc6600;">read</span>();
<span style="color: #cc6600;">if</span> (serialByte==<span style="color: #006699;">'F'</span>) break;
}
}
}
}
}
</pre><b><span style="color: #6aa84f;">--------- FIN DEL CODIGO ---------</span> <br />
</b><br />
<br />
<br />
<br />
Por lo que en la pestaña <b>Send</b>, le enviaremos el caracter ASCII => C<br />
Veremos como empezamos a ver en la parte superior los datos recibidos.<br />
Después en la pestaña <b>Capture</b>, seleccionar la ruta del archivo donde se capturan los datos y pulsamos <b>Start Overwrite</b>. Si <b>Direct Capture</b> está seleccionado, dejaremos de ver los datos recibidos (acelera el proceso).<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifY14XXfB3gZgnfz_YD_JikRJZ4KPXv5L8JntjdCgVfmQlFtAMYQd968BPaLyTZjiqPefqZBRsy6uLb_pI1N3vt5yPNyx_2IFxpx9c-PHBEjAeE6a24_LJ1lafweOzHFxbZPbHoJotYmYR/s1600/Realterm_Configuration.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifY14XXfB3gZgnfz_YD_JikRJZ4KPXv5L8JntjdCgVfmQlFtAMYQd968BPaLyTZjiqPefqZBRsy6uLb_pI1N3vt5yPNyx_2IFxpx9c-PHBEjAeE6a24_LJ1lafweOzHFxbZPbHoJotYmYR/s640/Realterm_Configuration.JPG" /></a><br />
</div><div style="text-align: center;"><span style="color: red;">(click sobre la imagen para ver en tamaño completo)</span><br />
</div><br />
<br />
Ahora con el archivo creado y actualizandose con los datos recibidos, sólo nos queda irnos a Kst.<br />
Alli, pulsamos sobre<b> Data Wizard</b> y elegimos la ruta donde se encuentra nuestro archivo.<br />
En <b>Configure</b>, elegimos cual es nuestro limitador de columnas, en mi ejemplo " <b>;</b> ".<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHvW9DBV3YT35kTwiYYGtwBLjUKuyEJo9Itdxa70GrahhYLW7APw5fk4QH70JRXA8NY47cabwOt2hw_xYR7vM1pb3R7dsM7r2CsP6UtaRUYEUBYIYvOSZjj9XMf9XiZjtflCsuilKQxHIC/s1600/Configure_KST.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHvW9DBV3YT35kTwiYYGtwBLjUKuyEJo9Itdxa70GrahhYLW7APw5fk4QH70JRXA8NY47cabwOt2hw_xYR7vM1pb3R7dsM7r2CsP6UtaRUYEUBYIYvOSZjj9XMf9XiZjtflCsuilKQxHIC/s640/Configure_KST.JPG" /></a><br />
</div><div style="text-align: center;"><span style="color: red;">(click sobre la imagen para ver en tamaño completo)</span><br />
</div><br />
En las siguientes pantallas, configuramos que queremos crear una gráfica siendo X la primera columna (tiempo en us) e Y la segunda columna (mV entrada analógica 0).<br />
<br />
<br />
Ya tenemos nuestro gráfico!!! el cual se irá actualizando a la medida que se vayan recibiendo nuevos datos (hay un pequeño retraso, no es instantaneo).<br />
A continuación, un ejemplo de una señal capturada de un potenciómetro, para realizar este pequeño tutorial.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCsXNPY-5glafH5F4kE1W_SC1Rk5IM_18Aw03utbKwsWrpxUq82SrKpclDVO0pYC6-0WnydlxL2gDl6pwNWaBUjIcmEOjyan8YE1EcxsbhxkxKeFoj1Eie7drodZRpbsIzChQb-nM6zJLI/s1600/KST_Final.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCsXNPY-5glafH5F4kE1W_SC1Rk5IM_18Aw03utbKwsWrpxUq82SrKpclDVO0pYC6-0WnydlxL2gDl6pwNWaBUjIcmEOjyan8YE1EcxsbhxkxKeFoj1Eie7drodZRpbsIzChQb-nM6zJLI/s640/KST_Final.JPG" /></a><br />
</div><div style="text-align: center;"><span style="color: red;">(click sobre la imagen para ver en tamaño completo)</span><br />
</div><br />
<br />
Podremos usar Kst para ver los datos en real-time ó abrir datos grabados anteriormente.<br />
Veamos un video demostrativo:<br />
<br />
<object height="505" width="640"><param name="movie" value="http://www.youtube.com/v/FgwOgb73lrE&hl=es_ES&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/FgwOgb73lrE&hl=es_ES&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="505"></embed></object><br />
<br />
<br />
<br />
<br />
<br />
<br />
Espero que sea de utilidad este mini-tutorial.<br />
<br />
<br />
<span style="color: white;">. </span>Igorhttp://www.blogger.com/profile/07332255486737492708noreply@blogger.com31tag:blogger.com,1999:blog-5229899856062584712.post-56543260228450468082009-11-15T01:51:00.000-08:002011-01-18T06:22:17.953-08:00LINKDUINO<div style="color: red; font-family: Verdana,sans-serif; text-align: center;"><br />
<span style="font-size: x-large;"><b>Rapid Prototyping Hardware</b></span><br />
</div><br />
<br />
<br />
<span style="color: white;">.</span><code><br />
<script src="http://www.gmodules.com/ig/ifr?url=http://www.google.com/ig/modules/translatemypage.xml&up_source_language=es&w=160&h=60&title=&border=&output=js">
</script> </code><br />
<br />
<div style="text-align: center;"><a href="http://cid-d2ee689f353f15bc.skydrive.live.com/self.aspx/P%C3%BAblico/Linkduino%20brochure.pdf" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9kd75Q2N7PxcPoJRrWR2DyFdINSGg4YQqFSBIkt7PprABnoBR_Y7czRLs9xm8vHDh5ZYeeu13vOOK3L_I4s5OMpa7WQjvZQnziKMQNSmUbyXQyeZX0Pn0gc3BT7Mf136R8B-fQM0j6uWc/s400/Get+Document.png" /></a><span style="font-size: large;"><a href="http://cid-d2ee689f353f15bc.skydrive.live.com/self.aspx/P%C3%BAblico/Linkduino%20brochure.pdf"><b> CLICK TO DOWNLOAD ENGLISH BROCHURE</b></a></span><br />
</div><br />
<br />
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjopXWPXGSQPSaITAO360wxlmPvRAZ2TpLVwmPSIE0TCJ2wuHepUlxyH3biHv2WOC1td8ayQ3lcH_JpV0IfVoujy-LoD8zF391JKFCeZUjlg8BtdixehZCAdVQG5gG8RB4DTxIKC324OfXF/s1600-h/Rapid_Prototype_Blog.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjopXWPXGSQPSaITAO360wxlmPvRAZ2TpLVwmPSIE0TCJ2wuHepUlxyH3biHv2WOC1td8ayQ3lcH_JpV0IfVoujy-LoD8zF391JKFCeZUjlg8BtdixehZCAdVQG5gG8RB4DTxIKC324OfXF/s640/Rapid_Prototype_Blog.jpg" /></a><br />
</div><br />
<br />
Como ingenieros de sistemas, conocemos perfectamente lo valioso que es el tiempo y lo exigente que es la industria privada cuando se requiere una solución.<br />
<br />
El tiempo es dinero, y el poder poner en práctica lo que tienes en mente, sin tener que pasar horas buscando una plataforma adecuada, hace que al final, tu solución no sea competitiva.<br />
<br />
Además, es muy importante que el tiempo de aprendizaje necesario para poder obtener resultados tangibles, sea corto.<br />
<br />
Una de las cosas que más importancia tiene a la hora de elección, es el hecho de disponer soporte técnico y ejemplos de aplicación.<br />
<br />
Por todas estas razones, ofrecemos una plataforma basada en hardware/software libre, en la que existe una gran comunidad por detrás, y en la que hay multitud de recursos en la red.<br />
<br />
<br />
Los requisitos que hemos exigido son:<br />
<br />
<ul><li>Open hardware.</li>
<li>Sin licencias software.</li>
<li>Low cost.</li>
<li>Rápida línea de aprendizaje en su uso.</li>
<li>Documentación.</li>
<li>Comunicaciones: CAN, RS232, RS485, Ethernet, Wifi, Internet.</li>
<li>Todos los componentes, por si solos, deben tener una comunidad por detrás.</li>
<li>Programación en alto nivel.</li>
<li>Posibilidad de almacenaje de datos.</li>
<li>Interface con los principales software: Matlab/Simulink, Excel, Labview, PHP, MySQL, Scilab,… (Todas ellas marcas registradas).</li>
<li>No debe ser motivo de obsesión, ser la herramienta hardware más potente del mercado, ya que su objetivo no es el mismo.</li>
<li>Lo más abierta posible, buscando abarcar el máximo de sectores industriales.</li>
<li>Librerías y/o ejemplos básicos, para que en la mayoría de aplicaciones, el usuario tenga el 80% del trabajo realizado.</li>
<li>Posibilidad de profundizar y exprimir al máximo posible en caso de necesitarlo.</li>
</ul><br />
<br />
<br />
<span style="font-size: large;"><b style="color: red;">LINKDUINO</b></span><br />
<ul><li>Router WRT54GL con mod para SD/MMC ó similar.<br />
</li>
<li>ATMega1280 (basado en proyecto Arduino).</li>
<li>Hardware para disponer de RS485 y bus CAN.</li>
<li>Posibilidad de expandir con gps, lcd, glcd, ...<br />
</li>
</ul>De ésta unión, conseguimos disponer de un dispositivo de altísima potencia, del que nos podemos aprovechar de la cantidad de recursos existentes:<br />
<br />
<ul><li>DD-WRT: Eleva con este firmware las características del router a niveles profesionales.</li>
<li>Arduino IDE</li>
<li>Putty</li>
<li>RealTerm</li>
<li>WinSCP: Facilita la transferencia segura de archivos entre dos sistemas informáticos, el local y uno remoto que ofrezca servicios <acronym>SSH</acronym>. Descarga drag&drop archivos grabados en tu router.</li>
<li>NetCom OCX</li>
<li>Ostrosoft Winsock Component</li>
<li>... y muchos más.</li>
</ul><br />
Combina la potencia de tener un sistema operativo Linux, junto a la programación en "bajo nivel" del micro ATmega. Tus ideas quedarán rápidamente materializadas. Siempre buscando la sencillez, para alcanzar el objetivo marcado.<br />
<br />
<div style="color: red;">- Configura tu red Ethernet/Wifi gracias a la potente interface web. Sin necesidad de conocimiento de comandos unix.<br />
</div><div style="color: red;">- Olvídate de bajos niveles de programación TCP/IP ó de red.<br />
</div><div style="color: red;">- Crea web embebida en tu dispositivo, usando html,php,ajax,... <br />
</div><div style="color: red;">- Vuelca datos en SD/MMC,en la memoria de tu router ó en un equipo de tu red.<br />
</div><div style="color: red;">- Añade hardware necesario para cubrir tus necesidades gracias a las múltiples I/O, entradas analógicas, SPI, I2C, uarts,... <br />
</div><div style="color: red;">- Conecta con los aparatos industriales gracias a RS232, RS485 ó CAN.<br />
- Amplia cobertura wireless, añadiendo otros routers (WDS).<br />
</div><div style="color: red;">- Utiliza la multitud de librerias y ejemplos que existen por la red.<br />
</div><br />
<br />
<br />
<b>Algunos ámbitos de uso, podrían ser:</b><br />
- Realización de software para el control, configuración y monitorización de variadores de potencia, analizadores eléctricos, maquinas frigoríficas, ventiladores, ...<br />
- Sistema domóticos, de riego, alarmas, ...<br />
- Telemetría para bancos de ensayos.<br />
- Monitorización de procesos.<br />
- Control de flotas. <br />
- Obtención de datos de procesos industriales y almacenaje en bases de datos en red (SQL).<br />
- Estaciones meteorológicas remotas.<br />
- Creación de simuladores para el testeo de maquinas, centralitas,... <br />
- Añade conectividad a tus proyectos.<br />
- Tests automoción <br />
- etc...<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<div style="color: blue;">¿Quieres que te ayudemos para comenzar en tu proyecto con este hardware?<br />
</div><div style="color: blue;">¿No dispones de tiempo para crear el hardware por ti mismo y deseas que te lo proporcionemos listo para empezar?<br />
</div><div style="color: blue;">¿Tienes ideas para mejorar el sistema? => Publica tu comentario (evitar Anónimo).<br />
</div><div style="color: blue;">¿Quieres contarnos tus experiencias? => Publica tu comentario (evitar Anónimo).<br />
</div><div style="color: blue;">¿Quieres expresarnos ánimo para seguir adelante con la idea? => Publica tu comentario (evitar Anónimo). <br />
</div><div style="color: blue;">¿Quieres mostrar el proyecto que has realizado con LINKDUINO ó similar?<br />
</div><br />
<div class="separator" style="clear: both; text-align: center;"><b style="color: red;">CONTACTA POR EMAIL</b><br />
</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjL1_dB6L3jVXijjgDT_9qFg4QXyaj26Wz7y4AMLqx9359gayX8G1A7xNcEaE7wNaRKk1FV9xIDT0Kia2nyEk9A3xpq8fXXyV6jcygEPHre6IzEdlidn-YM8F3TQvvsffXu0RPJg4Bej_1U/s1600-h/mail_logo.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjL1_dB6L3jVXijjgDT_9qFg4QXyaj26Wz7y4AMLqx9359gayX8G1A7xNcEaE7wNaRKk1FV9xIDT0Kia2nyEk9A3xpq8fXXyV6jcygEPHre6IzEdlidn-YM8F3TQvvsffXu0RPJg4Bej_1U/s640/mail_logo.JPG" /></a><br />
</div><br />
<br />
<div style="text-align: justify;"><span style="font-size: large;"><b><i><span style="color: blue;">Se irán añadiendo periódicamente ejemplos creados con LINKDUINO, prevaleciendo la sencillez y rapidez para la puesta en marcha</span></i></b></span><span style="font-size: large;"><b><i><span style="color: blue;">.</span></i></b></span><span style="font-size: large;"><b><i><span style="color: blue;"> Usa el menu izquierdo para navegar por el contenido de la web.</span></i></b></span><br />
</div><br />
<br />
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><br />
</div><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi62nLdm5ZNmm-9E-vwwTB6XDdv3LBBQ9CUaXS6sPEBz-9o4TOWN6FdW1nb2kqTv_8tu-2ZdP_B9_7mj2n9iqDZYeOrDGwbArJ_uesVtDYW1hXj_NKkNDKI7f4_nBOiNU9gtQEIRTrGHRDM/s640/Linkduino.jpg" /><br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://twitter.com/real2electronic" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjF99R2GrMLx1bQ5BOdwacsoRMCYaQ-v-hUBoof6SsIv63jBCA6wGF-eKaHODb_PN1zaHr0CDqMramNtG-todcxuCb3fZJWiWvDlX7JLed3iroFEj7OtDSro43WG5-NFF8HIFabRixVQiL0/s320/twitter.JPG" /></a><br />
</div><br />
<div style="text-align: center;"><b style="color: red; font-family: Georgia,"Times New Roman",serif;">Síguenos con Twitter</b><br />
</div><br />
<br />
<br />
<br />
<br />
<br />
<ul></ul>Igorhttp://www.blogger.com/profile/07332255486737492708noreply@blogger.com0tag:blogger.com,1999:blog-5229899856062584712.post-12608671845951846232009-10-18T12:27:00.000-07:002011-01-18T06:22:17.954-08:00LINKDUINO: Linksys + Arduino + Excel-Telnet<span style="color: white;">.</span><code><br />
<script src="http://www.gmodules.com/ig/ifr?url=http://www.google.com/ig/modules/translatemypage.xml&up_source_language=es&w=160&h=60&title=&border=&output=js">
</script> </code><br />
<br />
<span style="color: white;"> </span> <br />
Veremos como conectar este magnifico router junto a Arduino. Hasta ahora, siempre habia utilizado este router para crear redes WDS ó como repetidor universal. <br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2I_sGy32e0cS025ZNobjgxfk4kT2MCbRfZ41mxu2PlhdHMtaRkeiSX_KbvQ-hU8A-r3_4ayeNn3P9kihTlhEaEdoaCv7_kYTUXOTJP7PZjv08ZrmMRQPtuQLT2VmVhOGC5DZW7XMNYrlG/s1600-h/Repetidor+WIFI.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2I_sGy32e0cS025ZNobjgxfk4kT2MCbRfZ41mxu2PlhdHMtaRkeiSX_KbvQ-hU8A-r3_4ayeNn3P9kihTlhEaEdoaCv7_kYTUXOTJP7PZjv08ZrmMRQPtuQLT2VmVhOGC5DZW7XMNYrlG/s640/Repetidor+WIFI.JPG" /></a><br />
</div><div style="text-align: center;"> <i><span style="color: red;">Repetidor externo gracias a WRT54GL en una caja con IP65: apto para alimentación 220v ó con batería 12v </span></i> <br />
</div><div style="color: white;">.<br />
</div><br />
<br />
<br />
La ventaja de este router, es la de disponer de linux en su interior y ésto ha creado una gran comunidad, la cual ha desarrollado nuevos firmwares, que añaden multitud de ventajas respecto al original. Haciendo que este router de consumo no tenga nada que envidiar a equipos profesionales.<br />
Uno de ellos es DD-WRT (<a href="http://www.dd-wrt.com/">http://www.dd-wrt.com</a>)<br />
<br />
Buscando por la red información, encontré multitud de proyectos que lo usaban, llamandome la atención el poder usar el puerto serie del micro (Broadcom BCM5352).Véase: <a href="http://ahorcandoeltiempo.blogspot.com/search/label/Arduino">http://ahorcandoeltiempo.blogspot.com/search/label/Arduino</a><br />
<br />
Existe un libro de cómo hackearlo: <br />
<ul><li><a href="http://books.google.com/books?id=GBtJdvMeAJQC&printsec=frontcover&hl=es&source=gbs_v2_summary_r&cad=0#v=onepage&q=&f=false">http://books.google.com/books?id=GBtJdvMeAJQC&printsec=frontcover&hl=es&source=gbs_v2_summary_r&cad=0#v=onepage&q=&f=false</a></li>
<li><a href="http://www.amazon.com/Linksys-WRT54G-Ultimate-Hacking-Asadoorian/dp/1597491667">http://www.amazon.com/Linksys-WRT54G-Ultimate-Hacking-Asadoorian/dp/1597491667</a><br />
</li>
</ul><br />
No hace falta explicar aquí como se debe cambiar el software ó el pin-out del puerto serie, ya que existe multitud de información en la red, pero sólamente recalcar el hecho de tener primero que instalar la version mini ó micro de firmware, antes que cualquier otra. <b style="color: red;">La salida serie del router Linksys es 3v3 y la del arduino es 5v...CUIDADO!!</b><br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgz0jpUave9IUQKlCdizH6qiGxX3jnKF-D5G_dzaqFAemTIvHYDkzqvMmYmrPaUeKEko8EHGjCBzb1LfTMx_8KcpLP-a_AJE0Y57n2Om0Nb9ndVh9yfI2xafR0R28Z-F_r7FftWDRMepGVT/s1600-h/Linksys+y+Arduino.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgz0jpUave9IUQKlCdizH6qiGxX3jnKF-D5G_dzaqFAemTIvHYDkzqvMmYmrPaUeKEko8EHGjCBzb1LfTMx_8KcpLP-a_AJE0Y57n2Om0Nb9ndVh9yfI2xafR0R28Z-F_r7FftWDRMepGVT/s400/Linksys+y+Arduino.JPG" /></a><br />
</div><br />
<div style="text-align: center;"><b><span style="color: red;">WRT 54 GL v1.1 + Arduino</span></b><br />
</div><br />
<br />
Una vez con el firmware instalado, nos podemos conectar al shell del router mediante telnet ó ssh. Para ello podemos usar el <a href="http://www.putty.org/">putty</a>. El usuario y contraseña por defecto una vez instalado el dd-wrt es: <span style="color: blue;"><b>User</b>:</span><b>root</b> y <b><span style="color: blue;">Password:</span>admin</b>.<br />
<br />
Ahora, abrimos dos sesiones de telnet del router (Rx y Tx):<br />
<span style="color: red; font-size: small;"><b>+</b></span> En la primera, sacaremos toda la información del puerto serie al shell. Para ello usaremos:<br />
<div style="text-align: center;"><b style="color: blue;">cat < /dev/cua/1</b><span style="color: red; font-size: small;"><b> </b></span><br />
</div><div style="text-align: left;"><span style="color: red; font-size: small;"><b>+</b></span> En la segunda, enviaremos las cadenas de texto que queramos al puerto serie.<br />
</div><div style="color: blue; text-align: center;"><b>echo cadenaaenviar > /dev/cua/1</b><br />
</div><br />
<br />
En el ejemplo que he realizado, en la parte Arduino se programa un simple prótocolo serie, en el que al recibir una pequeña trama, encienda ó apague un led. Las ordenes serán <b><span style="color: red;">S1F</span></b> ó <b style="color: red;">S0F</b>.<br />
Veamos un diagrama de flujo del programa:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYI7tPD79aTeXjsw4dbxS1jMaFBxFsM4fvltr7B4fXLSHjL3Xb_j8Ogqv4VStS2Qg1vaXE6XFCCEF2ktpPrywr0AlAPNBvJC10vbUtM9Gnc6njNZdJuqtCwzQIo3tEMz6BaB0ush0-bGVR/s1600-h/flowchart.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYI7tPD79aTeXjsw4dbxS1jMaFBxFsM4fvltr7B4fXLSHjL3Xb_j8Ogqv4VStS2Qg1vaXE6XFCCEF2ktpPrywr0AlAPNBvJC10vbUtM9Gnc6njNZdJuqtCwzQIo3tEMz6BaB0ush0-bGVR/s640/flowchart.JPG" /></a><br />
</div><br />
<div style="color: red;"><b>Por supuesto que podría mejorarse, pero vamos paso a paso... Ya que no se contempla rutinas de salida cuando se reciben carácteres no esperados ó por exceso de tiempo, checksum,...<br />
</b><br />
</div><br />
Aquí adjunto el programa de arduino:<br />
<br />
<br />
<b>Code:</b><br />
<pre class="code" style="height: 300px; margin: 0px; overflow: auto; width: auto;">//Mini protocolo serie
//Igor Real
int luz1= 13;
int el1;
int estado=0;
byte dato_recibido;
void setup() {
pinMode(luz1, OUTPUT);
pinMode(12, OUTPUT);
digitalWrite(12,LOW);
Serial.begin(9600);
}
void loop()
{
//trama a recibir --> S1F o 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;
}
if (((dato_recibido=='1')||(dato_recibido=='0')) && estado==1){
estado=2;
if (dato_recibido=='1') el1=1;
if (dato_recibido=='0') el1=0;
}
if (dato_recibido=='F' && estado==2){
estado=0;
digitalWrite(luz1,el1);
if (el1==0) Serial.println("APAGADO");
if (el1==1) Serial.println("ENCENDIDO");
}
}
}
</pre><br />
En mi montaje, el led va unido entre el pin 12 (cátodo) y 13 (ánodo).<br />
<br />
<br />
<br />
A continuación, veremos una captura de pantalla de los dos shell abiertos contra el router. En la superior vemos los que nos contesta Arduino, y en la inferior le enviamos las ordenes.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtXju-PFAcsDjqZ_FcNYDiBXTeSPZyM4eKFB6s8az-Jn4oSSi5luKbnHkrowf9q6lym2iY2LvSKwfaEHYPb4FSI0eGu7qvTkmpLTMfoGYtGtmckZfBVMJIqDCDYuKm60JPuGBAwOLZFPck/s1600-h/Captura+Putty.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtXju-PFAcsDjqZ_FcNYDiBXTeSPZyM4eKFB6s8az-Jn4oSSi5luKbnHkrowf9q6lym2iY2LvSKwfaEHYPb4FSI0eGu7qvTkmpLTMfoGYtGtmckZfBVMJIqDCDYuKm60JPuGBAwOLZFPck/s640/Captura+Putty.JPG" /></a><br />
</div><div style="text-align: center;"><i><span style="color: red;">(click para ampliar)</span></i><br />
</div><br />
<br />
Y sólo nos queda ver el video funcionando.... Curioso en la electrónica, que todo se resume en encender/apagar leds de diferentes formas....je,je,je<br />
<br />
<br />
<br />
<div style="text-align: center;"><object height="505" width="640"><param name="movie" value="http://www.youtube.com/v/RlqnFY9nutQ&hl=es&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/RlqnFY9nutQ&hl=es&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="505"></embed></object><br />
</div><br />
<br />
<br />
Ahora, por la parte de PC, nos queda hacer una aplicación un poco más vistosa. Ya que no es muy profesional usar el putty y trabajar en modo comandos...<br />
<br />
Veamos como darle conectividad mediante Excel, lo cual nos añade un potencial grandísimo.<br />
<b>1)</b> Para poder conectarnos a telnet con Excel, nos podemos descargar la libreria COM gratuita <b style="color: red;">Ostrosoft Winsock Component</b> => <a href="http://www.ostrosoft.com/oswinsck.asp">http://www.ostrosoft.com/oswinsck.asp</a><br />
<b>2)</b> Seguir las instrucciones de la web para registar la libreria.<br />
<b>3)</b> ¡¡ Ya podemos utilizar el control en Excel !! Para ello sólamente tenemos que añadir nuestro nuevo control mediante la barra de herramientas "Cuadro de controles" y en "Más controles..." buscamos Winsock Component.<br />
<br />
Por ejemplo, podríamos hacer algo asi:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoGztudZAgv4uD29w1FaCfC8kahkZ_Dkx4zkyn7BgBNXBBsIzr1kaCJgYoRpnD-U4BwGYwbzKukagKB_CRe0-15idFZUsnrc5GszcMxxki92vNJAzlcXiuCF31wvrxAE3IHcvqHRNJ5m8u/s1600-h/Captura+telnet+con+Excel.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoGztudZAgv4uD29w1FaCfC8kahkZ_Dkx4zkyn7BgBNXBBsIzr1kaCJgYoRpnD-U4BwGYwbzKukagKB_CRe0-15idFZUsnrc5GszcMxxki92vNJAzlcXiuCF31wvrxAE3IHcvqHRNJ5m8u/s640/Captura+telnet+con+Excel.JPG" /></a><br />
</div><br />
En la hoja dispongo de:<br />
- Celdas de configuración de la IP del router, usuario y password del mismo.<br />
- Botones (4) que corresponden a establecer conexión, cerrar conexión, encender led y apagar led.<br />
- Cuadro de texto dónde adjunto info recibida de la conexión establecida.<br />
<br />
En la imagen se puede ver el resultado tras establecer una conexión y haber encendido/apagado 3 veces el led.<br />
<br />
Veamos el código de Excel:<br />
<br />
<b>Code:</b><br />
<pre class="code" style="height: 300px; margin: 0px; overflow: auto; width: auto;">Private Sub CommandButton1_Click()
TextBox1.Text = ""
Winsock1.RemoteHost = Range("B2").Text
Winsock1.Protocol = sckTCPProtocol
Winsock1.Connect
End Sub
Private Sub CommandButton2_Click()
Winsock1.SendData "echo S1F > /dev/cua/1" & vbCrLf
End Sub
Private Sub CommandButton3_Click()
Winsock1.SendData "echo S0F > /dev/cua/1" & vbCrLf
End Sub
Private Sub CommandButton4_Click()
Winsock1.CloseWinsock
End Sub
Private Sub Winsock1_OnConnect()
Winsock1.SendData Range("B3").Text & vbCrLf
Application.Wait Now + TimeValue("0:0:01")
Winsock1.SendData Range("B4").Text & vbCrLf
Application.Wait Now + TimeValue("0:0:01")
End Sub
Private Sub Winsock1_OnDataArrival(ByVal bytesTotal As Long)
Winsock1.GetData data
TextBox1.Text = TextBox1.Text + data
End Sub
Private Sub Winsock1_OnError(ByVal Number As Integer, Description As String, ByVal Scode As Long, ByVal Source As String, ByVal HelpFile As String, ByVal HelpContext As Long, CancelDisplay As Boolean)
MsgBox Number & ": " & Description
End Sub
</pre><br />
<br />
Ahora ya tendremos de forma muy sencilla una interfaz gráfica, en que mediante los botones encendemos/apagamos nuestro led via WIFI.... no queda nada mal, ¿verdad?<br />
<i>(El cuadro de texto está para la depuración con la información que devuelve la conexión de telnet, no hace falta para nada)</i><br />
Ya puedes darle conectividad Wireless a tus proyectos con Arduino, aprovechándote del potencial de Excel para graficar, cálculos, Visual Basic,....<i><br />
</i><br />
<br />
<br />
<br />
<div style="text-align: center;"><a href="http://cid-d2ee689f353f15bc.skydrive.live.com/self.aspx/P%c3%bablico/Telnet.xls"><span style="font-size: large;"><span style="color: red;">PULSA AQUI PARA DESCARGAR EXCEL DE EJEMPLO</span></span></a><br />
</div><br />
<br />
<br />
<br />
<br />
Ahora, incrementamos el nivel.... <b><span style="color: blue;">GRAFICAR UN VALOR ANALÓGICO EN "TIEMPO REAL"</span></b><br />
<br />
<br />
<div style="text-align: center;"><span style="font-size: large;"><b style="color: red;"> TELEMETRÍA CON ARDUINO</b></span><br />
</div><br />
<div class="separator" style="clear: both; text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj62H3VXZOUUDNfmE-F1pEyvrsjgFWFIi-UV4Vk1fUlj-YBPTaIMy-h98yOR3MYBCzyGHFQvElV1xl2YOqDyO8vJrsYKbSslKGF9Pex4NPVNSXYYWSGK7Lg_CcFjtoKioW4z6Q81mUr7eEe/s640/scheme_wifi.JPG" /><br />
</div><br />
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjl32sZxhIljyZwg_LlFHy5wyTbp52NAmGMysvoagks1amVCwgXzqMZ7P8fiX_GlgbQUcSvuPPJPlgrl5St08uZosBy2UHtK_QTcxd_4RZCWYaQxy0GaIO9XYb_PBrB5F0Fm7JA9H2dB7w5/s320/Arduino+Linksys.JPG" /><br />
</div><div class="separator" style="clear: both; color: red; text-align: center;">Fotos del montaje<br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: left;">Mejor, si vemos un video:<br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><object height="505" width="640"><param name="movie" value="http://www.youtube.com/v/OhKh4_D8-Ac&hl=es_ES&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/OhKh4_D8-Ac&hl=es_ES&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="505"></embed></object><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;">Aqui tenemos una captura de pantalla de la hoja excel :<br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhStmvL4hqRvWDkT1Vq1Nz8LsKoUoNBjaro1DhyphenhyphenoDmXhJBXtp7ADbjtKqSeIwBIH3rUZSGl80BP36Herv7OUSqBsfejHeylCHpYsrKySNK6_9B9G7Z0aUFro9L-JRAhnkWUuOoW8Kka68ph/s640/Telnet_Excel_2.JPG" /><br />
</div><br />
<br />
<br />
<br />
<br />
<br />
<br />
Pues ahora queda en la imaginación de cada uno el potencial que se dispone gracias a ésto... Existen en el mercado, routers compatibles con DD-WRT que disponen de USB... (ejemplo<b> Asus WL-520GU,</b><b>Linksys WRT350N y Linksys WRT600N</b><b>)</b> <br />
Véase:<br />
<a href="http://www.mightyohm.com/blog/2008/10/building-a-wifi-radio-part-1-introduction/">http://www.mightyohm.com/blog/2008/10/building-a-wifi-radio-part-1-introduction/</a><br />
<a href="http://www.jbprojects.net/projects/wifirobot/">http://www.jbprojects.net/projects/wifirobot/</a><br />
<a href="http://www.youtube.com/watch?v=Wp0q9eTZECk">http://www.youtube.com/watch?v=Wp0q9eTZECk</a><br />
<br />
<div style="color: red;"><span style="font-size: large;"><i><b>Telemetría; Telecontrol; Alarmas; Robótica, Domótica; Apertura/Cierre de puertas,calderas, camaras frigoríficas,... a través de intranet/internet.<br />
</b></i></span><br />
</div><br />
<br />
<br />
<div style="text-align: center;"><span style="font-size: large;"><b><span style="color: magenta;">Puedes ver más ejemplos con este hardware, navegando por el menu izquierdo (Proyecto LINKDUINO).</span></b></span><br />
</div><br />
<br />
<br />
<br />
<br />
<br />
<div style="color: blue;"><b>Igor R.</b><br />
</div>Igorhttp://www.blogger.com/profile/07332255486737492708noreply@blogger.com11tag:blogger.com,1999:blog-5229899856062584712.post-48948707642997448992009-10-05T11:41:00.000-07:002011-01-18T06:22:17.956-08:00Cálculo de número de marcha con RPM y Velocidad<code><br />
<script src="http://www.gmodules.com/ig/ifr?url=http://www.google.com/ig/modules/translatemypage.xml&up_source_language=es&w=160&h=60&title=&border=&output=js">
</script> </code><br />
<br />
<br />
Vamos a explicar como crear un display de marchas para una moto ó coche mediante un canal matemático, el cual usa la velocidad del vehículo y las rpm motor. Normalmente resulta dificil intrumentar la caja de cambios, pero hoy en día es casi inmediato disponer de la señal de velocidad ruedas y velocidad motor.<br />
<b>Muy útil para motos.</b><br />
<br />
Primero se estudiará el sistema mecánico el cual une la salida motor con las ruedas, para ello nos ayudamos del siguiente diagrama: <br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8KtS3yqituw6_c8VTLenaVxEWR1Cd9HtfRn60ZAxCDop47PxYn4PUizVwbOghUdyRGAkfvosP5ZIPx1tXwwLVzKNATNXKZkLRwyd6jM4uRd1xnTYOWjJfSk37ZNz8um6ZnbFIsKgyOHDa/s1600-h/Gear+Ratio+Diagram.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8KtS3yqituw6_c8VTLenaVxEWR1Cd9HtfRn60ZAxCDop47PxYn4PUizVwbOghUdyRGAkfvosP5ZIPx1tXwwLVzKNATNXKZkLRwyd6jM4uRd1xnTYOWjJfSk37ZNz8um6ZnbFIsKgyOHDa/s400/Gear+Ratio+Diagram.JPG" /></a><br />
</div><div class="separator" style="clear: both; text-align: left;">siendo RPM=revoluciones por minuto, Speed=velocidad del vehículo, Rwheel= el radio de la rueda.<br />
</div><div class="separator" style="clear: both; text-align: left;">Por lo cual, resulta sencillo observa que si disponemos la velocidad en rueda y la de motor, nuestra única incognita será el ratio entre ambas (caja cambios + grupo final). <br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;">En youtube se puede ver un video subido por Herbold de cómo obtener el dato de grupo final experimentalmente <a href="http://www.youtube.com/watch?v=i_Enyf67KTs">http://www.youtube.com/watch?v=i_Enyf67KTs</a>:<br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><object height="505" width="640"><param name="movie" value="http://www.youtube.com/v/i_Enyf67KTs&hl=es&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/i_Enyf67KTs&hl=es&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="505"></embed></object><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;">Veamos algunos ejemplos reales (fuente <a href="http://en.wikipedia.org/wiki/Gear_ratio">wikipedia</a>), Corvette C5 Z06:<br />
</div><div class="separator" style="clear: both; color: blue; text-align: left;"><b> 1st => 2'97</b><br />
</div><div class="separator" style="clear: both; color: blue; text-align: left;"><b> 2nd => 2'07</b><br />
</div><div class="separator" style="clear: both; color: blue; text-align: left;"><b> 3rd => 1.43</b><br />
</div><div class="separator" style="clear: both; color: blue; text-align: left;"><b> 4th => 1</b><br />
</div><div class="separator" style="clear: both; color: blue; text-align: left;"><b> 5th => 0'84</b><br />
</div><div class="separator" style="clear: both; color: blue; text-align: left;"><b> 6th => 0'56</b><br />
</div><div class="separator" style="clear: both; color: blue; text-align: left;"><b> Final drive (diferencial)=> 3.42</b><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;">Esto significa, por ejemplo, cada 2.97x3.42=10.16 vueltas motor en primera, gira una de rueda (1:10.16)<br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: left;">Veamos el tipo de señal que obtenemos usando dicho canal matemático. Podemos observar la señal azul, la cual corresponde a nuestro canal calculado. Se observa, que la señal no es limpia, y sobretodo si tenemos patinaje de ruedas (wheelspin) ó en el momento de pisar embrague. Veáse un ejemplo de wheelspin en la parte rodeada de la figura. También vemos la señal rosa, la cual proviene de un sensor rotativo en el selector de marchas (barrel), la cual es perfecta.<br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"> <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1_JvV7bGtSwWcaQDv-iqDbNIKxmETJon-wjEsOEKetRBiEESiBu0-lMF2w950gYsH6BdVAZJHy1JpNRNkj7PJVBT45wF4D_XyPSLpWhyphenhypheneNpwMtZR-zzmmy0qnM2sXvDvxBCl7Ph4VJkZ7/s1600-h/Gear+Ratio.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1_JvV7bGtSwWcaQDv-iqDbNIKxmETJon-wjEsOEKetRBiEESiBu0-lMF2w950gYsH6BdVAZJHy1JpNRNkj7PJVBT45wF4D_XyPSLpWhyphenhypheneNpwMtZR-zzmmy0qnM2sXvDvxBCl7Ph4VJkZ7/s400/Gear+Ratio.JPG" /></a><br />
</div><div class="separator" style="clear: both; text-align: center;"><span style="color: red;">Estas señales son reales grabadas con un sistema adquisición de datos.</span><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><br />
<div class="separator" style="clear: both; text-align: left;">Una mejora de la señal, se consigue aplicando un filtro de tipo Moving Average. En la figura, se ha aplicado dicho filtro tomando 5 muestras.<br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;">Por ejemplo, se podría calcular dicho canal cada 50 Hz (20 ms) gracias a un timer, y el pseudocódigo sería algo como:<br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; color: red; text-align: left;">función cada 20ms{<br />
</div><div class="separator" style="clear: both; color: red; text-align: left;"> si (Velocidad >0)<br />
</div><div class="separator" style="clear: both; color: red; text-align: left;"> { <br />
</div><div class="separator" style="clear: both; color: red; text-align: left;"> n=(3.6*Radio_rueda*3.14159*RPM)/(30*Speed);<br />
</div><div class="separator" style="clear: both; color: red; text-align: left;"> }<br />
</div><div class="separator" style="clear: both; color: red; text-align: left;"><br />
</div><div class="separator" style="clear: both; color: red; text-align: left;"> filtro1=filtro2;<br />
</div><div class="separator" style="clear: both; color: red; text-align: left;"> filtro2=filtro3;<br />
</div><div class="separator" style="clear: both; color: red; text-align: left;"> filtro3=filtro4;<br />
</div><div class="separator" style="clear: both; color: red; text-align: left;"> filtro4=filtro5;<br />
</div><div class="separator" style="clear: both; color: red; text-align: left;"> filtro5=n;<br />
</div><div class="separator" style="clear: both; color: red; text-align: left;"><br />
</div><div class="separator" style="clear: both; color: red; text-align: left;"> Ratio= (filtro1+filtro2+filtro3+filtro4+filtro5)/5;<br />
</div><div class="separator" style="clear: both; color: red; text-align: left;">}<br />
</div><div class="separator" style="clear: both; color: red; text-align: left;"><b><br />
</b><br />
</div><div class="separator" style="clear: both; color: red; text-align: left;"><b><span style="color: blue;">RPM =revoluciones por minuto del motor</span></b><br />
</div><div class="separator" style="clear: both; color: red; text-align: left;"><b><span style="color: blue;">Velocidad=Km/h</span></b><br />
</div><div class="separator" style="clear: both; color: red; text-align: left;"><b><span style="color: blue;">Radio_rueda= en metros</span> <br />
</b><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><br />
<div class="separator" style="clear: both; text-align: left;">Una vez obtenido el ratio (caja cambios + grupo final), ya sabemos en que marcha nos encontramos, por lo cual sólo quedará mostrarla al usuario. Ya que con el ratio +/- un cierto margen histeresis, tendremos directamente la marcha actual.<br />
</div><br />
<div class="separator" style="clear: both; text-align: left;">Para conseguir los dos canales necesarios (velocidad y rpm), normalmente nos encontramos dos tipos de tecnologías en los sensores utilizados en automoción:<br />
</div><div class="separator" style="clear: both; text-align: left;">- Sensores inductivos (pasivos)<br />
</div><div class="separator" style="clear: both; text-align: left;">- Sensores Hall (activos)<br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgE1P1IHq_XkPu3TWZadWjzs4zl04AzlTuxeqnnNIUGkI29HhZrYu3xUIs50OT396Mqx78m5JQ9PPbFmLbOEABVvD_2t0s7Qaqn7-wu5GHUSx6mzRr9F_ntg3gSTFA-Wvx8v-x5LH8sqcE3/s1600-h/Inductive+signal.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgE1P1IHq_XkPu3TWZadWjzs4zl04AzlTuxeqnnNIUGkI29HhZrYu3xUIs50OT396Mqx78m5JQ9PPbFmLbOEABVvD_2t0s7Qaqn7-wu5GHUSx6mzRr9F_ntg3gSTFA-Wvx8v-x5LH8sqcE3/s320/Inductive+signal.JPG" /></a><br />
</div><div class="separator" style="clear: both; text-align: center;"><span style="color: red;">Ejemplo señal sensor inductivo</span><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: justify;">Los primeros generan un voltaje cuya frecuencia y amplitud son proporcionales a la velocidad.<br />
</div><div class="separator" style="clear: both; text-align: justify;">Para poder introducir este tipo de señal a un microcontrolador, deberemos usar una etapa de adaptación de señales, como puede ser un <a href="http://www.national.com/mpf/LM/LM1815.html">lm1815</a> ó etapa con AO para convertir a señal de pulsos tipo TTL. Este tipo de etapas suelen tener el zero-crossing (detectan el paso por cero) y la histeresis ajustables. Gracias a ésto último, se puede reducir el efecto del ruido que suelen tener dichas entradas.<br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;">En los sensores hall, nos podemos encontrar algunos que su salida tiene un offset DC sobre la señal de pulsos. Para eliminarla, podemos usar un condensador en serie con la señal. Si la señal no tiene la amplitud suficiente (mayor de 2,5 V), tendremos que adaptar para hacer ésto posible, por ejemplo con la ayuda de transistores.<br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;">Las RPM, a parte de poder recogerlas del sensor cigueñal motor, podríamos sacar de una de las fases del alternador. Hay que tener en cuenta, que la velocidad motor y la velocidad del alternador no es la misma, ya que van unidas por una polea con ratios típicos de 1:2.2; 1:3 hasta 1:5.<br />
</div><div class="separator" style="clear: both; text-align: left;">La frecuencia medida en una de las fases será =><b><span style="color: red;"> f=p*n/60</span></b> , siendo p el número de polos (típicamente 6 ó 8) y n la velocidad del alternador.<br />
</div><div class="separator" style="clear: both; text-align: left;">Algunos alternadores vienen ya preparados con dicha señal (Terminal W).<br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;">La mayoría de los coches, disponen señal de tacómetro en los conectores de la radio, en el cuadro,... por lo que es una posible fuente de la señal de la velocidad del vehiculo.<br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;">También se puede disponer de las rpm de las señales de control de los inyectores.<br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;">Para mayor información de donde sacar dichas señales, puedes visitar el proyecto MPGuino:<br />
</div><div class="separator" style="clear: both; text-align: left;"><a href="http://ecomodder.com/wiki/index.php/MPGuino">http://ecomodder.com/wiki/index.php/MPGuino</a><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><b><i>Cabe destacar, que la señal cuadrada debe superar aproximadamente Vcc/2 para que nuestro micro ATMega lo reconozca.</i></b><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;">Para aprender un poco más de los sensores utilizados en automoción, podemos visitar el siguiente link:<br />
</div><div class="separator" style="clear: both; text-align: left;"><a href="http://www.mecanicavirtual.org/sensores2-modelos.htm">http://www.mecanicavirtual.org/sensores2-modelos.htm</a><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;">La ventaja principal entre sensores hall e inductivos, es que los primeros son capaces de detectar bajas velocidades e integran la electrónica de adaptación de la señal obteniendo directamente pulsos. También son mejores ante ruido eléctrico, ya normalmente existe distancia entre los sensores inductivos y sus etapas de adaptación de señales. <b>Cabe recordar el uso de una resistencia de pull-up con los sensores hall. </b>Si se va a puentear dicha señal del cableado del coche o moto, ya dispondrá de ella la ecu motor.<br />
</div><div class="separator" style="clear: both; text-align: left;">Dichas señales deben entrar a las entradas de interrupción de nuestro Arduino. Conviene proteger dichas entradas con una resistencia en serie de gran valor ,ya que las entradas de nuestro micro disponen de "clamping diodes", los cuales convierten señales elevadas de voltaje en señal cuadrada de valor igual al de alimentación +/- 0.5V. <b>Atmel recomienda que por dichos diodos no circulen más de 1mA.</b><br />
</div><div class="separator" style="clear: both; text-align: left;">Si es posible, añadir un diodo tipo TVS ó zener entre señal y masa para proteger de transitorios a nuestra entrada.<br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;">Aunque no tenga nada que ver,este video es de regalo.... cómo funciona un diferencial.<br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><object height="505" width="640"><param name="movie" value="http://www.youtube.com/v/K4JhruinbWc&hl=es&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/K4JhruinbWc&hl=es&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="505"></embed></object><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><br />
<div class="separator" style="clear: both; text-align: left;"><br />
</div>Igorhttp://www.blogger.com/profile/07332255486737492708noreply@blogger.com2tag:blogger.com,1999:blog-5229899856062584712.post-79506864472637445642009-09-13T05:15:00.000-07:002011-04-01T08:32:14.599-07:00Arduino and RS485 (ENGLISH VERSION)<div dir="ltr" style="text-align: left;" trbidi="on"><span style="color: white;">.</span><br />
<br />
<b>NEWS</b> => Are you interested in CAN Bus with Arduino? Visit <a href="http://secuduino.blogspot.com/">http://secuduino.blogspot.com/</a> <br />
<br />
<br />
RS485 is a standard serial protocol, with bus topology where you can connect several devices in a very cheap way. Here will be explained how to create a microcontrollers network just with 2 wires.<br />
<br />
<br />
It is based in a differential couple of wires with which we can get a half-duplex comunication channel. The driver has a configurable input that provides us the possibility to set our transceiver as sender or receiver.<br />
<br />
What do we need apart of our Arduino?<br />
<ul><li>MAX485</li>
<li>SN75176 (cheaper)</li>
</ul><br />
What will be it used for? It is a voltage level converter in order to use our UART as RS485 interface.<br />
<br />
<br />
<div style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHRS-BfAWunkbnFU1ZImo8vpKUBiidh9heHicuwpXfCkYTyRAIB2iqVkP7g4varpJSxPY5FWdHe1b7Zii_qu51EG03AnLiauvpqC7YAdNIX2ctsh6s8torfneqm8h3UAG_RcTsBaCwH3Q2/s1600-h/MAX485.JPG" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5379417673302781858" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHRS-BfAWunkbnFU1ZImo8vpKUBiidh9heHicuwpXfCkYTyRAIB2iqVkP7g4varpJSxPY5FWdHe1b7Zii_qu51EG03AnLiauvpqC7YAdNIX2ctsh6s8torfneqm8h3UAG_RcTsBaCwH3Q2/s400/MAX485.JPG" style="margin: 0pt 10px 10px 0pt;" /></a></div><br />
<br />
Ok, now we are ready to start. RS485 resides in the physical layer based on the OSI Model, so it just tell us about voltages, physic parameters,....<br />
<br />
Recommended links:<br />
<br />
<a href="http://www.i-micro.com/pdf/articulos/rs-485.pdf">http://www.i-micro.com/pdf/articulos/rs-485.pdf</a><a href="http://www.i-micro.com/pdf/articulos/rs-485.pdf">df</a><br />
<a href="http://www.maxim-ic.com/appnotes.cfm?appnote_number=763&CMP=WP-1">http://www.maxim-ic.com/appnotes.cfm?appnote_number=763&CMP=WP-1</a><br />
<a href="http://www.neoteo.com/rs485-domotica-al-alcance-de-tu-mano-15810.neo">http://www.neoteo.com/rs485-domotica-al-alcance-de-tu-mano-15810.neo</a><a href="http://www.neoteo.com/rs485-domotica-al-alcance-de-tu-mano-15810.neo">-alcance-de-tu-mano-15810.neo</a><br />
RS485 Oscilloscope Screenshots<br />
<a href="http://www.sbc-support.ch/faq/files/files.get.php?ZSESSIONID=n38bphov4ls4cdsvtbd8tl6jb4&fi_index=100179" target="_blank">http://www.sbc-support.ch/faq/files/files.get.php?ZSESSIONID=n38bphov4ls4cdsvtbd8tl6jb4&fi_index=100179</a><br />
<br />
Then, we need an structural way to send our information. We will use as frames a configuration already created by Fuji in their industrial variators.<br />
<br />
Look at: <a href="http://www.cdautomation.com/download/ENG_L_M_FUJI_RS485_COMM_for_FRENIC-Mini.PDF">http://www.cdautomation.com/download/ENG_L_M_FUJI_RS485_COMM_for_FRENIC-Mini.PDF</a><a href="http://www.cdautomation.com/download/ENG_L_M_FUJI_RS485_COMM_for_FRENIC-Mini.PDF">L_M_FUJI_RS485_COMM_for_FRENIC-Mini.PDF</a><br />
<br />
Let's take a look at the frame configuration:<br />
<div><br />
<div style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-dXbwqUE4J0A77zpH7UEOUXJmR5MTjEp5g6oP-IVvjpbrCZdKO_5Ci7ZpvQtzXP9IgIhPjGM4Lz2YxOuhV6P0i850aaP-WomMJbiqSma0ksFCvuDayBZnN31sb69df0qBctv-e6wBknZq/s1600-h/RS485_conexionado.JPG" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5379420144499317010" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-dXbwqUE4J0A77zpH7UEOUXJmR5MTjEp5g6oP-IVvjpbrCZdKO_5Ci7ZpvQtzXP9IgIhPjGM4Lz2YxOuhV6P0i850aaP-WomMJbiqSma0ksFCvuDayBZnN31sb69df0qBctv-e6wBknZq/s400/RS485_conexionado.JPG" style="margin: 0pt 10px 10px 0pt;" /></a></div><br />
<br />
<ul><li>Byte 1: Start Byte ( 0 hexadecimal ).</li>
<li>Byte 2-3: ASCII Arduino's address.</li>
<li>Byte 4: Byte ENQ, ACK or NAK (0x05h, 0x06h y 0x15h) .</li>
<li>Byte 5: ASCII Requested command.</li>
<li>Byte 6 y 7: ASCII Function number.</li>
<li>Byte 8: Sign byte (Positive 0x20h y Negative 2D)</li>
<li>Byte 9-12: ASCII of data bytes (0x00h-0xFFFFh)</li>
<li>Byte 13: Byte EOT (End of Text) (0x03h)</li>
<li>Byte 14-15: Checksum (addition from 2nd byte to 13th byte)</li>
</ul><br />
<br />
With this configuration we have<br />
<ul><li>1 Byte indicating the Function Number</li>
<li>2 Bytes indicating the sub-function Number</li>
</ul><br />
<br />
So imagine the possibles combinations!!! For instance:<br />
A01 Requet of value on Analog input 1<br />
P01 Request Configuration of PWM 1 with setup data in DATA bytes<br />
And so on!!!! Is not wonderful?<br />
<br />
Notice:<br />
- Commands are ASCII Coded<br />
- Control bytes are not ASCII Coded<br />
It is a nice feature due to, in case we receive a 0x00 (thinking it is the start byte), the program will understand it is the starting frame instead of as 0 value, because in this case, it should be sent as ASCII (0x30).<br />
<br />
Please take a look at the ASCII Table, even better print it! :P Probably most of us we have a copy pasted in front of us all the time, wrong?<br />
<a href="http://www.cs.utk.edu/~pham/ascii_table.jpg">http://www.cs.utk.edu/~pham/ascii_table.jpg</a><br />
<br />
<img alt="" border="0" id="BLOGGER_PHOTO_ID_5379426831296192610" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHtBe2WgRLVNeo1WTKYQw0gCAZlEZ9D9ZOGmOxb0YMKSehdUCW9z0N-zwS_4qlUlzWAmVYZEk81UaCXhKJjgIyT4J1_Mjc-xKiUGrcS9WReFGqvtZUBzxKJgPm1yQ5UMokHvHIBbsOWjJS/s400/ascii_table.jpg" style="display: block; margin: 0px auto 10px; text-align: center;" /><br />
<br />
<br />
Let's see an example:<br />
Imagine we need an arduino(master) which will decide either switch on or switch off a remote lights. Then, it have to send a command on our RS485 network and then other arduino (slave) will interpretate the command and excute it.<br />
<br />
Then, the master will follow the switchces state, a and as needed, the master will send the frame requesting switch on/off to the slave called 01. The function will be called D and number 0.(you can set it up as needed). So,<br />
Master sends: Slave(01)-Request execution function(D)-SubFunction(0)<br />
<span style="color: blue;">0x00 0x30 0x31 0x05 0x44 0x30 0x30 0x20 0x30 0x30 0x30 0x31 0x03 0x01 0xEE</span><br />
Slave answers: AKNOWLEDGE (ACK).<br />
<span style="color: blue;">0x00 0x30 0x31 0x06 0x44 0x30 0x30 0x20 0x30 0x30 0x30 0x31 0x03 0x01 0xEF</span><br />
<br />
<br />
The salve's ACK frame has the following configuration(take a look at Byte 4 due to here is specified ACK)<br />
<br />
Even better, watch the following video: <a href="http://www.youtube.com/watch?v=ABcjU0Ua-d4">http://www.youtube.com/watch?v=ABcjU0Ua-d4</a><br />
<br />
<div style="text-align: center;"><br />
<object height="344" width="425"><param name="movie" value="http://www.youtube.com/v/ABcjU0Ua-d4&color1=0xb1b1b1&color2=0xcfcfcf&hl=es&feature=player_embedded&fs=1"><param name="allowFullScreen" value="true"><param name="allowScriptAccess" value="always"><embed src="http://www.youtube.com/v/ABcjU0Ua-d4&color1=0xb1b1b1&color2=0xcfcfcf&hl=es&feature=player_embedded&fs=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="425" height="344"></embed></object></div><br />
<div>Urgh!!!!Sorry but the switcher is just a couple of wires going from VCC to GND! ;)<br />
<br />
In order to see the frames flowing on the net, you need just a USB <----> RS232 like FTDI232 or MAX232+MAX485,... If you have an Arduino PCB, notice you can remove the uC from its socket and you'll have an USB <---->Rs232 converter!<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuvxZOQSu_OdihhgEGU_-PiwsntFdHIK5-bJS3CdhO3PsDW7w5QQS_8R7ONumfYG7Px0fopP3hWSKclTax2vzRgE0rQoW8ednERWmHanBZ-WHylBeTgXmcCLLhDO_xEzVixMv54DovaVJM/s1600-h/primer+ejemplo.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuvxZOQSu_OdihhgEGU_-PiwsntFdHIK5-bJS3CdhO3PsDW7w5QQS_8R7ONumfYG7Px0fopP3hWSKclTax2vzRgE0rQoW8ednERWmHanBZ-WHylBeTgXmcCLLhDO_xEzVixMv54DovaVJM/s400/primer+ejemplo.JPG" /></a></div><div style="text-align: center;"></div><br />
If you want to monitorize what is going on , you can use Hyperterminal, or any one that include some useful features as format output, saving options,....for instance we like:<br />
<a href="http://realterm.sourceforge.net/">RealTerm</a><br />
<a href="http://www.serial-port-monitor.com/free-serial-port-monitor-product-details.html">FREE SERIAL TERMINAL MONITOR</a> </div><div></div><div>Really nice if you want to sniff RS232 frames<br />
<br />
In this example we have 3 arduinos connected. The master have 2 switchers used to switch on/off leds connected to each of the slaves.<br />
<span style="color: white;">.</span><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7f3kzOBrdn1VBFxlX3mngdy52-sbDck8EpL7Tb6UoQiChHwOg_8njhCLtqHRyhmOEBtgs8Dc-UgZZHppb8K6nSjJKGu96RHq9WrPIrCGn_-lel_4_BMaXsoVxlY7JRkIrYZ8Zyow_L800/s1600-h/RS485+2+Esclavos.JPG" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" style="margin-left: 1em; margin-right: 1em;"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5379429156460641954" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7f3kzOBrdn1VBFxlX3mngdy52-sbDck8EpL7Tb6UoQiChHwOg_8njhCLtqHRyhmOEBtgs8Dc-UgZZHppb8K6nSjJKGu96RHq9WrPIrCGn_-lel_4_BMaXsoVxlY7JRkIrYZ8Zyow_L800/s400/RS485+2+Esclavos.JPG" style="display: block; margin: 0px auto 10px; text-align: center;" /></a></div><div style="border-bottom: medium none; border-left: medium none; border-right: medium none; border-top: medium none; text-align: center;"></div><br />
<br />
<div style="text-align: center;"><object height="344" width="425"><param name="movie" value="http://www.youtube.com/v/S9FSQaToVZ4&hl=es&fs=1&"><param name="allowFullScreen" value="true"><param name="allowscriptaccess" value="always"><embed src="http://www.youtube.com/v/S9FSQaToVZ4&hl=es&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object></div><br />
<br />
Let's see how it works: <a href="http://www.youtube.com/watch?v=S9FSQaToVZ4">http://www.youtube.com/watch?v=S9FSQaToVZ4</a><br />
<br />
<div style="text-align: center;"></div><br />
Now...THE CODE!</div><div><br />
<span style="color: blue;"><b>IMPORTANT:</b> <i><br />
Checksum are done directly in hex instead of convert it to ASCII. Change it could be necessary , to don't have problems. This entry is a howto paper to show you how RS485 works and explain how to implemnt a protocol, but is not 100% debbuged.</i></span><br />
<br />
<br />
<div style="color: #cc0000;"><b><span style="font-size: large;">MASTER:</span></b></div><br />
<br />
<pre class="code" style="height: 300px; margin: 0px; overflow: auto; width: auto;">//----------------------------------
//RS 485
//By Igor Real
//24-06-09
//----------------------------------
byte data[12];
unsigned long previous_time;
unsigned long previous_time2;
byte times_repeat=5;
byte times_repeat2=5;
byte state=0;
byte state2=0;
#define pinCONTROL 02
#define myaddress 01
void setup() {
pinMode(13,OUTPUT);
pinMode(pinCONTROL,OUTPUT);
digitalWrite(13,HIGH);
digitalWrite(12,LOW);
pinMode(8,INPUT);
pinMode(9,INPUT);
digitalWrite(pinCONTROL,LOW);
Serial.begin(9600);
Serial.println("Empezamos");
state=0;
state2=0;
}
void loop()
{
if (digitalRead(8)==state){
state=!state;
times_repeat=0;
}
if (digitalRead(9)==state2){
state2=!state2;
times_repeat2=0;
}
if (times_repeat<4){
Serial.flush();
//(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4)
if (digitalRead(8)==HIGH){
sendMSG(48,49,68,48,48,32,48,48,48,49);
}else {
sendMSG(48,49,68,48,48,32,48,48,48,48);
}
times_repeat=times_repeat+1;
previous_time=millis();
while (((millis()-previous_time)<500) && (Serial.available()!=15)){
;;
}
if (Serial.available()>=15){
if (receiveMSG()==1){
Serial.println("Trama correcta");
if (data[0]==48 && data[1]==49 && data[2]==6){
//ACK
times_repeat=5;
Serial.println("ACK recibido");
}
}
}
}
if (times_repeat2<4){
Serial.flush();
//(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4)
if (digitalRead(9)==HIGH){
sendMSG(48,50,68,48,48,32,48,48,48,49);
}else {
sendMSG(48,50,68,48,48,32,48,48,48,48);
}
times_repeat2=times_repeat2+1;
previous_time2=millis();
while (((millis()-previous_time2)<500) && (Serial.available()!=15)){
;;
}
if (Serial.available()>=15){
if (receiveMSG()==1){
//Serial.println("Trama correcta");
if (data[0]==48 && data[1]==50 && data[2]==6){
//ACK
times_repeat2=5;
//Serial.println("ACK recibido");
}
}
}
}
}
//------------------------
//FUNCIONES
//------------------------
byte receiveMSG(){
byte byte_receive;
byte state=0;
byte cont1=1;
byte trace_OK=0;
unsigned int checksum;
unsigned int checksum_trace;
while (Serial.available() > 0){
byte_receive=Serial.read();
if (byte_receive==00){
state=1;
checksum_trace=0;
checksum=0;
trace_OK=0;
cont1=1;
}else if (state==1 && cont1<=12){
data[cont1-1]=byte_receive;
checksum=checksum+byte_receive;
cont1=cont1+1;
}else if (state==1 && cont1==13){
checksum_trace=byte_receive<<8;
cont1=cont1+1;
}else if (state==1 && cont1==14){
checksum_trace=checksum_trace+byte_receive;
cont1=cont1+1;
state=0;
if (checksum_trace==checksum){
trace_OK=1;
}else{
trace_OK=0;
}
break;
}
}
return trace_OK;
}
void sendMSG(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4){
unsigned int checksum_ACK;
checksum_ACK=address1+address2+5+data_type+code1+code2+Sign+data1+data2+data3+data4+3;
UCSR0A=UCSR0A |(1 << TXC0);
digitalWrite(pinCONTROL,HIGH);
delay(1);
Serial.print(0,BYTE);
Serial.print(address1,BYTE);
Serial.print(address2,BYTE);
Serial.print(5,BYTE);
Serial.print(data_type,BYTE);
Serial.print(code1,BYTE);
Serial.print(code2,BYTE);
Serial.print(Sign,BYTE);
Serial.print(data1,BYTE);
Serial.print(data2,BYTE);
Serial.print(data3,BYTE);
Serial.print(data4,BYTE);
Serial.print(3,BYTE);
Serial.print(((checksum_ACK>>8)&255),BYTE);
Serial.print(((checksum_ACK)& 255),BYTE);
while (!(UCSR0A & (1 << TXC0)));
digitalWrite(pinCONTROL,LOW);
}
void sendACK(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4){
unsigned int checksum_ACK;
checksum_ACK=address1+address2+6+data_type+code1+code2+Sign+data1+data2+data3+data4+3;
UCSR0A=UCSR0A |(1 << TXC0);
digitalWrite(pinCONTROL,HIGH);
delay(1);
Serial.print(0,BYTE);
Serial.print(address1,BYTE);
Serial.print(address2,BYTE);
Serial.print(6,BYTE);
Serial.print(data_type,BYTE);
Serial.print(code1,BYTE);
Serial.print(code2,BYTE);
Serial.print(Sign,BYTE);
Serial.print(data1,BYTE);
Serial.print(data2,BYTE);
Serial.print(data3,BYTE);
Serial.print(data4,BYTE);
Serial.print(3,BYTE);
Serial.print(((checksum_ACK>>8)&255),BYTE);
Serial.print(((checksum_ACK)&255),BYTE);
while (!(UCSR0A & (1 << TXC0)));
digitalWrite(pinCONTROL,LOW);
}
void sendNAK(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4){
unsigned int checksum_ACK;
checksum_ACK=address1+address2+6+data_type+code1+code2+Sign+data1+data2+data3+data4+3;
UCSR0A=UCSR0A |(1 << TXC0);
digitalWrite(pinCONTROL,HIGH);
delay(1);
Serial.print(0,BYTE);
Serial.print(address1,BYTE);
Serial.print(address2,BYTE);
Serial.print(15,BYTE);
Serial.print(data_type,BYTE);
Serial.print(code1,BYTE);
Serial.print(code2,BYTE);
Serial.print(Sign,BYTE);
Serial.print(data1,BYTE);
Serial.print(data2,BYTE);
Serial.print(data3,BYTE);
Serial.print(data4,BYTE);
Serial.print(3,BYTE);
Serial.print(((checksum_ACK>>8)&255),BYTE);
Serial.print(((checksum_ACK)&255),BYTE);
while (!(UCSR0A & (1 << TXC0)));
digitalWrite(pinCONTROL,LOW);
}
byte hex2num(byte x){
byte result;
if (x>=48 && x<=57){
result=x-48;
}else if (x>=65 && x<=70){
switch(x){
case 65:
result=10;
break;
case 66:
result=11;
break;
case 67:
result=12;
break;
case 68:
result=13;
break;
case 69:
result=14;
break;
case 70:
result=15;
break;
}
}
return result;
}
</pre><br />
<div style="color: #cc0000;"><span style="font-size: large;"><b>SLAVES:</b></span></div>(you have to change myaddress to 01 or 02) <br />
<br />
<br />
<pre class="code" style="height: 300px; margin: 0px; overflow: auto; width: auto;">//----------------------------------
//RS 485
//By Igor Real
//24-06-09
//----------------------------------
byte data[12];
byte address;
byte function;
byte function_code;
unsigned int data_received;
byte byte_receive;
byte state=0;
byte cont1=1;
byte trace_OK=0;
unsigned int checksum;
unsigned int checksum_trace;
#define pinCONTROL 02
#define myaddress 02
void setup() {
pinMode(13,OUTPUT);
pinMode(pinCONTROL,OUTPUT);
digitalWrite(2,LOW);
Serial.begin(9600);
Serial.println("Empezamos");
}
void loop()
{
while (Serial.available() > 0){
byte_receive=Serial.read();
if (byte_receive==00){
//Serial.println("Se ha recibido byte Start");
state=1;
checksum_trace=0;
checksum=0;
trace_OK=0;
address=0;
data_received=0;
cont1=1;
}else if (state==1 && cont1<=12){
data[cont1-1]=byte_receive;
checksum=checksum+byte_receive;
cont1=cont1+1;
}else if (state==1 && cont1==13){
checksum_trace=byte_receive<<8;
cont1=cont1+1;
//Serial.print("Primer Byte Checksum");
//Serial.print(checksum_trace,HEX);
}else if (state==1 && cont1==14){
checksum_trace=checksum_trace+byte_receive;
cont1=cont1+1;
state=0;
//Serial.println(byte_receive,HEX);
//Serial.println("Recibida trama");
//Serial.print("Checksum Trace= ");
//Serial.println(checksum_trace,HEX);
//Serial.print("Checksum= ");
//Serial.println(checksum,HEX);
//Serial.println(checksum,DEC);
//Serial.println("Trama= ");
//Serial.print(data[0]);
//Serial.print(data[1]);
//Serial.print(data[2]);
//Serial.print(data[3]);
//Serial.print(data[4]);
//Serial.print(data[5]);
//Serial.print(data[6]);
//Serial.print(data[7]);
//Serial.print(data[8]);
//Serial.print(data[9]);
//Serial.print(data[10]);
//Serial.println(data[11]);
if (checksum_trace==checksum){
trace_OK=1;
address=(hex2num(data[0])<<4)+(hex2num(data[1]));
function=data[3];
function_code=(hex2num(data[4])<<4)+(hex2num(data[5]));
data_received=(hex2num(data[7])<<12)+(hex2num(data[8])<<8)+(hex2num(data[9])<<4)+(hex2num(data[10]));
//Serial.println("TRAZA CORRECTA");
//Serial.println(address,DEC);
//Serial.println(data_received);
if (address==myaddress){
if ((function=='D') && (function_code==0) && data[2]==5){
if (data_received==1){
digitalWrite(13,HIGH);
//Serial.println(data_received,DEC);
sendACK(data[0],data[1],data[3],data[4],data[5],data[6],data[7],data[8],data[9],data[10]);
}else if (data_received==0){
digitalWrite(13,LOW);
sendACK(data[0],data[1],data[3],data[4],data[5],data[6],data[7],data[8],data[9],data[10]);
}
}
}
}else{
//Serial.println("TRAZA INCORRECTA");
sendNAK(data[0],data[1],data[3],data[4],data[5],data[6],data[7],data[8],data[9],data[10]);
}
}
}
}
//------------------------
//FUNCIONES
//------------------------
byte receiveMSG(){
byte byte_receive;
byte state=0;
byte cont1=1;
byte trace_OK=0;
unsigned int checksum;
unsigned int checksum_trace;
while (Serial.available() > 0){
byte_receive=Serial.read();
if (byte_receive==00){
state=1;
checksum_trace=0;
checksum=0;
trace_OK=0;
cont1=1;
}else if (state==1 && cont1<=12){
data[cont1-1]=byte_receive;
checksum=checksum+byte_receive;
cont1=cont1+1;
}else if (state==1 && cont1==13){
checksum_trace=byte_receive<<8;
cont1=cont1+1;
}else if (state==1 && cont1==14){
checksum_trace=checksum_trace+byte_receive;
cont1=cont1+1;
state=0;
if (checksum_trace==checksum){
trace_OK=1;
}else{
trace_OK=0;
}
break;
}
}
return trace_OK;
}
void sendMSG(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4){
unsigned int checksum_ACK;
checksum_ACK=address1+address2+5+data_type+code1+code2+Sign+data1+data2+data3+data4+3;
UCSR0A=UCSR0A |(1 << TXC0);
digitalWrite(pinCONTROL,HIGH);
delay(1);
Serial.print(0,BYTE);
Serial.print(address1,BYTE);
Serial.print(address2,BYTE);
Serial.print(5,BYTE);
Serial.print(data_type,BYTE);
Serial.print(code1,BYTE);
Serial.print(code2,BYTE);
Serial.print(Sign,BYTE);
Serial.print(data1,BYTE);
Serial.print(data2,BYTE);
Serial.print(data3,BYTE);
Serial.print(data4,BYTE);
Serial.print(3,BYTE);
Serial.print(((checksum_ACK>>8)&255),BYTE);
Serial.print(((checksum_ACK)& 255),BYTE);
while (!(UCSR0A & (1 << TXC0)));
digitalWrite(pinCONTROL,LOW);
}
void sendACK(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4){
unsigned int checksum_ACK;
checksum_ACK=address1+address2+6+data_type+code1+code2+Sign+data1+data2+data3+data4+3;
UCSR0A=UCSR0A |(1 << TXC0);
digitalWrite(pinCONTROL,HIGH);
delay(1);
Serial.print(0,BYTE);
Serial.print(address1,BYTE);
Serial.print(address2,BYTE);
Serial.print(6,BYTE);
Serial.print(data_type,BYTE);
Serial.print(code1,BYTE);
Serial.print(code2,BYTE);
Serial.print(Sign,BYTE);
Serial.print(data1,BYTE);
Serial.print(data2,BYTE);
Serial.print(data3,BYTE);
Serial.print(data4,BYTE);
Serial.print(3,BYTE);
Serial.print(((checksum_ACK>>8)&255),BYTE);
Serial.print(((checksum_ACK)&255),BYTE);
while (!(UCSR0A & (1 << TXC0)));
digitalWrite(pinCONTROL,LOW);
}
void sendNAK(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4){
unsigned int checksum_ACK;
checksum_ACK=address1+address2+6+data_type+code1+code2+Sign+data1+data2+data3+data4+3;
UCSR0A=UCSR0A |(1 << TXC0);
digitalWrite(pinCONTROL,HIGH);
delay(1);
Serial.print(0,BYTE);
Serial.print(address1,BYTE);
Serial.print(address2,BYTE);
Serial.print(15,BYTE);
Serial.print(data_type,BYTE);
Serial.print(code1,BYTE);
Serial.print(code2,BYTE);
Serial.print(Sign,BYTE);
Serial.print(data1,BYTE);
Serial.print(data2,BYTE);
Serial.print(data3,BYTE);
Serial.print(data4,BYTE);
Serial.print(3,BYTE);
Serial.print(((checksum_ACK>>8)&255),BYTE);
Serial.print(((checksum_ACK)&255),BYTE);
while (!(UCSR0A & (1 << TXC0)));
digitalWrite(pinCONTROL,LOW);
}
byte hex2num(byte x){
byte result;
if (x>=48 && x<=57){
result=x-48;
}else if (x>=65 && x<=70){
switch(x){
case 65:
result=10;
break;
case 66:
result=11;
break;
case 67:
result=12;
break;
case 68:
result=13;
break;
case 69:
result=14;
break;
case 70:
result=15;
break;
}
}
return result;
}
</pre><br />
<br />
<br />
Now, we will learn how to wire a bus topology: <br />
<div style="text-align: center;"><span style="background-color: white; color: white;">.</span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSsDtkSo-1bdDimQJH018bvIvsoxCSz5sxc-guANgJ7qjXLJlpLLwzqwQbx_po7zt-Jsq1ZUR3e1AKmhD2WaXgfuXInSshq9npQycqPssesNr8Tyak3l3k0z7vdrPl7gJITxt21q2AYizM/s1600-h/Network+connection.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSsDtkSo-1bdDimQJH018bvIvsoxCSz5sxc-guANgJ7qjXLJlpLLwzqwQbx_po7zt-Jsq1ZUR3e1AKmhD2WaXgfuXInSshq9npQycqPssesNr8Tyak3l3k0z7vdrPl7gJITxt21q2AYizM/s400/Network+connection.JPG" /></a> </div><div class="separator" style="clear: both; text-align: center;"><span style="color: white;">.</span></div><div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: left;">Each Arduino or gadget conneted to the net, is wired with an Y welded which comes out 2 connectors from same family different kind(Male/female). The shorter the better. Each connector will have VCC,Sginal A, Singal B and GND. This way, if we want to connect another device onto the net, you need just insert each device or put it at the end. Now is easy understand why we are putting a Y , it's extremely easy connect and disconnect a device from the bus, due to each device has male an female. Is worthy have always a couple of connectors with a end-resistor between Singal A and Signal B RS485 pins in order to "close" the wires' end. If we need add another device is as easy as disconnet the connector with the end-resistor, insert the new device and close again with that connector. Wire VCC and GND is extremely easy, and in future, will make things really easier in possible expansions..... Take care, and twist Signal A and Signal B wires. Please take a loot at next link if needed : <a href="http://www.rs-485.com/download/485%20network%20topology.pdf">http://www.rs-485.com/download/485%20network%20topology.pdf</a></div><div class="separator" style="clear: both; text-align: left;"></div><span style="color: white;">.</span><br />
This paper was based on spanish Igor R's one. Thanks Igor R!! Cheers!!! <br />
<span style="color: white;">.</span><br />
<span style="color: white;">.</span><br />
<div class="separator" style="clear: both; text-align: left;"><b><span class="Apple-style-span" style="color: #000099;">Aritz R.</span></b></div><div class="separator" style="clear: both; text-align: left;"><b><span style="color: white;">.</span></b></div><div class="separator" style="clear: both; text-align: left;"><b><span style="color: white;">.</span></b></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;"></div></div></div></div>Aritz Rhttp://www.blogger.com/profile/01175349926423359912noreply@blogger.com24tag:blogger.com,1999:blog-5229899856062584712.post-3339656634732515332009-09-11T11:32:00.000-07:002011-01-18T06:22:05.716-08:00SENSORAISER<div style="color: white;">.<br />
<div style="color: blue; font-family: "Trebuchet MS",sans-serif;"><div style="text-align: center;"><span style="font-size: large;"><b style="font-family: Georgia,"Times New Roman",serif;"><span style="color: red;">LOW COST SENSOR TESTER</span></b></span><b><span style="font-size: large;"><span style="color: red; font-family: Verdana,sans-serif;"> </span></span><br />
</b><br />
</div><br />
<b>Do you need your own tester for your application? </b><br />
</div><div style="color: blue; font-family: "Trebuchet MS",sans-serif;"><b>Our tester has 2 inputs which can be used to check accelerometers, potentiometers, hall sensors, gyros, ntc, ptc, pressure, valves (frecuency and duty cycle)...</b><br />
</div><div style="color: blue; font-family: "Trebuchet MS",sans-serif;"><b>You can watch the voltage and physical data from the sensors in the display.</b><br />
</div><div style="color: black;"><b><span style="color: blue; font-family: "Trebuchet MS",sans-serif;">Sensor database, menu, ... 100 % configurable</span></b><br />
<b><span style="color: blue; font-family: "Trebuchet MS",sans-serif;">Low pass filter. </span></b><br />
<b><span style="color: blue; font-family: "Trebuchet MS",sans-serif;">Power with auto shut down (save battery).</span></b><br />
<b><span style="color: blue; font-family: "Trebuchet MS",sans-serif;">Send data to your computer (Excel, matlab, hyperterminal,...) <br />
</span></b><br />
</div><div style="color: white; text-align: center;">.<br />
</div><div style="color: black; text-align: center;"><span style="color: white;">.</span><br />
</div></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhhSWuI1YH0UAM11WfXFW7Zi6noVuCnjU_xfUZqSODRxr4HQrYiyHAMHcvBFfGi6LpFUwfLZJkaY_G08Pb49YhgNt9bTFIlJBpDJj8jmPVNWwzHwj4eoibtx0yR3FPJpMIJj2xyJT0WXXR/s1600-h/Sensoraiser+1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhhSWuI1YH0UAM11WfXFW7Zi6noVuCnjU_xfUZqSODRxr4HQrYiyHAMHcvBFfGi6LpFUwfLZJkaY_G08Pb49YhgNt9bTFIlJBpDJj8jmPVNWwzHwj4eoibtx0yR3FPJpMIJj2xyJT0WXXR/s640/Sensoraiser+1.jpg" /></a><br />
</div><div class="separator" style="clear: both; text-align: center;"><span style="font-size: large;"><b style="color: red;"> (click to enlarge) </b></span><br />
</div><div class="separator" style="clear: both; color: white; text-align: center;"> .<br />
</div><div class="separator" style="clear: both; color: white; text-align: center;"><br />
</div><div class="separator" style="clear: both; color: white; text-align: center;"><br />
</div><div class="separator" style="clear: both; color: white; text-align: center;"> .<br />
</div><div class="separator" style="clear: both; text-align: center;"><span style="color: white;">.</span> <img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXvXZyPh2NoVTFeq6YEG2EUdKSS0q0hbLlcyyFMsfTuwVVPgk1YDZFSwG3sJsieBiJ9uRVDgxuHxliidSoRt0N8-pHv0-9Fxeb4KbKzkhxmm6as08uL08RqjAT_PQpZaHbBt4wDbXqd8vA/s640/PhotoFunia-19f1a6d.jpg" /><br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; color: white; text-align: left;">.<br />
</div><div class="separator" style="clear: both; color: white; text-align: left;">.<br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><object height="505" width="640"><param name="movie" value="http://www.youtube.com/v/DSFzXPfoe98&hl=es&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/DSFzXPfoe98&hl=es&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="505"></embed></object><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; color: white; text-align: left;">.<br />
</div><div class="separator" style="clear: both; color: white; text-align: left;">.<br />
</div><div class="separator" style="clear: both; color: white; text-align: left;">.<br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div>Igorhttp://www.blogger.com/profile/07332255486737492708noreply@blogger.com0tag:blogger.com,1999:blog-5229899856062584712.post-63259815114157318192009-09-11T02:33:00.000-07:002011-03-13T15:46:57.717-07:00CAN BUS DISPLAY<div dir="ltr" style="text-align: left;" trbidi="on"><div style="color: white;">.<br />
<div style="color: black;"><div style="text-align: center;"><span style="font-size: large;"><b><span style="color: red;">LOW COST CAN BUS DISPLAY</span></b></span><br />
<div style="text-align: left;"><span style="font-size: large;"><b><span style="color: red;"><span style="font-size: small;"><span style="color: white;">. </span></span><br />
</span></b></span></div></div><div style="color: blue;"><b>Do you need a display or any kind of solution based on BUS CAN?</b></div><div><b><span style="color: blue;">We can offer you a HDI (Human Display Interface) customized based on your requirementes </span><span style="color: blue;">( CAN, RS485, RS232, GPRS, TouchScreen, Analog Inputs, Outputs,...) as well we are opened to new challenges, just let us know what, and we will tell you how. You will receive a friendly and personal treatment with us in order to solve your specific needs. </span></b></div><div style="color: white;">.</div><span style="color: white;">.</span><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiaYhGepjkRQJ8z5ZalpNbAab4egywUsJ-nGzG-LNCHiThEGhRvNBsxT1C0a7K4pnDBJ8ZLs3-uokiVAMqXmt1h1yF4Kg79vQ1364H_ISDXc49cHTgCBlxtbVI9zXf-4-OD1COi5Qat8iap/s1600-h/PhotoFunia-19ed3c0.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiaYhGepjkRQJ8z5ZalpNbAab4egywUsJ-nGzG-LNCHiThEGhRvNBsxT1C0a7K4pnDBJ8ZLs3-uokiVAMqXmt1h1yF4Kg79vQ1364H_ISDXc49cHTgCBlxtbVI9zXf-4-OD1COi5Qat8iap/s200/PhotoFunia-19ed3c0.jpg" /></a></div><br />
<br />
<b style="color: red;">- DEMO -</b><br />
In the example, we can see an arduino Decimilia sending data through can bus (Poti =>ADC=>can bus) against our <b style="color: blue;">Can Display Module</b> which is controlling the screen. We have simulated 4 possible controllers:</div><ol style="color: black;"><li>RPMs</li>
<li>Battery Level</li>
<li>Gear</li>
<li>Speed</li>
</ol><span style="color: black;">Furthermore is possible to see an sniffer we have created, in order to monitor the messages are on our network. That is an idea we had, because many times we miss to have an external CAN sniffer could we use to plug directly to our network an see what it is going on.</span></div><ul><li>ATMega 1280 with MCP2515 can bus controller (Up to 1 Mbit/s)</li>
<li>Can 2.0 a/b<br />
</li>
<li>Big GLDC Display 4.3'' (240x128 dots)</li>
<li>SunLight Readable technology<br />
</li>
<li>Flash Memory: 128 Kb</li>
<li>SRAM: 8Kb</li>
<li>EEPROM: 4 Kb</li>
<li>Clock Speed: 16 MHz</li>
<li>16 Analog Inputs (10 bits)</li>
<li>4 UARTS</li>
<li>USB <-> RS232 converter (FTDI)<br />
</li>
</ul><div style="color: black;"></div><div style="color: black;"></div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHMhF34MLpek8EN4QbDlVD_zVB_BcoxEnVXCA6seoHvxhh8GnJ_rLUtFJnhZ0yPnFjNzfDJ9CEyqo-wxlJe_qR3TbqNpFG5IgldKwgymjQ8cW_Ym_-LLjN0o3EKpnPxxypDUOH-2JFvKWW/s1600-h/CAN_GLDC_1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHMhF34MLpek8EN4QbDlVD_zVB_BcoxEnVXCA6seoHvxhh8GnJ_rLUtFJnhZ0yPnFjNzfDJ9CEyqo-wxlJe_qR3TbqNpFG5IgldKwgymjQ8cW_Ym_-LLjN0o3EKpnPxxypDUOH-2JFvKWW/s400/CAN_GLDC_1.jpg" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="color: white;">. </span></div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjO5s6vrZuOS0V1HTgrgiSsn7FTqMenTj_KdjXCs1Jy5fUN8qd-6kvpqoCIq-dOeuJtA_F_GwmyFji_GAmOO9HZzsd50BMrKchSdk05PZM1LhoEJTbOWaCER3gUx5Ekvpe242AuvvQrcEpB/s1600-h/CAN_GLDC_3.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjO5s6vrZuOS0V1HTgrgiSsn7FTqMenTj_KdjXCs1Jy5fUN8qd-6kvpqoCIq-dOeuJtA_F_GwmyFji_GAmOO9HZzsd50BMrKchSdk05PZM1LhoEJTbOWaCER3gUx5Ekvpe242AuvvQrcEpB/s400/CAN_GLDC_3.jpg" /></a></div><div style="text-align: center;"><span style="color: white;">.</span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPEVCr03sUXWnHRfMVXRuZxL1G3_Z7I4jPL8zYS13D-XKRK18d5Hw-5eU-jeuPjVlMBhyvrSVtw57eUrLZCcG5JiU9MIjS9IKARPQ9i49HyQQoUcY1M8-vfYbk_IIImAGtbd-kMx3RTXPU/s1600-h/CAN_GLDC_2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPEVCr03sUXWnHRfMVXRuZxL1G3_Z7I4jPL8zYS13D-XKRK18d5Hw-5eU-jeuPjVlMBhyvrSVtw57eUrLZCcG5JiU9MIjS9IKARPQ9i49HyQQoUcY1M8-vfYbk_IIImAGtbd-kMx3RTXPU/s400/CAN_GLDC_2.jpg" /></a></div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><i style="color: red;"><b>White Backlight</b></i></div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; color: white; text-align: left;"><br />
</div><div class="separator" style="clear: both; color: white; text-align: left;">.</div><div class="separator" style="clear: both; color: white; text-align: left;">.</div><div class="separator" style="clear: both; color: black; text-align: left;">Watch video: <a href="http://www.youtube.com/watch?v=CZGxynxNAlM">http://www.youtube.com/watch?v=CZGxynxNAlM</a></div><div class="separator" style="clear: both; color: white; text-align: left;">.</div><div class="separator" style="clear: both; color: black; text-align: left;"><br />
</div><div class="separator" style="clear: both; color: black; text-align: left;"><br />
</div><div class="separator" style="clear: both; color: black; text-align: center;"><object height="505" width="640"><param name="movie" value="http://www.youtube.com/v/CZGxynxNAlM&hl=es&fs=1&"><param name="allowFullScreen" value="true"><param name="allowscriptaccess" value="always"><embed src="http://www.youtube.com/v/CZGxynxNAlM&hl=es&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="505"></embed></object></div><div class="separator" style="clear: both; color: white; text-align: left;"><br />
</div><div class="separator" style="clear: both; color: white; text-align: left;"><br />
</div><div class="separator" style="clear: both; color: white; text-align: left;"><br />
</div><div class="separator" style="clear: both; color: white; text-align: left;">.</div><div class="separator" style="clear: both; color: white; text-align: left;">.</div><div class="separator" style="clear: both; text-align: left;"><b><span style="font-size: large;">CHECK THE NEW SECUduino PROJECT => <a href="http://secuduino.blogspot.com/">http://secuduino.blogspot.com/</a></span></b> </div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;">Cheers!!</div><div class="separator" style="clear: both; color: white; text-align: left;">.</div><div class="separator" style="clear: both; color: white; text-align: left;">.</div><div class="separator" style="clear: both; color: white; text-align: left;">.</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div><br />
<div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div></div>Igorhttp://www.blogger.com/profile/07332255486737492708noreply@blogger.com7tag:blogger.com,1999:blog-5229899856062584712.post-15076320400038644942009-09-09T16:03:00.000-07:002011-01-18T06:22:05.720-08:00Nunchuck + MatLab + Arduino<div style="color: white;">.</div><br />
Arduino reads I2C from Nunchuck (WII) and sends to Matlab via serial port. First plot shows joystick movements and the below`s graph shows XYZ accelerometers movements of the WII controller (XYZ of 3D cylinder)<br />
<br />
Nunchuck with Arduino: <a dir="ltr" href="http://www.windmeadow.com/node/42" rel="nofollow" target="_blank" title="http://www.windmeadow.com/node/42">http://www.windmeadow.com/node/42</a><br />
<br />
Example: <a href="http://www.youtube.com/watch?v=5e3zSxABh4g">http://www.youtube.com/watch?v=5e3zSxABh4g</a><br />
<br />
<div style="text-align: center;"><object height="505" width="640"><param name="movie" value="http://www.youtube.com/v/5e3zSxABh4g&hl=es&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/5e3zSxABh4g&hl=es&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="505"></embed></object></div><div style="text-align: center;"></div><div style="text-align: left;"><div style="color: white;">. </div><span style="color: white;">. </span><br />
Cheers!!</div><div style="color: white; text-align: left;">.</div><div style="text-align: left;"><span style="color: white;">.</span></div><div style="color: blue; text-align: left;"><b>Igor R.</b></div><div style="color: white; text-align: left;">.</div><div style="text-align: left;"><span style="color: white;">.</span></div>Igorhttp://www.blogger.com/profile/07332255486737492708noreply@blogger.com3tag:blogger.com,1999:blog-5229899856062584712.post-21639505193585842592009-09-09T15:48:00.000-07:002011-01-18T06:22:05.721-08:00Uniendo Excel con Arduino<span style="color: white;">.</span><br />
<code><br />
<script src="http://www.gmodules.com/ig/ifr?url=http://www.google.com/ig/modules/translatemypage.xml&up_source_language=es&w=160&h=60&title=&border=&output=js">
</script> </code><br />
<br />
No cabe duda, que poder disponer de los datos adquiridos de nuestra placa de arduino en Excel resulta de lo más interesante. Una vez alli, graficar, crear canales matemáticos,... es facilísimo!!!<br />
(link foro arduino donde fue escrito originalmente => <a href="http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1230677761">http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1230677761</a> ) <br />
<br />
Para ello, podemos usar el objeto NETCommOCX (similar el MSComm).<br />
<a href="http://home.comcast.net/%7Ehardandsoftware/NETCommOCX.htm" target="_blank">http://home.comcast.net/~hardandsoftware/NETCommOCX.htm</a><br />
<br />
Veamos un ejemplo: <br />
<br />
<br />
<div style="text-align: center;"><object height="505" width="640"><param name="movie" value="http://www.youtube.com/v/4uxvAf0iLMM&hl=es&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/4uxvAf0iLMM&hl=es&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="505"></embed></object><br />
</div><br />
<br />
<span style="color: red;"></span><br />
<span style="color: red;"><span style="color: black;">Por la parte Arduino, necesitamos algo así:</span><br />
int serialByte;<br />
if (Serial.available()>0) serialByte=Serial.read();<br />
<br />
// Si recibe una C,envia datos de forma continua<br />
if (serialByte==67){ //Letra C mayuscula<br />
while (1)<br />
{<br />
analog5=analogRead(5);<br />
// Convierto a milivoltios<br />
fanalog5=(analog5)*(5000.0/1023);<br />
Serial.print(millis());<br />
Serial.print(",");<br />
Serial.println (fanalog5,DEC);<br />
if (PIND & B00100000) break;<br />
}<br />
<br />
}<br />
// Si recibe un D,envia un dato<br />
if (serialByte==68){ //Letra D mayuscula <br />
analog5=analogRead(5);<br />
// Convierto a milivoltios<br />
fanalog5=(analog5)*(5000.0/1023);<br />
Serial.print(millis());<br />
Serial.print(",");<br />
Serial.println (fanalog5,DEC);<br />
}</span><br />
<br />
<span style="color: red;"></span>Simplemente, si recibe una "C" por el puerto serie, empieza a mandar el dato de la entrada analógica de forma continua hasta que pulse el boton de mi hardware (leo todo el puerto D y aplico mascara para saber si he pulsado el botón).<br />
Si recibe una "D" manda un dato individual (esto es lo que uso para Excel).<br />
Los datos que envio son de la forma:<br />
<span style="color: red;">tiempo,valor_en_mv</span> con CR+CF<br />
<br />
<br />
En la parte EXCEL, lo que hago es añadir el objeto NETComm (en el codigo es NETComm2) a mi hoja. Para esto puedes ver culquier ejemplo con MSComm, que es similar. <br />
El único truco, es realizar una especie de Timer en excel. Es decir, que cada cierto tiempo,realice una acción. Para esto uso una llamada a una API de windows que te devuelve el tiempo en ms desde que inicio Windows.<br />
<br />
<span style="color: blue;">Private Declare Function timeGetTime Lib "winmm.dll" () As Long</span><br />
<br />
<span style="color: blue;">tiempo_inicial = timeGetTime()</span><br />
<span style="color: blue;"> Hoja2.Range("L3").FormulaR1C1 = 1</span><br />
<span style="color: blue;"> While (Hoja2.Range("L3").FormulaR1C1 <> "0")</span><br />
<span style="color: blue;"> tiempo_actual = timeGetTime()</span><br />
<span style="color: blue;"> If (tiempo_actual - tiempo_inicial) >= 200 Then</span><br />
<span style="color: blue;"> tiempo_inicial = timeGetTime()</span><br />
<span style="color: blue;"> NETComm2.Output = "D"</span><br />
<span style="color: blue;"> End If</span><br />
<span style="color: blue;"> kk = DoEvents()</span><br />
<span style="color: blue;"> Wend</span><br />
<br />
Como ves, cada 200 ms aproximadamente, envio una D por el puerto serie. Uso la casilla L3 de control, mientras no haya un 0, estoy enviando una D cada 200 ms.<br />
<br />
Luego, el objeto NETComm tiene un evento cada vez que recibe un dato por el puerto serie. Lo que hago es configurarlo para que entre cada vez que recibo un byte, y separo tiempo y dato. Lo pongo en dos casillas diferente. Luego no tengo más que añadir gráficos en Excel que esten vinculados a estas casillas.....<br />
<br />
<br />
<br />
<div style="text-align: center;"><span style="font-size: large;"><a href="http://cid-d2ee689f353f15bc.skydrive.live.com/self.aspx/P%c3%bablico/Comunicaci%c3%b3n%20con%20Arduino%20v2.xls"><span style="color: red;">CLICK AQUI PARA DESCARGAR EXCEL EJEMPLO</span></a> <b><span style="color: red;"></span></b></span><br />
</div><br />
<br />
<br />
Puedes ver otro ejemplo basado en este trabajo realizado por Nicolas:<br />
<a href="http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1230677761">http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1230677761</a> <br />
<br />
<br />
<div style="text-align: center;"><object height="505" width="640"><param name="movie" value="http://www.youtube.com/v/JSbESa5wclI&hl=es&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/JSbESa5wclI&hl=es&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="505"></embed></object><br />
</div><br />
( <a href="http://ingenegros.com.ar/Microcontroladores/graficar-con-el-excel-mediciones-tomadas-por-arduino.html">http://ingenegros.com.ar/Microcontroladores/graficar-con-el-excel-mediciones-tomadas-por-arduino.html</a> )<br />
<br />
<br />
<br />
<br />
Saludos!!<br />
<div style="color: white;">.<br />
</div><span style="color: white;">.</span><br />
<div style="color: blue;"><i><b>Igor R.</b></i><br />
</div><div style="color: white;">.<br />
</div><div style="color: white;">.<br />
</div><div style="color: white;">.<br />
</div>Igorhttp://www.blogger.com/profile/07332255486737492708noreply@blogger.com10tag:blogger.com,1999:blog-5229899856062584712.post-14399167145328309492009-09-09T15:17:00.000-07:002011-01-18T06:22:05.723-08:00Power Sleep Mode<b><span style="color: red;"> </span></b><b style="color: white;">. </b><br />
Vamos a ver como poder ahorrar consumo en nuestros diseños con Arduino. El ATMega168 dispone de diferentes tipos de sleep mode (ver documentación de atmel).<br />
<br />
En el playground,disponemos algo de información:<a href="http://www.arduino.cc/playground/Learning/ArduinoSleepCode"> http://www.arduino.cc/playground/Learning/ArduinoSleepCode </a><br />
<br />
Aquí hableremos del <b>Power Save Mode</b>, para sustituir esto los delays y poder ahorrar bateria. En concreto el micro se pone a dormir y se despierta cuando hay un Overflow del Timer2.<br />
<br />
Pongo el código de una simple aplicación que hace parpadear el led del pin 13 del Diecimila durante 2 segundos (para poder medir la corriente).<br />
Los resultados han sido:<br />
<ul><li><span style="color: red;">Sleep Mode and turn off devices</span> => Led_on=12,98 mA; Led_off=9,91 mA</li>
<li><span style="color: red;">No Sleep and turn off devices</span> => Led_on=28,9 mA ; Led_off=25,9 mA</li>
<li><span style="color: red;">No Sleep </span> => Led_on=32,2 mA ; Led_off=29,2 mA</li>
</ul><br />
Turn off devices es que apago el ADC, Timer 0, Timer 1, USART, TWI y SPI.<br />
<br />
<br />
<br />
<br />
<br />
<span style="font-size: large;"><b><span style="color: red;">SLEEP MODE TEST CODE</span></b></span><br />
<br />
<br />
<br />
<pre class="code" style="height: 300px; margin: 0px; overflow: auto; width: auto;">#include <avr interrupt.h="">
#include <avr sleep.h="">
volatile int cont;
void setup()
{
pinMode(13,OUTPUT);
TCCR2A=0;
TCCR2B=(0<<7)|(0<<6)|(0<<5)|(0<<4)|(0<<3)|(1<<2)|(1<<1)|(1<<0);
// Bit 0.- Overflow
TIMSK2=(0<<2)|(0<<1)|(1<<0);
//Power Save Mode
SMCR=(0<<3)|(1<<2)|(1<<1)|(0<<0);
}
ISR(TIMER2_OVF_vect)
{
cont++;
}
void loop()
{
sleep_enable();
//Turn off ADC
ADCSRA=0;
// TWI | TIMER2 | TIMER0 | VOID | TIMER1 | SPI | USART | ADC
PRR=(1<<7)|(0<<6)|(1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|(1<<0);
sei();
while (cont<122)
{
//Go to Sleep
sleep_mode();
}
//Disable Sleep
sleep_disable();
//Disable interrupts
cli();
cont=0;
digitalWrite(13,!digitalRead(13));
}
</avr></avr></pre><br />
<br />
<span style="font-size: large;"><b><span style="color: red;">NO SLEEP AND TURN OFF DEVICES</span></b></span><br />
<br />
<br />
<pre class="code" style="height: 300px; margin: 0px; overflow: auto; width: auto;">#include <avr interrupt.h="">
#include <avr sleep.h="">
volatile int cont;
void setup()
{
pinMode(13,OUTPUT);
TCCR2A=0;
TCCR2B=(0<<7)|(0<<6)|(0<<5)|(0<<4)|(0<<3)|(1<<2)|(1<<1)|(1<<0);
// Bit 0.- Overflow
TIMSK2=(0<<2)|(0<<1)|(1<<0);
//Turn off ADC
ADCSRA=0;
// TWI | TIMER2 | TIMER0 | VOID | TIMER1 | SPI | USART | ADC
PRR=(1<<7)|(0<<6)|(1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|(1<<0);
sei();
}
ISR(TIMER2_OVF_vect)
{
cont++;
if (cont<122)
{
cont=0;
digitalWrite(13,!digitalRead(13));
}
}
void loop()
{
}
</avr></avr></pre><br />
<br />
<span style="font-size: large;"><b><span style="color: red;">NO SLEEP</span></b></span><br />
<br />
<br />
<pre class="code" style="height: 300px; margin: 0px; overflow: auto; width: auto;">#include <avr interrupt.h="">
#include <avr sleep.h="">
volatile int cont;
void setup()
{
pinMode(13,OUTPUT);
TCCR2A=0;
TCCR2B=(0<<7)|(0<<6)|(0<<5)|(0<<4)|(0<<3)|(1<<2)|(1<<1)|(1<<0);
// Bit 0.- Overflow
TIMSK2=(0<<2)|(0<<1)|(1<<0);
//Turn off ADC
//ADCSRA=0;
// TWI | TIMER2 | TIMER0 | VOID | TIMER1 | SPI | USART | ADC
//PRR=(1<<7)|(0<<6)|(1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|(1<<0);
sei();
}
ISR(TIMER2_OVF_vect)
{
cont++;
if (cont==122)
{
cont=0;
digitalWrite(13,!digitalRead(13));
}
}
void loop()
{
}
</avr></avr></pre><b style="color: white;">. </b><b><span style="color: red;"> </span></b><br />
<b><span style="color: red;"> </span></b><b style="color: white;">. <br />
</b><br />
<b><span style="color: red;"> </span></b><b style="color: white;">. <br />
</b><br />
<span style="color: red;"><span style="color: black;">Saludos</span></span><br />
<b style="color: white;">. </b><b><span style="color: red;"> </span></b><br />
<b><span style="color: red;"> </span></b><b style="color: white;">. <br />
</b><br />
<b><span style="color: red;"> </span></b><b style="color: white;">. </b><br />
<b><span style="color: red;"><span style="color: black;"><span style="color: blue;">Igor R.</span> </span></span></b><br />
<b style="color: white;">. </b><b><span style="color: red;"> </span></b><br />
<b><span style="color: red;"> </span></b><b style="color: white;">. <br />
</b><br />
<b><span style="color: red;"> </span></b><b style="color: white;">. </b><br />
<b><span style="color: red;"><span style="color: black;"> </span> <br />
</span></b>Igorhttp://www.blogger.com/profile/07332255486737492708noreply@blogger.com1tag:blogger.com,1999:blog-5229899856062584712.post-81806622972616457212009-09-09T06:01:00.000-07:002011-04-28T09:45:38.583-07:00Shift Lights con Arduino<div dir="ltr" style="text-align: left;" trbidi="on"><span style="color: white;">. </span><br />
<code><br />
<script src="http://www.gmodules.com/ig/ifr?url=http://www.google.com/ig/modules/translatemypage.xml&up_source_language=es&w=160&h=60&title=&border=&output=js">
</script> </code><br />
<br />
<br />
Un amigo me pidió que le hiciera unas "Shift Lights" para su coche de competición. Son luces de cambio, es decir, según las revoluciones motor, se van encendiendo progresivamente.<br />
<br />
Es un coche antiguo y he sacado la señal del distribuidor. Disponía de un sensor Hall (conmuta con masa para dar la chispa. Está en serie con la bobina). La entrada al pin 2 (int 0) la he protegido con una resistencia en serie de gran valor y un zener de 5V1 (recordad que está en serie con una bobina). A parte, las entradas del ATMega 168 vienen protegidos con "clamp diodes" (como máximo permiten 1 mA).<br />
<br />
Recordad: el arbol del levas va a la mitad de velocidad que las revoluciones motor. Además, en mi montaje, por cada vuelta hay 4 pulsos.<br />
<br />
He eliminado el conector de alimentación externa del Arduino, y he soldado unos cables para la alimentación en su lugar. También he puesto un Varistor para proteger de sobretensiones la etapa de alimentación.<br />
<br />
He usado diodos leds tricolores (los puedes encontrar en Bricogeek ó Sparkfun).<br />
<br />
<br />
Es un montaje muy rápido preparar y de programar.Pongo un video del resultado:<br />
<br />
<div style="text-align: center;"></div><div style="text-align: center;"></div><div style="text-align: center;"> <object height="505" width="640"><param name="movie" value="http://www.youtube.com/v/PxaYx8HX9Og&hl=es&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/PxaYx8HX9Og&hl=es&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="505"></embed></object></div><br />
<br />
La secuencia según aumentan las rpm:<br />
<b>1)</b> primer led verde on<br />
<b>2)</b> dos primeros verdes on <br />
<b>3)</b> los dos primeros leds verdes on y el tercero en azul on<br />
<b>4)</b> en el momento de cambio=> los 3 leds on en rojo.<br />
<br />
Para avisar de overrevs, se le ponen todas en azul (viene bien sobre todo cuando se baja de marcha si no quieres que sufran válvulas y sus muelles, etc).<br />
<br />
En el video, parece que los leds iluminan mucho, pero está bien. Es un problema de la calidad (grabado con un móvil). Tampoco es la ubicación definitiva y se podría hacer más pequeño.... al gusto del consumidor... <b>;)</b><br />
<br />
<br />
<br />
<pre class="code" style="height: 300px; margin: 0px; overflow: auto; width: auto;">//SHIFT LIGHTS
//By Igor Real
//13-09-09
#define Primera_ON 5500
#define Segunda_ON 6000
#define Tercera_ON 6500
#define Todas_ON 7000
#define OVERREV 8000
//----------------------------
#define Third_Red 13
#define Third_Blue 12
#define Third_Green 11
//----------------------------
#define Second_Red 10
#define Second_Blue 9
#define Second_Green 8
//----------------------------
#define First_Red 5
#define First_Blue 6
#define First_Green 7
volatile unsigned long cont_rpm;
void setup()
{
pinMode(Third_Red, OUTPUT);
pinMode(Third_Green, OUTPUT);
pinMode(Third_Blue, OUTPUT);
pinMode(Second_Red, OUTPUT);
pinMode(Second_Green, OUTPUT);
pinMode(Second_Blue, OUTPUT);
pinMode(First_Red, OUTPUT);
pinMode(First_Green, OUTPUT);
pinMode(First_Blue, OUTPUT);
//-----------------------------------------
digitalWrite(Third_Red,LOW);
digitalWrite(Third_Green,LOW);
digitalWrite(Third_Blue,LOW);
digitalWrite(Second_Red,LOW);
digitalWrite(Second_Green,LOW);
digitalWrite(Second_Blue,LOW);
digitalWrite(First_Red,LOW);
digitalWrite(First_Green,LOW);
digitalWrite(First_Blue,LOW);
//-----------------------------------------
pinMode(2,INPUT);
attachInterrupt(0, rpm, RISING);
Serial.begin(9600);
}
void rpm()
{
cont_rpm++;
}
void loop()
{
static unsigned long rpm_ant;
static unsigned long t_anterior;
static float rpm_actuales;
rpm_ant=cont_rpm;
t_anterior=millis();
delay(100);
rpm_actuales=(cont_rpm-rpm_ant)/(2.0*(millis()-t_anterior)/60000);
Serial.println(rpm_actuales);
if (rpm_actuales<primera_on){>
digitalWrite(Third_Red,LOW);
digitalWrite(Third_Green,LOW);
digitalWrite(Third_Blue,LOW);
digitalWrite(Second_Red,LOW);
digitalWrite(Second_Green,LOW);
digitalWrite(Second_Blue,LOW);
digitalWrite(First_Red,LOW);
digitalWrite(First_Green,LOW);
digitalWrite(First_Blue,LOW);
}else if((rpm_actuales>=Primera_ON) && (rpm_actuales <segunda_on)){>
digitalWrite(First_Green,HIGH);
digitalWrite(Third_Red,LOW);
digitalWrite(Third_Green,LOW);
digitalWrite(Third_Blue,LOW);
digitalWrite(Second_Red,LOW);
digitalWrite(Second_Green,LOW);
digitalWrite(Second_Blue,LOW);
digitalWrite(First_Red,LOW);
digitalWrite(First_Blue,LOW);
}else if ((rpm_actuales>=Segunda_ON) && (rpm_actuales <tercera_on)){>
digitalWrite(Second_Green,HIGH);
digitalWrite(First_Green,HIGH);
digitalWrite(Third_Red,LOW);
digitalWrite(Third_Green,LOW);
digitalWrite(Third_Blue,LOW);
digitalWrite(Second_Red,LOW);
digitalWrite(Second_Blue,LOW);
digitalWrite(First_Red,LOW);
digitalWrite(First_Blue,LOW);
}else if ((rpm_actuales>=Tercera_ON) && (rpm_actuales <todas_on)){>
digitalWrite(Third_Blue,HIGH);
digitalWrite(First_Green,HIGH);
digitalWrite(Second_Green,HIGH);
digitalWrite(Third_Red,LOW);
digitalWrite(Third_Green,LOW);
digitalWrite(Second_Red,LOW);
digitalWrite(Second_Blue,LOW);
digitalWrite(First_Red,LOW);
digitalWrite(First_Blue,LOW);
}else if ((rpm_actuales>=Todas_ON) && (rpm_actuales <overrev)){>
digitalWrite(Third_Red,HIGH);
digitalWrite(Second_Red,HIGH);
digitalWrite(First_Red,HIGH);
digitalWrite(Third_Green,LOW);
digitalWrite(Third_Blue,LOW);
digitalWrite(Second_Green,LOW);
digitalWrite(Second_Blue,LOW);
digitalWrite(First_Green,LOW);
digitalWrite(First_Blue,LOW);
}else if (rpm_actuales>=OVERREV){
digitalWrite(Third_Red,LOW);
digitalWrite(Third_Green,LOW);
digitalWrite(Second_Red,LOW);
digitalWrite(Second_Green,LOW);
digitalWrite(First_Red,LOW);
digitalWrite(First_Green,LOW);
digitalWrite(Third_Blue,HIGH);
digitalWrite(Second_Blue,HIGH);
digitalWrite(First_Blue,HIGH);
delay(1000);
}
}
</overrev)){></todas_on)){></tercera_on)){></segunda_on)){></primera_on){></pre><div style="color: white;">.</div><div style="color: white;">.</div><span style="color: white;">.</span>Saludos!!<br />
<div style="color: white;">.</div><div style="color: white;">.</div><span style="color: white;">.</span><br />
<i><b style="color: blue;">Igor R.</b></i><br />
<div style="color: white;">.</div><div style="color: white;">.</div><span style="color: white;">.</span></div>Igorhttp://www.blogger.com/profile/07332255486737492708noreply@blogger.com4tag:blogger.com,1999:blog-5229899856062584712.post-54630388937013562062009-09-09T05:49:00.000-07:002011-01-18T06:22:05.727-08:00Añadiendo logger a tu Arduino....Vinculum<span style="color: white;">.</span><br />
<span style="color: white;"></span>He estado experimentando un poco con el chip Vinculum de FTDI. En concreto con el módulo de prototipos VDIP1. <a href="http://www.vinculum.com/prd_vdip1.html" target="_blank">http://www.vinculum.com/prd_vdip1.html</a><br />
<br />
Te permite manejar un dispositivo USB y maneja archivos FAT de forma transparente, por lo que es ideal para aplicaciones donde se desea guardar datos sin muchas complicaciones. El precio es de 22 euros desde la web del fabricante.<br />
He realizado un pequeño ejemplo basandome en la información que hay en el Playground de Arduino y a un ejemplo de la web del fabricante con un PIC.<br />
<a href="http://www.arduino.cc/playground/Main/UsbMemory" target="_blank">http://www.arduino.cc/playground/Main/UsbMemory</a><br />
<a href="http://www.vinculum.com/downloads.html#vutilities" target="_blank">http://www.vinculum.com/downloads.html#vutilities</a><br />
<br />
He usado el Mega con el Serial 3, y sin "flow control". Lo suyo sería utilizar las lineas CTS y RTS para saber si el dispositivo esta preparado para recibir información.<br />
La conexión del VDIP1:<br />
<span style="color: red;"><b>Pin 1.- 5 voltios<br />
Pin 6.- TXD<br />
Pin 7.- GND<br />
Pin 8.-RXD<br />
Pin 10.- GND</b></span><br />
<br />
En el ejemplo, cada vez que se pulsa un pulsador conectado al pin 9, se abre un archivo como escritura llamado igor.txt y se guarda una linea de texto en la que pone IGOR y el tiempo millis() en una linea. Es un poco tonto, pero para empezar esta bien... Voy sacando la info del programa por el Serial (el USB de programar).<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_HqRWIKU8Y2yNJv6kBiqI7D8sCgag3EcnPAqQGeVg7PoBXG5jY859CKNeHqsts1QbWNWGsi9UWLkPf3iyVAOaGElLDPVHlXXL0JNZ7rNJeZRc5DZt7Qdt3wbZnTQF9uHQn0Qq-bv-GIWX/s1600-h/Arduino_Mega_Shield.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_HqRWIKU8Y2yNJv6kBiqI7D8sCgag3EcnPAqQGeVg7PoBXG5jY859CKNeHqsts1QbWNWGsi9UWLkPf3iyVAOaGElLDPVHlXXL0JNZ7rNJeZRc5DZt7Qdt3wbZnTQF9uHQn0Qq-bv-GIWX/s400/Arduino_Mega_Shield.JPG" /></a> </div><div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"> <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirE8ewD_usT3vDXKYiVu7xjTyb332TSMbGi9sN1u_zrQ26bn2w5Hgm90E-R5h0Sl6RmSATpWJHku3UyQ5N1WT91wXrgRRxc9pRjM8YBQx53yqJeGyq1k_fURIz7nQfW3JsMOhaYqeBy3it/s1600-h/Arduino_Mega_Shield2.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirE8ewD_usT3vDXKYiVu7xjTyb332TSMbGi9sN1u_zrQ26bn2w5Hgm90E-R5h0Sl6RmSATpWJHku3UyQ5N1WT91wXrgRRxc9pRjM8YBQx53yqJeGyq1k_fURIz7nQfW3JsMOhaYqeBy3it/s400/Arduino_Mega_Shield2.JPG" /></a></div><br />
<br />
<br />
<br />
<br />
<br />
<pre class="code" style="height: 300px; margin: 0px; overflow: auto; width: auto;">//---------------------------------------
//By Igor Real
//VDIP1 without flow control
//11-07-09
//---------------------------------------
byte dato_recibido;
byte VNC1_State=0;
int noOfChars=1;
long int x;
long int val;
void setup() {
pinMode(9,INPUT);
Serial.begin(9600);
Serial3.begin(9600);
Serial3.flush();
Serial3.print("IPA");
Serial3.print(13,BYTE); //RETURN
//CONTESTA UN D:\> + CR
if (VNC1_Confirmation()){
Serial.println("CONFIGURADO LONG COMMAND");
}else{
Serial.println("ALGO FALLO");
}
}
void loop()
{
if (digitalRead(9)==1){
delay(300);
//VNC1_State=0 => Sync
//VNC1_State=1 => FindDisk
switch(VNC1_State){
case 0:
if (VNC1_Sync()==1){
if (VNC1_FindDisk()==1){
VNC1_State=1;
}else{
Serial.println("No hay disco");
}
}else{
Serial.println("Imposible Sync");
}
break;
case 1:
Serial.println("Hay disco");
Serial3.flush();
//Abro fichero para escritura
Serial3.print("OPW igor.txt");
Serial3.print(13,BYTE); //RETURN
//CONTESTA UN D:\> + CR
while (VNC1_Confirmation()==0);
//Meto datos
val=millis();
x=val;
noOfChars=1;
while (x>= 10){
noOfChars++;
x/=10;
}
noOfChars +=7;
Serial3.print("WRF ");
Serial3.print(noOfChars);
Serial3.print(13,BYTE); //RETURN
Serial3.print(73,BYTE); //I
Serial3.print(71,BYTE); //G
Serial3.print(79,BYTE); //O
Serial3.print(82,BYTE); //R
Serial3.print(32,BYTE); //<space>
Serial3.print(val);
Serial3.print(13,BYTE); //RETURN
Serial3.print(10,BYTE); //NEW LINE
Serial3.print(13,BYTE); //RETURN
//CONTESTA UN D:\> + CR
while (VNC1_Confirmation()==0);
Serial3.print("CLF igor.txt");
Serial3.print(13,BYTE);
//CONTESTA UN D:\> + CR
while (VNC1_Confirmation()==0);
VNC1_Sync();
Serial.println("Sacar el disco");
VNC1_State=0;
break;
default:
VNC1_State=0;
}
}
}
//----------------------------------------------------------------
// FUNCION: MIRAR SI HAY PENDRIVE
//----------------------------------------------------------------
byte VNC1_FindDisk(){
byte FindDisk=0;
Serial3.flush();
Serial3.print(13,BYTE); //RETURN
//CONTESTA UN D:\> + CR
if (VNC1_Confirmation()){
FindDisk=1;
}else{
FindDisk=0;
}
//Serial.print("FindDisk= ");
//Serial.println(FindDisk,DEC);
Serial3.flush();
return FindDisk;
}
//----------------------------------------------------------------
// FUNCION: MIRAR SI HE RECIBIDO D:\>
//----------------------------------------------------------------
byte VNC1_Confirmation(){
byte state=0;
byte byte_received;
byte confirm=0;
while (Serial3.available()<5) ;
//Serial.print("Buffer= ");
//Serial.println(Serial3.available(),DEC);
while (Serial3.available()){
byte_received=Serial3.read();
//Serial.println(byte_received,DEC);
if (byte_received==68 && state==0){
//Received "D"
state=1;
//Serial.println ("Estado 1");
}else if (byte_received==58 && state==1){
//Received ":"
state=2;
//Serial.println ("Estado 2");
}else if (byte_received==92 && state==2){
//Received "\"
state=3;
//Serial.println ("Estado 3");
}else if (byte_received==62 && state==3){
//Received ">"
state=4;
//Serial.println ("Estado 4");
}else if (byte_received==13 && state==4){
//Received "CR"
state=0;
confirm=1;
//Serial.println ("Estado 5");
break;
}else{
confirm=0;
break;
}
}
return confirm;
}
//----------------------------------------------------------------
// FUNCION: SYNC
//----------------------------------------------------------------
byte VNC1_Sync(){
byte cont_E=0;
byte confirm_E=0;
byte confirm_e=0;
byte state=0;
byte byte_received=0;
Serial3.flush();
while (confirm_E==0 && cont_E<255){
Serial3.print(69,BYTE); //E
Serial3.print(13,BYTE); //RETURN
cont_E++;
//Serial.print("Contador= ");
//Serial.println(cont_E,DEC);
while (Serial3.available()<2) ;
while (Serial3.available()){
byte_received=Serial3.read();
//Serial.println(byte_received,DEC);
if (byte_received==69 && state==0){
//Received "E"
state=1;
//Serial.println ("Estado 1");
}else if (byte_received==13 && state==1){
//Received "CR"
state=2;
confirm_E=1;
//Serial.println ("Estado 2");
break;
}else{
confirm_E=0;
delay(10);
}
}
}
if (confirm_E==1){
//Serial.println("Vamos por e");
Serial3.print(101,BYTE); //e
Serial3.print(13,BYTE); //RETURN
while (Serial3.available()<2) ;
if (Serial3.read()==101){
if (Serial3.read()==13){
confirm_e=1;
}
}
}
return confirm_e;
}
//----------------------------------------------------------------
</space></pre><br />
<span style="color: white;">.</span><br />
<span style="color: white;">.</span><br />
Saludos<br />
<br />
<span style="color: white;">.</span><br />
<span style="color: white;">.</span><i><b style="color: blue;">Igor R.</b></i><br />
<span style="color: white;">.</span><br />
<span style="color: white;">.</span>Igorhttp://www.blogger.com/profile/07332255486737492708noreply@blogger.com8tag:blogger.com,1999:blog-5229899856062584712.post-36258596470445308902009-09-09T03:27:00.000-07:002011-01-18T06:22:05.729-08:00Buses de campo para Arduino.... RS485<div style="color: white;">. </div><span style="color: white;">. </span><br />
Originalmente, toda la información la publiqué en el foro de Arduino en español. Puedes seguirlo <a href="http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1245014666/all">aquí</a>.<br />
<br />
El RS485 es un estandar de comunicación serie en el cual se pueden tener varios dispositivos en topología de bus y de una manera muy económica. Aquí explicaremos brevemente como realizar una pequeña red basada en 2 hilos.<br />
Dado que sólo se usan dos hilos balanceados (diferencial), las comunicaciones son semiduplex. Para configurar el driver como transmisor o receptor, el driver dispone de una entrada digital para su configuración.<br />
<br />
Para darle conectividad RS485 a nuestro arduino, sólo necesitamos de un convertidor de niveles para usar la UART del micro, y por menos de 1 euro tendremos todo lo necesario.<br />
Los chips más usados son:<br />
- Max485<br />
- SN75176 (siendo éste el más económico)<br />
<br />
<br />
<div style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHRS-BfAWunkbnFU1ZImo8vpKUBiidh9heHicuwpXfCkYTyRAIB2iqVkP7g4varpJSxPY5FWdHe1b7Zii_qu51EG03AnLiauvpqC7YAdNIX2ctsh6s8torfneqm8h3UAG_RcTsBaCwH3Q2/s1600-h/MAX485.JPG" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5379417673302781858" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHRS-BfAWunkbnFU1ZImo8vpKUBiidh9heHicuwpXfCkYTyRAIB2iqVkP7g4varpJSxPY5FWdHe1b7Zii_qu51EG03AnLiauvpqC7YAdNIX2ctsh6s8torfneqm8h3UAG_RcTsBaCwH3Q2/s400/MAX485.JPG" style="margin: 0pt 10px 10px 0pt;" /></a></div><br />
<br />
La norma RS485 sólo establece las características físicas, no definiendo ningún protocolo ó forma de conexionado.<br />
<br />
Señalamos unos links muy recomendables:<br />
<a href="http://www.i-micro.com/pdf/articulos/rs-485.pdf">http://www.i-micro.com/pdf/articulos/rs-485.p</a><a href="http://www.i-micro.com/pdf/articulos/rs-485.pdf">df</a><br />
<a href="http://www.maxim-ic.com/appnotes.cfm?appnote_number=763&CMP=WP-1">http://www.maxim-ic.com/appnotes.cfm?appnote_number=763&CMP=WP-1</a><br />
<a href="http://www.neoteo.com/rs485-domotica-al-alcance-de-tu-mano-15810.neo">http://www.neoteo.com/rs485-domotica-al</a><a href="http://www.neoteo.com/rs485-domotica-al-alcance-de-tu-mano-15810.neo">-alcance-de-tu-mano-15810.neo</a><br />
Documento con tramas de ejemplo para solucionar problemas <br />
<a href="http://www.sbc-support.ch/faq/files/files.get.php?ZSESSIONID=n38bphov4ls4cdsvtbd8tl6jb4&fi_index=100179" target="_blank">http://www.sbc-support.ch/faq/files/files.get.php?ZSESSIONID=n38bphov4ls4cdsvtbd...</a><br />
<br />
<br />
<br />
La manera más sencilla de aprender como realizar un protocolo, es basarte en algo que ya existe. Para ello, me he basado en el protocolo profesional usado por Fuji para sus variadores industriales.<br />
Véase: <a href="http://www.cdautomation.com/download/ENG_L_M_FUJI_RS485_COMM_for_FRENIC-Mini.PDF">http://www.cdautomation.com/download/ENG_</a><a href="http://www.cdautomation.com/download/ENG_L_M_FUJI_RS485_COMM_for_FRENIC-Mini.PDF">L_M_FUJI_RS485_COMM_for_FRENIC-Mini.PDF</a><br />
<br />
Veamos un diagrama explicativo de la trama:<br />
<br />
<br />
<div style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-dXbwqUE4J0A77zpH7UEOUXJmR5MTjEp5g6oP-IVvjpbrCZdKO_5Ci7ZpvQtzXP9IgIhPjGM4Lz2YxOuhV6P0i850aaP-WomMJbiqSma0ksFCvuDayBZnN31sb69df0qBctv-e6wBknZq/s1600-h/RS485_conexionado.JPG" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5379420144499317010" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-dXbwqUE4J0A77zpH7UEOUXJmR5MTjEp5g6oP-IVvjpbrCZdKO_5Ci7ZpvQtzXP9IgIhPjGM4Lz2YxOuhV6P0i850aaP-WomMJbiqSma0ksFCvuDayBZnN31sb69df0qBctv-e6wBknZq/s400/RS485_conexionado.JPG" style="margin: 0pt 10px 10px 0pt;" /></a></div><br />
Las tramas son de 15 bytes:<br />
<ul><li>Byte 1: Byte de start ( 0 hexadecimal ).</li>
<li>Byte 2-3: SCII de la dirección del arduino.</li>
<li>Byte 4: Byte ENQ, ACK ó NAK (0x05h, 0x06h y 0x15h) .</li>
<li>Byte 5: ASCII del comando petición.</li>
<li>Byte 6 y 7: ASCII del número de función.</li>
<li>Byte 8: Byte signo (Positivo 0x20h y Negativo 2D)</li>
<li>Byte 9-12: ASCII con el dato (0x00h-0xFFFFh)</li>
<li>Byte 13: Byte fin de texto (0x03h)</li>
<li>Byte 14-15: Checksum (suma de byte 2 al byte13)</li>
</ul><br />
Con esta trama se dispone de un byte que indica función + 2 bytes con el número de la función, por lo cual se pueden hacer multitud de combinaciones… Algunos ejemplos pueden ser: A01 realiza una petición de datos de la entrada analógica 1, P01 realiza una configuración de PWM 1 con el dato enviado en los 4 bytes de datos,… Elección del diseñador!!!<br />
Se puede observar que los comandos están en ASCII y los bytes de control no. Esto ayuda enormente en la programación, ya que si recibimos 0x00 (suponiendo que es el byte de start), nuestro programa sabe que es un inicio de trama y no lo entiende como un "0" (número cero), ya que éste se enviaría en ASCII (0x30).<br />
A continuación, adjunto una tabla ASCII sacada de <a href="http://www.cs.utk.edu/%7Epham/ascii_table.jpg">http://www.cs.utk.edu/~pham/ascii_table.jpg</a><br />
<br />
<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHtBe2WgRLVNeo1WTKYQw0gCAZlEZ9D9ZOGmOxb0YMKSehdUCW9z0N-zwS_4qlUlzWAmVYZEk81UaCXhKJjgIyT4J1_Mjc-xKiUGrcS9WReFGqvtZUBzxKJgPm1yQ5UMokHvHIBbsOWjJS/s1600-h/ascii_table.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5379426831296192610" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHtBe2WgRLVNeo1WTKYQw0gCAZlEZ9D9ZOGmOxb0YMKSehdUCW9z0N-zwS_4qlUlzWAmVYZEk81UaCXhKJjgIyT4J1_Mjc-xKiUGrcS9WReFGqvtZUBzxKJgPm1yQ5UMokHvHIBbsOWjJS/s400/ascii_table.jpg" style="display: block; margin: 0px auto 10px; text-align: center;" /></a><br />
<br />
Veamos un ejemplo:<br />
Queremos que un arduino (maestro) envíe la orden de encendido/apagado de un led conectado a otro arduino arduino (esclavo). El interruptor está en el maestro y la actuación (encendido/apagado) en el esclavo.<br />
<br />
Según el estado del interruptor, el maestro envía la trama de petición de encendio/apagado, al esclavo ,cuya dirección es 01. Se ha decidido que la función se llamará D y el número 00 (completamente configurable).<br />
Ej: 0x00 0x30 0x31 0x05 0x44 0x30 0x30 0x20 0x30 0x30 0x30 0x31 0x03 0x01 0xEE<br />
El esclavo, contesta con un ACK (byte 4) al maestro confirmando el dato recibido.<br />
Ej: 0x00 0x30 0x31 0x06 0x44 0x30 0x30 0x20 0x30 0x30 0x30 0x31 0x03 0x01 0xEF<br />
<br />
Mejor,lo vemos con un video: <a href="http://www.youtube.com/watch?v=ABcjU0Ua-d4">http://www.youtube.com/watch?v=ABcjU0Ua</a><a href="http://www.youtube.com/watch?v=ABcjU0Ua-d4">-d4</a><br />
<br />
<div style="text-align: center;"><object height="640" width="505"><param name="movie" value="http://www.youtube.com/v/ABcjU0Ua-d4&hl=es&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/ABcjU0Ua-d4&hl=es&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object></div><br />
(el interruptor es un triste cable que lo llevo a masa o VCC.... sorry!!!)<br />
<br />
Para poder ver las tramas, bastará un conversor USB <--> RS232 basado en chip ftdi, ó un MAX232+MAX485,... Si tienes una placa Arduino de sobra, quitale el micro y tendrás un conversor USB --> RS232.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuvxZOQSu_OdihhgEGU_-PiwsntFdHIK5-bJS3CdhO3PsDW7w5QQS_8R7ONumfYG7Px0fopP3hWSKclTax2vzRgE0rQoW8ednERWmHanBZ-WHylBeTgXmcCLLhDO_xEzVixMv54DovaVJM/s1600-h/primer+ejemplo.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuvxZOQSu_OdihhgEGU_-PiwsntFdHIK5-bJS3CdhO3PsDW7w5QQS_8R7ONumfYG7Px0fopP3hWSKclTax2vzRgE0rQoW8ednERWmHanBZ-WHylBeTgXmcCLLhDO_xEzVixMv54DovaVJM/s400/primer+ejemplo.JPG" /></a></div><br />
<br />
El software para monitorizar lo que está pasado, puede ser el hyperterminal de windows ó alguno gratuito que añaden mejoras como poder ver los datos en hexadecimal, grabar,...:<br />
<a href="http://realterm.sourceforge.net/">RealTerm</a><br />
<a href="http://www.serial-port-monitor.com/free-serial-port-monitor-product-details.html">FREE SERIAL TERMINAL MONITOR</a><br />
<br />
<br />
Ahora veamos un ejemplo con 3 arduinos interconectados. El mestro dispone de 2 switch, los cuales comandan el encendido/apagado de un led conectado a cada uno de los esclavos.<br />
<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7f3kzOBrdn1VBFxlX3mngdy52-sbDck8EpL7Tb6UoQiChHwOg_8njhCLtqHRyhmOEBtgs8Dc-UgZZHppb8K6nSjJKGu96RHq9WrPIrCGn_-lel_4_BMaXsoVxlY7JRkIrYZ8Zyow_L800/s1600-h/RS485+2+Esclavos.JPG" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5379429156460641954" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7f3kzOBrdn1VBFxlX3mngdy52-sbDck8EpL7Tb6UoQiChHwOg_8njhCLtqHRyhmOEBtgs8Dc-UgZZHppb8K6nSjJKGu96RHq9WrPIrCGn_-lel_4_BMaXsoVxlY7JRkIrYZ8Zyow_L800/s400/RS485+2+Esclavos.JPG" style="display: block; margin: 0px auto 10px; text-align: center;" /></a><br />
<br />
Veamos el video de funcionamiento: <a href="http://www.youtube.com/watch?v=S9FSQaToVZ4">http://www.youtube.com/watch?v=S9FSQaToVZ4<br />
</a><br />
<br />
<div style="text-align: center;"><object height="640" width="505"><param name="movie" value="http://www.youtube.com/v/S9FSQaToVZ4&hl=es&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/S9FSQaToVZ4&hl=es&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object></div><br />
<br />
Ahora toca el código:<br />
<br />
<span style="color: blue;"><b>IMPORTANTE:</b> <i>El checksum lo hago directamente en hexadecimal en vez de convertirlo a ASCII. Se debería cambiar el código, para no tener problemas. Esta publicación se trata de un acercamiento de como manejar el bus rs485 y explicar como implementar un protocolo, por lo que no está 100%.<br />
</i></span><br />
<br />
<br />
<br />
<div style="color: #cc0000;"><b><span style="font-size: large;">MAESTRO:</span></b></div><br />
<br />
<pre class="code" style="height: 300px; margin: 0px; overflow: auto; width: auto;">//----------------------------------
//RS 485
//By Igor Real
//24-06-09
//----------------------------------
byte data[12];
unsigned long previous_time;
unsigned long previous_time2;
byte times_repeat=5;
byte times_repeat2=5;
byte state=0;
byte state2=0;
#define pinCONTROL 02
#define myaddress 01
void setup() {
pinMode(13,OUTPUT);
pinMode(pinCONTROL,OUTPUT);
digitalWrite(13,HIGH);
digitalWrite(12,LOW);
pinMode(8,INPUT);
pinMode(9,INPUT);
digitalWrite(pinCONTROL,LOW);
Serial.begin(9600);
Serial.println("Empezamos");
state=0;
state2=0;
}
void loop()
{
if (digitalRead(8)==state){
state=!state;
times_repeat=0;
}
if (digitalRead(9)==state2){
state2=!state2;
times_repeat2=0;
}
if (times_repeat<4){
Serial.flush();
//(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4)
if (digitalRead(8)==HIGH){
sendMSG(48,49,68,48,48,32,48,48,48,49);
}else {
sendMSG(48,49,68,48,48,32,48,48,48,48);
}
times_repeat=times_repeat+1;
previous_time=millis();
while (((millis()-previous_time)<500) && (Serial.available()!=15)){
;;
}
if (Serial.available()>=15){
if (receiveMSG()==1){
Serial.println("Trama correcta");
if (data[0]==48 && data[1]==49 && data[2]==6){
//ACK
times_repeat=5;
Serial.println("ACK recibido");
}
}
}
}
if (times_repeat2<4){
Serial.flush();
//(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4)
if (digitalRead(9)==HIGH){
sendMSG(48,50,68,48,48,32,48,48,48,49);
}else {
sendMSG(48,50,68,48,48,32,48,48,48,48);
}
times_repeat2=times_repeat2+1;
previous_time2=millis();
while (((millis()-previous_time2)<500) && (Serial.available()!=15)){
;;
}
if (Serial.available()>=15){
if (receiveMSG()==1){
//Serial.println("Trama correcta");
if (data[0]==48 && data[1]==50 && data[2]==6){
//ACK
times_repeat2=5;
//Serial.println("ACK recibido");
}
}
}
}
}
//------------------------
//FUNCIONES
//------------------------
byte receiveMSG(){
byte byte_receive;
byte state=0;
byte cont1=1;
byte trace_OK=0;
unsigned int checksum;
unsigned int checksum_trace;
while (Serial.available() > 0){
byte_receive=Serial.read();
if (byte_receive==00){
state=1;
checksum_trace=0;
checksum=0;
trace_OK=0;
cont1=1;
}else if (state==1 && cont1<=12){
data[cont1-1]=byte_receive;
checksum=checksum+byte_receive;
cont1=cont1+1;
}else if (state==1 && cont1==13){
checksum_trace=byte_receive<<8;
cont1=cont1+1;
}else if (state==1 && cont1==14){
checksum_trace=checksum_trace+byte_receive;
cont1=cont1+1;
state=0;
if (checksum_trace==checksum){
trace_OK=1;
}else{
trace_OK=0;
}
break;
}
}
return trace_OK;
}
void sendMSG(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4){
unsigned int checksum_ACK;
checksum_ACK=address1+address2+5+data_type+code1+code2+Sign+data1+data2+data3+data4+3;
UCSR0A=UCSR0A |(1 << TXC0);
digitalWrite(pinCONTROL,HIGH);
delay(1);
Serial.print(0,BYTE);
Serial.print(address1,BYTE);
Serial.print(address2,BYTE);
Serial.print(5,BYTE);
Serial.print(data_type,BYTE);
Serial.print(code1,BYTE);
Serial.print(code2,BYTE);
Serial.print(Sign,BYTE);
Serial.print(data1,BYTE);
Serial.print(data2,BYTE);
Serial.print(data3,BYTE);
Serial.print(data4,BYTE);
Serial.print(3,BYTE);
Serial.print(((checksum_ACK>>8)&255),BYTE);
Serial.print(((checksum_ACK)& 255),BYTE);
while (!(UCSR0A & (1 << TXC0)));
digitalWrite(pinCONTROL,LOW);
}
void sendACK(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4){
unsigned int checksum_ACK;
checksum_ACK=address1+address2+6+data_type+code1+code2+Sign+data1+data2+data3+data4+3;
UCSR0A=UCSR0A |(1 << TXC0);
digitalWrite(pinCONTROL,HIGH);
delay(1);
Serial.print(0,BYTE);
Serial.print(address1,BYTE);
Serial.print(address2,BYTE);
Serial.print(6,BYTE);
Serial.print(data_type,BYTE);
Serial.print(code1,BYTE);
Serial.print(code2,BYTE);
Serial.print(Sign,BYTE);
Serial.print(data1,BYTE);
Serial.print(data2,BYTE);
Serial.print(data3,BYTE);
Serial.print(data4,BYTE);
Serial.print(3,BYTE);
Serial.print(((checksum_ACK>>8)&255),BYTE);
Serial.print(((checksum_ACK)&255),BYTE);
while (!(UCSR0A & (1 << TXC0)));
digitalWrite(pinCONTROL,LOW);
}
void sendNAK(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4){
unsigned int checksum_ACK;
checksum_ACK=address1+address2+6+data_type+code1+code2+Sign+data1+data2+data3+data4+3;
UCSR0A=UCSR0A |(1 << TXC0);
digitalWrite(pinCONTROL,HIGH);
delay(1);
Serial.print(0,BYTE);
Serial.print(address1,BYTE);
Serial.print(address2,BYTE);
Serial.print(15,BYTE);
Serial.print(data_type,BYTE);
Serial.print(code1,BYTE);
Serial.print(code2,BYTE);
Serial.print(Sign,BYTE);
Serial.print(data1,BYTE);
Serial.print(data2,BYTE);
Serial.print(data3,BYTE);
Serial.print(data4,BYTE);
Serial.print(3,BYTE);
Serial.print(((checksum_ACK>>8)&255),BYTE);
Serial.print(((checksum_ACK)&255),BYTE);
while (!(UCSR0A & (1 << TXC0)));
digitalWrite(pinCONTROL,LOW);
}
byte hex2num(byte x){
byte result;
if (x>=48 && x<=57){
result=x-48;
}else if (x>=65 && x<=70){
switch(x){
case 65:
result=10;
break;
case 66:
result=11;
break;
case 67:
result=12;
break;
case 68:
result=13;
break;
case 69:
result=14;
break;
case 70:
result=15;
break;
}
}
return result;
}
</pre><br />
<div style="color: #cc0000;"><span style="font-size: large;"><b>ESCLAVOS:</b></span></div>(hay que cambiar la dirección en myaddress a 01 y 02,dependiendo del esclavo) <br />
<br />
<br />
<pre class="code" style="height: 300px; margin: 0px; overflow: auto; width: auto;">//----------------------------------
//RS 485
//By Igor Real
//24-06-09
//----------------------------------
byte data[12];
byte address;
byte function;
byte function_code;
unsigned int data_received;
byte byte_receive;
byte state=0;
byte cont1=1;
byte trace_OK=0;
unsigned int checksum;
unsigned int checksum_trace;
#define pinCONTROL 02
#define myaddress 02
void setup() {
pinMode(13,OUTPUT);
pinMode(pinCONTROL,OUTPUT);
digitalWrite(2,LOW);
Serial.begin(9600);
Serial.println("Empezamos");
}
void loop()
{
while (Serial.available() > 0){
byte_receive=Serial.read();
if (byte_receive==00){
//Serial.println("Se ha recibido byte Start");
state=1;
checksum_trace=0;
checksum=0;
trace_OK=0;
address=0;
data_received=0;
cont1=1;
}else if (state==1 && cont1<=12){
data[cont1-1]=byte_receive;
checksum=checksum+byte_receive;
cont1=cont1+1;
}else if (state==1 && cont1==13){
checksum_trace=byte_receive<<8;
cont1=cont1+1;
//Serial.print("Primer Byte Checksum");
//Serial.print(checksum_trace,HEX);
}else if (state==1 && cont1==14){
checksum_trace=checksum_trace+byte_receive;
cont1=cont1+1;
state=0;
//Serial.println(byte_receive,HEX);
//Serial.println("Recibida trama");
//Serial.print("Checksum Trace= ");
//Serial.println(checksum_trace,HEX);
//Serial.print("Checksum= ");
//Serial.println(checksum,HEX);
//Serial.println(checksum,DEC);
//Serial.println("Trama= ");
//Serial.print(data[0]);
//Serial.print(data[1]);
//Serial.print(data[2]);
//Serial.print(data[3]);
//Serial.print(data[4]);
//Serial.print(data[5]);
//Serial.print(data[6]);
//Serial.print(data[7]);
//Serial.print(data[8]);
//Serial.print(data[9]);
//Serial.print(data[10]);
//Serial.println(data[11]);
if (checksum_trace==checksum){
trace_OK=1;
address=(hex2num(data[0])<<4)+(hex2num(data[1]));
function=data[3];
function_code=(hex2num(data[4])<<4)+(hex2num(data[5]));
data_received=(hex2num(data[7])<<12)+(hex2num(data[8])<<8)+(hex2num(data[9])<<4)+(hex2num(data[10]));
//Serial.println("TRAZA CORRECTA");
//Serial.println(address,DEC);
//Serial.println(data_received);
if (address==myaddress){
if ((function=='D') && (function_code==0) && data[2]==5){
if (data_received==1){
digitalWrite(13,HIGH);
//Serial.println(data_received,DEC);
sendACK(data[0],data[1],data[3],data[4],data[5],data[6],data[7],data[8],data[9],data[10]);
}else if (data_received==0){
digitalWrite(13,LOW);
sendACK(data[0],data[1],data[3],data[4],data[5],data[6],data[7],data[8],data[9],data[10]);
}
}
}
}else{
//Serial.println("TRAZA INCORRECTA");
sendNAK(data[0],data[1],data[3],data[4],data[5],data[6],data[7],data[8],data[9],data[10]);
}
}
}
}
//------------------------
//FUNCIONES
//------------------------
byte receiveMSG(){
byte byte_receive;
byte state=0;
byte cont1=1;
byte trace_OK=0;
unsigned int checksum;
unsigned int checksum_trace;
while (Serial.available() > 0){
byte_receive=Serial.read();
if (byte_receive==00){
state=1;
checksum_trace=0;
checksum=0;
trace_OK=0;
cont1=1;
}else if (state==1 && cont1<=12){
data[cont1-1]=byte_receive;
checksum=checksum+byte_receive;
cont1=cont1+1;
}else if (state==1 && cont1==13){
checksum_trace=byte_receive<<8;
cont1=cont1+1;
}else if (state==1 && cont1==14){
checksum_trace=checksum_trace+byte_receive;
cont1=cont1+1;
state=0;
if (checksum_trace==checksum){
trace_OK=1;
}else{
trace_OK=0;
}
break;
}
}
return trace_OK;
}
void sendMSG(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4){
unsigned int checksum_ACK;
checksum_ACK=address1+address2+5+data_type+code1+code2+Sign+data1+data2+data3+data4+3;
UCSR0A=UCSR0A |(1 << TXC0);
digitalWrite(pinCONTROL,HIGH);
delay(1);
Serial.print(0,BYTE);
Serial.print(address1,BYTE);
Serial.print(address2,BYTE);
Serial.print(5,BYTE);
Serial.print(data_type,BYTE);
Serial.print(code1,BYTE);
Serial.print(code2,BYTE);
Serial.print(Sign,BYTE);
Serial.print(data1,BYTE);
Serial.print(data2,BYTE);
Serial.print(data3,BYTE);
Serial.print(data4,BYTE);
Serial.print(3,BYTE);
Serial.print(((checksum_ACK>>8)&255),BYTE);
Serial.print(((checksum_ACK)& 255),BYTE);
while (!(UCSR0A & (1 << TXC0)));
digitalWrite(pinCONTROL,LOW);
}
void sendACK(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4){
unsigned int checksum_ACK;
checksum_ACK=address1+address2+6+data_type+code1+code2+Sign+data1+data2+data3+data4+3;
UCSR0A=UCSR0A |(1 << TXC0);
digitalWrite(pinCONTROL,HIGH);
delay(1);
Serial.print(0,BYTE);
Serial.print(address1,BYTE);
Serial.print(address2,BYTE);
Serial.print(6,BYTE);
Serial.print(data_type,BYTE);
Serial.print(code1,BYTE);
Serial.print(code2,BYTE);
Serial.print(Sign,BYTE);
Serial.print(data1,BYTE);
Serial.print(data2,BYTE);
Serial.print(data3,BYTE);
Serial.print(data4,BYTE);
Serial.print(3,BYTE);
Serial.print(((checksum_ACK>>8)&255),BYTE);
Serial.print(((checksum_ACK)&255),BYTE);
while (!(UCSR0A & (1 << TXC0)));
digitalWrite(pinCONTROL,LOW);
}
void sendNAK(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4){
unsigned int checksum_ACK;
checksum_ACK=address1+address2+6+data_type+code1+code2+Sign+data1+data2+data3+data4+3;
UCSR0A=UCSR0A |(1 << TXC0);
digitalWrite(pinCONTROL,HIGH);
delay(1);
Serial.print(0,BYTE);
Serial.print(address1,BYTE);
Serial.print(address2,BYTE);
Serial.print(15,BYTE);
Serial.print(data_type,BYTE);
Serial.print(code1,BYTE);
Serial.print(code2,BYTE);
Serial.print(Sign,BYTE);
Serial.print(data1,BYTE);
Serial.print(data2,BYTE);
Serial.print(data3,BYTE);
Serial.print(data4,BYTE);
Serial.print(3,BYTE);
Serial.print(((checksum_ACK>>8)&255),BYTE);
Serial.print(((checksum_ACK)&255),BYTE);
while (!(UCSR0A & (1 << TXC0)));
digitalWrite(pinCONTROL,LOW);
}
byte hex2num(byte x){
byte result;
if (x>=48 && x<=57){
result=x-48;
}else if (x>=65 && x<=70){
switch(x){
case 65:
result=10;
break;
case 66:
result=11;
break;
case 67:
result=12;
break;
case 68:
result=13;
break;
case 69:
result=14;
break;
case 70:
result=15;
break;
}
}
return result;
}
</pre><br />
Ahora veamos como cablear una red de topología bus:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSsDtkSo-1bdDimQJH018bvIvsoxCSz5sxc-guANgJ7qjXLJlpLLwzqwQbx_po7zt-Jsq1ZUR3e1AKmhD2WaXgfuXInSshq9npQycqPssesNr8Tyak3l3k0z7vdrPl7gJITxt21q2AYizM/s1600-h/Network+connection.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSsDtkSo-1bdDimQJH018bvIvsoxCSz5sxc-guANgJ7qjXLJlpLLwzqwQbx_po7zt-Jsq1ZUR3e1AKmhD2WaXgfuXInSshq9npQycqPssesNr8Tyak3l3k0z7vdrPl7gJITxt21q2AYizM/s400/Network+connection.JPG" /></a> </div><div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: left;">En cada Arduino o dispositivo de la red, se cablea con una Y soldada en la cual salen dos conectores de la misma familia. Debe tener la longitud más corta posible.</div>Cada conector tiene Alimentación, Señal A, Señal B y Masa.<br />
<br />
De esta forma, si se quiere ir ampliando la red con dispositivos, bastará con ir intercalandolos ó poniendolos a final. Ya que cada dispositivo tiene conectores macho y hembra, por lo que encaja perfecto.<br />
Se puede preparar un par de conectores, con una resistencia terminadora puesta en los terminales correspondientes a la Señal A y Señal B del bus RS485 para cerrar los extremos (siempre quedará un par de conectores libres). Si se necesita añadir más dispositivos, se desconecta dicho conector con la resistencia terminadora, se intercala el nuevo dispostivo y se vuelve a cerrar la red.<br />
<br />
Llevar alimentación en el cableado, no cuesta nada y todo será más fácil para futuras ampliaciones...<br />
El cable de Señal A y B debe ser trenzado.<br />
<div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;">Recomiendo este link acerca del conexionado: <a href="http://www.rs-485.com/download/485%20network%20topology.pdf">http://www.rs-485.com/download/485%20network%20topology.pdf </a></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; color: white; text-align: left;">. </div><div class="separator" style="clear: both; color: white; text-align: left;">.</div><div class="separator" style="clear: both; color: white; text-align: left;">.</div><div class="separator" style="clear: both; text-align: left;"><span style="color: white;">. </span></div><div class="separator" style="clear: both; text-align: left;">Saludos!!</div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;"><i style="color: blue;"><b><span style="font-family: Times,"Times New Roman",serif;"><span style="color: white;">. </span><br />
</span></b></i></div><div class="separator" style="clear: both; text-align: left;"><i style="color: blue;"><b><span style="font-family: Times,"Times New Roman",serif;">Igor</span><span style="font-family: Times,"Times New Roman",serif;"> R.</span></b></i></div><div class="separator" style="clear: both; color: white; text-align: left;">.</div><div class="separator" style="clear: both; text-align: left;"><span style="color: white;">. </span></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;"></div>Igorhttp://www.blogger.com/profile/07332255486737492708noreply@blogger.com46