Tema 4 – Conceptos básicos de programación (3)

Estructuras de control (Control de Flujo)

  • if:  es un estamento que se utiliza para probar si una determinada condición se ha alcanzado, como por ejemplo averiguar si un valor analógico está por encima de un cierto número, y ejecutar una serie de declaraciones (operaciones) que se escriben dentro de llaves, si es verdad. Si es falso (la condición no se cumple) el programa salta y no ejecuta las operaciones que están dentro de las llaves.

Else puede ir precedido de otra condición de manera que se pueden establecer varias estructuras condicionales de tipo unas dentro de las otras (anidamiento) de forma que sean mutuamente excluyentes pudiéndose ejecutar a la vez. Es incluso posible tener un número ilimitado de estos condicionales. Recuerde sin embargo que sólo un conjunto de declaraciones se llevará a cabo dependiendo de la condición probada.

http://arduino.cc/en/Reference/If

  • if… else:  viene a ser un estructura que se ejecuta en respuesta a la idea “si esto no se cumple haz esto otro”. Por ejemplo, si se desea probar una entrada digital, y hacer una cosa si la entrada fue alto o hacer otra cosa si la entrada es baja.

http://arduino.cc/en/Reference/Else

  • for: La declaración for se usa para repetir un bloque de sentencias encerradas entre llaves un número determinado de veces. Cada vez que se ejecutan las instrucciones del bucle se vuelve a testear la condición. La declaración for tiene tres partes separadas por (;). La inicialización de una variable local se produce una sola vez y la condición se testea cada vez que se termina la ejecución de las instrucciones dentro del bucle. Si la condición sigue cumpliéndose, las instrucciones del bucle se vuelven a ejecutar. Cuando la condición no se cumple, el bucle termina.

Cualquiera de los tres elementos de cabecera puede omitirse, aunque el punto y coma es obligatorio. También las declaraciones de inicialización, condición y expresión puede ser cualquier estamento válido en lenguaje C sin relación con las variables declaradas. Estos tipos de estados son raros pero permiten disponer soluciones a algunos problemas de programación raras.

http://arduino.cc/en/Reference/For

  • While: Un bucle del tipo while es un bucle de ejecución continua mientras se cumpla la expresión colocada entre paréntesis en la cabecera del bucle. La variable de prueba tendrá que cambiar para salir del bucle. La situación podrá cambiar a expensas de una expresión dentro el código del bucle o también por el cambio de un valor en una entrada de un sensor.

http://arduino.cc/en/Reference/While

http://arduino.cc/en/Tutorial/WhileLoop

  • do..while: El bucle do while funciona de la misma manera que el bucle while, con la salvedad de que la condición se prueba al final del bucle, por lo que el bucle siempre se ejecutará al menos una vez.

http://arduino.cc/en/Reference/DoWhile

  • switch..case: Al igual que if, swtich..case controla el flujo del programa especificando en el programa que código se debe ejecutar en función de unas variables. En este caso en la instrucción switch se compara el valor de una variable sobre los valores especificados en la instrucción case.
    break es la palabra usada para salir del switch. Si no hay break en cada case, se ejecutará la siguiente instrucción case hasta que encuentre un break o alcance el final de la instrucción.
    default es la palabra que se usa para ejecutar el bloque en caso que ninguna de las condiciones se cumpla.

http://arduino.cc/en/Reference/SwitchCase

  • goto: transfiere el flujo de programa a un punto del programa que está etiquetado.

http://arduino.cc/en/Reference/Goto

break se usa en las instrucciones do, for, while para salir del bucle de una forma diferente a la indicada en el bucle.

http://arduino.cc/en/Reference/Break

continue se usa en las instrucciones do, for, while para saltar el resto de las instrucciones que están entre llaves y se vaya a la siguiente ejecución del bucle comprobando la expresión condicional.

http://arduino.cc/en/Reference/Continue

Y por su puesto ante cualquier duda: http://arduino.cc/en/Reference/HomePage

Funciones definidas por el usuario

Una función es un bloque de código que tiene un nombre y un conjunto de instrucciones que son ejecutadas cuando se llama a la función. Son funciones setup() y loop() de las que ya se ha hablado.

Las funciones de usuario pueden ser escritas para realizar tareas repetitivas y para reducir el tamaño de un programa.

Las funciones se declaran asociadas a un tipo de valor. Este valor será el que devolverá la función, por ejemplo ‘int’ se utilizará cuando la función devuelva un dato numérico de tipo entero. Si la función no devuelve ningún valor entonces se colocará delante la palabra “void”, que significa “función vacía”

Sintaxis:

tipo nombreFunción(parámetros){
instrucciones;
}

Para llamar a una función, simplemente:
nombreFunción(parámetros);

Return: Termina una función y devuelve un valor a quien ha llamado a la función.

http://arduino.cc/en/Reference/Return

Más información: http://arduino.cc/en/Reference/FunctionDeclaration

Nombres de funciones

Generalmente los nombres de las funciones deben ser en minúscula, con las palabras separadas por un guión bajo, aplicándose éstos tanto como sea necesario para mejorar la legibilidad.

“mixedCase” (primera palabra en minúscula) es aceptado únicamente en contextos en donde éste es el estilo predominante con el objetivo de mantener la compatibilidad con versiones anteriores.

En el caso de las clases, los nombres deben utilizar la convención “CapWords” (palabras que comienzan con mayúsculas).

Librerías

Como se ha visto anteriormente, las librerías son trozos de código hechas por terceros que usamos en nuestro sketch. Esto nos facilita mucho la programación y hace que nuestro programa sea más sencillo de hacer y luego de entender. En el curso avanzado veremos como hacer una librería.

Este tutorial explica como crear una librería: http://arduino.cc/en/Hacking/LibraryTutorial

Guia de estilo para escribir librerías: http://arduino.cc/en/Reference/APIStyleGuide

Listado de librerías: http://playground.arduino.cc/Main/LibraryList

Otras funciones

Ejercicio: Ejercicio19-BlinkSinDelay.

Hacer el ejercicio: http://arduino.cc/en/Tutorial/BlinkWithoutDelay

Añadir un contador de un botón y ejecutar periódicamente para que muestre por el puerto serie cuantas veces hemos pulsado el botón.  Comprobar la multitarea.

Hacer el mismo ejercicio con las librerias mstimer2 y la librería Timer  http://www.doctormonk.com/2012/01/arduino-timer-library.html

¿Y si queremos hacerlo con dos leds?

Solución: https://github.com/jecrespo/Aprendiendo-Arduino/tree/master/Ejercicio19-BlinkSinDelay

Monitor Serie. Debug

A la hora de hacer depuración de un sketch, tanto a la hora de desarrollarlo como cuando esté en producción y se detecten fallos, disponemos del puerto serie para que muestre datos de errores o datos de variables internas de comprobación de funcionamiento que nos permite saber si todo va bien o que está fallando.

Es similar a cuando vemos a un técnico que conecta una consola a un equipo como una máquina climatizadora o en el taller cuando colocan la máquina de diagnóstico para saber qué está pasando.

A la hora de realizar nuestro programa debemos establecer qué parámetros queremos tener monitorizados y sacarlos por el puerto serie para hacer el debug.

Incluso podemos pensar en poner una pantalla LED que nos saque por un segundo puerto serie y nos sirva de pantalla de debug.

Un técnica para hacer debug es usar la directiva de preprocesamiento #define que permite asociar a una palabra un valor sin que ocupe espacio en memoria, lo que hace el compilador es sustituir esa palabra por el valor definido. Más información en: http://arduino.cc/en/pmwiki.php?n=Reference/Define

Además para mejorar la funcionalidad de #define tenemos otras directivas de preprocesamiento: #if y #endif que son directivas lógicas, es decir, no sólo no se ejecutan sino que ni se compilan.

Las directivas de preprocesamiento nos permiten añadir o quitar código a nuestro antojo antes de compilar para tener una versión para debug o detección de errores y otra versión de producción.

A la hora de hacer debug de nuestro sketch, usaremos Serial.print y sacaremos por el puerto serie para leer por consola aquellas variables o elementos que nos interese monitorizar y saber lo que está pasando con ellas en tiempo real.

Ejemplo:

#define DEBUG 0

void setup(){
inicializa();
}

void loop(){
compruebaTemperatura();
#if DEBUG
imprimeVariablesDebug();
#endif
}

Más adelante veremos herramientas propias para hacer debug, pero para ello será necesario hardware adicional y otro software que no es el IDE de Arduino.

Ejercicio20: Hacer debug con el puerto serie.

Hacer un programa usando las directivas de preprocesamiento.
Hacer un programa sencillo que imprima cosas por puerto serie, la memoria libre, etc… y selecciones que haga una cosas u otras en función del la directiva de preprocesamiento. Comprueba los tiempos de loop, el tamaño ocupado en la flash y el uso de memoria con las opciones DEBUG y VERBOSE y sin ellas.

Solución: https://github.com/jecrespo/Aprendiendo-Arduino/tree/master/Ejercicio20-Debug

Y aún más…

Una buena chuleta para tener a mano cuando programemos.

Cheat Sheet: https://dlnmh9ip6v2uc.cloudfront.net/learn/materials/8/Arduino_Cheat_Sheet.pdf

Más código: ¿Os interesa revisar alguno?

Práctica: Ver este ejemplo de programa y entender la estructura: https://github.com/jecrespo/Home_Power_Meter/blob/master/Home_Power_Meter.ino