Package personalizado de JW Control para programar placas basadas en ESP32 desde Arduino IDE, optimizado para el ecosistema JWPLC Basic.
El objetivo del package es ofrecer una experiencia industrial más directa que el core ESP32 genérico: menos variantes innecesarias, APIs de alto nivel y periféricos integrados al runtime del JWPLC.
v2.0.0 corresponde a la release estable inicial del package Arduino JW Control ESP32 Boards para JWPLC Basic.
Objetivo:
Publicar una versión estable inicial, instalable desde Boards Manager, validada con Arduino IDE, Arduino CLI y hardware real.Esta release toma como base el trabajo validado en:
v2.0.0-alpha.31
v2.0.0-beta.1Durante este ciclo, alpha31 actuó como validación técnica integral del package instalado desde cero, y beta1 fue publicada como etapa de package validation antes de la estable.
A partir de v2.0.0, el flujo recomendado puede simplificarse en ciclos futuros:
alphas técnicas -> última alpha de verificación -> release estableBeta queda como etapa opcional cuando se requiera validación pública o de terceros. RC queda como etapa opcional si se necesita un candidato final adicional.
Queda fuera de v2.0.0:
- OpenPLC como runtime integrado directamente dentro del package Arduino;
- definición final de OTA;
- publicación de
bootloader.bincomo definitivo; - precompilación de librerías internas;
- cambios de arquitectura multicore;
- eliminación de periféricos del autoload normal solo por velocidad;
- partición recovery;
- soporte formal para hardware de 8 MB/16 MB;
- coredump como feature documentada de usuario.
Nota: a partir de la etapa
alpha32-openplc-integration, OpenPLC Editor v4 queda validado como integración externa/opcional mediante patch, sin modificar el package Arduino establev2.0.0.
v2.1.0-alpha.2 corresponde a una pre-release técnica enfocada en mejoras y correcciones de JWPLC_Display, refresco TFT y panel de estado IDLE.
Esta alpha no reemplaza todavía a v2.0.0 como canal estable público. Su objetivo es validar sobre hardware real los cambios de HMI antes de preparar una publicación estable posterior.
Objetivo:
Mejorar la experiencia de uso del TFT integrado, permitir configuración directa desde setup() y mostrar estados más claros para ETH/BUS en la pantalla IDLE.Alcance principal:
setUserRefreshPeriodMs()ahora controla realmente la frecuencia dejwplcUserDisplayRefreshCallback()en modoUSER.- Las configuraciones principales de
JWPLC_Displaypueden declararse desdesetup(), sin esperarisReady()enloop(). - Los indicadores
RUN,ERR,BUSyETHya no son pisados por la inicialización interna de la TFT. BUSpuede funcionar en modo automático usando actividad real deJWPLC_RS485.ETHyBUSusan estados visuales más claros: gris, apagado, verde y rojo.- Se agregan códigos internos de prueba en
JWPLC/Test_Codespara conservar histórico de validación. - Se validó Modbus RTU Master/Slave entre dos JWPLC Basic usando el puerto RS-485 físico.
Estados visuales definidos para BUS y ETH:
| Estado visual | Significado general |
|---|---|
| Gris | Periférico no disponible, deshabilitado o no iniciado. |
| Apagado / negro | Periférico disponible, pero sin actividad o sin link activo. |
| Verde | Estado OK o actividad reciente. |
| Rojo | Error real detectado. |
Queda fuera de v2.1.0-alpha.2:
- OpenPLC como runtime integrado obligatorio.
- OTA.
- definición final de Flash Frequency como decisión de producto.
- publicación de
bootloader.binprecompilado como definitivo. - cambios de arquitectura multicore.
- nuevas mejoras visuales de TFT no necesarias para cerrar esta alpha.
Cualquier mejora adicional de UX del display debería moverse a una alpha posterior para mantener
v2.1.0-alpha.2acotada y verificable.
JWPLC Basic es una plataforma industrial basada en ESP32-WROOM-32E. Este package permite programarla desde Arduino IDE manteniendo una sintaxis familiar, pero con periféricos industriales ya integrados:
- I/O industrial por TCA6424A.
- Display TFT ST7789.
- Botonera tipo LOGO!.
- RTC.
- FRAM.
- microSD.
- Ethernet W5500.
- RS-485.
- Modbus RTU base.
La idea es que el usuario pueda escribir código tipo Arduino:
pinMode(I0_0, INPUT);
pinMode(Q0_0, OUTPUT);
bool state = digitalRead(I0_0);
digitalWrite(Q0_0, state);sin tener que manejar directamente expansores I2C, buses SPI, pines internos, inicialización de periféricos o detalles del hardware.
El package JWPLC mantiene un enfoque compacto y orientado a producto:
| Placa | Uso recomendado | Periféricos esperados |
|---|---|---|
| ESP32 Board | Desarrollo ESP32 genérico dentro del package JWPLC. | Sin periféricos JWPLC automáticos. |
| JWPLC Basic | Hardware completo JWPLC Basic. | I/O industrial, Display, botonera, RTC, FRAM, microSD, Ethernet, RS-485 y Modbus RTU base. |
| JWPLC Basic Core | Validación del core y pruebas esenciales sin periféricos opcionales. | I/O industrial y periféricos esenciales; FRAM, SD y Ethernet pueden reportar disabled. |
No se mantiene soporte visible para ESP32-S2, ESP32-S3, ESP32-C3, ESP32-C6, ESP32-H2 u otras familias dentro del package JWPLC mientras no sean requeridas por un producto real.
Esto reduce peso, simplifica mantenimiento y evita confusión dentro de Arduino IDE.
Una de las metas del package JWPLC es reducir el tamaño frente al package ESP32 genérico, manteniendo solo lo necesario para el ecosistema JWPLC Basic.
Medición local en Windows:
| Package | Tamaño | Tamaño en disco | Archivos | Carpetas |
|---|---|---|---|---|
jwplc |
1.57 GB | 1.58 GB | 9,371 | 1,951 |
esp32 oficial |
5.72 GB | 5.80 GB | 44,264 | 11,327 |
Reducción aproximada:
| Métrica | Reducción |
|---|---|
| Tamaño | 72.6 % |
| Cantidad de archivos | 78.8 % |
| Cantidad de carpetas | 82.8 % |
En la práctica, el package JWPLC ocupa alrededor del 27.4 % del tamaño del package ESP32 oficial medido, es decir, es aproximadamente 3.6 veces más compacto.
Para usuarios finales, usar el índice público:
https://raw.githubusercontent.com/JW-Control/platform-jwplc/main/JWPLC/package_jwplc_index.jsonEste canal está pensado para mostrar versiones estables y versiones públicas seleccionadas, evitando que el usuario final vea todas las alphas históricas.
En Arduino IDE, ingresa este enlace en:
Archivo > Preferencias > Gestor de URLs adicionales de tarjetasLuego abre:
Herramientas > Placa > Gestor de tarjetasBusca:
JW Control ESP32 Boardse instala:
2.0.0Para validación interna con alphas y betas históricas, usar:
https://raw.githubusercontent.com/JW-Control/platform-jwplc/main/JWPLC/package_jwplc_index_dev.jsonEste canal no se recomienda para usuarios finales.
Versiones esperadas en este canal durante el ciclo 2.1.0:
2.1.0-alpha.1
2.1.0-alpha.2Para pruebas locales de PR o desarrollo activo se recomienda usar un package local separado, por ejemplo:
jwplc_local:esp32:jwplcbasicy enlazarlo por junction/symlink hacia:
JWPLC/2.1.0Esto permite probar cambios del repo local sin alterar la instalación estable jwplc:esp32 instalada desde Boards Manager.
Después de instalar el package, selecciona una de las placas disponibles:
| Placa | FQBN | Uso recomendado |
|---|---|---|
| ESP32 Board | jwplc:esp32:esp32 |
Desarrollo ESP32 genérico dentro del package JWPLC. |
| JWPLC Basic | jwplc:esp32:jwplcbasic |
Hardware completo JWPLC Basic. |
| JWPLC Basic Core | jwplc:esp32:jwplcbasiccore |
Validación del core y pruebas sin periféricos opcionales. |
FQBN recomendado para JWPLC Basic:
jwplc:esp32:jwplcbasicDesde alpha30, JWPLC Basic y JWPLC Basic Core usan una configuración fija para reducir combinaciones no validadas y estabilizar el FQBN.
| Parámetro | Valor |
|---|---|
| CPU | 240 MHz |
| Flash size | 4 MB |
| Flash frequency | 40 MHz |
| Flash mode | DIO |
| Bootloader base | QIO |
| Partition scheme | huge_app |
| Upload speed | 921600 |
| LoopCore | default del core |
| EventsCore | default del core |
La partición huge_app deja 3 MB para aplicación:
Maximum is 3145728 bytes.- OTA no está integrado todavía.
- OpenPLC no forma parte obligatoria del package Arduino; queda validado como integración externa/opcional mediante patch para OpenPLC Editor v4.
- No se publica
bootloader.binprecompilado como definitivo. - No se eliminan periféricos del autoload normal por velocidad.
- No se precompilan librerías internas en
v2.0.0. platform.txtse mantiene sin cambios salvo bloqueante real.app-onlyqueda documentado como herramienta útil, no como solución principal de compilación.
| Periférico / API | ESP32 Board | JWPLC Basic | JWPLC Basic Core |
|---|---|---|---|
pinMode() / digitalRead() / digitalWrite() sobre I/O industrial |
No automático | Sí | Sí |
| TCA6424A integrado al core | No automático | Sí | Sí |
JWPLC_Display |
No automático | Sí | Sí |
JWPLC_Buttons |
No automático | Sí | Sí |
JWPLC_RTC |
No automático | Sí | Sí |
JWPLC_FRAM |
No automático | Sí | Disabled |
JWPLC_SD |
No automático | Sí | Disabled |
JWPLC_Ethernet |
No automático | Sí | Disabled |
JWPLC_RS485 |
No automático | Sí | Sí |
JWPLC_ModbusRTU |
No automático | Sí | Sí |
En JWPLC Basic Core, mensajes como
Ethernet disabled,SD disabledoFRAM size: 0son esperados si esa variante fue compilada sin esos periféricos.
Una de las bases del package JWPLC es que el expansor TCA6424A queda integrado al core para que las entradas y salidas industriales se usen con funciones estándar de Arduino.
pinMode(I0_0, INPUT);
pinMode(Q0_0, OUTPUT);
bool state = digitalRead(I0_0);
digitalWrite(Q0_0, state);El usuario no necesita usar manualmente Wire, I2C ni escribir código directo para el TCA6424A.
| Nombre JWPLC | Uso |
|---|---|
I0_0 |
Entrada digital 0 |
I0_1 |
Entrada digital 1 |
I0_2 |
Entrada digital 2 |
I0_3 |
Entrada digital 3 |
I0_4 |
Entrada digital 4 |
I0_5 |
Entrada digital 5 |
I0_6 |
Entrada digital 6 |
I0_7 |
Entrada digital 7 |
| Nombre JWPLC | Uso |
|---|---|
Q0_0 |
Salida digital / relé 0 |
Q0_1 |
Salida digital / relé 1 |
Q0_2 |
Salida digital / relé 2 |
Q0_3 |
Salida digital / relé 3 |
Q0_4 |
Salida digital / relé 4 |
Q0_5 |
Salida digital / relé 5 |
Q0_6 |
Salida digital / relé 6 |
Q0_7 |
Salida digital / relé 7 |
Además del uso pin a pin, alpha29 incorporó APIs de lectura/escritura por bloque:
uint32_t inputs = digitalReadBlock(I0_X);
uint32_t outputs = JWPLC_readOutputs();
JWPLC_writeOutputs(0x0000000F);
digitalWriteBlock(Q0_X, 0x000000AA);APIs disponibles:
digitalReadBlock(I0_X);
digitalWriteBlock(Q0_X, bitmap);
JWPLC_readInputs();
JWPLC_readOutputs();
JWPLC_writeOutputs(bitmap);Esto permite trabajar con mapas de bits para integración con lógica PLC, Modbus u otros runtimes.
En JWPLC Basic, el package expone objetos globales para trabajar con sintaxis directa:
JWPLC_Display
JWPLC_Ethernet
JWPLC_SD
JWPLC_FRAM
JWPLC_RTC
JWPLC_Buttons
JWPLC_RS485
JWPLC_ModbusRTULa idea es que el usuario final no tenga que repetir inicializaciones internas ni recordar pines, buses SPI, buses I2C o detalles de hardware.
El package incluye librerías internas del ecosistema JWPLC y snapshots estables de librerías JW distribuibles.
| Librería | Descripción | README |
|---|---|---|
JWPLC_Display |
Manejo de TFT ST7789, pantallas IDLE/USER, callbacks de HMI e indicadores visuales. | Ver README |
JWPLC_Ethernet |
Integración del W5500, DHCP/static IP, reconexión, estado de link y coexistencia SPI. | Ver README |
JWPLC_RS485 |
API nativa para usar el puerto RS-485 físico del JWPLC Basic sobre Serial2. |
Ver README |
JWPLC_ModbusRTU |
Modbus RTU base sobre JWPLC_RS485, con soporte inicial master/slave. |
Ver README |
JWPLC_GlobalPeripheralsno tiene README independiente por ahora. Su función principal es agrupar y exponer los objetos globales del ecosistema JWPLC.
Estas librerías tienen repositorio propio y el README apunta al branch main oficial, que es la referencia pública para consulta y descarga independiente.
| Librería | Descripción | README |
|---|---|---|
JW_FRAM |
Librería SPI FRAM con API tipo EEPROM para guardar variables, estructuras, strings y configuraciones. | Ver README |
JW_RTC |
Librería para RTC DS3232M / DS3232 con manejo de fecha/hora, timestamp Unix, temperatura, alarmas y NVRAM. | Ver README |
JW_SD |
Wrapper para microSD basado en SD, pensado para trabajar de forma segura con bus SPI compartido. |
Ver README |
JW_MatrixButtons |
Librería para lectura de botonera matricial con debounce, eventos, repeat y helpers de navegación HMI/PLC. | Ver README |
JW_DWIN_RS485 |
Librería complementaria para comunicación con pantallas DWIN por RS-485 / Modbus RTU. No forma parte del runtime base de JWPLC Basic v2.0.0. | Ver README |
En
JWPLC Basic, varias de estas librerías se usan a través de objetos globales ya integrados al runtime. Para uso normal del PLC, el usuario no necesita inicializar manualmente todos los periféricos ni recordar pines internos del hardware.
JWPLC_Display se inicializa automáticamente en placas compatibles y muestra una pantalla IDLE con estado general del equipo.
La API recomendada usa estilo objeto con punto:
JWPLC_Display.setIdleWakeMode(IDLE_WAKE_ANY_BUTTON);
JWPLC_Display.setIdleReturnMode(IDLE_RETURN_ESC_ONLY);
JWPLC_Display.setUserRefreshPeriodMs(100);
JWPLC_Display.setRunLed(true);Desde v2.1.0-alpha.2, las configuraciones principales del display pueden declararse directamente desde setup().
Ya no es necesario crear una lógica en loop() del tipo if (JWPLC_Display.isReady()) solo para configurar comportamiento del display.
Ejemplo recomendado:
#include <Arduino.h>
#include <JWPLC_Display.h>
void setup()
{
Serial.begin(115200);
JWPLC_Display.setIdleWakeMode(IDLE_WAKE_ANY_BUTTON);
JWPLC_Display.setIdleReturnMode(IDLE_RETURN_ESC_ONLY);
JWPLC_Display.setIdleRefreshPeriodMs(1000);
JWPLC_Display.setUserRefreshPeriodMs(100);
JWPLC_Display.setRunLed(true);
JWPLC_Display.setErrLed(false);
JWPLC_Display.setBusLedAuto(true);
JWPLC_Display.setEthLedAuto(true);
}
void loop()
{
// Lógica normal del sketch.
}APIs validadas como configuración desde setup():
JWPLC_Display.setIdleWakeMode(...);
JWPLC_Display.setIdleWakeButton(...);
JWPLC_Display.setIdleReturnMode(...);
JWPLC_Display.setIdleReturnButton(...);
JWPLC_Display.setIdleTimeoutMs(...);
JWPLC_Display.setIdleRefreshPeriodMs(...);
JWPLC_Display.setUserRefreshPeriodMs(...);
JWPLC_Display.setRunLed(...);
JWPLC_Display.setErrLed(...);
JWPLC_Display.setBusLed(...);
JWPLC_Display.setBusLedAuto(...);
JWPLC_Display.setEthLed(...);
JWPLC_Display.setEthLedAuto(...);isReady() sigue siendo útil para saber cuándo la TFT ya está disponible para dibujo directo, pero no es necesario para definir la configuración básica del display.
IDLE es la pantalla automática base del JWPLC. Muestra:
- título del equipo;
- indicadores laterales
PWR,RUN,ERR,BUS,ETH; - entradas digitales;
- salidas digitales;
- RTC cuando está disponible.
USER es la pantalla personalizada del sketch. Se entra a USER cuando:
- se presiona una tecla de la botonera según el modo configurado;
- el sketch llama manualmente a
JWPLC_Display.enterUserUI().
Modos de entrada desde IDLE a USER:
IDLE_WAKE_ANY_BUTTON
IDLE_WAKE_BUTTON_ONLY
IDLE_WAKE_DISABLEDModos de retorno desde USER a IDLE:
IDLE_RETURN_TIMEOUT
IDLE_RETURN_ESC_ONLY
IDLE_RETURN_BUTTON_ONLY
IDLE_RETURN_DISABLEDEjemplo:
JWPLC_Display.setIdleWakeMode(IDLE_WAKE_ANY_BUTTON);
JWPLC_Display.setIdleReturnMode(IDLE_RETURN_ESC_ONLY);setUserRefreshPeriodMs(ms) define cada cuánto se llama:
jwplcUserDisplayRefreshCallback(...)en modo USER.
Desde v2.1.0-alpha.2, el core respeta este periodo también cuando no hay eventos de botones.
Ejemplos validados:
JWPLC_Display.setUserRefreshPeriodMs(100); // 10 FPS
JWPLC_Display.setUserRefreshPeriodMs(20); // prueba rápida de refrescoEl runtime limita el valor a un rango seguro para evitar valores nulos o demasiado agresivos.
Para dibujar directamente con Adafruit ST7789, incluye:
#include <JWPLC_Display.h>y usa:
auto &tft = JWPLC_Display.tft();También existe el alias:
auto &display = JWPLC_Display.display();El acceso directo a la TFT debe hacerse cuando la pantalla ya esté inicializada. Lo más ordenado es dibujar desde los callbacks:
extern "C" void jwplcUserDisplayEnterCallback()
{
auto &tft = JWPLC_Display.tft();
tft.fillScreen(ST77XX_BLACK);
}
extern "C" void jwplcUserDisplayRefreshCallback(const JWPLC_IOState *io, const JWPLC_RTCState *rtc)
{
auto &tft = JWPLC_Display.tft();
// Redibujar solo áreas pequeñas.
}Los indicadores laterales resumen el estado del equipo:
| LED | Uso |
|---|---|
PWR |
Encendido del sistema. |
RUN |
Estado de ejecución definido por el usuario/runtime. |
ERR |
Estado de error definido por el usuario/runtime. |
BUS |
Estado o actividad del bus RS-485/Modbus RTU. |
ETH |
Estado de Ethernet W5500. |
Desde v2.1.0-alpha.2, BUS y ETH usan estados visuales de cuatro niveles:
| Color / estado | Significado |
|---|---|
| Gris | Periférico no disponible, deshabilitado o no iniciado. |
| Negro / apagado | Periférico disponible, pero sin actividad o sin link activo. |
| Verde | Estado OK o actividad reciente. |
| Rojo | Error real detectado. |
Modo manual:
JWPLC_Display.setBusLed(true);
JWPLC_Display.setBusLed(false);setBusLed(...) desactiva el modo automático y fuerza el estado manual.
Modo automático:
JWPLC_Display.setBusLedAuto(true);En modo automático, BUS depende de JWPLC_RS485:
| Condición | LED BUS |
|---|---|
| RS-485 no disponible o no iniciado | Gris |
| RS-485 iniciado, sin tráfico reciente | Apagado |
TX/RX reciente por JWPLC_RS485 o JWPLC_ModbusRTU |
Verde |
| Error RS-485 o error Modbus RTU reciente | Rojo |
Este indicador no inicializa RS-485 por sí mismo. Para que BUS salga de gris, el sketch debe iniciar JWPLC_RS485 o JWPLC_ModbusRTU.
Modo manual:
JWPLC_Display.setEthLed(true);
JWPLC_Display.setEthLed(false);setEthLed(...) desactiva el modo automático y fuerza el estado manual.
Modo automático:
JWPLC_Display.setEthLedAuto(true);En modo automático:
| Condición | LED ETH |
|---|---|
| Ethernet no disponible o deshabilitado por variante | Gris |
| Ethernet disponible, pero no iniciado / link off | Apagado |
| Ethernet OK | Verde |
| Falla real de Ethernet | Rojo |
En JWPLC Basic Core, donde Ethernet puede estar deshabilitado por configuración, ETH debe mostrarse en gris.
En callbacks del display, evita hacer operaciones pesadas o consultas directas a periféricos SPI. Lo recomendado es:
- Leer Ethernet, SD o FRAM desde
loop(). - Guardar resultados en variables simples.
- Dibujar en pantalla usando esas variables ya cacheadas.
Evita consultar JWPLC_Ethernet, JWPLC_SD o JWPLC_FRAM directamente dentro de callbacks de dibujo repetitivos.
JWPLC_Buttons permite usar la botonera frontal del JWPLC Basic sin escanear manualmente la matriz.
Uso típico:
if (JWPLC_Buttons.upPressed()) {
// acción
}
if (JWPLC_Buttons.okPressed()) {
// confirmar
}La botonera se integra con el flujo de pantallas del display, permitiendo interfaces tipo menú, navegación o edición de parámetros.
JWPLC_RTC permite usar el RTC integrado del JWPLC Basic para fecha y hora del sistema.
Uso típico:
auto now = JWPLC_RTC.now();Aplicaciones:
- Registro de eventos.
- Fechado de logs.
- Sincronización de pantallas.
- Tiempos de proceso.
- Diagnóstico básico.
JWPLC_FRAM permite almacenar datos persistentes de forma más robusta que EEPROM emulada.
Aplicaciones típicas:
- Contadores.
- Último estado de máquina.
- Parámetros de usuario.
- Setpoints.
- Flags de diagnóstico.
Ejemplo conceptual:
uint32_t starts = 0;
JWPLC_FRAM.get(0, starts);
starts++;
JWPLC_FRAM.put(0, starts);En JWPLC Basic Core, FRAM puede estar deshabilitada y reportar tamaño 0.
JWPLC_SD permite trabajar con archivos en microSD.
Aplicaciones típicas:
- Logs.
- Recetas.
- Archivos de configuración.
- Recursos para HMI.
- Exportación de datos.
Notas prácticas:
- Se recomienda FAT32.
- Para tarjetas grandes, usar partición MBR.
- microSD comparte SPI con TFT, W5500 y FRAM.
Ethernet W5500 queda integrado al runtime del JWPLC Basic.
En uso normal no es necesario llamar manualmente:
JWPLC_Ethernet.begin();
JWPLC_Ethernet.maintain();El runtime se encarga de:
- Inicializar Ethernet automáticamente en variantes compatibles.
- Evitar bloqueos largos cuando no hay RJ45 conectado.
- Reintentar al conectar RJ45 después del arranque.
- Mantener DHCP.
- Proteger el bus SPI compartido.
- Actualizar el indicador
ETHen pantalla IDLE.
Desde v2.1.0-alpha.2, ETH usa cuatro estados visuales:
| Condición | LED ETH |
|---|---|
| Ethernet disabled / Basic Core / variante sin W5500 | Gris |
| Ethernet disponible, pero no iniciado | Apagado |
| RJ45 desconectado / Link OFF | Apagado |
| Ethernet OK | Verde |
| Falla real de Ethernet | Rojo |
El color gris se reserva para indicar que el periférico no está disponible o está deshabilitado por configuración de placa. Esto evita confundir “no existe/no está habilitado” con “existe, pero está sin link”.
El indicador puede controlarse manualmente:
JWPLC_Display.setEthLed(true);
JWPLC_Display.setEthLed(false);o dejarse en modo automático:
JWPLC_Display.setEthLedAuto(true);Cuando se usa setEthLed(...), el modo automático se desactiva para respetar el valor definido por el sketch.
El JWPLC Basic incluye API nativa para RS-485 usando Serial2.
JWPLC_RS485.begin(); // 115200, SERIAL_8N1| Señal | ESP32 |
|---|---|
| RX2 | IO16 |
| TX2 | IO17 |
El JWPLC Basic usa transceptor MAX13487 con auto-direccionamiento, por lo que no se requiere controlar manualmente DE/RE.
RS-485 no se inicializa automáticamente. El usuario debe llamar a begin() porque el mismo Serial2 puede usarse como UART RS-485 genérico o como Modbus RTU.
Desde v2.1.0-alpha.2, JWPLC_RS485 registra actividad reciente de recepción/transmisión:
JWPLC_RS485.lastActivityMs();
JWPLC_RS485.lastRxActivityMs();
JWPLC_RS485.lastTxActivityMs();
JWPLC_RS485.hasRecentActivity(800);Estas APIs permiten que JWPLC_Display actualice automáticamente el LED BUS en la pantalla IDLE.
La actividad se detecta cuando el sketch usa:
JWPLC_RS485.available();
JWPLC_RS485.read();
JWPLC_RS485.write(...);o cuando se usa JWPLC_ModbusRTU, porque Modbus RTU trabaja sobre JWPLC_RS485.
Si un sketch usa
Serial2directamente sin pasar porJWPLC_RS485, el indicador automáticoBUSno puede detectar esa actividad. Para mantener integración con el panel IDLE, usarJWPLC_RS485oJWPLC_ModbusRTU.
En modo automático:
JWPLC_Display.setBusLedAuto(true);| Condición | LED BUS |
|---|---|
| RS-485 no disponible o no iniciado | Gris |
| RS-485 iniciado, sin tráfico reciente | Apagado |
| TX/RX reciente por RS-485 | Verde |
| Error RS-485 / Modbus RTU reciente | Rojo |
JWPLC_RS485.begin(115200, SERIAL_8N1);
JWPLC_RS485.println("Hola RS485");Para recibir:
while (JWPLC_RS485.available() > 0)
{
int value = JWPLC_RS485.read();
if (value >= 0)
{
Serial.write((uint8_t)value);
}
}El package incluye base Modbus RTU sobre RS-485.
#include <JWPLC_ModbusRTU.h>
JWPLC_ModbusRTU.begin(); // Slave ID 1, 19200, SERIAL_8E1JWPLC_ModbusRTU.h incluye internamente JWPLC_RS485.h, por lo que no es necesario incluir ambas librerías cuando el sketch solo usa Modbus RTU.
JWPLC_ModbusRTU.begin(...) inicializa el puerto RS-485 con la configuración indicada. No debe llamarse adicionalmente JWPLC_RS485.begin(...) en el mismo sketch, salvo que se esté cerrando/reconfigurando el bus de forma intencional.
Funciones soportadas en modo slave:
| Código | Función |
|---|---|
0x03 |
Read Holding Registers |
0x06 |
Write Single Register |
0x10 |
Write Multiple Registers |
Funciones soportadas en modo master:
| API | Función |
|---|---|
readHoldingRegisters() |
Lectura de holding registers |
writeSingleRegister() |
Escritura de un holding register |
En v2.1.0-alpha.2 se validó comunicación Modbus RTU entre dos JWPLC Basic:
JWPLC Basic Master <-> RS-485 <-> JWPLC Basic SlaveResultado validado:
- Master lee holding registers del Slave.
- Master escribe un registro del Slave.
- Slave actualiza registros internos.
- LED
BUSparpadea en ambos equipos durante tráfico real. - El mismo test sirve para validar el modo automático del LED
BUS.
Los códigos internos de prueba se conservan en:
JWPLC/Test_Codes/alpha2_ModbusRTU_BusLedAuto_Master/
JWPLC/Test_Codes/alpha2_ModbusRTU_BusLedAuto_Slave/A partir de la etapa alpha32-openplc-integration, el JWPLC Basic v2.0.0 fue validado como target externo para OpenPLC Editor v4.
Esta integración no modifica el package Arduino estable platform-jwplc v2.0.0. Se entrega como un patch externo para OpenPLC Editor, ubicado en:
docs/alpha32_openplc_integration/open-plc-editor/- OpenPLC Editor reconoce
JWPLC BASIC [2.0.0]. - Compilación desde OpenPLC usando Arduino CLI.
- Subida por USB al JWPLC Basic.
- Debugger de OpenPLC operativo.
- Pin Mapping compatible con
I0_0..I0_7yQ0_0..Q0_7. - Lectura de entradas digitales.
- Activación de salidas digitales.
- Concordancia entre OpenPLC, E/S físicas y TFT.
- Modbus TCP por Ethernet W5500.
- DHCP y puerto TCP 502 validados.
- Pruebas con ModbusTool como master TCP.
Modbus RTU y Modbus TCP fueron validados de forma independiente:
RTU solo: funcional.
TCP solo: funcional.
RTU + TCP simultáneo: TCP funciona; RTU queda pendiente de revisión.La guía y los scripts de instalación están en:
docs/alpha32_openplc_integration/Para instalación rápida en Windows:
docs/alpha32_openplc_integration/installer/install_openplc_jwplc_patch.batEl instalador crea un backup automático y copia los archivos modificados sobre la carpeta local de OpenPLC Editor.
| OpenPLC | Modbus TCP | JWPLC Basic |
|---|---|---|
%IX0.0 |
Discrete Input 0 | I0_0 |
%IX0.1 |
Discrete Input 1 | I0_1 |
%IX0.2 |
Discrete Input 2 | I0_2 |
%IX0.3 |
Discrete Input 3 | I0_3 |
%IX0.4 |
Discrete Input 4 | I0_4 |
%IX0.5 |
Discrete Input 5 | I0_5 |
%IX0.6 |
Discrete Input 6 | I0_6 |
%IX0.7 |
Discrete Input 7 | I0_7 |
%QX0.0 |
Coil 0 | Q0_0 |
%QX0.1 |
Coil 1 | Q0_1 |
%QX0.2 |
Coil 2 | Q0_2 |
%QX0.3 |
Coil 3 | Q0_3 |
%QX0.4 |
Coil 4 | Q0_4 |
%QX0.5 |
Coil 5 | Q0_5 |
%QX0.6 |
Coil 6 | Q0_6 |
%QX0.7 |
Coil 7 | Q0_7 |
Ver documentación completa en:
docs/alpha32_openplc_integration/openplc-io-map.md
docs/alpha32_openplc_integration/openplc-validation-report.md
docs/alpha32_openplc_integration/openplc-modbus-test-guide.mdOpenPLC queda como integración externa/opcional. El uso normal del JWPLC Basic desde Arduino IDE sigue funcionando sin requerir OpenPLC.
El JWPLC Basic comparte SPI entre:
- TFT ST7789.
- Ethernet W5500.
- FRAM.
- microSD.
Regla recomendada para sketches avanzados:
- Consultar periféricos SPI desde
loop(). - Guardar resultados en variables simples.
- En callbacks gráficos del display, dibujar solo variables cacheadas.
Evita consultar JWPLC_Ethernet, JWPLC_SD o JWPLC_FRAM directamente dentro de callbacks de dibujo.
Desde alpha30 se documentó el comportamiento real de compilación:
| Prueba | Tiempo |
|---|---|
| Build limpio con configuración fija | 02:01.014 |
| Build incremental del mismo sketch | 00:31.861 |
| Segundo sketch usando cache de core | 01:58.993 |
| Build incremental del segundo sketch | 00:31.296 |
Conclusiones:
- La primera compilación de un sketch sigue siendo la más pesada.
- Las compilaciones posteriores del mismo sketch son mucho más rápidas.
- El
bootloader.binprecompilado no aportó una mejora significativa. - La precarga global del package no se considera suficiente para alpha30.
- La optimización principal fue fijar la configuración de placa y reducir combinaciones.
El flujo app-only permite subir únicamente la aplicación a 0x10000, sin regrabar bootloader, particiones ni boot_app0.bin.
Resultado medido:
| Prueba | Tiempo |
|---|---|
| App-only aislado | 00:06.352 |
Conclusión:
app-only es útil para desarrollo cuando la placa ya tiene bootloader y particiones correctas, pero no resuelve el tiempo principal de compilación.
Se evaluó publicar un bootloader.bin precompilado en la variante jwplcbasic.
Resultado:
- Build limpio mejoró aproximadamente 2.9 s.
- Build incremental empeoró aproximadamente 2.5 s.
Decisión:
No se publica bootloader.bin precompilado como definitivo. Se mantiene la generación automática desde:
bootloader_qio_40m.elfOTA no está integrado todavía en JWPLC Basic v2.0.0.
La configuración actual usa huge_app para priorizar espacio de aplicación en hardware de 4 MB.
Pendientes futuros:
- Evaluar hardware de 8 MB/16 MB.
- Evaluar partición recovery.
- Evaluar interfaz de actualización desde display.
- Evaluar actualización desde microSD o Ethernet.
La partición huge_app conserva una partición coredump, que puede ser útil para diagnóstico de fallos graves del ESP32.
Uso futuro esperado:
- Diagnóstico de
Guru Meditation. - Análisis de backtrace.
- Identificación de tarea que falló.
- Depuración de
loopTask,jwplcSystemTasku otros módulos.
El uso formal de coredump queda pendiente de validación y documentación en una versión posterior.
v2.0.0 recoge las validaciones realizadas en alpha31 y beta1.
| Área | Resultado |
|---|---|
| Instalación limpia desde Boards Manager | OK |
| Instalación y manejo desde otra PC | OK |
| Arduino IDE | OK |
| Arduino CLI | OK |
ESP32 Board |
OK |
JWPLC Basic |
OK |
JWPLC Basic Core |
OK |
| Sketch vacío | OK |
| Sketch Serial mínimo | OK |
| Subida por USB | OK |
| Monitor serial | OK |
| Librerías bundled desde package | OK |
| I/O TCA6424A | OK |
| Display | OK |
| Botonera | OK |
| RTC | OK |
| FRAM | OK |
| microSD | OK |
| Ethernet W5500 | OK |
| RS-485 | OK |
| Modbus RTU | OK |
| Coexistencia SPI Ethernet + SD + FRAM + Display | OK |
| Área | Resultado |
|---|---|
OpenPLC Editor v4 reconoce JWPLC BASIC [2.0.0] |
OK |
| Compilación desde OpenPLC usando Arduino CLI | OK |
| Subida por USB desde OpenPLC | OK |
| Debugger OpenPLC | OK |
Pin Mapping I0_x / Q0_x |
OK |
| Lectura de entradas digitales | OK |
| Activación de salidas digitales | OK |
| Concordancia con TFT | OK |
| Modbus TCP por W5500 | OK |
| DHCP | OK |
| Puerto TCP 502 | OK |
| FC01 Read Coils | OK |
| FC02 Read Discrete Inputs | OK |
| RTU solo | OK |
| TCP solo | OK |
| RTU + TCP simultáneo | Parcial: TCP OK, RTU pendiente |
| Área | Resultado |
|---|---|
Package local jwplc_local:esp32:jwplcbasic apuntando a JWPLC/2.1.0 |
OK |
setUserRefreshPeriodMs(100) con refresco USER a 10 FPS |
OK |
setUserRefreshPeriodMs(20) como prueba rápida de refresco |
OK |
Configuración de JWPLC_Display desde setup() |
OK |
RUN, ERR, BUS, ETH manuales desde setup() |
OK |
ETH automático con encendido/apagado según estado real |
OK |
BUS automático por actividad JWPLC_RS485 |
OK |
BUS y ETH con estado gris para periférico no disponible/no iniciado |
OK |
| Modbus RTU Master/Slave entre dos JWPLC Basic | OK |
Parpadeo de BUS en ambos equipos con tráfico RS-485 real |
OK |
Test codes guardados en JWPLC/Test_Codes |
OK |
Estos son los ejemplos principales usados y/o revisados para validación alpha31/beta1/v2.0.0.
DigitalIO_BlockReadDigitalIO_BlockMirror
RS485_USB_Bridge
ModbusRTU_CRC_TestModbusRTU_Master_ExternModbusRTU_Master_ReadHoldingRegistersModbusRTU_Master_WriteSingleRegisterModbusRTU_Slave_ExternModbusRTU_Slave_HoldingRegisters
BasicRead
Basic_RW
CardInfoBasicReadWrite
Display_DotAPI_MinimalDisplay_UserUI_CallbacksDisplay_Idle_Return_ModesDisplay_FlappyBirdDisplay_Tetris
Estos códigos no son necesariamente ejemplos públicos finales; se conservan para histórico de validación del package:
JWPLC/Test_Codes/alpha2_JWPLC_Display_SetupLedTestJWPLC/Test_Codes/alpha2_JWPLC_Display_SetupLedAutoTestJWPLC/Test_Codes/alpha2_JWPLC_Display_BusLedAutoRS485TestJWPLC/Test_Codes/alpha2_ModbusRTU_BusLedAuto_MasterJWPLC/Test_Codes/alpha2_ModbusRTU_BusLedAuto_Slave
Ethernet_Auto_DHCP_StatusEthernet_Display_StatusEthernet_SPI_Coexistence
Los ejemplos/proyectos de OpenPLC se conservan como integración externa/documental en:
docs/alpha32_openplc_integration/Pruebas mínimas recomendadas:
- Blink de
Q0_0desde Ladder. - Entrada
I0_0controlando salidaQ0_0. - Lectura de coils por Modbus TCP.
- Lectura de discrete inputs por Modbus TCP.
- Instalar el package desde
package_jwplc_index.json. - Seleccionar ESP32 Board y compilar sketch vacío.
- Seleccionar JWPLC Basic y compilar sketch vacío.
- Seleccionar JWPLC Basic Core y compilar sketch vacío.
- Verificar que
JWPLC Basiccompile con particiónhuge_app. - Verificar que el máximo de programa sea
3145728 bytes. - Probar
pinMode(),digitalRead()ydigitalWrite()conI0_x/Q0_x. - Probar lectura/escritura por bloque.
- Probar Display IDLE.
- Probar retorno
USER -> IDLEpor timeout. - Probar retorno
USER -> IDLEpor ESC. - Probar Ethernet con RJ45 conectado y desconectado.
- Probar microSD insertada/retirada.
- Probar FRAM con lectura/escritura.
- Probar coexistencia Ethernet + SD + FRAM + Display.
- Probar RS-485 con bridge USB ↔ RS-485.
- Probar Modbus RTU como slave y master.
- Probar Arduino CLI con
jwplc:esp32:jwplcbasic,jwplc:esp32:jwplcbasiccoreyjwplc:esp32:esp32.
- Probar con package local
jwplc_local:esp32:jwplcbasic. - Verificar que el log de compilación use
JWPLC/2.1.0. - Probar
setUserRefreshPeriodMs(100)y confirmar refresco USER a 10 FPS. - Probar
setUserRefreshPeriodMs(20)como prueba rápida. - Configurar
JWPLC_Displaydesdesetup()sin lógica adicional enloop(). - Verificar LEDs manuales
RUN,ERR,BUS,ETHdesdesetup(). - Verificar
setEthLedAuto(true)con RJ45 conectado/desconectado. - Verificar
setBusLedAuto(true)con tráfico RS-485. - Probar Modbus RTU Master/Slave entre dos JWPLC Basic.
- Confirmar parpadeo de
BUSen ambos equipos durante tráfico real. - Confirmar
BUSgris cuando RS-485/Modbus no está iniciado. - Confirmar
ETHgris en variante sin Ethernet o con Ethernet disabled. - Confirmar que no se agregaron nuevas dependencias obligatorias.
- Confirmar que OpenPLC, OTA y bootloader precompilado no se asumen como parte de esta alpha.
- Instalar OpenPLC Editor v4.
- Aplicar patch externo desde
docs/alpha32_openplc_integration/open-plc-editor/. - Seleccionar
JWPLC BASIC [2.0.0]en OpenPLC Editor. - Compilar proyecto mínimo.
- Subir por USB.
- Verificar Debugger.
- Validar Pin Mapping.
- Validar
I0_0..I0_7yQ0_0..Q0_7. - Habilitar Modbus TCP con DHCP.
- Validar puerto TCP
502. - Probar FC01 Read Coils.
- Probar FC02 Read Discrete Inputs.
JWPLC/
package_jwplc_index.json
package_jwplc_index_dev.json
2.1.0/
boards.txt
platform.txt
cores/
variants/
libraries/
JWPLC_Display/
JWPLC_Ethernet/
JWPLC_RS485/
JWPLC_ModbusRTU/
...
JWPLC-2.0.0/
boards.txt
platform.txt
cores/
variants/
libraries/
Test_Codes/
alpha2_JWPLC_Display_SetupLedTest/
alpha2_JWPLC_Display_SetupLedAutoTest/
alpha2_JWPLC_Display_BusLedAutoRS485Test/
alpha2_ModbusRTU_BusLedAuto_Master/
alpha2_ModbusRTU_BusLedAuto_Slave/Notas:
JWPLC/2.1.0es la carpeta activa para el ciclo de desarrollo2.1.0.JWPLC/JWPLC-2.0.0conserva la fuente histórica/estable dev2.0.0.JWPLC/Test_Codesconserva pruebas internas y sketches de validación que no necesariamente deben aparecer como ejemplos públicos de Arduino IDE.
Documentación y patch OpenPLC:
docs/
alpha32_openplc_integration/
README.md
open-plc-editor/
installer/
openplc-integration-plan.md
openplc-io-map.md
openplc-architecture-review.md
openplc-validation-report.md
openplc-modbus-test-guide.md
openplc-alpha32-checklist.mdhttps://github.com/JW-Control/platform-jwplcEste repositorio mantiene la licencia indicada en el archivo LICENSE.