Tablero de controles para simulador de vuelo

@jhonny195 has hecho un trabajo genial con el display LCD para ver qué enviaba link2fs al Arduino. Y efectivamente, faltaba que mandase el CR/LF. Yo asumí que lo enviaba, porque así me era más fácil saber cuándo termina cada paquete de datos.

En cuanto a añadir más encoders: en principio se podría probar a añadir para ver si van bien y no pierden pasos. Aún así, esta es una primera versión de la librería, porque tengo pensado cambiarla para que no “recorra” todos los elementos seguidos, sino que cuando “recorra” todos los elementos que no son encoders, los haga de uno en uno en cada ciclo del loop() y “recorriendo” todos los encoders entre cada uno de ellos. De esta forma no sería tan crítico que sean añadidos muchos más elementos. Así que, en principio, no te quedes con ganas de añadir más líneas para controlar más elementos.

También tenía pensado añadir la funcionalidad de un teclado matricial como el que tú tienes. Pero no he tenido tiempo de ponerme con ello. Quiero implementarlo desde cero y que barra una tecla en cada ciclo del loop(), para que no pase mucho tiempo sin atender los encoders. Además, la idea es que se pueda configurar muy parecido a los pines de entradas con link2FS.addPinIn(). Pero sólo podrían trabajar con ellos como pulsadores, ya que no permite tener dos "teclas" pulsadas a la vez. Con lo que las "entradas directas" serían mayormente para los interruptores y aquellos pulsadores que pudieran tener que estar pulsados más de uno a la vez.

Respecto al tren de aterrizaje, sabiendo ahora que en ?Yxxx el valor 1 indica que una parte del tren está en transición: te propongo que, en lugar de un único led para indicar que el tren de aterrizaje está en transición, utilices tres ledes rojos, uno para para la nariz, otro para el izquierdo y el tercero para el derecho. E incluso podrías sustituir los ledes verdes que tienes ahora, por unos bicolor (rojo y verde) de tal forma que al estar en transición se pondrán en rojo cada uno de ellos, indicando claramente qué parte es la que está en transición (rojo), cuál está replegada (apagado) y cual completamente desplegada (verde). Por cierto, si vas a adquirir ledes, te recomiendo que sean difusos o mate, no transparentes. Los transparentes no se ven bien desde cualquier ángulo. Los mate sí.

Si te decides por lo de un led para cada parte del tren de aterrizaje, no tienes más que añadir tres líneas de código al programa. Por ejemplo: si los conectan a los pines 11, 12 y 13, sólo hace falta añadir estas tres líneas de código:

    link2FS.addPinOut(11, HIGH, "?Y#==", 1); // Led de transición del tren de aterrizaje nariz
    link2FS.addPinOut(12, HIGH, "?Y=#=", 1); // Led de transición del tren de aterrizaje izquierda
    link2FS.addPinOut(13, HIGH, "?Y==#", 1); // Led de transición del tren de aterrizaje derecha

Fíjate que lo único que cambia con respecto a los ledes verdes del tren de aterrizaje, son los pines y el valor que los activa, que en lugar de ser el 2 es el 1.

Veo que tienes un LCD I2C. Se podría intentar usar para mostrar algunos datos. Decide qué datos y cómo los quieres ver, y dime qué “parámetro” es el que envía link2fs y el formato. Para hacer las pruebas con algo “útil”. por ejemplo:

Al: 12343  12:16
Fl: 15º         

Donde se muestra la altura, la hora del simulador y el ángulo de los flaps. Eso sí, siempre que el link2fs pueda dar esa información al Arduino.

Hola @IgnoranteAbsoluto
Sobre lo de la matriz, se podría hacer "adaptable"? digamos:
hoy armo 12 teclas (matrix 3x4)
este codigo es un invento para explicarte (ni idea el formato que llevaria)

rowini = 1 //filas inician en pin 1
rowfin = 3 //filas finaleza en pin 3
colini = 4 //columna inicio
colfin = 7 //columna fin

Mañana necesito 3 teclas mas (3x5) , modificar solo el colfin = 7 y poner colfin = 8
y extender el string de los datos a 3 mas para los nuevos códigos (como veras te hablo basándome en lo que paso surbyte pero vos sabras decirme si es viable o no, idealmente estaría bueno porque si alguien quiere configurar mas teclas solo modifica "2 cosas".
Al margen de eso, sos vos el que conoce las posibilidades de todo esto, asi que tenes la batuta jajaja :laughing: .

Por el lado de el tren de aterrizaje es espectacular la idea que tiraste de los leds bicolor, pero el mio lo dejare asi, porque tengo todo soldado en el aire (sin placa ) y pegado con silicona. Lo que si voy a hacer es poner ese led rojo que tengo a uno de los 3 (creo que el tren de la derecha siempre baja o sube último usaría ese que marcaria el mayor tiempo de transición)

Por el LCD hay mucho que se podría poner, mi amigo no lo cree necesario....
Aca lo podria poner y mostrar la info de este componente que justamente tiene solo 2 renglones:

Costo un poco con word pero salio (otra cosa no se usar para dibujar jaja)

Esas platillas de tableritos son:
El primero - La de arriba el piloto automático de varios modelos de aviones chicos. esa pantalla no muestra mucha info y solo cambian cuando los varias vos :

  • Alt es la altura a mantener por el piloto automático
  • VS (vertical speed) se setea la velocidad de ascenso/descenso del avión con el piloto automático activado.

En cuanto a funciones ahí hay 7 botones push y un encender (la función REV no se utiliza va sin botón)
Pensé poner un led detrás de cada cartelito para que cuando se active cada función se ilumine de atras (estan disponibles esas extracciones) pero si sigo cableando tendré que comprar 3 arduinos para todo lo que me gustaría poner jajaj

Podríamos poner el LCD para indicar cuando esas funciones están activadas.
Ejemplo: con piloto automático activo al arduino llegaria =ax (x = 0 desactivado x = 1 activado) que el lcd muestre AP on o AP Off asi tendria lugar para 4 datos.
si lo dejamos en blanco y que al activar el piloto auto solo aparezca AP tendríamos lugar para mas.
Aca te los detallo (para todos el formato es el signo igual una letra y un valor que puede ser 1 o 0) :
=a ==> AP
=j ==> HDG
=o ==> NAV
=m ==> APR
=k ==> ALT

Si pusiéramos las cosas como están en la pantalla (valor de ALT y VS):
para el valor de la ALT llega con =bxxxxx (creo que te recorta el numero, osea si la altura fuera 100 no te manda =b00100 te manda =b100)
para el valor de la VS llega con =cxxxx y recorta como el otro también.

El segundo - Es un panelcito para 5 encoders (en 3 se usa también el pulsador) + 5 botones push

como te digo hay mucho cable y pines para ocupar, por eso te consulte por la matriz de botones para ahorrar pines para meter mas cosas jaja

Saludos :smiley: :smiley:

@jhonny195, he añadido la gestión del teclado matricial. A diferencia de lo que tenías hecho, este no necesita tener los pines consecutivos. Se definen los pines de las “filas” con el array PINES_FILAS[] y el de las columnas con PINES_COLUMNAS[]. En el código de ejemplo he puesto los mismos que tenías. Pero insisto, no tienen por qué ser consecutivos. Y se pueden añadir o quitar los que se quieran. Las constantes NUMERO_FILAS y NUMERO_COLUMNAS no hay que tocarlas, sus valores se calculan “automáticamente” a partir de los dos arrays.

Para usarlos se emplea link2FS.addMatrizIn(), que funciona de forma muy parecida a link2FS.addPinIn(), pero con ciertas diferencias. Lo más importante es que en lugar de indicar el pin de entrada, en los primeros dos parámetros, se indica fila y columna en la que está conectado el pulsador que se desea “gestionar”. Hay que tener en cuenta que las filas y columnas se empiezan a numerar a partir del cero. Es el número de la posición de la definición de los pines en los arrays PINES_FILAS[] y PINES_COLUMNAS[]. Yo he tratado de definir los arrays para que se comporten tal como lo tenías en el código que has puesto al principio. Pero no garantizo que sea el orden correcto. Ya sabes: toca probar y “afinar” a base de prueba y error.

El problema de la matriz de pulsadores es que no detecta correctamente la pulsación de dos o más de ellos a la vez. Es por esto que no pueden funcionar con un interruptor, como el del freno de estacionamiento. Es por esto que tengo pensado implementar, más adelante, la posibilidad de configurar algunos pulsadores a modo de “enclavamiento”. Es decir: que en lugar de estar “activo” mientras se pulsa y “desactivarse” al soltarlo, que se “active” con un pulso y se desactive con otro. Por ejemplo: se podría usar para el freno de estacionamiento, una pulsación lo pone y una nueva pulsación lo quita. Obviamente, si se vuelve a pulsar se vuelve a poner… Así sucesivamente. Pero esto es para más adelante. Tampoco sé si realmente sería de utilidad alguna.

Nota: el control de la matriz de pulsadores la he hecho “desde cero” y no escanea todos los pulsadores en cada ciclo del loop() principal, sino uno cada vez. Esto es para que no se “entretenga demasiado” y le de más “tiempo de CPU” al control de los encoders.

Aquí tienes el código actualizado. Lo he procurado configurar según creo que tienes. Seguramente tendrás que corregir algo. Siéntete libre de modificar lo que quieras.

#include "Link2FS.h" // "Librería que se encarga de todo con link2FS

// Definición de los pines que forman las filas de la matriz de pulsadores
const byte PINES_FILAS[] = {18, 19, 20, 21, 22, 23};
// Definición de los pines que forman las columnas de la matriz de pulsadores
const byte PINES_COLUMNAS[] = {24, 25, 26, 27, 28, 29, 30};
// El número de pines de las filas se calcula automáticamente en la siguiente línea (no hay que modificarla nunca)
const byte NUMERO_FILAS = sizeof(PINES_FILAS) / sizeof(PINES_FILAS[0]);
// El número de pines de las columnas se calcula automáticamente en la siguiente línea (no hay que modificarla nunca)
const byte NUMERO_COLUMNAS = sizeof(PINES_COLUMNAS) / sizeof(PINES_COLUMNAS[0]);

Link2FS link2FS(Serial, PINES_FILAS, PINES_COLUMNAS, NUMERO_FILAS, NUMERO_COLUMNAS); // Objeto que se encarga de todo con link2FS. Se le indicua cual es el puerto serie al que está conectado, los pines de la filas de la matriz, los pines de las columnas de la matriz, número de filas, número de columnas

void setup() {
    Serial.begin(115200);

    // Parámetros de addEncoder
    //   Pin al que está conectado el CLK
    //   Pin al que está conectado el DT
    //   Formato de la cadena que hay que enviar al simulador (la que se utiliza en el priftf)
    //   Valor inicial del encoder (1 o 9 en el código original)
    //   Valor mínimo del encoder (0 en el código original)
    //   Valor máximo del encoder (10 en el código original). Si este parámetro y el anterior se ponen a cero, se auto ajusta en el momento del calibrado.
    //   Valor mínimo que envía al simulador (0 en el código original)
    //   Valor máximo que envía al simulador (99 en el código original, 100 en este código)
    //   Tiempo, en milisegundos, que ha de trasncurrir desde el último movimiento de calibrado para que se de por teminada la calibración. En este caso se indica cero porque ya los límites están definido (de 0 a 10)
    link2FS.addEncoder(48, 49, "C56%03u", 0, 0, 10, 0, 100, 0); // Palanca de Gases Motor 1
    link2FS.addEncoder(52, 53, "C57%03u", 0, 0, 10, 0, 100, 0); // Palanca de Gases Motor 2
    link2FS.addEncoder(50, 51, "C60%03u", 0, 0, 10, 0, 100, 0); // Paso de Helice Motor 1
    link2FS.addEncoder(45, 44, "C61%03u", 0, 0, 10, 0, 100, 0); // Paso de Helice Motor 2
    link2FS.addEncoder(42, 43, "C58%03u", 10, 0, 10, 0, 100, 0); // Palanca de Mezcla Motor 1
    link2FS.addEncoder(47, 46, "C59%03u", 10, 0, 10, 0, 100, 0); // Palanca de Mezcla Motor 2

    // Parámetros de addPinInFS:
    //   Pin de entrada
    //   Valor de la lectura del pin cuando está "activado"
    //   Indica si se utiliza la resistencia pull up interna o no (INPUT_PULLUP o INPUT)
    //   Cadena que hay que enviar si el pin está "activado"
    //   Cadena que hay que enviar si el pin está "desactivado"
    //   Inicio de la cadena que se recibe con el valor que confirma la recepción del dato
    //   Tiempo que espera antes de volve a comunicar el estado, si no recibe la cadena de "confirmación". Si es cero, no lo reenvía
    link2FS.addPinIn(31, LOW, INPUT_PULLUP, "C040", "C041", "<q", 2000); // Interruptor freno de estacionamiento
    link2FS.addPinIn(36, LOW, INPUT_PULLUP, "C02", "C01", "?Y", 2000); // Interruptor tren de aterrizaje
    link2FS.addPinIn(34, LOW, INPUT_PULLUP, "C14", NULL, NULL, 0); // Pulsador de flaps DOWN
    link2FS.addPinIn(35, LOW, INPUT_PULLUP, "C15", NULL, NULL, 0); // Pulsador de flaps UP

    // Parámetros de addMatrizIn:
    //   Fila de la matriz a la que está conetrado el pulsador (empieza en cero)
    //   Columna de la matriz a la que está conetrado el pulsador (empieza en cero)
    //   Cadena que hay que enviar cuanto se pulsa
    //   Cadena que hay que enviar cuando se libera
    //   Inicio de la cadena que se recibe con el valor que confirma la recepción del dato
    //   Tiempo que espera antes de volve a comunicar el estado, si no recibe la cadena de "confirmación". Si es cero, no lo reenvía
    // Primera fila de la matriz
    link2FS.addMatrizIn(0, 0, "H25", NULL, NULL, 0);
    link2FS.addMatrizIn(0, 1, "H09", NULL, NULL, 0);
    link2FS.addMatrizIn(0, 2, "H22", NULL, NULL, 0);
    link2FS.addMatrizIn(0, 3, "H20", NULL, NULL, 0);
    link2FS.addMatrizIn(0, 4, "H23", NULL, NULL, 0);
    link2FS.addMatrizIn(0, 5, "H21", NULL, NULL, 0);
    link2FS.addMatrizIn(0, 6, "G14", NULL, NULL, 0);
    // Segunda fila de la matriz
    link2FS.addMatrizIn(1, 0, "C26", NULL, NULL, 0);
    link2FS.addMatrizIn(1, 1, "A56", NULL, NULL, 0);
    link2FS.addMatrizIn(1, 2, "G18", NULL, NULL, 0);
    link2FS.addMatrizIn(1, 3, "G09", NULL, NULL, 0);
    link2FS.addMatrizIn(1, 4, "G13", NULL, NULL, 0);
    link2FS.addMatrizIn(1, 5, "G12", NULL, NULL, 0);
    link2FS.addMatrizIn(1, 6, "H01", NULL, NULL, 0);
    // Tercera fila de la matriz
    link2FS.addMatrizIn(2, 0, "C25", NULL, NULL, 0);
    link2FS.addMatrizIn(2, 1, "A55", NULL, NULL, 0);
    link2FS.addMatrizIn(2, 2, "H17", NULL, NULL, 0);
    link2FS.addMatrizIn(2, 3, "H18", NULL, NULL, 0);
    link2FS.addMatrizIn(2, 4, "H19", NULL, NULL, 0);
    link2FS.addMatrizIn(2, 5, "H20", NULL, NULL, 0);
    link2FS.addMatrizIn(2, 6, "H21", NULL, NULL, 0);
    // Cuarta fila de la matriz
    link2FS.addMatrizIn(3, 0, "H24", NULL, NULL, 0);
    link2FS.addMatrizIn(3, 1, "H23", NULL, NULL, 0);
    link2FS.addMatrizIn(3, 2, "H22", NULL, NULL, 0);
    link2FS.addMatrizIn(3, 3, "H21", NULL, NULL, 0);
    link2FS.addMatrizIn(3, 4, "H20", NULL, NULL, 0);
    link2FS.addMatrizIn(3, 5, "H19", NULL, NULL, 0);
    link2FS.addMatrizIn(3, 6, "H18", NULL, NULL, 0);
    // Quinta fila de la matriz
    link2FS.addMatrizIn(4, 0, "B12", NULL, NULL, 0);
    link2FS.addMatrizIn(4, 1, "B11", NULL, NULL, 0);
    link2FS.addMatrizIn(4, 2, "A57", NULL, NULL, 0);
    link2FS.addMatrizIn(4, 3, "H14", NULL, NULL, 0);
    link2FS.addMatrizIn(4, 4, "H15", NULL, NULL, 0);
    link2FS.addMatrizIn(4, 5, "H16", NULL, NULL, 0);
    link2FS.addMatrizIn(4, 6, "H17", NULL, NULL, 0);
    // Sexta fila de la matriz
    link2FS.addMatrizIn(5, 0, "A58", NULL, NULL, 0);
    link2FS.addMatrizIn(5, 1, "H37", NULL, NULL, 0);
    link2FS.addMatrizIn(5, 2, "H38", NULL, NULL, 0);
    link2FS.addMatrizIn(5, 3, "H39", NULL, NULL, 0);
    link2FS.addMatrizIn(5, 4, "H40", NULL, NULL, 0);
    link2FS.addMatrizIn(5, 5, "H41", NULL, NULL, 0);
    link2FS.addMatrizIn(5, 6, "H42", NULL, NULL, 0);

    // Parámetros de addPinOutFS:
    //   Pin de salida
    //   Valor de la salida del pin cuando está "activado"
    //   Modelo de la cadena que se recibe con el dato
    //   Valor numerico del dato para "activar" la salida
    link2FS.addPinOut(41, HIGH, "?Y#==", 2); // Led tren de aterrizaje nariz
    link2FS.addPinOut(40, HIGH, "?Y=#=", 2); // Led tren de aterrizaje izquierda
    link2FS.addPinOut(38, HIGH, "?Y==#", 2); // Led tren de aterrizaje derecha
    link2FS.addPinOut(32, HIGH, "<q#", 1); // Led del freno de estacionamiento
    link2FS.addPinOut(33, LOW, "<G==#", 0); // Led de los flaps
}

void loop() {
    link2FS.loop(); // Se ha de realizar constantemente esta llamada para que se controle todo
}

Obviamente, se ha de descargar y actualizar también los dos ficheros siguientes:
Link2FS.h (9.2 KB)
Link2FS.cpp (12.4 KB)

Tema aparte: el display y la “decodificación” de los valores que manda link2fs. Me vendría bien saber cual es el formato de los valores de los parámetros. He estado mirando un poco por Internet y me ha parecido ver que algunos parámetros pueden tener un signo al principio o un punto decimal. También quisiera saber cual es el valor o tamaño máximo que puede llegar a tener un parámetro. Y en particular los que te interesen. Para empezar los de ALT y VS. Por cierto, ¿qué es VS? Entiendo que ALT es la altura, pero tampoco estoy seguro del todo.

GENIO!!!!! bueno te cuento que me fui a mis pagos y por hacer un tramite con personal el sistema por error me corto la linea asi que no pude ver el foro hasta ayer (sábado a la noche) que volví a la ciudad, vi tu respuesta y de las ganas que tenia de verlo andar estoy despierto ahora contestando pq recien termino de armar y probar la placa con la matriz jajaj (son las 4:40 de la madrugada)

En fin, a lo que estamos haciendo:
El código con la matriz espectacular, por ahora solo utilice 2x4 para la placa del piloto automático que tenía 8 botones y tengo que hacer otra placa con 8 botones mas, asi que bloquee los grupos de renglones que no usaba con /* */ despues ire habilitando líneas.
aca te dejo una foto de como quedo la placa :smiley: :

Como veras es copia del tablero que se ve en la esquina superior de mi notebook con el agregado del encoder, y me quedo buen espacio para el display en la placa.
Tengo casi todos los pines de la doble fila del mega ocupados ya, me quedan del 0 al 21 digitales y los 15 analogicos. La otra placa que tengo que armar son 5 encoders mas otra parte de la matriz (esa otra matriz solo son 2 cables de las columnas, las filas ya estan) osea que ocuparía 12 pines, me quedan 9, si dejo reservados los de la pantalla me quedan 7 digitales.
Pregunta, los analogicos se pueden usar como digitales? :thinking: (suponiendo necesidad de meter mas botones o encoders)

sobre cómo llegan los datos:

como te lo habia puesto ahi, para AP, HDG, NAV, APR, REV, ALT, llegan los respectivos códigos de arriba con un 0 o un 1 para mostrar desactivado/activado respectivamente.

En el caso de el altímetro te llega =bxxxxx (osea 5 cifras después de la letra b)
Alt es la altura que se le setea al piloto automático para que mantenga.
En el caso de VS ( vertical speed o velocidad vertical) que es la velocidad de ascenso o descenso del avión esta si te confirmo que llega con signo en este formato =c+xxxx o =c-xxxx ( igual - letra c - signo (+ o -) - 4 cifras.

Saludos

@jhonny195 aquí tienes una nueva versión. En la que he añadida la funcionalidad de “enclavar” cualquier pulsador y el uso del LCD.

Me he llevado un pequeño susto al probar el mostrar datos por el LCD. No me funcionaba correctamente la obtención del valor de =bxxx. Me llevó un rato darme cuenta de que estaba utilizando el carácter = para indicar en el modelo de decodificación del tren de aterrizaje qué caracteres no habían de tenerse en cuenta. Y resulta que el parámetro a decodificar, =bxxx, empieza por el carácter =. Así que he cambiado de carácter, y ahora se utiliza el carácter * (asterisco). Espero que el asterisco no se use para nada. Con el cambio las líneas:

    link2FS.addPinOut(41, HIGH, "?Y#==", 2); // Led tren de aterrizaje nariz
    link2FS.addPinOut(40, HIGH, "?Y=#=", 2); // Led tren de aterrizaje izquierda
    link2FS.addPinOut(38, HIGH, "?Y==#", 2); // Led tren de aterrizaje derecha
    link2FS.addPinOut(32, HIGH, "<q#", 1); // Led del freno de estacionamiento
    link2FS.addPinOut(33, LOW, "<G==#", 0); // Led de los flaps

Con el cambio de los iguales por asteriscos, queda así:

    link2FS.addPinOut(41, HIGH, "?Y#**", 2); // Led tren de aterrizaje nariz
    link2FS.addPinOut(40, HIGH, "?Y*#*", 2); // Led tren de aterrizaje izquierda
    link2FS.addPinOut(38, HIGH, "?Y**#", 2); // Led tren de aterrizaje derecha
    link2FS.addPinOut(32, HIGH, "<q#", 1); // Led del freno de estacionamiento
    link2FS.addPinOut(33, LOW, "<G**#", 0); // Led de los flaps

El LCD usado es I2C y los pines del MEGA para el I2C son el 20 y 21. Ambos pines se estaban usando para la matriz de pulsadores. Así que los pines 20 y 21 para la matriz los he cambiado por los pines 16y 17 respectivamente. Esto supone cambiar los dos cables en cuanto al hardware. Mientras que en el programa sólo hay que cambiar esos dos valores en la definición del array PINES_FILAS[], quedando así:

const byte PINES_FILAS[] = {18, 19, 16, 17, 22, 23};

En teoría no habría que tocar nada más del código. Porque el orden de nueración de las “filas lógicas” no han cambiado.

Para el LCD he implementado link2FS.addLcd(). Digamos que tiene dos posibles formas de uso. Una es indicando sólo los seis primeros parámetros, hasta “el formato”, para mostrar el valor numérico que nos llega. La otra es añadiendo al menos un parámetro más, que es la cadena que se muestra cuando el valor no está “activo”. En este último caso, la cadena del formato pasa a ser la cadena que se muestra cuando el valor está “activo” y no se debe de utilizar el formateo con el %. Se le puede indicar un octavo parámetro, que es el valor cuando está “activo”, pero no es necesario si ese valor es 1 pues el valor que toma si no se indica el parámetro.

El primer parámetro del link2FS.addLcd() es el objeto que da acceso al LCD. Como en este caso el LCD se conecta al I2c, cabe la posibilidad de añadir más LCD con diferentes direcciones LCD. Si fuera el caso, sólo habría que definir un objeto por cada LCD que se añada y pasarlo como primer parámetro a cada llamada de link2FS.addLcd() que corresponda. En el setup() al principio se inicializa y configura el LCD. A modo de ejemplo y para pruebas, he añadido al programa el mostrar varios parámetros que comentastes en el LCD, los del piloto automático.

Un detalle sobre la librería que controla el LCD. Estoy usando LCD_I2C.h y tiene la particularidad que no admite más que los de 16x2. Si se quiere utilizar otro tamaño de pantalla (20x4, por ejemplo) habría que utilizar una librería diferente.

Respecto al piloto automático, supongo que queda el poder establecer valores con los encoders. Para esto me surgen dos dudas. La primera: no creo que la altura la quieras establecer pie a pie, ¿tal vez de 100 en 100? La segunda: siguiendo el ejemplo de la altura del piloto automático, supongo que querrás que incremente o decremente el valor que se recibe mediante el parámetro =bxxxxx ¿cierto?

Pregunta: ¿Cuáles son los valores que quieres establecer con los encoders, cómo vienen de link2fs y cómo se le indica a link2fs?

En cuanto al “enclavamiento” de los pulsadores: es válido tanto para los que se definen con link2FS.addPinIn() como para los definidos con link2FS.addMatrizIn(). Ahora tiene la posibilidad de añadir dos parámetros booleanos. El primero por defecto es false, si se pone true es para indicar que se quiere “enclavamiento”. Esto es que se “activa” o “desactiva” con cada pulsación, con lo que hay que mantenerlo pulsado para que se mantenga activo. En plan “ON/OFF”, como si fuera un interruptor. El siguiente parámetro es para indicar qué valor ha de tener al encenderse el Arduino. Si no se indica es fase, que significa que está “inactivo” al encenderse el Arduino. Si se configura con enclavamiento, sí que tendría sentido indicar la cadena al indicar que cadena se envía al estar “inactivo”. De esta nueva funcionalidad no he puesto ningún ejemplo.

El código de lo que tengo hasta ahora:

#include "Link2FS.h" // "Librería que se encarga de todo con link2FS
#include <LCD_I2C.h>
#include <Wire.h>

// Definición de los pines que forman las filas de la matriz de pulsadores
const byte PINES_FILAS[] = {18, 19, 16, 17, 22, 23};
// Definición de los pines que forman las columnas de la matriz de pulsadores
const byte PINES_COLUMNAS[] = {24, 25, 26, 27, 28, 29, 30};
// El número de pines de las filas se calcula automáticamente en la siguiente línea (no hay que modificarla nunca)
const byte NUMERO_FILAS = sizeof(PINES_FILAS) / sizeof(PINES_FILAS[0]);
// El número de pines de las columnas se calcula automáticamente en la siguiente línea (no hay que modificarla nunca)
const byte NUMERO_COLUMNAS = sizeof(PINES_COLUMNAS) / sizeof(PINES_COLUMNAS[0]);

Link2FS link2FS(Serial, PINES_FILAS, PINES_COLUMNAS, NUMERO_FILAS, NUMERO_COLUMNAS); // Objeto que se encarga de todo con link2FS. Se le indicua cual es el puerto serie al que está conectado, los pines de la filas de la matriz, los pines de las columnas de la matriz, número de filas, número de columnas

LCD_I2C lcd(0x27);


void setup() {
    Serial.begin(115200);

    lcd.begin();
    lcd.backlight();
    lcd.noCursor();
    lcd.clear();

    // Parámetros de addEncoder
    //   Pin al que está conectado el CLK
    //   Pin al que está conectado el DT
    //   Formato de la cadena que hay que enviar al simulador (la que se utiliza en el priftf)
    //   Valor inicial del encoder (1 o 9 en el código original)
    //   Valor mínimo del encoder (0 en el código original)
    //   Valor máximo del encoder (10 en el código original). Si este parámetro y el anterior se ponen a cero, se auto ajusta en el momento del calibrado.
    //   Valor mínimo que envía al simulador (0 en el código original)
    //   Valor máximo que envía al simulador (99 en el código original, 100 en este código)
    //   Tiempo, en milisegundos, que ha de trasncurrir desde el último movimiento de calibrado para que se de por teminada la calibración. En este caso se indica cero porque ya los límites están definido (de 0 a 10)
    link2FS.addEncoder(48, 49, "C56%03u", 0, 0, 10, 0, 100, 0); // Palanca de Gases Motor 1
    link2FS.addEncoder(52, 53, "C57%03u", 0, 0, 10, 0, 100, 0); // Palanca de Gases Motor 2
    link2FS.addEncoder(50, 51, "C60%03u", 0, 0, 10, 0, 100, 0); // Paso de Helice Motor 1
    link2FS.addEncoder(45, 44, "C61%03u", 0, 0, 10, 0, 100, 0); // Paso de Helice Motor 2
    link2FS.addEncoder(42, 43, "C58%03u", 10, 0, 10, 0, 100, 0); // Palanca de Mezcla Motor 1
    link2FS.addEncoder(47, 46, "C59%03u", 10, 0, 10, 0, 100, 0); // Palanca de Mezcla Motor 2

    // Parámetros de addPinInFS:
    //   Pin de entrada
    //   Valor de la lectura del pin cuando está "activado"
    //   Indica si se utiliza la resistencia pull up interna o no (INPUT_PULLUP o INPUT)
    //   Cadena que hay que enviar si está "activado"
    //   Cadena que hay que enviar si está "desactivado"
    //   Inicio de la cadena que se recibe con el valor que confirma la recepción del dato
    //   Tiempo que espera antes de volve a comunicar el estado, si no recibe la cadena de "confirmación". Si es cero, no lo reenvía
    //   Indica si es con enclavamiento (con cada pulsación bascula el estado). Es opcional, por defecto es false (sin enclavamiento)
    //   Valor inicial si tiene activado el enclavamiento. ES opcional, por defecto es false ("inactivo")
    link2FS.addPinIn(31, LOW, INPUT_PULLUP, "C040", "C041", "<q", 2000); // Interruptor freno de estacionamiento
    link2FS.addPinIn(36, LOW, INPUT_PULLUP, "C02", "C01", "?Y", 2000); // Interruptor tren de aterrizaje
    link2FS.addPinIn(34, LOW, INPUT_PULLUP, "C14", NULL, NULL, 0); // Pulsador de flaps DOWN
    link2FS.addPinIn(35, LOW, INPUT_PULLUP, "C15", NULL, NULL, 0); // Pulsador de flaps UP

    // Parámetros de addMatrizIn:
    //   Fila de la matriz a la que está conetrado el pulsador (empieza en cero)
    //   Columna de la matriz a la que está conetrado el pulsador (empieza en cero)
    //   Cadena que hay que enviar cuanto se pulsa
    //   Cadena que hay que enviar cuando se libera
    //   Inicio de la cadena que se recibe con el valor que confirma la recepción del dato
    //   Tiempo que espera antes de volve a comunicar el estado, si no recibe la cadena de "confirmación". Si es cero, no lo reenvía
    // Primera fila de la matriz
    link2FS.addMatrizIn(0, 0, "H25", NULL, NULL, 0);
    link2FS.addMatrizIn(0, 1, "H09", NULL, NULL, 0);
    link2FS.addMatrizIn(0, 2, "H22", NULL, NULL, 0);
    link2FS.addMatrizIn(0, 3, "H20", NULL, NULL, 0);
    link2FS.addMatrizIn(0, 4, "H23", NULL, NULL, 0);
    link2FS.addMatrizIn(0, 5, "H21", NULL, NULL, 0);
    link2FS.addMatrizIn(0, 6, "G14", NULL, NULL, 0);
    // Segunda fila de la matriz
    link2FS.addMatrizIn(1, 0, "C26", NULL, NULL, 0);
    link2FS.addMatrizIn(1, 1, "A56", NULL, NULL, 0);
    link2FS.addMatrizIn(1, 2, "G18", NULL, NULL, 0);
    link2FS.addMatrizIn(1, 3, "G09", NULL, NULL, 0);
    link2FS.addMatrizIn(1, 4, "G13", NULL, NULL, 0);
    link2FS.addMatrizIn(1, 5, "G12", NULL, NULL, 0);
    link2FS.addMatrizIn(1, 6, "H01", NULL, NULL, 0);
    // Tercera fila de la matriz
    link2FS.addMatrizIn(2, 0, "C25", NULL, NULL, 0);
    link2FS.addMatrizIn(2, 1, "A55", NULL, NULL, 0);
    link2FS.addMatrizIn(2, 2, "H17", NULL, NULL, 0);
    link2FS.addMatrizIn(2, 3, "H18", NULL, NULL, 0);
    link2FS.addMatrizIn(2, 4, "H19", NULL, NULL, 0);
    link2FS.addMatrizIn(2, 5, "H20", NULL, NULL, 0);
    link2FS.addMatrizIn(2, 6, "H21", NULL, NULL, 0);
    // Cuarta fila de la matriz
    link2FS.addMatrizIn(3, 0, "H24", NULL, NULL, 0);
    link2FS.addMatrizIn(3, 1, "H23", NULL, NULL, 0);
    link2FS.addMatrizIn(3, 2, "H22", NULL, NULL, 0);
    link2FS.addMatrizIn(3, 3, "H21", NULL, NULL, 0);
    link2FS.addMatrizIn(3, 4, "H20", NULL, NULL, 0);
    link2FS.addMatrizIn(3, 5, "H19", NULL, NULL, 0);
    link2FS.addMatrizIn(3, 6, "H18", NULL, NULL, 0);
    // Quinta fila de la matriz
    link2FS.addMatrizIn(4, 0, "B12", NULL, NULL, 0);
    link2FS.addMatrizIn(4, 1, "B11", NULL, NULL, 0);
    link2FS.addMatrizIn(4, 2, "A57", NULL, NULL, 0);
    link2FS.addMatrizIn(4, 3, "H14", NULL, NULL, 0);
    link2FS.addMatrizIn(4, 4, "H15", NULL, NULL, 0);
    link2FS.addMatrizIn(4, 5, "H16", NULL, NULL, 0);
    link2FS.addMatrizIn(4, 6, "H17", NULL, NULL, 0);
    // Sexta fila de la matriz
    link2FS.addMatrizIn(5, 0, "A58", NULL, NULL, 0);
    link2FS.addMatrizIn(5, 1, "H37", NULL, NULL, 0);
    link2FS.addMatrizIn(5, 2, "H38", NULL, NULL, 0);
    link2FS.addMatrizIn(5, 3, "H39", NULL, NULL, 0);
    link2FS.addMatrizIn(5, 4, "H40", NULL, NULL, 0);
    link2FS.addMatrizIn(5, 5, "H41", NULL, NULL, 0);
    link2FS.addMatrizIn(5, 6, "H42", NULL, NULL, 0);

    // Parámetros de addPinOutFS:
    //   Pin de salida
    //   Valor de la salida del pin cuando está "activado"
    //   Modelo de la cadena que se recibe con el dato
    //   Valor numerico del dato para "activar" la salida
    link2FS.addPinOut(41, HIGH, "?Y#**", 2); // Led tren de aterrizaje nariz
    link2FS.addPinOut(40, HIGH, "?Y*#*", 2); // Led tren de aterrizaje izquierda
    link2FS.addPinOut(38, HIGH, "?Y**#", 2); // Led tren de aterrizaje derecha
    link2FS.addPinOut(32, HIGH, "<q#", 1); // Led del freno de estacionamiento
    link2FS.addPinOut(33, LOW, "<G**#", 0); // Led de los flaps

    // Parámetros de addLcd:
    //   Modelo de la cadena que se recibe con el dato
    //   Columna del display en donde se muestra el dato
    //   Fila del display en donde se muestra el dato
    //   Formato en que se muestra el dato o cadena que se muestra cuando está activo
    //   Cadena que se muestra cuando no está activo. Por defecto es NULL, que significa que no se usa. Una cadena vacía ("") o con cualquier contenido: hace que se muestre cuando está desactivado
    //   Valor del dato para considerar que está "activo". No se usa si la cadena anterior es NULL. Por defecto es 1
    link2FS.addLcd(lcd, "=a", 4, 0, "AP", "");    // Piloto autotomático activo
    link2FS.addLcd(lcd, "=d", 0, 0, "HDG", "");   // Heading
    link2FS.addLcd(lcd, "=b", 7, 0, "ALT %05ld"); // Altura del piloto automático
    link2FS.addLcd(lcd, "=o", 0, 1, "NAV", "");   // Nav
    link2FS.addLcd(lcd, "=m", 4, 1, "APR", "");   // Aproach hold
    link2FS.addLcd(lcd, "=c", 8, 1, "VS %05ld"); // Velocidad vertical

}

void loop() {
    link2FS.loop(); // Se ha de realizar constantemente esta llamada para que se controle todo
}

Los dos ficheros actualizados:
Link2FS.cpp (14.6 KB)
Link2FS.h (10.3 KB)

Me vendría bien que, si modificas el programa adaptándolo a tus necesidades, lo pusieras aquí, por si nuevas características necesitan de cambios más profundos en el .ino.

Respecto a poner más cosas y/o necesitar más pines: si no me equivoco, los pines analógicos también pueden funcionar como pines digitales (aunque en algunos Arduinos hay algún pin que sólo es para la lectura analógica. Pero creo que no es el caso del MEGA. Seguramente alguien del foro lo sabrá mejor que yo). Pero no recomiendo “sobrecargar” el Arduino con demasiadas funcionalidades porque el atender los encoders es “crítico” y si tiene demasiadas de las “otras tareas” puede suponer “pérdidas de pasos” en la lectura de los encoders. O si se pone una matriz de pulsadores muy grande, puede que haya demasiado lag o retraso en la lectura de las pulsaciones, incluso “perderse” alguna si se pulsa demasiado rápido. Así que tal vez se tenga que añadir más Arduinos para repartir las funcionalidades o para tener muchas más. Para esto, aparte de que exista la posibilidad de conectar varios Arduinos diréctamenta al liks2fs a través de otros puertos serie, creo que se podrían poner los Arduinos en “cascada”. Aprovechando que el MEGA tiene más de un puerto serie, se podría usar un segundo puerto serie para conectar otro Arduino que se encargue de otras cosas. Lo que llega del link2fs al Serial del primer Arduino, se lo “pasa” al segundo Arduino por el Serial1 y lo que reciba por el Serial1 del segundo Ardunio, se lo pasa por el Serial al link2fs. De hecho el segundo Arduino podría hacer lo mismo con un tercer Arduino, y así sucesivamente. Esta funcionalidad es unas de las cosas que tengo pensada implementar.

¿En algún momento interesa que parpadee algo en el LCD o algún led? Es otra cosa que se podría implementar.

Supongo que en el caso de que se necesite alguna señal sonora, se podría conectar un zumbador “activo” a algún pin y, en lugar de encender un led, active el zumbador que sonaría por sí solo. ¿Pero interesa tener al menos un zumbador “pasivo” por cada Arduino, que se active con la función tone()?

@IgnoranteAbsoluto :smiley: aca te dejo como me pediste el codigo toqueteado para mis funciones:

#include "Link2FS.h" // "Librería que se encarga de todo con link2FS
#include <LCD_I2C.h>
#include <Wire.h>

// Definición de los pines que forman las filas de la matriz de pulsadores
const byte PINES_FILAS[] = {25, 26, 27, 28};
// Definición de los pines que forman las columnas de la matriz de pulsadores
const byte PINES_COLUMNAS[] = { 29, 30};
// El número de pines de las filas se calcula automáticamente en la siguiente línea (no hay que modificarla nunca)
const byte NUMERO_FILAS = sizeof(PINES_FILAS) / sizeof(PINES_FILAS[0]);
// El número de pines de las columnas se calcula automáticamente en la siguiente línea (no hay que modificarla nunca)
const byte NUMERO_COLUMNAS = sizeof(PINES_COLUMNAS) / sizeof(PINES_COLUMNAS[0]);

Link2FS link2FS(Serial, PINES_FILAS, PINES_COLUMNAS, NUMERO_FILAS, NUMERO_COLUMNAS); // Objeto que se encarga de todo con link2FS. Se le indicua cual es el puerto serie al que está conectado, los pines de la filas de la matriz, los pines de las columnas de la matriz, número de filas, número de columnas

LCD_I2C lcd(0x27);


void setup() {
    Serial.begin(115200);

    lcd.begin();
    lcd.backlight();
    lcd.noCursor();
    lcd.clear();

    // Parámetros de addEncoder
    //   Pin al que está conectado el CLK
    //   Pin al que está conectado el DT
    //   Formato de la cadena que hay que enviar al simulador (la que se utiliza en el priftf)
    //   Valor inicial del encoder (1 o 9 en el código original)
    //   Valor mínimo del encoder (0 en el código original)
    //   Valor máximo del encoder (10 en el código original). Si este parámetro y el anterior se ponen a cero, se auto ajusta en el momento del calibrado.
    //   Valor mínimo que envía al simulador (0 en el código original)
    //   Valor máximo que envía al simulador (99 en el código original, 100 en este código)
    //   Tiempo, en milisegundos, que ha de trasncurrir desde el último movimiento de calibrado para que se de por teminada la calibración. En este caso se indica cero porque ya los límites están definido (de 0 a 10)
    link2FS.addEncoder(48, 49, "C56%03u", 0, 0, 10, 0, 100, 0); // Palanca de Gases Motor 1
    link2FS.addEncoder(52, 53, "C57%03u", 0, 0, 10, 0, 100, 0); // Palanca de Gases Motor 2
    link2FS.addEncoder(50, 51, "C60%03u", 10, 0, 10, 0, 100, 0); // Paso de Helice Motor 1
    link2FS.addEncoder(45, 44, "C61%03u", 10, 0, 10, 0, 100, 0); // Paso de Helice Motor 2
    link2FS.addEncoder(42, 43, "C58%03u", 10, 0, 10, 0, 100, 0); // Palanca de Mezcla Motor 1
    link2FS.addEncoder(47, 46, "C59%03u", 10, 0, 10, 0, 100, 0); // Palanca de Mezcla Motor 2
    link2FS.addEncoder(24, 23, "B32%05u", 0, 0, 500, 0, 50000, 0); // Altura de referencia Piloto automatico

    // Parámetros de addPinInFS:
    //   Pin de entrada
    //   Valor de la lectura del pin cuando está "activado"
    //   Indica si se utiliza la resistencia pull up interna o no (INPUT_PULLUP o INPUT)
    //   Cadena que hay que enviar si está "activado"
    //   Cadena que hay que enviar si está "desactivado"
    //   Inicio de la cadena que se recibe con el valor que confirma la recepción del dato
    //   Tiempo que espera antes de volve a comunicar el estado, si no recibe la cadena de "confirmación". Si es cero, no lo reenvía
    //   Indica si es con enclavamiento (con cada pulsación bascula el estado). Es opcional, por defecto es false (sin enclavamiento)
    //   Valor inicial si tiene activado el enclavamiento. ES opcional, por defecto es false ("inactivo")
    link2FS.addPinIn(31, LOW, INPUT_PULLUP, "C040", "C041", "<q", 2000); // Interruptor freno de estacionamiento
    link2FS.addPinIn(36, LOW, INPUT_PULLUP, "C02", "C01", "?Y", 2000); // Interruptor tren de aterrizaje
    link2FS.addPinIn(34, LOW, INPUT_PULLUP, "C14", NULL, NULL, 0); // Pulsador de flaps DOWN
    link2FS.addPinIn(35, LOW, INPUT_PULLUP, "C15", NULL, NULL, 0); // Pulsador de flaps UP

    // Parámetros de addMatrizIn:
    //   Fila de la matriz a la que está conetrado el pulsador (empieza en cero)
    //   Columna de la matriz a la que está conetrado el pulsador (empieza en cero)
    //   Cadena que hay que enviar cuanto se pulsa
    //   Cadena que hay que enviar cuando se libera
    //   Inicio de la cadena que se recibe con el valor que confirma la recepción del dato
    //   Tiempo que espera antes de volve a comunicar el estado, si no recibe la cadena de "confirmación". Si es cero, no lo reenvía
    // Primera fila de la matriz
    link2FS.addMatrizIn(0, 0, "B14", NULL, NULL, 0);
    link2FS.addMatrizIn(0, 1, "B08", NULL, NULL, 0);
/*    link2FS.addMatrizIn(0, 2, "H22", NULL, NULL, 0);
    link2FS.addMatrizIn(0, 3, "H20", NULL, NULL, 0);
    link2FS.addMatrizIn(0, 4, "H23", NULL, NULL, 0);
    link2FS.addMatrizIn(0, 5, "H21", NULL, NULL, 0);
    link2FS.addMatrizIn(0, 6, "G14", NULL, NULL, 0);
*/   
    // Segunda fila de la matriz
    link2FS.addMatrizIn(1, 0, "B13", NULL, NULL, 0);
    link2FS.addMatrizIn(1, 1, "B10", NULL, NULL, 0);
/*    link2FS.addMatrizIn(1, 2, "G18", NULL, NULL, 0);
    link2FS.addMatrizIn(1, 3, "G09", NULL, NULL, 0);
    link2FS.addMatrizIn(1, 4, "G13", NULL, NULL, 0);
    link2FS.addMatrizIn(1, 5, "G12", NULL, NULL, 0);
    link2FS.addMatrizIn(1, 6, "H01", NULL, NULL, 0);
*/ 
    // Tercera fila de la matriz
    link2FS.addMatrizIn(2, 0, "B05", NULL, NULL, 0);
    link2FS.addMatrizIn(2, 1, "B04", NULL, NULL, 0);
/*    link2FS.addMatrizIn(2, 2, "H17", NULL, NULL, 0);
    link2FS.addMatrizIn(2, 3, "H18", NULL, NULL, 0);
    link2FS.addMatrizIn(2, 4, "H19", NULL, NULL, 0);
    link2FS.addMatrizIn(2, 5, "H20", NULL, NULL, 0);
    link2FS.addMatrizIn(2, 6, "H21", NULL, NULL, 0);
*/
    // Cuarta fila de la matriz
    link2FS.addMatrizIn(3, 0, "B09", NULL, NULL, 0);
    link2FS.addMatrizIn(3, 1, "B01", NULL, NULL, 0);
 /*   link2FS.addMatrizIn(3, 2, "H22", NULL, NULL, 0);
    link2FS.addMatrizIn(3, 3, "H21", NULL, NULL, 0);
    link2FS.addMatrizIn(3, 4, "H20", NULL, NULL, 0);
    link2FS.addMatrizIn(3, 5, "H19", NULL, NULL, 0);
    link2FS.addMatrizIn(3, 6, "H18", NULL, NULL, 0);
*/


    // Parámetros de addPinOutFS:
    //   Pin de salida
    //   Valor de la salida del pin cuando está "activado"
    //   Modelo de la cadena que se recibe con el dato
    //   Valor numerico del dato para "activar" la salida
    link2FS.addPinOut(41, HIGH, "?Y#**", 2); // Led tren de aterrizaje nariz
    link2FS.addPinOut(40, HIGH, "?Y*#*", 2); // Led tren de aterrizaje izquierda
    link2FS.addPinOut(38, HIGH, "?Y**#", 2); // Led tren de aterrizaje derecha
    link2FS.addPinOut(32, HIGH, "<q", 1); // Led del freno de estacionamiento
    link2FS.addPinOut(33, LOW, "<G", 0); // Led de los flaps

    // Parámetros de addLcd:
    //   Modelo de la cadena que se recibe con el dato
    //   Columna del display en donde se muestra el dato
    //   Fila del display en donde se muestra el dato
    //   Formato en que se muestra el dato o cadena que se muestra cuando está activo
    //   Cadena que se muestra cuando no está activo. Por defecto es NULL, que significa que no se usa. Una cadena vacía ("") o con cualquier contenido: hace que se muestre cuando está desactivado
    //   Valor del dato para considerar que está "activo". No se usa si la cadena anterior es NULL. Por defecto es 1
    link2FS.addLcd(lcd, "=a", 0, 0, "AP", "");    // Piloto autotomático activo
    link2FS.addLcd(lcd, "=d", 3, 0, "HDG", "");   // Heading
    link2FS.addLcd(lcd, "=b", 7, 0, "ALT %05ld"); // Altura del piloto automático
    link2FS.addLcd(lcd, "=o", 0, 1, "NAV", "");   // Nav
    link2FS.addLcd(lcd, "=m", 4, 1, "APR", "");   // Aproach hold
    link2FS.addLcd(lcd, "=c", 8, 1, "VS %05ld"); // Velocidad vertical

}

void loop() {
    link2FS.loop(); // Se ha de realizar constantemente esta llamada para que se controle todo
}

El código nuevo funciona perfecto, los estuve probando hasta recien.. ( solo cambie el orden que aparece AP y HDG en la pantalla pero todo perfecto.

Una duda:
Aca lei 9 parámetros (7 anteriores + los dos nuevos de enclavamiento) pero sigue habiendo 7 en cada linea, si no estan significa desactivado y se puede agregar si se necesita?

    // Parámetros de addPinInFS:
    //   Pin de entrada
    //   Valor de la lectura del pin cuando está "activado"
    //   Indica si se utiliza la resistencia pull up interna o no (INPUT_PULLUP o INPUT)
    //   Cadena que hay que enviar si está "activado"
    //   Cadena que hay que enviar si está "desactivado"
    //   Inicio de la cadena que se recibe con el valor que confirma la recepción del dato
    //   Tiempo que espera antes de volve a comunicar el estado, si no recibe la cadena de "confirmación". Si es cero, no lo reenvía
    //   Indica si es con enclavamiento (con cada pulsación bascula el estado). Es opcional, por defecto es false (sin enclavamiento)
    //   Valor inicial si tiene activado el enclavamiento. ES opcional, por defecto es false ("inactivo")
    link2FS.addPinIn(31, LOW, INPUT_PULLUP, "C040", "C041", "<q", 2000); // Interruptor freno de estacionamiento

Ahora te respondo las dudas:
Sobre la matriz como veras la achique, por que por ahora solo ocupare 8 botones asi que no molesta con los pines del LCD.
Sobre el encoder de altura del GPS agregue la linea:

    link2FS.addEncoder(24, 23, "B32%05u", 0, 0, 500, 0, 50000, 0); // Altura de referencia Piloto automatico

y como veras tuve que jugar un rato con valores para que aplique a tu formula y a su vez cumpla mis requerimientos, jajaj :laughing: . Necesitaba poner un max y un min asi que le mande 0 y 50000 y al poner 500 de valor máximo del encoder sube de 100 en 100, asi que eso ya lo tengo resuelto

Al enviar el codigo B32xxxxx mando al simulador la altura deseada y al mismo tiempo el simulador me enviara devuelta esa cifra con el codigo =bxxxxx para actualizar el LCD.

por conectar varios arduinos no te preocupes que el mismo link2fs te permite administrar que información quieres enviar a cada arduino y de cualquiera que tengas conectado podes enviar los códigos de control. Esto esta bueno por que se podrían armar los "módulos" (radio, comandos de acelerador, GPS) por separado con Arduinos nano con un USB cada uno a la PC.
Hubiera sido mas simple para mi para evitar tanto cableado, y demas, peero $$$$$ jejej

Mira te iba a preguntar si se puede controlar el brillo, no manualmente con botones ni nada, si no en el mismo codigo por ejemplo bajarlo al %50 o algo pq es bien potente y molesto jaja

sobre el tema de tonos, el mismo simulador te hace los ruidos no seria necesario, preferiría reservar pines para funciones de entrada.

Saludos :smiley:

Efectivamente, si no lo necesitas no hace falta añadir ni el octavo, ni el noveno parámetro. Lo hice por si en algún momento se necesita que un pulsador funcione en modo "on/off". Con una pulsación lo activas, con otra lo desactivas y vuelta a empezar. Por ejemplo: si se quisiera gestionar el freno de estacionamiento con un pulsador de la matriz de pulsadores, como no se puede dejar todo el tiempo “pulsado”, lo configuramos con “enclavamiento”. De tal forma que se ha de pulsar para poner o quitar el freno. Como lo queremos configurar con enclavamiento, añadimos el parámetro true al final, después del parámetro de “tiempo de espera”. Esto sirve tanto para link2FS.addMatrizIn() como para ink2FS.addPinIn(). El siguiente parámetro simplemente es para indicar si queremos que, al arrancar el programa, empiece “activado” o “desactivado”. Por defecto es false (desactivado), con lo que inicialmente manda la cadena que indica que está “desactivado”. Si se quiere que inicialmente mande la cadena para cuando está “activado”, basta con poner ese parámetro a true, aunque también se podría intercambiar ambas cadenas (con lo que ese parámetro está de más, sólo es para que “quede bonito”).

Respecto a la altura del piloto automático: efectivamente, la idea era configurarlo como lo has hecho. Pero además, si quieres, puedes establecer un valor inicial distinto de cero. Si por ejemplo quieres que al encenderse el Arduino esté puesto a 25000, sustituye el primer cero por un 250. Recuerda que ese parámetro es el que establece el valor inicial de la “posición” del encoder. La línea de definición de la altura con un valor inicial de 25000 sería:

    link2FS.addEncoder(24, 23, "B32%05u", 250, 0, 500, 0, 50000, 0); // Altura de referencia Piloto automático

Respecto al “teclado matricial”, no sé si te has dado cuenta de que la forma en que más “pulsadores” se puede gestionar es asignando a las filas y a las columnas la mitad de las entradas disponibles (en el caso de ser impar, lógicamente, una de ellas tendría una más). En tu caso estás asignando un total de 6 pines, 4 para las filas y 2 para las columnas (realmente da igual el orden). Con esa distribución gestionas 8 pulsadores. Si lo hubieras distribuido 3 y 3, serían 9 los pulsadores que podrías tener.

No sé si ya no necesitas más funcionalidades. Aún así, tal vez le añada el control de servos. Podría usarse para la indicación de la posición de los flaps.

De la matriz y la distribución si lo tengo claro a eso, pasa que ahora tenia activas solo 2 columnas para probar el panel del piloto automático,( que por cierto esta terminado jaja) cuando arme el otro panel que agregare 5 encoders mas y 8 botones mas habilitare dos columnas mas y asi queda de 4 x 4 la matriz y tengo los 16 botones.


Los botones están detrás de las "teclas" grises asi parece mas realista :smiley:

Por lo que mi amigo quiere hasta acá estoy, peero he visto un video en youtube donde arman un horizonte artificial con servos y esta buena la idea jaja aca te dejo el link, utiliza 2 servos en este caso y se leen con los códigos:
<Q+xxxx o <Q-xxxx donde los valores van de -180 a +180 donde el 0 seria el centro con el avión nivelado
<R+xxxx o <R-xxxx con la misma descripción de el de arriba +/-180 con 0 en el centro nivelado.

Pregunta grande, suponiendo que alguien arme algo más grande y decida repartir en varios arduinos las funciones, este código funcionaria en un UNO, o NANO, o un DUE?

Si te parece con todo esta parte de controles completa y agregando extracciones quisiera mientras investigar para aplicar lo que te había consultado a el Arduino Leonardo para que asi, si alguien tiene otro simulador (el link2fs solo funciona en el Flight Simulator X que es viejisimo ) o si fuera para un juego se pueda aplicar tal vez usar los códigos del link to FS para controlar un código mas básico en un leonardo y este haga de joystick, ya escarbare y te cuento que encuentro.

Saludos

Hola de nuevo, @jhonny195 . Aquí tienes una nueva actualización de la “librería”. Ahora puede controlar los servos. Habría que actualizar los dos ficheros:

Link2FS.cpp (16.1 KB)
Link2FS.h (11.6 KB)

A modo de ejemplo de cómo utilizar el control de un servo con ink2FS.addServoFS(), añadir lo siguiente en el setup() :

    // Parámetros de addServoFS
    //   Pin PWM al que está conectado el servo
    //   Ángulo correspondiente al mínimo valor del dato recibido
    //   Ángulo correspondiente al máximo valor del dato recibido
    //   Modelo de la cadena que se recibe con el dato
    //   Valor mínimo del dato que se recibe
    //   Valor máximo del dato que se recibe
    link2FS.addServoFS(9, 10, 55, "<G", 0, 100);  // Ejemplo de indicador del ángulo de los flaps

En el ejemplo anterior, el servo se conecta al pin 9, los ángulos del servo van desde los 10° hasta los 55°. Se puede ponerlos al revés si es lo que nos viene mejor. La cadena con la que se manda el dato es ”<G”. Y he asumido que el valor es el porcentaje (de 0 a 100). Como siempre, se puede jugar con los parámetros para ajustarlo a las necesidades de cada uno.

En cuanto a pines de entrada y salida, tanto las entradas analógicas como las salidas PWM, se pueden utilizar como pines de entrada y/o salidas normales. Respecto a los PWM, hay que tener en cuenta que cada Arduino tiene limitada la cantidad máxima de pines que pueden trabajar a la vez como PWM.

En principio el programa, adaptando los pines, debería de servir para cualquier Arduino (UNO, NANO, DUE, Leonardo...), limitado sólo a la disposición y cantidad de pines que tiene cada uno. E insisto, independientemente de que se puede conectar varios Arduinos al link2fs, cabe la posibilidad de implementar que se utilice otro puerto serie del Arduino MEGA para que haga de pasarela entre el link2fs y otro Arduino. Y si este otro es otro MEGA, a este segundo se podría conectar un tercero.

Saludos.

Querido @IgnoranteAbsoluto como te eh dicho y no me canso, ESPECTACULAR!!!

Te cuento que probé el ultimo código y funciona perfecto, lo que si en el link2fs baje la velocidad de actualización de datos (que envía al Arduino) porque el servo se vuelve loco.
Pero si vi algo que tal vez lo armaste para probar y se te paso sacarlo jaja
llega esto por puerto serie también (lo encerrado en el rectángulo rojo:

Eso si, por conectar el servo tuve que agregar una fuente al Arduino por la caída de tensión que provoca el movimiento del servo.

Después en el LCD (esto ocurría ya antes de que agregues el servo) la indicación del ALT a veces se cambia sola ejemplos:
.- Si el simulador manda 2900, el LCD muestra 29000
.- A veces pone valores "raros" por ejemplo en ves de mostrar 2900 muestra 2904

El simulador no muestra la variación, parece como que el código interpreta mal el dato
Estas fallitas se acomodan a veces cuando vuelve a recibir el dato.

Cosa a parte, te interesa convertir esto al leonardo (no tendra extracciones creo) pero al menos hacer funcionar los comandos pero sin depender del link2fs, te lo pregunto con la intencion de abrir otro hilo con este codigo como base de proyecto para adaptarlo a la libreria del leonardo.

Aca estan las librerias base:
Joystick.cpp (6.7 KB)
Joystick.h (2.2 KB)

Este es el codigo basico que viene con las librerias esas.

// Simple example application that shows how to read four Arduino
// digital pins and map them to the USB Joystick library.
//
// The digital pins 9, 10, 11, and 12 are grounded when they are pressed.
//
// NOTE: This sketch file is for use with Arduino Leonardo and
//       Arduino Micro only.
//
// by Matthew Heironimus
// 2015-11-20
//--------------------------------------------------------------------

#include <Joystick.h>

void setup() {
  // Initialize Button Pins
  pinMode(9, INPUT_PULLUP);
  pinMode(10, INPUT_PULLUP);
  pinMode(11, INPUT_PULLUP);
  pinMode(12, INPUT_PULLUP);

  // Initialize Joystick Library
  Joystick.begin();
}

// Constant that maps the phyical pin to the joystick button.
const int pinToButtonMap = 9;

// Last state of the button
int lastButtonState[4] = {0,0,0,0};

void loop() {

  // Read pin values
  for (int index = 0; index < 4; index++)
  {
    int currentButtonState = !digitalRead(index + pinToButtonMap);
    if (currentButtonState != lastButtonState[index])
    {
      Joystick.setButton(index, currentButtonState);
      lastButtonState[index] = currentButtonState;
    }
  }

  delay(50);
}

Si te parece arrancarlo, tengo el hardware para testear lo que escribas :slight_smile:
Saludos :raised_hand_with_fingers_splayed:

Hola @jhonny195, te respondo a tus comentarios.

Efectivamente, me dejé atrás un par de líneas que puse para verificar el correcto funcionamiento del map() cuando se ponían ciertos valores. Lo he quitado en esta nueva versión.

Creo que tal vez eso se solucione con esta nueva versión. He añadido la posibilidad de un nuevo séptimo parámetro que indiqua cuánto tiempo ha de pasar entre cada grado que se incrementa o decrementa en la posición del servo. Tomo como ejemplo la línea que se ve en la captura que has puesto. En la que el servo ha de ir de 175 a 0 grados para valores de 0 a 100. Le añado un parámetro más con el valor 20. Esto significa que si el valor recibido pasa de 0 a 100, el servo no se mueve “a toda velocidad” de 175 grados a 0, sino que entre cada movimiento de grado a grado (175, 174, 173…) se espera 20 milisegundos. De esta forma, si al servo le llega “posiciones intermedias” consecutivas, no se posiciona “dando saltos” sino que “va a su paso”. Deberás jugar con ese valor de tiempo, para que vaya a una velocidad “razonable” y que resulte de tu agrado.

    // Parámetros de addServoFS
    //   Pin PWM al que está conectado el servo
    //   Ángulo correspondiente al mínimo valor del dato recibido
    //   Ángulo correspondiente al máximo valor del dato recibido
    //   Modelo de la cadena que se recibe con el dato
    //   Valor mínimo del dato que se recibe
    //   Valor máximo del dato que se recibe
    //   Tiempo de espera, en milisegundos, que ha de transcurrir entre cada cambio de grado en grado. Por defecto, si no se pone, es cero
    link2FS.addServoFS(9, 175, 0, "<G", 0, 100, 20);  // Ejemplo de indicador del ángulo de los flaps

Prueba a jugar con ese valor y a volver a subir la velocidad de actualización.

Nota: una vez arranca el Arduino, el servo se posiciona “sin pausa” en el primer valor que reciba. Para los siguientes valores sí que realiza la pausa entre grado y grado, al cambiar de posición.

Los ficheros actualizados con la nueva funcionalidad:

Link2FS.h (12.0 KB)
Link2FS.cpp (16.6 KB)

Respecto a esto que me dices del LCD, no sé qué puede estar pasando. Tal vez sea lo que dices; que el código que esté interpretando mal el dato, aunque me parece poco probable. También podría ser algún problema de “ruido” en la transmisión de los datos. Puede que del link2fs al Arduino o del Arduino al LCD (aunque esto último me parece muy poco probable). Por si fuera del link2fs al Arduino, tal vez desaparezca el problema probando a bajar la velocidad de transmisión de 115200 baudios a 57600, si lo permite el link2fs. Lo cierto es que es algo que me resulta muy extraño.

Ahora mismo no dispongo de un Leonardo. Voy a ver si logro hacerme con uno para poder hacer pruebas. Tendría que ver cómo funciona esa librería y no sé qué es lo que realmente se podría hacer con ella. Supongo que servirá para simular un joystick, indicando la posición de los ejes x e y del joystick y si están pulsado o no una serie de botones. Pero no sé si se puede hacer algo con los encoders. Tampoco sé si se puede extraer información del simulador. Necesitaría ayuda y consejo sobre todo esto del USB.

Respecto a abrir otro hilo para intentar algo con el USB del Leonardo, la verdad es que no sé qué sería lo más correcto, si abrir otro hilo o continuar con este. Tal vez @Surbyte nos podría orientar sobre ello.

@IgnoranteAbsoluto acabo de probar la modificación, y perfecto :smiley: el servo con esas pausas de 20 funciona muy bien, el movimiento es mas estable sin disparadas locas jaja.

Sobre esto, no se puede modificar el baud rate, pero bueno.
Lo que si vi y es problema del link2fs es que a veces aleatoriamente y a pesar de tener activado que envié los datos con line feed junta 2 o 3 datos en una misma línea pero bueno eso escapa a nuestras manos jeje.

@jhonny195 olvida lo de modificar el baud rate. El problema es justo lo que comentas, que a veces el link2fs manda los datos en una misma línea. Cuando hace eso, el programa del Arduino “lee algún número de más”. Y no, no escapa a nuestras manos. Tan solo hay que tener en cuenta que además de el “salto de línea” hay que tener en cuenta los caracteres =, <, ? y / para que “finalice” la cadena si ya se había leído algo. Además de “guardar” ese carácter para la próxima cadena. Aquí tienes los dos ficheros con la modificación de la clase LectorLineas para que tenga todo esto en cuenta y solucione el problema de fallos en la lectura cuando el lin2fs lo manda todo junto.

Link2FS.cpp (17.1 KB)
Link2FS.h (12.0 KB)

Hola de nuevo @IgnoranteAbsoluto estuve ausente porque estaba en mis pagos trabajando en el taller jeje, recién termino de armar la segunda placa de enconders y paso algo raro.
Nueva placa :smiley: :smiley:


Aca una foto del problema abajo te lo detallo:

Como veras en la imagen el encoder E3 subiendo valores imprime los valores en el puerto serie, pero bajándolos se nota que internamente los baja pero no lo muestra en el puerto serie, de esto me di cuenta por que al aumentar el valor nuevamente se nota que el valor bajo. Otra aclaración sobre esto es que los cables correspondientes a ese encoder corresponden al pin 0 (Rx0) y pin 1 (Tx0) del MEGA, puede ser esto el problema? el pin 0 se define como 0, o se pone otro nombre?

Te agrego: De esta falla al conectar al link2fs para testear las demas cosas cuando giro ese encoder me dice: "No Linefeed from Card1 or Card1 buffer flooded. Receive Buffer Emptied."

Otra consulta, te acordas que los encoders tienen una formula que multiplica x10 los valores (por los encoders con movimiento limitado de las palancas yo lo había hecho así) habrá posibilidad de insertar ese parámetro de "multiplicador" en la linea de los encoders? así cuando tengo cosas como frecuencias de radio que saltan de 5 en 5 o parámetros como el rumbo que va de 0 a 360 puedo acomodar fácilmente el valor que se envía.
Algo asi:

   // Parámetros de addEncoder
    //   Pin al que está conectado el CLK
    //   Pin al que está conectado el DT
    //   Formato de la cadena que hay que enviar al simulador (la que se utiliza en el priftf)
    //   Valor inicial del encoder (1 o 9 en el código original)
    //   Valor mínimo del encoder (0 en el código original)
    //   Valor máximo del encoder (10 en el código original). Si este parámetro y el anterior se ponen a cero, se auto ajusta en el momento del calibrado.
    //   Valor mínimo que envía al simulador (0 en el código original)
    //   Valor máximo que envía al simulador (99 en el código original, 100 en este código)
    // Multiplicador
   //   Tiempo, en milisegundos, que ha de transcurrir desde el último movimiento de calibrado para que se de por terminada la calibración. En este caso se indica cero porque ya los límites están definido (de 0 a 10)
    link2FS.addEncoder(48, 49, "C56%03u", 0, 0, 10, 0, 100, 5, 0); // Palanca de Gases Motor 1

ahí justamente el multiplicador seria x 5

Saludos

@IgnoranteAbsoluto te tengo otra consulta jeje, tengo uno de los encoders, que en vez de imprimir una cadena mas un valor numérico, cuando incremento tiene que mandar H10 (en cada paso del encoder lo envía) y si giro hacia el otro lado envía H11 en casa paso. Digamos que cada paso del encoder seria como presionar un botón.

Quise jugar con el renglón normal que armaste:

link2FS.addEncoder(17, 16, "H1%1u", , 0, 10, 0, 1, 0); // G1000 PDF group knob

pero no pude hacerlo funcionar como quiero :confused:

saludos

Sí, ese es el problema, @jhonny195. Esos dos pines están asociados al puerto serie del MEGA con el que se está comunicando con el link2fs (Serial). Si tratas de utilizar esos pines para otra cosa, no logras más que problemas. Lo que pongas interfiere en la comunicación serie y la comunicación serie interfiere en lo que pongas. Has de usar otros pines. Recuerda que los pines analógicos se pueden usar como un pin “normal”.

Para configurar el encoder para “saltos” de 5 en 5 en un rango determinado, lo que has de poner es, por un lado, el valor mínimo y el máximo que se envía al simulador. Mientras que, por otro lado, para el valor mínimo del encoder pones cero y para el valor máximo del encoder pones el valor que resulte de dividir por el “paso” la diferencia entre el valor mínimo y el máximo que envía al simulador.

Por ejemplo, si quieres que el valor a enviar al simulador esté entre 800 y 995; y el paso sea de 5 en 5: los valores para el encoder son 0 y (995 - 800) / 5. Es decir, 0 y 39.

Y si quieres que inicialmente valga 900 entonces el valor inicial del encoder ha de ser (900 - 800) / 5 = 20. La línea que lo configuraría sería algo así:

    link2FS.addEncoder(48, 49, "C56%03u", 20, 0, 39, 800, 995, 0);

De esta forma, no hace falta ningún parámetro para indicar el valor de incremento/decremento. Fíjate que eso es parecido a lo que se hizo para la altura del piloto automático. Que va de 0 a 50000 de 100 en 100. Los valores para el encoder son 0 y (50000 - 0) / 100 = 500.


Respecto al rumbo, que dices que va de 0 a 360: ¿realmente es así? ¿O quieres que sea “circular”? Es decir, que si va de 5 en 5, los valores sean de 0 a 355 y cuando esté en 355 y se incremente, pase a valer 0. Mientra que si está a 0 y se decrementa, pasa a valer 355. De tal manera que no se para ni en el límite inferior (cero) ni en el límite superior (355), sino que continúa pasando de 355 a cero o de cero a 355. Si es así, he modificado la librería para que se pueda configurar este comportamiento. Para ello se añade un décimo parámetro opcional. Para este comportamiento, el valor de este parámetro ha de ser ENCODER_CIRCULAR. Teniendo en cuenta todo esto, calculamos el valor máximo del encoder: (355 - 0) / 5 = 71. Así que la línea para configurar ese encoder sería algo así como:

    link2FS.addEncoder(48, 49, "XX%3u", 0, 0, 71, 0, 355, 0, ENCODER_CIRCULAR);

Como no has dicho cómo es el formato de lo que ha de enviar, yo lo he encabezado con XX. Ya, si eso, lo ajustas a los pines y valores correctos. Por cierto, si “funciona al revés”, si incrementa cuando deber decrementar y viceversa, basta con intercambiar los dos pines a los que está conectado o intercambiar una de las parejas de mínimo y máximo. Pero intercambia sólo una cosa, porque dos intercambios hace que funcione igual.

Respecto a esto, tal como estaba la librería no se podía configurar. Porque desde el principio, en el caso de sobrepasar los límites, no se envía repetidamente el valor límite. Sólo se envía una vez, cuando se alcanza el límite. Así que he aprovechado el nuevo parámetro y tiene otro posible valor: ENCODER_REPETITIVO_SIN_INICIAL. Esto le indica que, si se trata de superar el límite, ha de enviar el valor límite una y otra vez. Además de que no ha de mandar el valor al encender el Arduino. Esto último es para que no mande nada hasta que se mueva el encoder, para que "no se mueva" al "arrancar". Así que con esto ya podemos hacer lo que querías. Tan sólo hay que configurar que envíe valores entre cero y uno para los valores cero y uno del encoder. Sería algo tal que así:

    //   Comportamiento en los límites del encoder. Parámetro opcional. Valores posibles: ENCODER_LIMITADO (valor por defecto), ENCODER_REPETITIVO (si trata de sobrepasar el límite, enviá de nuevo el valor límite). ENCODER_CIRCULAR (si sobrepasa el máximo pasa al mínimo y viceversa)
    link2FS.addEncoder(17, 16, "H1%u", 0, 0, 1, 0, 1, 0, ENCODER_REPETITIVO_SIN_INICIAL);

Los otros posibles valores para el nuevo campo son: ENCODER_LIMITADO que es el comportamiento que tiene por defecto, siendo el único comportamiento que había hasta ahora, que no repite el valor límite. ENCODER_REPETITIVO que envía el valor límite cada vez que se intenta sobrepasar.

Los dos ficheros actualizados con el soporte del nuevo parámetro:
Link2FS.h (13.0 KB)
Link2FS.cpp (18.0 KB)

Sensacional querido @IgnoranteAbsoluto, funciona todo perfecto.

La función esa de encoder circular la necesitaba pero no te lo quería pedir para no molestarte tanto. jaja

Si me di cuenta horas después que te mande la consulta, haciendo otras pruebas, caí en la forma de operar que tiene, así que disculpa.

por los encoders para el rumbo, va de 0 a 359 y de uno en uno, no te preocupes ya lo entendí y lo configure jaja, así quedo:

    link2FS.addEncoder(2, 3, "A59%03u", 0, 0, 359, 0, 359, 0, ENCODER_CIRCULAR);

Aca dejo el codigo completo como me quedo a mi, conectado todo, funcionando:

#include "Link2FS.h" // "Librería que se encarga de todo con link2FS
#include <LCD_I2C.h>
#include <Wire.h>

// Definición de los pines que forman las filas de la matriz de pulsadores
const byte PINES_FILAS[] = {25, 26, 27, 28};
// Definición de los pines que forman las columnas de la matriz de pulsadores
const byte PINES_COLUMNAS[] = { 19, 18, 29, 30};
// El número de pines de las filas se calcula automáticamente en la siguiente línea (no hay que modificarla nunca)
const byte NUMERO_FILAS = sizeof(PINES_FILAS) / sizeof(PINES_FILAS[0]);
// El número de pines de las columnas se calcula automáticamente en la siguiente línea (no hay que modificarla nunca)
const byte NUMERO_COLUMNAS = sizeof(PINES_COLUMNAS) / sizeof(PINES_COLUMNAS[0]);

Link2FS link2FS(Serial, PINES_FILAS, PINES_COLUMNAS, NUMERO_FILAS, NUMERO_COLUMNAS); // Objeto que se encarga de todo con link2FS. Se le indicua cual es el puerto serie al que está conectado, los pines de la filas de la matriz, los pines de las columnas de la matriz, número de filas, número de columnas

LCD_I2C lcd(0x27);


void setup() {
    Serial.begin(115200);

    lcd.begin();
    lcd.backlight();
    lcd.noCursor();
    lcd.clear();

    // Parámetros de addEncoder
    //   Pin al que está conectado el CLK
    //   Pin al que está conectado el DT
    //   Formato de la cadena que hay que enviar al simulador (la que se utiliza en el sprintf)
    //   Valor inicial del encoder. 
    //   Valor mínimo del encoder.
    //   Valor máximo del encoder. Si este parámetro y el anterior se ponen a cero, se auto ajusta en el momento del calibrado.
    //   Valor mínimo que envía al simulador
    //   Valor máximo que envía al simulador (99 en el código original, 100 en este código)
    //   Tiempo, en milisegundos, que ha de trasncurrir desde el último movimiento de calibrado para que se de por teminada la calibración. En este caso se indica cero porque ya los límites están definido (de 0 a 10)
    //   Comportamiento en los límites del encoder. Parámetro opcional. Valores posibles abajo:
    //   ENCODER_LIMITADO (valor por defecto). 
    //   ENCODER_REPETITIVO (si trata de sobrepasar el límite, enviá de nuevo el valor límite).
    //   ENCODER_CIRCULAR (si sobrepasa el máximo pasa al mínimo y viceversa)
    //   ENCODER_REPETITIVO_SIN_INICIAL (Si se trata de superar el límite, envia valor límite una y otra vez).
   
    link2FS.addEncoder(48, 49, "C56%03u", 0, 0, 10, 0, 100, 0, ENCODER_LIMITADO); // Palanca de Gases Motor 1
    link2FS.addEncoder(52, 53, "C57%03u", 0, 0, 10, 0, 100, 0, ENCODER_LIMITADO); // Palanca de Gases Motor 2
    link2FS.addEncoder(50, 51, "C60%03u", 10, 0, 10, 0, 100, 0, ENCODER_LIMITADO); // Paso de Helice Motor 1
    link2FS.addEncoder(45, 44, "C61%03u", 10, 0, 10, 0, 100, 0, ENCODER_LIMITADO); // Paso de Helice Motor 2
    link2FS.addEncoder(42, 43, "C58%03u", 10, 0, 10, 0, 100, 0, ENCODER_LIMITADO); // Palanca de Mezcla Motor 1
    link2FS.addEncoder(47, 46, "C59%03u", 10, 0, 10, 0, 100, 0, ENCODER_LIMITADO); // Palanca de Mezcla Motor 2
    link2FS.addEncoder(23, 24, "B32%05u", 0, 0, 500, 0, 50000, 0, ENCODER_LIMITADO); // Altura de referencia Piloto automatico
    link2FS.addEncoder(16, 17, "H1%01u", 0, 2, 3, 2, 3, 0, ENCODER_REPETITIVO_SIN_INICIAL); // G1000 PDF group knob
    link2FS.addEncoder(15, 14, "B33%03u", 0, 0, 359, 0, 359, 0, ENCODER_CIRCULAR); // OBS/ ¿VOR?
    link2FS.addEncoder(2, 3, "A59%03u", 0, 0, 359, 0, 359, 0, ENCODER_CIRCULAR); // HEADING
    link2FS.addEncoder(4, 5, "A17%03u", 97, 0, 195, 800, 1775, 0, ENCODER_LIMITADO); // NAV1
    link2FS.addEncoder(6, 7, "A0%01u", 3, 3, 4, 3, 4, 0, ENCODER_REPETITIVO_SIN_INICIAL); // COM1

    // Parámetros de addPinInFS:
    //   Pin de entrada
    //   Valor de la lectura del pin cuando está "activado"
    //   Indica si se utiliza la resistencia pull up interna o no (INPUT_PULLUP o INPUT)
    //   Cadena que hay que enviar si está "activado"
    //   Cadena que hay que enviar si está "desactivado"
    //   Inicio de la cadena que se recibe con el valor que confirma la recepción del dato
    //   Tiempo que espera antes de volve a comunicar el estado, si no recibe la cadena de "confirmación". Si es cero, no lo reenvía
    //   Indica si es con enclavamiento (con cada pulsación bascula el estado). Es opcional, por defecto es false (sin enclavamiento)
    //   Valor inicial si tiene activado el enclavamiento. ES opcional, por defecto es false ("inactivo")
    link2FS.addPinIn(31, LOW, INPUT_PULLUP, "C040", "C041", "<q", 2000); // Interruptor freno de estacionamiento
    link2FS.addPinIn(36, LOW, INPUT_PULLUP, "C02", "C01", "?Y", 2000); // Interruptor tren de aterrizaje
    link2FS.addPinIn(34, LOW, INPUT_PULLUP, "C14", NULL, NULL, 0); // Pulsador de flaps DOWN
    link2FS.addPinIn(35, LOW, INPUT_PULLUP, "C15", NULL, NULL, 0); // Pulsador de flaps UP

    // Parámetros de addMatrizIn:
    //   Fila de la matriz a la que está conetrado el pulsador (empieza en cero)
    //   Columna de la matriz a la que está conetrado el pulsador (empieza en cero)
    //   Cadena que hay que enviar cuanto se pulsa
    //   Cadena que hay que enviar cuando se libera
    //   Inicio de la cadena que se recibe con el valor que confirma la recepción del dato
    //   Tiempo que espera antes de volve a comunicar el estado, si no recibe la cadena de "confirmación". Si es cero, no lo reenvía
    // Primera fila de la matriz
    link2FS.addMatrizIn(0, 0, "A06", NULL, NULL, 0);
    link2FS.addMatrizIn(0, 1, "A18", NULL, NULL, 0);
    link2FS.addMatrizIn(0, 2, "B01", NULL, NULL, 0);
    link2FS.addMatrizIn(0, 3, "B09", NULL, NULL, 0);
/*    link2FS.addMatrizIn(0, 4, "H23", NULL, NULL, 0);
    link2FS.addMatrizIn(0, 5, "H21", NULL, NULL, 0);
    link2FS.addMatrizIn(0, 6, "G14", NULL, NULL, 0);
*/   
    // Segunda fila de la matriz
    link2FS.addMatrizIn(1, 0, "H08", NULL, NULL, 0);
    link2FS.addMatrizIn(1, 1, "H10", NULL, NULL, 0);
    link2FS.addMatrizIn(1, 2, "B04", NULL, NULL, 0);
    link2FS.addMatrizIn(1, 3, "B05", NULL, NULL, 0);
/*    link2FS.addMatrizIn(1, 4, "G13", NULL, NULL, 0);
    link2FS.addMatrizIn(1, 5, "G12", NULL, NULL, 0);
    link2FS.addMatrizIn(1, 6, "H01", NULL, NULL, 0);
*/ 
    // Tercera fila de la matriz
    link2FS.addMatrizIn(2, 0, "H07", NULL, NULL, 0);
    link2FS.addMatrizIn(2, 1, "H11", NULL, NULL, 0);
    link2FS.addMatrizIn(2, 2, "B10", NULL, NULL, 0);
    link2FS.addMatrizIn(2, 3, "B13", NULL, NULL, 0);
/*    link2FS.addMatrizIn(2, 4, "H19", NULL, NULL, 0);
    link2FS.addMatrizIn(2, 5, "H20", NULL, NULL, 0);
    link2FS.addMatrizIn(2, 6, "H21", NULL, NULL, 0);
*/
    // Cuarta fila de la matriz
    link2FS.addMatrizIn(3, 0, "d1", NULL, NULL, 0);
    link2FS.addMatrizIn(3, 1, "H19", NULL, NULL, 0);
    link2FS.addMatrizIn(3, 2, "B08", NULL, NULL, 0);
    link2FS.addMatrizIn(3, 3, "B14", NULL, NULL, 0);
/*    link2FS.addMatrizIn(3, 4, "H20", NULL, NULL, 0);
    link2FS.addMatrizIn(3, 5, "H19", NULL, NULL, 0);
    link2FS.addMatrizIn(3, 6, "H18", NULL, NULL, 0);
*/


    // Parámetros de addPinOutFS:
    //   Pin de salida
    //   Valor de la salida del pin cuando está "activado"
    //   Modelo de la cadena que se recibe con el dato
    //   Valor numerico del dato para "activar" la salida
    link2FS.addPinOut(41, HIGH, "?Y#**", 2); // Led tren de aterrizaje nariz
    link2FS.addPinOut(40, HIGH, "?Y*#*", 2); // Led tren de aterrizaje izquierda
    link2FS.addPinOut(38, HIGH, "?Y**#", 2); // Led tren de aterrizaje derecha
    link2FS.addPinOut(32, HIGH, "<q", 1); // Led del freno de estacionamiento
    link2FS.addPinOut(33, LOW, "<G", 0); // Led de los flaps

    // Parámetros de addLcd:
    //   Modelo de la cadena que se recibe con el dato
    //   Columna del display en donde se muestra el dato
    //   Fila del display en donde se muestra el dato
    //   Formato en que se muestra el dato o cadena que se muestra cuando está activo
    //   Cadena que se muestra cuando no está activo. Por defecto es NULL, que significa que no se usa. Una cadena vacía ("") o con cualquier contenido: hace que se muestre cuando está desactivado
    //   Valor del dato para considerar que está "activo". No se usa si la cadena anterior es NULL. Por defecto es 1
    link2FS.addLcd(lcd, "=a", 0, 0, "AP", "");    // Piloto autotomático activo
    link2FS.addLcd(lcd, "=j", 3, 0, "HDG", "");   // Heading
    link2FS.addLcd(lcd, "=b", 7, 0, "ALT %05ld"); // Altura del piloto automático
    link2FS.addLcd(lcd, "=o", 0, 1, "NAV", "");   // Nav
    link2FS.addLcd(lcd, "=m", 4, 1, "APR", "");   // Aproach hold
    link2FS.addLcd(lcd, "=c", 8, 1, "VS %05ld"); // Velocidad vertical

// Parámetros de addServoFS
    //   Pin PWM al que está conectado el servo
    //   Ángulo correspondiente al mínimo valor del dato recibido
    //   Ángulo correspondiente al máximo valor del dato recibido
    //   Modelo de la cadena que se recibe con el dato
    //   Valor mínimo del dato que se recibe
    //   Valor máximo del dato que se recibe
//    link2FS.addServoFS(9, 175, 10, "<R", -180, +180, 20);  // Ejemplo de indicador del ángulo de los flaps

}

void loop() {
    link2FS.loop(); // Se ha de realizar constantemente esta llamada para que se controle todo
}

Muchas gracias @IgnoranteAbsoluto por el trabajo que haz hecho.