Empieza por un resultado que puedas comprobar
Imagina un pequeño panel junto al volante o los mandos de vuelo. Cuatro luces indican estados y un OLED muestra velocidad, revoluciones y combustible. Para empezar, los números proceden del monitor serie del IDE de Arduino. Así no necesitas ejecutar un simulador y puedes provocar cada respuesta de forma controlada.
El requisito es controlar cada LED por separado y mostrar los valores recibidos. La tarea del programa es validar mensajes completos, aceptar todos sus campos juntos y señalar cuándo los datos han caducado. El resultado será un módulo comprensible para seguir aprendiendo, no una integración automática con cualquier simulador.
La IA puede explicar conexiones, proponer código e interpretar errores. Tú decides qué debe suceder, cuándo y cómo reconocerás el éxito. Puedes responder a esas preguntas aunque todavía no sepas qué es una variable. Pide que cada concepto nuevo se explique usando la parte del montaje que estás probando.
Componentes concretos para este montaje
Necesitas un Arduino Uno R3, cable USB de datos, protoboard, cables, cuatro LED indicadores rojos normales y cuatro resistencias individuales de 1 kΩ, de al menos 0,125 W. El OLED elegido es exactamente Adafruit 4440: SSD1306, 128 × 32 píxeles, I²C en 0x3C y reinicio automático. Utiliza un cable adaptador STEMMA QT o pines correctamente soldados.
El fabricante admite lógica de 5 V en este modelo. Eso no autoriza a conectar cualquier OLED parecido: comprueba controlador, orden de pines, alimentación y niveles de señal. Una pantalla SH1106 o una placa antigua con cable de reset necesita cambios. Identifica el producto antes de darle alimentación.
El Uno R3 basta para esta pequeña pantalla de texto. Su memoria limitada aconseja mantener el primer ejercicio sencillo. La comparación de microcontroladores ayuda a elegir cuando quieras más gráficos, dispositivos o capacidad de procesamiento.
Conecta los cuatro LED y el OLED
Desconecta el USB antes de montar o mover cables. Une primero las masas y añade cada función por separado. Cada LED lleva su propia resistencia; compartir una entre los cuatro no es correcto. El ánodo suele ser la patilla larga y el lado plano del encapsulado identifica el cátodo. Si las patillas están cortadas, comprueba la documentación.
Con una caída aproximada de 2 V en un LED rojo, 5 V y 1 kΩ dan unos 3 mA. Esa corriente moderada es apropiada para el ensayo de mesa. No utilices este esquema para tiras LED, iluminación potente o fuentes externas. Consulta iluminación LED antes de ampliar las salidas.
| Componente / señal | Conexión | Comprobación |
|---|---|---|
| LED 1 | D2 → 1 kΩ → ánodo; cátodo → GND | Una resistencia por LED |
| LED 2 | D3 → 1 kΩ → ánodo; cátodo → GND | Nunca directamente a D3 |
| LED 3 | D4 → 1 kΩ → ánodo; cátodo → GND | Revisar polaridad |
| LED 4 | D5 → 1 kΩ → ánodo; cátodo → GND | Revisar polaridad |
| OLED VIN | Uno 5V | Solo el módulo indicado |
| OLED GND | Uno GND | Masa común |
| OLED SDA | Uno A4 / SDA | Es la misma señal |
| OLED SCL | Uno A5 / SCL | Es la misma señal |
| OLED RST | Sin conectar | 4440 tiene reinicio automático |
Define primero el significado de los datos
El formato de aprendizaje es V1,velocidad,rpm,combustible,máscara, terminado con salto de línea LF, a 115200 baudios. Solo se admiten enteros no negativos: velocidad 0–999, rpm 0–20000, combustible 0–100 y máscara 0–15. No añadas unidades, espacios ni decimales. Envía como máximo cinco mensajes completos por segundo.
La máscara suma los valores de cada luz: LED 1 vale 1, LED 2 vale 2, LED 3 vale 4 y LED 4 vale 8. Un 5 enciende los LED 1 y 3; 15 enciende todos y 0 los apaga. Los dígitos del OLED están ordenados de LED 1 a LED 4, de izquierda a derecha: 1010 indica LED 1 y 3 encendidos.
Al arrancar aparece WAIT. Un mensaje válido obtiene OK por serie y muestra DATA. Uno inválido obtiene ERR sin modificar parcialmente los valores anteriores. Tras tres segundos sin datos válidos se apagan los LED y aparece STALE; las últimas cifras permanecen visibles como datos antiguos. Este comportamiento debe formar parte del encargo desde el principio.
Aquí S representa velocidad en km/h, R revoluciones por minuto y F porcentaje de combustible. El sketch muestra los números sin convertirlos; cualquier conversión posterior corresponde al emisor. Los bits LED son indicadores de prueba, sin función fija en un simulador.
Un prompt completo para pedir ayuda a la IA
Un buen prompt de Arduino indica hardware, datos y comportamiento observable. Adjunta enlaces del fabricante y la identificación exacta de tus piezas. Pide primero la lista de conexiones y las dudas pendientes. Si tus componentes son diferentes, acláralo antes de aceptar un esquema generado. Este encargo sirve como punto de partida:
Ayúdame a construir un módulo de cabina para aprender. Soy principiante: explica los pasos y no inventes pines ni interfaces de simuladores.
Hardware: Arduino Uno R3; cuatro LED rojos en D2,D3,D4,D5, cada uno mediante 1 kOhm, cátodos a GND. OLED Adafruit 4440, SSD1306 128x32 I2C 0x3C; VIN=5V, GND=GND, SDA=A4, SCL=A5, reinicio automático sin cable RST.
Tarea: entregar un sketch completo con Wire, Adafruit GFX y Adafruit SSD1306. Recibir mis mensajes de prueba USB-serie a 115200 baudios, máximo 5 líneas/s: V1,speed,rpm,fuel,flags y LF; admitir CRLF. Rangos: speed 0..999, rpm 0..20000, fuel 0..100, flags 0..15. Los valores 1,2,4,8 seleccionan LED1..4.
Resultado: cuatro líneas de texto con valores y estados. Inicio WAIT; mensaje válido DATA/OK; inválido ERR sin actualización parcial. Tras 3000 ms sin datos válidos, apagar LED y mostrar STALE conservando las últimas cifras.
Límites: búfer fijo de 64 bytes; descartar líneas demasiado largas hasta LF; sin objetos String dinámicos ni delay en loop; actualizar pantalla como máximo cada 200 ms. Contabilizar SRAM y los 512 bytes del búfer OLED. Explicar fallos de conexión y memoria.
Incluye conexiones, código completo, bibliotecas y pruebas de cada LED, todos juntos, valores incorrectos, exceso de longitud y corte de datos. Separa compilación y prueba física.
Prepara y carga el programa
En el IDE selecciona “Arduino Uno” y su puerto. Instala Adafruit SSD1306 y Adafruit GFX Library mediante el gestor de bibliotecas, incluida Adafruit BusIO. Wire pertenece al paquete AVR. Abre el archivo descargado dentro de una carpeta llamada uno-led-oled, compílalo primero y después cárgalo en tu placa.
El código completo puede desplegarse y descargarse aquí. La lógica procesa la entrada por pasos sin esperar con delay() y actualiza el OLED como máximo cinco veces por segundo. La transferencia I²C sigue consumiendo tiempo; esto no garantiza tiempo real estricto. Los cables largos y otros dispositivos del bus requieren pruebas adicionales.
El búfer de pantalla reserva 512 bytes además de variables, búferes y pila. La cifra de RAM estática del IDE no incluye toda esa reserva en ejecución. F() conserva textos constantes en flash y no se utilizan objetos Arduino String. Compilar correctamente no demuestra que el circuito esté bien conectado o que la pantalla funcione.
El sketch se compiló localmente para arduino:avr:uno con AVR 1.8.7, Adafruit SSD1306 2.5.9, GFX 1.11.9 y BusIO 1.15.0: 15.168 bytes de flash y 614 bytes de RAM estática, más los 512 bytes del búfer de pantalla. Aquí no se probó un montaje físico.
Descargar el sketch completo de Arduino
Mostrar el código completo del ejemplo
// Cockpit Suite workshop learning example. This is not a simulator protocol.
// Board: Arduino Uno R3. OLED: Adafruit 4440, SSD1306 128x32, I2C 0x3C.
// OLED VIN=5V, GND=GND, SDA=A4, SCL=A5; auto-reset, no reset wire.
// LEDs: D2/D3/D4/D5 -> individual 1k resistor -> anode; cathodes -> GND.
// Send at most 5 lines/second: V1,speed,rpm,fuel,flags followed by LF.
// Example: V1,120,3500,65,5 (LED1 and LED3 on). CR before LF is accepted.
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <string.h>
const uint8_t LED_PINS[4] = {2, 3, 4, 5};
const uint8_t OLED_ADDRESS = 0x3C;
const uint32_t DATA_TIMEOUT_MS = 3000;
const uint32_t SCREEN_INTERVAL_MS = 200;
Adafruit_SSD1306 display(128, 32, &Wire, -1);
char lineBuffer[64];
uint8_t lineLength = 0;
bool discardLine = false;
bool haveData = false;
bool oledReady = false;
uint16_t speedValue = 0, rpmValue = 0, fuelValue = 0, flagValue = 0;
uint32_t lastDataMs = 0, lastScreenMs = 0;
bool parseNumber(const char *&cursor, uint16_t limit, char separator,
uint16_t &result) {
if (*cursor < '0' || *cursor > '9') return false;
uint16_t value = 0;
while (*cursor >= '0' && *cursor <= '9') {
uint8_t digit = *cursor++ - '0';
if (value > limit / 10 ||
(value == limit / 10 && digit > limit % 10)) return false;
value = value * 10 + digit;
}
if (*cursor != separator) return false;
if (separator != '\0') ++cursor;
result = value;
return true;
}
bool parseLine(const char *line) {
if (strncmp(line, "V1,", 3) != 0) return false;
const char *cursor = line + 3;
uint16_t speed, rpm, fuel, flags;
if (!parseNumber(cursor, 999, ',', speed) ||
!parseNumber(cursor, 20000, ',', rpm) ||
!parseNumber(cursor, 100, ',', fuel) ||
!parseNumber(cursor, 15, '\0', flags)) return false;
speedValue = speed;
rpmValue = rpm;
fuelValue = fuel;
flagValue = flags;
lastDataMs = millis();
haveData = true;
return true;
}
void readSerial() {
// Bound each pass so a continuous stream cannot starve the outputs.
for (uint8_t count = 0; count < 32 && Serial.available(); ++count) {
char character = (char)Serial.read();
if (character == '\r') continue;
if (character == '\n') {
lineBuffer[lineLength] = '\0';
if (!discardLine && parseLine(lineBuffer)) Serial.println(F("OK"));
else Serial.println(F("ERR"));
lineLength = 0;
discardLine = false;
} else if (!discardLine) {
// NUL and non-printable input are not part of this text protocol.
if (character < 32 || character > 126 ||
lineLength >= sizeof(lineBuffer) - 1) {
discardLine = true;
} else {
lineBuffer[lineLength++] = character;
}
}
}
}
void renderScreen(bool fresh) {
display.clearDisplay();
display.setCursor(0, 0);
display.print(F("S:")); display.print(speedValue);
display.print(F(" R:")); display.println(rpmValue);
display.print(F("F:")); display.print(fuelValue);
display.print(F("% LED:"));
for (uint8_t index = 0; index < 4; ++index)
display.print(fresh && (flagValue & (1U << index)) ? '1' : '0');
display.println();
display.println(!haveData ? F("WAIT") : (fresh ? F("DATA") : F("STALE")));
display.print(F("DEMO SERIAL"));
display.display();
}
void setup() {
for (uint8_t index = 0; index < 4; ++index) {
digitalWrite(LED_PINS[index], LOW);
pinMode(LED_PINS[index], OUTPUT);
}
Serial.begin(115200);
Wire.begin();
#if defined(WIRE_HAS_TIMEOUT)
Wire.setWireTimeout(25000, true);
#endif
Wire.beginTransmission(OLED_ADDRESS);
bool addressResponds = (Wire.endTransmission() == 0);
oledReady = addressResponds &&
display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDRESS, false, false);
if (oledReady) {
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setTextWrap(false);
renderScreen(false);
} else {
Serial.println(F("OLED ERROR: check model, wiring, address, RAM"));
}
Serial.println(F("READY: V1,speed,rpm,fuel,flags"));
}
void loop() {
readSerial();
uint32_t now = millis();
bool fresh = haveData && (uint32_t)(now - lastDataMs) < DATA_TIMEOUT_MS;
for (uint8_t index = 0; index < 4; ++index)
digitalWrite(LED_PINS[index],
fresh && (flagValue & (1U << index)) ? HIGH : LOW);
if (oledReady && (uint32_t)(now - lastScreenMs) >= SCREEN_INTERVAL_MS) {
lastScreenMs = now;
renderScreen(fresh);
}
}
Comprueba el resultado con mensajes concretos
Después de cargarlo, ajusta el monitor serie a 115200 baudios y “Nueva línea” o “NL & CR”. Abrir el puerto puede reiniciar el Uno: espera READY. Inicialmente debe aparecer WAIT y todos los LED deben estar apagados.
Envía V1,120,3500,65,1: solo debe encenderse LED 1. Cambia el último valor por 2, 4 y 8 para comprobar cada salida. Con V1,120,3500,65,15 deben encenderse todos; con 0, ninguno. Compara las cifras del OLED con el mensaje. Prueba también V1,999,20000,100,15 y V1,0,0,0,0.
Introduce V1,120,3500,101,5 o elimina un campo: debe responder ERR sin cambios parciales. Una línea superior a 63 caracteres debe descartarse hasta su final; la siguiente correcta debe funcionar. Espera más de tres segundos: luces apagadas y STALE. Un nuevo mensaje válido debe recuperar el funcionamiento. Anota por separado resultado esperado y observado.
Comparación directa: V1,120,3500,65,15 enciende los cuatro LED, V1,120,3500,65,0 los apaga y V1,120,3500,65,5 enciende solo LED 1 y 3.
Describe el fallo antes de cambiar el circuito
Si falla un LED, revisa polaridad, resistencia y pin asignado. Si falla todo el OLED, revisa modelo, alimentación, masa, SDA/SCL y dirección. OLED ERROR puede indicar ausencia de respuesta I²C o fallo al reservar memoria. Una dirección que responde no demuestra por sí sola una imagen correcta.
Pregunta a la IA con hechos: “Uno R3, módulo 4440, programa sin cambios. Aparece READY, V1,120,3500,65,1 devuelve OK y LED1 funciona, pero el OLED está oscuro. ¿Qué conexiones debo comprobar primero sin alimentación?” Incluye versiones de bibliotecas y errores completos. Pide un cambio justificado cada vez.
Guarda la versión funcional antes de ampliarla y repite las pruebas tras modificarla. La guía de diagnóstico ayuda a ordenar el proceso. No adjuntes contraseñas, configuraciones privadas o carpetas ajenas al problema. Comprender un pequeño cambio es más útil que sustituir todo el programa sin saber por qué.
Del ejercicio a los datos de tu simulador
Los valores reales del simulador necesitan una ruta documentada en el PC: obtener datos, convertir unidades, validar y transmitir. V1 es únicamente el formato de este ejercicio, no una interfaz prometida de Cockpit Suite. Comprueba la conexión de dispositivos admitida antes de crear un puente automático. Normalmente el monitor serie y otra aplicación no pueden utilizar el mismo puerto a la vez.
Define si cada luz representa una orden solicitada o un estado confirmado por el simulador. Distingue también “sin datos” de “apagado”. Continúa con asignación de datos y pantallas e instrumentos.
Para botones y ejes como joystick USB, FreeJoy ofrece otra vía con hardware adecuado. Este sketch del Uno utiliza comunicación serie USB y no lo convierte en joystick nativo. Elige según la tarea y amplía el panel después de comprobar una ruta completa.
El siguiente paso también se construye en comunidad
Cockpit Suite reúne simuladores y dispositivos compatibles en un mismo entorno de software. Es un proyecto joven con software disponible y montajes reales. Las combinaciones preparadas simplifican la instalación cuando son compatibles; un módulo Arduino propio sigue requiriendo aprendizaje e integración. Tu experiencia documentada ayuda a mejorar esos pasos.
Comparte objetivo, componentes y última prueba correcta en el foro de Cockpit Suite. Queremos ayudarte a avanzar e intentamos responder el mismo día cuando es posible; las preguntas tardías pueden esperar hasta después. También tratamos impresión 3D, fresadoras CNC de pórtico y láser con LightBurn. Una comunidad activa en Europa y fuera de ella convierte los logros individuales en ayuda útil para otros constructores.
Fuentes y fundamentos técnicos
Consultadas el 18 de octubre de 2026. Procedimiento, formato y sketch propios para aprender. La documentación no sustituye las pruebas del montaje real.
- Arduino UNO R3Plataforma Uno R3 y documentación oficial de pines.
- Adafruit 4440: 128×32 I²C OLEDModelo exacto, resolución, niveles lógicos, reinicio automático y dirección I²C.
- Adafruit: Wiring 128×32 I²C DisplayConexiones I²C oficiales; distinguir placas antiguas del modelo 4440.
- Adafruit SSD1306 library implementationImplementación de la biblioteca: memoria, inicialización y transferencias.