Arduino en la práctica (parte 3.) – guía del usuario
Arduino en la práctica (parte 3.) – guía del usuario
Arduino en la práctica (parte 3.) – guía del usuario
- Arduino en la práctica - el principio de funcionamiento de una guía de ejemplo
- Arduino en la práctica - definir elementos de la guía
- Arduino en la práctica - uso de la guía
- Arduino - Información adicional sobre la creación de la guía
En el artículo anterior, presentamos los conceptos básicos para usar la superposición SHIELD-LCD16x2. En esta parte, hablaremos de la preparación de una solución práctica y específica que puede ser útil en proyectos de dispositivos posteriores: la placa tiene componentes que se pueden usar para crear la guía del usuario. Al principio, prepararemos un menú de un nivel, es decir, uno que iniciará una función inmediatamente, sin expandir el submenú.
Le recordamos que SHIELD-LCD16x2 es un tipo de superposición que extiende las capacidades de Arduino, equipado con un módulo de pantalla LCD (2 líneas de 16 caracteres), 4 botones y 8 líneas GPIO adicionales. La placa tiene un microcontrolador PIC que se comunica con Arduino UNO a través de la interfaz TWI. Las bibliotecas de funciones disponibles facilitan el funcionamiento de todo el módulo, incluso para usuarios sin experiencia. Comencemos con la descripción de cómo funciona el programa a partir del ejemplo.
Arduino en la práctica - el principio de funcionamiento de una guía de ejemplo
La solución propuesta se compone de varias funciones universales que, al igual que las bibliotecas Arduino, se pueden adaptar fácilmente a sus propias necesidades. Aunque este ejemplo usa una superposición SHIELD-LCD16x2 lista para usar, al cambiar ciertas definiciones (hablaremos de ellas más adelante), obtendremos la capacidad de configurar funciones de menú para usar con una pantalla de caracteres de cualquier resolución, por ejemplo, 4 líneas de 20 caracteres, 1 línea de 16 caracteres, etc. Al ejecutar un programa de menú, tendremos que buscar elementos avanzados del lenguaje C, como punteros, estructuras y matrices. Pero comencemos describiendo cómo funciona la guía.
El ejemplo implementa una guía con 4 líneas. Se muestra en la pantalla de 2 líneas por 16 caracteres y se maneja con cuatro botones. Se asumió que:
- Los botones están numerados desde la izquierda y numerados del 1 al 4.
- El botón "1" (primero desde la izquierda) mueve la marca de verificación de la línea de la guía hacia abajo.
- El botón "2" mueve el marcador de selección de línea de la guía hacia arriba.* El botón "3" es como renunciar a la opción. "Como si", porque si no estamos ante una guía multinivel, no se aplicará. Así que supongamos que es un botón que la aplicación puede usar libremente.
- El botón "4" (el primero desde la derecha) confirma la selección – el equivalente a la tecla Enter en un teclado de PC.
La pantalla del módulo LCD tiene 2 líneas de 16 caracteres cada una, y la guía en este ejemplo tiene 4 líneas, por lo que no podemos mostrar el menú completo y tenemos que dividirlo en fragmentos de 2 líneas. Se supone que después de encender o reiniciar el microcontrolador, la primera y la segunda línea de la guía se mostrarán en la pantalla, y la marca de verificación se mostrará en la primera línea. Después de presionar el botón "abajo", el marcador se moverá a la línea de la guía número 2. Cuando presione "abajo" nuevamente, el marcador permanecerá en la línea de visualización número 2, pero mostrará las líneas de la guía 2 y 3, por lo que el marcador mostrará línea de la guía número 3. Otra presión de "abajo" hará que aparezcan las líneas de la guía número 3 y 4, y el marcador permanecerá en la línea 2 de la pantalla, mostrando la opción número 4. Una presión adicional de "abajo" lo regresará a la posición inicial.
El botón “arriba” funciona de manera similar, pero el marcador se mueve en la dirección opuesta. Y así, si presiona el botón "arriba" al comienzo del programa, la marca de verificación se moverá para mostrar la línea número 2, y la pantalla mostrará las líneas de menú 3 y 4. Al presionar "arriba" se moverá el marcador a visualice la línea número 1, y la pantalla LCD seguirá mostrando las líneas de la guía 3 y 4. Si vuelve a presionar "arriba" dejará una marca de verificación en la primera línea de la pantalla, pero la pantalla mostrará las líneas de menú 2 y 3. Y así sucesivamente.
La línea de visualización permite mostrar una secuencia de 16 caracteres. 2 caracteres están ocupados por símbolos de marcador (">" y "<"), por lo que en nuestro menú la cadena puede tener 14 caracteres de longitud. La longitud del menú (número de opciones) es teóricamente arbitraria y, en la práctica, está limitada por el tamaño de la memoria del programa y la capacidad de las variables.
Después de presionar el botón número 4, la función User_Menu devuelve el número de la opción seleccionada, o 0 si no se hizo ninguna selección o es incorrecta.
Arduino en la práctica - definir elementos de la guía
Al comienzo del programa de ejemplo, puede encontrar una serie de definiciones y variables que le permiten definir los parámetros de la pantalla en la que se muestra en el menú, así como el número de sus opciones y mensajes. Primero, enumeramos la cantidad de opciones. Como se mencionó, la guía en este ejemplo tiene 4 líneas, por lo que la definición de opciones de menú debe ser 4.
#define menuoptions 4 En la siguiente definición, debe prestar atención a una determinada propiedad del lenguaje C, en la que se basa el compilador Arduino. En el lenguaje C, la definición de una cadena (texto) siempre termina con un byte 0. Indica al compilador que la cadena termina en este punto y que, por ejemplo, se debe detener la visualización o alguna otra operación. Si creamos un mensaje de 14 caracteres, lo definimos como comunicado char[14]. Algunos compiladores agregarán un 0 al final de dicha definición para terminar la cadena, y algunos compiladores no lo harán, tratando la definición como una cadena de números en lugar de una cadena. El compilador de Arduino no agrega un carácter 0, por lo que, al reservar espacio para una cadena de esta longitud, debe escribir su propia función mostrando un número específico de caracteres sin verificar si la cadena termina en el byte 0, o agregar un carácter más del mensaje necesita. Por lo tanto, el valor de menuitemlen debe calcularse como el número máximo de caracteres en la pantalla menos 1, y no como podría parecer 2, porque 2 caracteres están ocupados por los caracteres ">" y "<", usados para indicar la línea actual de la guía.
#define menuitemlen 15 La siguiente definición lcd_lines es trivial – solo tiene que especificar el número de líneas de la pantalla en la que se mostrará el menú. Para la pantalla de ejemplo, la definición es la siguiente:
#define lcd_lines 2 A continuación, se definió el elemento menuitem que contiene los parámetros de una única línea de menú. Es una estructura con campos:
- menu_message – descripción de la línea del menú (recuerde que no puede tener más de 14 caracteres).
- whereisptr – una constante que especifica el valor por el cual la indicación en la tabla con la definición del menú debe moverse para mostrar las dos líneas. Como es fácil de notar, las dos primeras líneas caben en la pantalla, por lo que la constante tiene el valor 0, y luego para cada línea subsiguiente se incrementa en 1. Si la pantalla tenía 4 líneas, entonces con las primeras 4 definiciones de mensaje sería 0, y luego 1, 2, 3, etc.
- y0 – indica en qué línea se encuentra el marcador de menú cuando se muestra el mensaje en la pantalla.
Se puede encontrar más sobre estructuras en la literatura sobre lenguaje C. Aquí solo nos centraremos en la aplicación práctica de la estructura. En otros idiomas, la estructura se suele denominar registro o tupla. El tipo de datos definido se utilizó para crear una matriz en el espacio constante del programa (const) que contiene la definición completa del menú. Esta matriz se llama menu_lines y cuenta las opciones de menú de los elementos, cada uno de los cuales es una estructura que une los campos de definición de una sola línea de menú.
Este ejemplo define mensajes muy generales para las líneas de menú. Y así, la primera línea muestra el fragmento del mensaje "First menu line", la segunda - "Second menu line", la tercera - " Third menu line" y la cuarta - "Fourth menu line”.
const menuitem menu_lines[menuoptions]= {{"First menu lin", 0, 1}, {"Second menu li", 0, lcd_lines}, {"Third menu lin", 1, lcd_lines}, {"Fourth menu li", 2, lcd_lines}}; También necesitaremos un puntero a las estructuras individuales en el menú, el número del elemento de menú actual (donde se muestran las etiquetas), una variable seleccionable por el usuario y, como en el ejemplo anterior, una variable con el número de botón.
menuitem*menu_lines_ptr; signed char menu_position; char user_choice; int pressed; Un puntero es un tipo de variable muy útil y hace que la programación sea muy sencilla. Si, como en el ejemplo, el puntero apunta al primer elemento de la matriz y le agregamos 1, entonces, sin contar los bytes innecesarios y sin determinar el tamaño de su elemento, apuntará a la posición número 2 en esta matriz.
Arduino en la práctica - uso de la guía
Después de definir los elementos del menú, podemos llamarlos en nuestro programa. Primero, en función void setup() necesitamos establecer el valor inicial a la variable que define la posición actual en el menú, es decir menu_position = 0; y mostrar el menú llamando a la función Display_Menu().
En la función void loop()leemos el número del botón pulsado mediante una llamada
pressed = Number_of_Button(); Si el usuario presionó un botón con un número diferente de 0, podemos llamar a la función User_Menu(pressed); aceptando el número de botón como parámetro y conteniendo una reacción adecuada. Y así, el botón "1" mueve los marcadores hacia abajo, "2" hacia arriba y "4" selecciona las opciones del menú. El número de la opción seleccionada es devuelto por la función y se puede considerar, por ejemplo, usando switch… case o if. En el ejemplo, para ilustrar el funcionamiento del menú, se llaman funciones para cambiar el brillo de la retroiluminación de la pantalla, pero por supuesto pueden ser cualquier otra definida por el programador.
void loop() { pressed = Number_of_Button(); if (pressed > 0) user_choice = User_Menu(pressed); switch (user_choice) { case 1: //acción 1 break; case 2: //acción 2 break; case 3: //acción 3 break; case 4: //acción 4 break; } } Arduino - Información adicional sobre la creación de la guía
Un puntero (pointer) es una variable que contiene la dirección de otra variable. El uso de punteros conduce a un código más eficiente que el obtenido por otros métodos. Desafortunadamente, su uso incompetente puede deteriorar la legibilidad del programa. Esto es especialmente cierto cuando se utilizan de forma caótica, sin comentarios, lo que indica variables de tipo desconocido. Por otro lado, la capacidad de apuntar directamente a áreas de la memoria y realizar acciones en ellas es uno de los mecanismos más fuertes de C.Echemos un vistazo al siguiente ejemplo:
char x = 1, y = 2, z[5]; char* indicador; indicador =&x; //el puntero variable apunta a x y =*indicador; //ahora la variable y tiene el valor 1 *indicador = 0; //ahora la variable x tiene el valor 0 indicador = &z[0] //el puntero variable apunta al primer elemento de la matriz z Al declarar punteros, se utiliza el símbolo * (asteriscos). el operador de direccionamiento indirecto. Este operador de C, utilizado para un puntero, proporciona el contenido del objeto referenciado. Hay otro método en C para asignar una indicación a una variable específica. El operator & (symbol and) devuelve la dirección de la variable (nota: solo se puede usar para objetos que ocupan la memoria de variables y matrices). La sintaxis de declaración de puntero debe imitar el elemento al que puede aparecer el puntero.
Gracias a los punteros, puede simplificar y acelerar el funcionamiento del programa. Por ejemplo, los programadores son muy conscientes de la necesidad de pasar parámetros a las funciones. En muchos lenguajes de programación, los parámetros se transmiten con una larga lista de ellos. Esto ocupa mucho espacio RAM. Por supuesto, a la hora de crear un programa para una PC, esto no supone un gran problema, pero en un microcontrolador esta memoria no suele ser muy extensa. Tener variables que indiquen una lista de parámetros, incluidas matrices largas, por ejemplo, que contengan mensajes mostrados por el programa o búferes de datos, se puede pasar simplemente apuntando a la dirección de memoria donde se encuentra la variable.
En el lenguaje C, los parámetros de llamada de función se pasan por valor. Como resultado, la función no puede acceder a los argumentos que pertenecen a la subrutina de llamada. La única forma de realizar operaciones en variables que provienen de otra subrutina es pasar punteros de llamadas a funciones a esas variables como argumentos.
void Reemplazar (int*Tx, int *Ty) { int temp; temp =*Tx; *Tx = *Ty; *Ty = temp; } void main(void) { int A = 10, B = 20; Reemplazar(&A,&B); //cambiar los valores de las variables A y B } En este ejemplo, las acciones dentro de la función se realizan directamente en las variables del programa principal, sin ningún "intermediario", por ejemplo, poner las variables en la pila en la memoria, etc.
Todas las operaciones en los indicadores se ajustan automáticamente al tamaño de los objetos indicados. Las reglas de la aritmética de punteros son muy simples. Si el puntero T apunta al comienzo de una matriz de elementos de tipo int y es él mismo *int , entonces la operación T=T+1; (de lo contrario, T++;) moverá el puntero al siguiente elemento de la matriz. El número 1 no se agregará a la dirección del puntero, sino 2, porque la variable de tipo int tiene 2 bytes de longitud.
Las operaciones de puntero válidas incluyen asignar punteros a objetos del mismo tipo, sumar y restar un puntero y un número entero, restar o comparar dos punteros a elementos de la misma matriz y establecer un puntero en 0 o igualar un puntero en 0. Todos los demás punteros las operaciones no son válidas. No está permitido agregar dos punteros (incluso del mismo tipo) o multiplicar, dividir, moverse a la derecha o izquierda, combinar con máscaras (operaciones AND y OR) o agregarles números de punto flotante. Ni siquiera, excepto por un puntero de tipo *void – puede asignar un puntero a un objeto de un tipo sin transformar (lanzar) un puntero a objetos de otro tipo.
En el ejemplo descrito, el puntero apunta a una matriz que contiene estructuras de datos (registros). Los campos individuales de una estructura tienen sus nombres y se puede hacer referencia a ellos directamente, sin la necesidad de especificar un desplazamiento para un elemento de estructura dado. El operador de flecha se usa para indicar un campo con un nombre específico “->”. Por ejemplo
typedef struct parámetros { int x; int y; int altura; } parámetros*indicador; indicador->x; habilita una referencia al campo x indicador-> altura; habilita la referencia al campo de altura le permite consultar el campo xindicator->altura; le permite hacer referencia al campo de altura
i creamos una matriz a partir de la estructura de parámetros, el puntero cambiará por el número de bytes que es el tamaño de un solo elemento de la matriz, apuntando a sus elementos individuales sin tener que calcular la cantidad de bytes.
parámetros de matriz _parámetros[10]; // definición de matriz-lista de parámetros parámetros*indicador = &tablica_parametrów[0]; //ahora el indicador muestra // al principio de la matriz (indicador+5)->x; //muestra el campo x del quinto elemento de la matriz // permitiéndole recuperar o modificar una variable; Los indicadores en el lenguaje C son un tema muy extenso. Si está interesado en ampliar sus conocimientos y en la aplicación práctica de indicadores, le animo a leer libros sobre el lenguaje C y numerosos tutoriales disponibles en Internet.

