martes, 20 de octubre de 2015

Octavo capitulo arduino empleando el Serial Monitor

En este nuevo post vamos a emplear el Serial Monitor de nuestro arduino mediante este Sketch escribiremos en el Serial Monitor una frase y arduino lo traducira a codigo Morse, es decir, a lineas y puntos y sera visualizado por medio del LED del pin numero 13 del arduino.

Al escribir este Sketch haremos uso de lo aprendido a modo de familiarizarse con lo visto hasta ahorita que como les mencionaba podemos hacer un sin fin de aplicaciones con lo poco visto. Algo que ocuparemos son los Arrays  y Strings. Lo nuevo que veremos en este octavo capitulo es transferir informacion desde nuestro arduino mediante el cable USB con el uso del Serial Monitor.

En la siguiente imagen se muestra las letras y los numeros del 0 al 9 en codigo Morse para nuestra aplicacion.



Enseguida escribiremos nuestro Sketch.

//Proyecto  Traductor de codigo Morse

Primero definimos nuestra salida en el pin numero 13 tambien definimos un retardo para variar la velocidad de parpadeo del Sketch.

int led = 13;
int retardo =200;

Enseguida definiremos un array para contener las letras.

char* letras [] = {" .- ", "  -... ", "  -.-. ", "  -.. ", " . ", " ..-. ", " --. ", " .... ", " .. ",  // de la A a la I
                            " .--- ","  -.- "," .-.. "," -- "," -. "," --- "," .--. "," --.- "," .-. ", // de la J-R
                             " ... "," - "," ..- "," ...- "," .-- "," -..- "," -.-- ","  --.. "}; // de la S-Z 

En setup  configuraremos el pin 13 como salida y se configurara el puerto serie para la comunicacion serial por medio del puerto USB . Esto se hace mediante el siguiente codigo.

void setup()
{  
pinMode(led, OUTPUT); // Definimos el pin 13 como salida
Serial.begin(9600); // Se habilita la comunicacion serial a 9600 baudios
}

El 9600 es la velocidad a la que se configura nuestro arduino se puede poner diferentes valores pero en este ejemplo lo definimos con esa velocidad ya que es la que tiene predifinida arduino y las computadoras.

Lo siguiente a configurar es el loop que como vimos es donde se ejecuta nuestro programa una y otra vez. Aqui se sondeara constantemente si se ha enviado letras al USB y si se tiene que procesar alguna letra o numero.

void loop ()
{
char ch;
if (Serial.available()){

ch = Serial.read();

if( ch >=  'a'  && ch <= 'z')

  secuencia(letras[ch - 'a']);  
}
else if ( ch>= 'A' && ch<= 'Z')
{
     secuencia(letras[ch - 'A']);
}

else if( ch == ' ')
{
 delay( retardo * 4);
}

}

}


Con la funcion Serial.available () sabremos si hay una letra o numero disponible en el puerto serie para convertir a codigo Morse. Con la funcion Serial.read() leeremos desde el puerto serie el valor de este caracter que asignamos a una variable llamada ch definida en el loop().

Con las sentencias if determinamos si hay una letra mayuscula, minuscula o un espacio en blanco que separa dos palabras. Si vemos bien en el primer if hacemos una comparacion si "a" es mayor o igual a este y si es igual o menor a "z" cumpliendose esta sentencia podemos buscar la secuencia de rayas y puntos definido en el array.

Para determinar la secuencia que debemos utilizar de la matriz restando "a" del caracter de ch. Puede parece ser extraño restar una letra de otra pero es aceptable en C por ejemplo si restamos "a"- "a" nos dara 0 y si restamos "d"- "a" nos dara 3 osea si leemos desde el puerto USB "d" esa se restara con "a"  y nos dara el 3 que si vemos en el array "letras[]" la posicion numero 3 la ocupa "  -.. "  que corresponde a la letra "d" que es la que recibimos.

Tambien definiremos una funcion llamada secuencia que recorre cada parte de la secuencia y realizar el destello en forma de punto o raya. Como la longitud de cada letra en codigo morse es diferente debemos poner un "tope" para hacer el recorrido esto se logra con NULL que nos indica el final de una cadena de caracteres. Dentro del while hacemos un recorrido de cada letra para hacer el destello de un punto o una raya.

void secuencia( char *secuencia){ 

int i = 0;
while (secuencia[i] != NULL){

secuenciaMorse(secuencia [i]);
i++;
}
delay (retardo * 3);

}

Como se puede ver se hace uso de otra funcion llamada secuenciaMorse esta solo tiene la finalidad de encender el led empleando if hace comparaciones si hay un punto o una raya para definir la duracion del destello.

void secuenciaMorse(char PuntoRaya)
{
 digitalWrite(led, HIGH);
if(PuntoRaya == '.')
{
   delay(retardo);
 }

else 
{
  delay(retardo *3 );
}
digitalWrite(led, LOW);
 delay(retardo);

}

Para hacer funcionar el sketch anterior hay que juntarlo y compilarlo. Para hacer pruebas es necesario abrir el Monitor Serial del IDE de arduino.

A continuacion el Sketch completo con los comentarios pertienentes.

//Proyecto  Traductor de codigo Morse

int led = 13; //Definicion del pin 13 
int retardo =200; // Variable como retardo


char* letras [] = {" .- ", "  -... ", "  -.-. ", "  -.. ", " . ", " ..-. ", " --. ", " .... ", " .. ",  // de la A a la I
                            " .--- ","  -.- "," .-.. "," -- "," -. "," --- "," .--. "," --.- "," .-. ", // de la J-R

                             " ... "," - "," ..- "," ...- "," .-- "," -..- "," -.-- ","  --.. "}; // de la S-Z 

void setup()
{  
pinMode(led, OUTPUT); // Definimos el pin 13 como salida
Serial.begin(9600); // Se habilita la comunicacion serial a 9600 baudios
}

void loop ()
{
char ch;
if (Serial.available()){  // Si hay un dato disponible en el puerto serie

ch = Serial.read(); // Se lee el puerto serie y el dato se guarda en ch

if( ch >=  'a'  && ch <= 'z') // Comparaciones

  secuencia(letras[ch - 'a']); // Manda a llamar la funcion secuencia y le pasa como argumento la direccion del
// array al que esta apuntando 
if ( ch>= 'A' && ch<= 'Z')
{
     secuencia(letras[ch - 'A']);
}

else if( ch == ' ')  si hay un espacio hacer un retardo mayor
{
 delay( retardo * 4);
}

}

}

void secuencia( char *secuencia){ // Toma el contenido de la direccion que se le paso 

int i = 0;
while (secuencia[i] != NULL){ // del contenido hace un recorrido hasta encontrar un NULL

secuenciaMorse(secuencia [i]); // Manda a llamar la funcion secuenciaMorse y le pasa como argumento la //posicion del contenido de una letra.
i++;
}
delay (retardo * 3);

}

void secuenciaMorse(char PuntoRaya) // Recibe el contenido de la posicion actual de la secuencia
{
 digitalWrite(led, HIGH); // Enciende el led del pin 13
if(PuntoRaya == '.') // Si el contenido es un "." hace un retardo
{
   delay(retardo);
 }

else  // Si no es un punto es una raya y da un retardo 3 veces mayor que el de un punto 
{
  delay(retardo *3 );
}
digitalWrite(led, LOW); //Apaga el led
 delay(retardo); // Hace un retardo para empezar de nuevo.
}

En los proximos capitulos continuaremos con el uso de otros recursos como es el convertidor analogico digital que emplearemos para leer señales provenientes del mundo real como puede ser la temperatura. 

jueves, 15 de octubre de 2015

Sexto capitulo arduino

En este parte profundizaremos un poco mas sobre la parte de programacion antes de pasar a nuestro siguiente proyecto.

Loops (bucles)


Los loops o bucles nos permiten repetir un grupo de comandos un numero determinado de veces o hasta que se cumpla una condicion. En el sketch anterior solo se deseaba que el led parpadera tres veces con S luego tres veces con O y por ultimo tres veces con S, por supuesto esto no implica una gran dificultad en el codigo. Sin embargo seria poco practico si esto lo quisieramos repetir unas 1000 veces. Por eso en C tenemos y podemos utilizar el comando for.

Por ejemplo si implementaramos lo anterior solo nos bastaria en poner.

for ( int i = 0; i < 1000 ; i ++)

    flash (200) //
}

El codigo anterior repetiria 1000 veces el destello del led para la letra S.

Otra forma de implementar un bluque en arduino es usando el comando "while".
El ejemplo anterior se podra llevar a cabo usando el comando "while" como se muestra.

int i= 0;
while (1 < 100)
{
      flash (200);
        i++;
}

El codigo descrito nos indica que miestras 1 sea menor que 100 se va a ejecutar el codigo que esta en el interior. Vemos que por cada vez que se ejecuta el codigo i se va incrementando en 1 en 1 indicado por  i++. Cuando  " i " se incrementa a 101  deja de ser cierta la condicion por lo que ya no se ejecuta el codigo en el interior.

Arrays (matrices)

Los arrays son una  forma de contener una lista de valores y se puede acceder a cualquiera de  esos valores por su posicion en la lista. Estas posiciones de indice comienza desde 0 en lugar de 1. Esto significa que el primer elemento es en realidad el elemento cero.

Ejemplo de como declarar un array.

int duracion [ ] = {200,200,200,500,500,500,200,200,200};

En el codigo anterior se coloca "[ ]" despues del nombre de la variable. Si se especifica el contenido de la matriz al mismo tiempo de declararla como en el ejemplo anterior, no es necesario especificar el tamaño de la matriz.  Si no se establece el contenido dentro de la matriz debera indicarse el tamaño de la matriz.

int duracion [10]; 

A continuacion se muestra un codigo donde se implementa un array.

void  loop( )
{

    for (int i = 0 ; i< 9 ; i++)
      {
             flash( duracion [i]);
       }
    delay(1000);


En el codigo anterior se ejecuta el codigo hasta que i sea menor que 9  y duracion[ i ] va accediendo a cada posicion de acuerdo como se vaya incrementando i .

martes, 13 de octubre de 2015

Septimo capitulo arduino Controlando un servomotor

En este post controlaremos un servomotor con solo lo que se ha visto. En primer lugar necesitamos saber que es un servomotor y como se maneja.

En en mercado existen gran variedad de servomotores entre los mas comerciales de facil adquision y economicos se encuentran en la siguiente imagen.


                                                         

                               Servomotores mas comunes que se pueden encontrar a bajo costo.


Estos servomotores no son mas que motores con la capacidad de posicionarse dentro de un rango segun se le ordene. Para ubicar un servomotor en una posicion dada se emplea la modulacion por ancho de pulso (PWM) donde dependiendo el ciclo util  del PWM es donde el servomotor se va ubicar.

Para esto primero se debe saber que la frecuencia a la que va funcionar el servomotor por lo regular es de 50 Hz, es decir, la onda tiene  un periodo de 20 ms y de este periodo depende el tiempo en que este en alto para ubicar la posicion del servomotor. En la siguiente imagen se ve que dependiendo el ciclo util es como se ubica el servomotor.

                        

Se aprecia en la figura que para que el servo se ubique a una posicion de 0 grados este debe tener un valor de 1ms en alto y el resto en bajo, como el periodo es de 20 ms se tiene 19 ms en bajo.

Para ubicarlo en 90 grados se sigue el mismo procedimiento, 1.5 ms en alto y 18.5ms en bajo. Por para ubicarlo en 180 grados se  tiene 2 ms en alto y 18 ms en alto.

Teniendo esos datos ya se puede hacer el programa que controle el servomotor en 3 posiciones diferentes: 0 grados, 90 grados y 180 grados.

Programando la aplicacion.


Para programar el giro del servomotor  para la siguiente secuencia 0 grados, 90 grados, 180 grados y de regreso a 0 grados se empleara el uso de una tabla. Esta tabla guarda el valor de las constantes para despues solo llamarlas dependiendo la ubicacion en que se encuentra la constante que vamos a emplear en realidad en este ejemplo vamos a emplear dos tablas, el uso de tablas es muy usado en la programacion de microcontroladores, estas tablas  es en realidad un Array.


 Vamos a definir nuestra salida que seria el pin 13 que es el que hemos ocupado hasta ahorita.

// Control de servomotor basico

int led = 13;

Definiremos nuestras tablas para el guardar nuestras constantes.
Para definir los valores que contienen las tablas vamos a razonar un poco. Primero sabemos que para controlar la  posicion de un servomotor se hace con una onda cuadrada con duracion de 20ms.

Segundo, de  la duracion de la onda cuadrada osea su periodo su  ciclo util para 0 grados es de 1ms para 90 grados es de 1.5 ms y 180 grados es de 2ms teniendo en cuenta eso para completar los 20 ms en 0 grados tenemos que 1ms tendra la onda en alto y 19 ms en bajo (1 ms + 19 ms = 20 ms).

Siguiendo con la logica anterior, para 90 grados (1.5ms + 18.5ms = 20ms), para 180 grados (2ms + 18ms = 20ms)  que son los valores que ocuparemos como constantes en nuestras tablas.

Y por ultimo estos valores constantes los vamos agrupar  para que ocupen la misma posicion en las diferentes tablas.

float tabla1 [ ] = {1, 1.5, 2};
float tabla2 [ ] = {19, 18.5, 18};

Solo por si no se ve la posicion 0 de la tabla 1 y 2 la ocupan (1 y 19) la posicion 1 la ocupan (1.5 + 18.5) y la posicion 2 la ocupan (2 y 18) que si se suman cualquier par dan como resultado 20 que es el periodo de la onda cuadrada que emplea el servomotor para funcionar.

Proseguiremos con la configuracion del pin 13 como salida

void setup ( )
{
  pinMode (led, OUTPUT); 

}

Vamos a definir nuestro programa principal

void loop ( )
 { 


servo_posicion(0);
delay(500);
servo_posicion(1);
delay(500);
servo_posicion(2);
delay(500);

}  

El programa principal primero inicia con la posicion 0 (0 grados) con la llamada a funcion servo_posicion, espera medio segundo (500ms), hace la siguiente llamada a funcion pero ahora con la posicion 1 (90 grados) espera medio segundo y manda a llamar la posicion 2 (180 grados) esperando otros 500 ms y vuelve a empezar el programa de nuevo haciendo la secuencia esperada (0 grados, 90 grados, 180 grados y de nuevo 0 grados).

La funcion servo_posicion se escribe enseguida.

void servo_posicion(int valor);
{
int i = 0;
 if (valor == 0)
{
 for( i = 0; i<10 ; i++){
 digitalWrite ( led, HIGH);
     delay ( tabla1 [0]); 
     digitalWrite (led, LOW);
     delay( tabla2 [0]);
}
}

 if (valor == 1)
{
for(i=0; i<10;i++){
 digitalWrite ( led, HIGH);
     delay ( tabla1 [1]); 
     digitalWrite (led, LOW);
     delay( tabla2 [1]);
}
}

 if (valor == 2)
{
for(i=0; i<10;i++){
 digitalWrite ( led, HIGH);
     delay ( tabla1 [2]); 
     digitalWrite (led, LOW);
     delay( tabla2 [2]);
}
}

}

La funcion servo_posicion trabaja de la siguiente forma. Recibe como parametro la posicion del servomotor  con el valor hace comparaciones con if y dependiendo la posicion se ejecuta el codigo dentro del if donde con digitalWrite(led, HIGH) se pone en alto el tiempo de la posicion de la tabla1  despues se paga con digitalWrite (led, LOW) el tiempo de la posicion de la tabla2 esto lo hace 10 veces para asegurar una onda repetitiva de un periodo de 20ms.

Por ejemplo para el primer valor la funcion servo_posicion recibe un 0 este valor se compara con if(valor == 0) como es verdadero se ejecuta el codigo dentro donde primero se pone en alto el pin 13  y con tabla1[0] que contiene el valor de 1 se mantiene en alto 1 ms ese pin cuando termina el retardo el pin pasa a bajo y con el contenido de tabla2 [0] que tiene 19 se mantendrá 19 ms en bajo esto 10 veces,  reflejando en la salida 10 ondas cuadradas con duracion de 20ms con 1ms de ciclo util esto con la finalidad de asegurar que el servomotor tenga el tiempo necesario para llegar a su posicion.

Es claro que este ejemplo se puede simplificar mucho mas, pero la finalidad de este sketch es ver como se emplea lo que se ha visto. Sin duda alguna con el conocimiento que se tiene hasta ahorita se puede hacer un sin fin de cosas. Pero para facilitar las cosas se tienen otras funciones y bibliotecas disponibles que veremos en capitulos posteriores.

Noveno capitulo arduino Monitor de temperatura controlado por la computadora Parte 1

En este nuevo capitulo haremos uso del convertidor analogico digital de arduino donde se monitorea la temperatura por medio de una computadora, pero tambien se puede desconectar y emplear pilas para seguir registrando la temperatura que se guarda, para posteriormente recuperar la informacion al volver a conectar  la computadora por medio del USB.

Pero antes de empezar con esta aplicación debemos considerar el uso basico del convertidor analogico digital de arduino. Por lo que empezaremos en esta primera parte a ver su funcionamiento.

Antes que nada debemos saber que un Convertidor analogico a digital es un dispositivo electronico capaz de convertir una señal analogica (una señal analogica es una señal continua en el tiempo puede ser el sonido, temperatura, etc..) en una señal digital (una señal digital es discreta en el tiempo es decir, que es descontinua en el tiempo que puede ser una serie de bits (ceros y unos)).

En la siguiente imagen se muestra los ejemplos de cada una de ellas.


En el interior de arduino osea del microcontrolador que se encarga de procesar la informacion que es el Atmega328 cuenta con uno, este se puede apreciar en la siguiente imagen.



Este convertidor analogico digital es el que emplearemos para realizar nuestro proyecto, pero primero veamos los pines que se emplean en el uso de arduino.



Como se aprecia en la imagen se puede notar los pines para las entradas analogicas que son de A0 a A5 y tambien se emplea el pin AREF pero solo en algunas aplicaciones "especiales" donde el nivel de referencia sea diferente de 5 volts ya que existen algunos sensores que pueden operan a 3.3 volts, 2.5 volts o a 1.5 volts y para ese caso emplearemos ese pin de referencia de voltaje, si no lo empleamos lo dejamos libre ya que por si mismo arduino tiene un voltaje de referencia de 5 volts, aqui lo importante es localizar los pines A0-A5 que se empleran.

Si se fijaron bien en las dos imagenes anteriores el atmega328 tiene solo un ADC y se tienen 5 pines como entradas analogicas pensaran que no es posible conectar todos los pines a la vez ya que solo se cuenta con un ADC, en cierto modo esto es verdadero, pero existe un "bonito truco" para que esto sea posible y a este "truco" se le conoce como multiplexacion, es decir, que se le asigna una pequeña parte de tiempo a cada canal para compartir el ADC, como puede ser que se le asigne lo que tarda el ADC en convertir un dato a un canal por ejemplo A0 y la siguiente vez que el ADC deba procesar un dato se le asigna al canal A1.


Otra cosa que debemos de tener en cuenta con el ADC es su resolucion, es decir, el numero de bits en que convierte la señal analogica en digital, en caso del arduino uno este tiene un ADC de 10 bits con 10 bits tenemos una combinacion de 1024 posibles valores que tiene arduino segun el nivel de voltaje que este monitoreando, es decir, si ocupamos una referencia de 5 volts y con la resolucion del ADC de 10 bits se tiene una variacion de 5 volts/ 1024 bits = 4.88 mV por bit. Por ejemplo si se mide un voltaje de 0 V en A3 se tiene : 0000000000, para 5mV se tiene: 0000000001, para 10mV se tiene: 0000000010, para 15mV se tiene: 0000000011, para 1 Volt se tiene 0011001100, para  5 volts se tiene : 1111111111, y asi se obtendrian los cambios para diferentes valores de voltaje en A3. Para facilitar lo anterior emplearemos una regla de 3.

Si   5 volts -------------------  1024 bits
      x volts--------------------- x bits

donde x denota cualquier numero.

(5 volts ) (x bits) = (1024 bits)( x volts)------- resolviendo para saber el numero de bits.

x bits = (1024 bits) (x volts)/ 5 volts

Por ejemplo si queremos encender un ventilador con un LM35 para cuando la temperatura de una habitacion supere los 30 grados primero se tiene que saber que el LM35 a cada grado que se eleve la temperatura varia en 10mV, donde a 25 grados equivale a 250mV  y a 30 grados equivale a 300mV entonces lo siguiente que se tiene que saber a que numero binario hay que encender el ventilador. para eso tenemos que los 300 mv = (0.3 Volts) equivale a los 30 grados. Sustituyendo eso en la formula.

x bits = (1024 bits)( .3 Volts )/ (5 volts)

x bits = 61.44  en binario para encender el ventilador a 30 grados pero como no existe el punto decimal se tendria que aproximar a 61 o 62 en binario. Esto se empleara mas adelante.

Ahora si con lo anterior descrito empecemos a ver las funciones que se emplearan para empezar a codificar nuestro Sketch.

Ejemplo 1

Para emplear el ADC del arduino solo basta con conectar la placa arduino a la computadora abrir el Monitor serial . Como se aprecia en la siguiente imagen.

learn_arduino_serial_monitor.jpg

Conectaremos un potenciometro de cualquier valor al pin A0.  Como en la siguiente imagen.


El sketch es el siguiente.

int valor = 0;

void setup()

{
 Serial.begin(9600); // Configura el puerto serie
}

loop()

{

valor = analogRead(0); // Lee valor del pin A0 y se lo pasa a la variable valor

Serial.println(valor); // Imprime el valor en el Monitor serial.

}

Al ir variando la posición del potenciomentro se vera reflejado los valores en el Monitor serial. Lo nuevo en este serie del curso es la funcion analogRead(arguento) que acepta como argumento para el arduino uno un valor de 0 a 5 donde, 0 equivale al pin A0, 1 al pin A1... hasta 5 que equivale el pin A5.



En la parte 2 de "Monitor de temperatura controlado por la computadora" seguiremos con mas ejemplos antes de pasar a la aplicacion que le da titulo al Noveno capitulo.