Índice
ToggleEC100 Guía de desarrollo del ordenador industrial ARM - La EC100 viene preinstalada con Node-RED 4.0 y NeuronEX-Lite, por lo que está lista para el desarrollo de aplicaciones edge desde el primer momento.
Node-RED proporciona una interfaz de programación visual de arrastrar y soltar para crear rápidamente la lógica empresarial, mientras que NeuronEX-Lite sirve como plataforma ligera de computación de borde que admite la conectividad de dispositivos a nivel de milisegundos gracias a la compatibilidad multiprotocolo. Esta combinación simplifica enormemente el desarrollo y permite un rápido despliegue de soluciones IoT industriales.
Preparación del desarrollo
1. Herramientas SSH
Le recomendamos que utilice MobaXterm, o puede elegir el que prefiera Herramienta SSH.
2. Herramienta de depuración del puerto serie
Recomendamos utilizar XCOM o elegir su herramienta de depuración de puertos serie.
3. Herramientas de hardware
Las herramientas de depuración más comunes son: Herramientas CAN a USB / herramientas 485 a USB / cables de red, etc. Prepárelos por su cuenta.
4. Cadena de herramientas de compilación cruzada
Cadena de herramientas de compilación cruzada
Entorno informático
OS: Embedded Linux 20.04.1; parcialmente recortado
NodeJs: v22.16.0
Python: python3.8
Shell: bash
GLIBC: 2.31
Interfaces periféricos
1. Puerto serie
El EC100 viene con dos transceptores RS485 integrados.
| Interfaz de hardware | Archivo de dispositivo |
|---|---|
| RS485-1 | /dev/ttyS4 |
| RS485-2 | /dev/ttyS3 |
Nota: Con la transmisión y recepción RS485, los usuarios no tienen que preocuparse de cambiar entre transmisión y recepción, ya que el hardware se encargará de ello automáticamente.
1.1. Prueba rápida
Utilice la herramienta minicom para realizar pruebas. Para obtener instrucciones de uso específicas, busque en Baidu o consulte DeepSeek.
1.2. Ejemplo de prueba de código
#include
#include
#include
#include
#include
#include
#include
#include
#define BUFFER_SIZE 256
typedef struct {
int baud_rate; // Velocidad en baudios
int data_bits; // Bits de datos (5,6,7,8)
int stop_bits; // Bits de parada (1,2)
char parity; // Paridad (N: Ninguna, O: Impar, E: Par)
} SerialConfig;
int set_serial_attr(int fd, SerialConfig *config)
{
struct termios tty;
if (tcgetattr(fd, &tty) < 0) { perror("tcgetattr"); return -1; } // Establece la velocidad en baudios speed_t speed;
switch (config->tasa_baudios) {
caso 9600: velocidad = B9600; break;
caso 19200: velocidad = B19200; break;
caso 38400: velocidad = B38400; break;
caso 57600: velocidad = B57600; break;
caso 115200: velocidad = B115200; break;
por defecto:
fprintf(stderr, "Velocidad de transmisión no admitida, utilizando 115200\n");
velocidad = B115200;
}
cfsetispeed(&tty, velocidad);
cfsetospeed(&tty, velocidad);
// Establecer datos
bits tty.c_cflag &= ~CSIZE;
switch (config->data_bits) {
caso 5: tty.c_cflag |= CS5; break;
caso 6: tty.c_cflag |= CS6; break;
caso 7: tty.c_cflag |= CS7; break;
caso 8: tty.c_cflag |= CS8; break;
por defecto:
fprintf(stderr, "Bits de datos no soportados, usando 8\n");
tty.c_cflag |= CS8;
}
// Configurar bits de parada
if (config->stop_bits == 2) {
tty.c_cflag |= CSTOPB; } else {
tty.c_cflag &= ~CSTOPB; }
// Establecer paridad
switch (config->paridad) {
caso 'N':
case 'n': tty.c_cflag &= ~PARENB; // Sin paridad
romper;
caso 'O':
case 'o': tty.c_cflag |= PARENB; // Paridad impar
tty.c_cflag |= PARODD; break;
caso 'E':
case 'e': tty.c_cflag |= PARENB; // Paridad par
tty.c_cflag &= ~PARODD; break;
por defecto:
fprintf(stderr, "Paridad no soportada, usando N\n");
tty.c_cflag &= ~PARENB;
}
// Otros ajustes
tty.c_cflag |= (CLOCAL | CREAD); // Habilitar receptor y modo local
tty.c_cflag &= ~CRTSCTS; // Desactiva el control de flujo por hardware
tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // Modo de entrada bruta
tty.c_oflag &= ~OPOST; // Modo de salida bruta
tty.c_cc[VMIN] = 1; // Número mínimo de caracteres a leer
tty.c_cc[VTIME] = 0; // Tiempo de espera de lectura (unidad: 0.1s)
if (tcsetattr(fd, TCSANOW, &tty) < 0) {
perror("tcsetattr");
return -1; }
Devuelve 0;
}
int main(int argc, char *argv[]) {
int fd;
char *nombrepuerto;
if (argc < 2) {
fprintf(stderr, "Usage: %s \n", argv[0]);
exit(EXIT_FAILURE);
}
portname = argv[1]; // Configuración del puerto serie
SerialConfig config = { .baud_rate = 115200, // Velocidad en baudios
.data_bits = 8, // Bits de datos
.stop_bits = 1, // Bits de parada
.parity = 'N' // Paridad (N: Ninguna, O: Impar, E: Par)
};
fd = open(nombrepuerto, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd < 0) {
perror("open");
exit(EXIT_FAILURE);
}
if (set_serial_attr(fd, &config)) {
close(fd);
exit(EXIT_FAILURE);
}
printf("Prueba de eco de puerto serie ejecutándose en %s\n", portname);
printf("Configuración: %d baud, %d data bits, %d stop bit, %c parity\n", config.baud_rate, config.data_bits, config.stop_bits, config.parity);
printf("Pulse Ctrl+C para salir.\n");
fd_set readfds;
char buffer[BUFFER_SIZE];
int n;
while (1) {
FD_ZERO(&readfds);
FD_SET(fd, &readfds); // Esperar indefinidamente los datos entrantes (sin tiempo de espera)
if (select(fd + 1, &readfds, NULL, NULL, NULL) < 0) {
perror("select");
break; }
if (FD_ISSET(fd, &readfds)) {
n = read(fd, buffer, BUFFER_SIZE - 1);
si (n > 0) {
buffer[n] = '\0';
printf("Recibidos %d bytes: %s\n", n, buffer); // Devuelve los datos por eco
write(fd, buffer, n); } else if (n < 0) {
if (errno != EAGAIN && errno != EWOULDBLOCK) {
perror("read");
romper;
}
}
}
}
close(fd);
Devuelve 0;
}
Compilar: gcc rs485_ejemplo.c -o rs485_ejemplo
Prueba de funcionamiento RS485-1: ./rs485_example/dev/ttyS4
2. LED
EC100 tiene un total de 4 indicadores luminosos, 2 de los cuales pueden ser programados por el usuario.
| Interfaz de hardware | Índice IO | Número IO | Grupo Chip | Notas |
|---|---|---|---|---|
| POW | / | / | / | LED indicador de alimentación. |
| EJECUTAR | 39 | GPIO1_A7 | gpiochip1 | Reservado por el firmware interno; no programable por el usuario; parpadea durante el funcionamiento normal. |
| LED1 | 38 | GPIO1_A6 | gpiochip1 | Programable por el usuario. |
| LED2 | 36 | GPIO1_A4 | gpiochip1 | Programable por el usuario. |
Nota: El índice IO se calcula a partir del número IO.
2.1. Prueba rápida
#!/bin/bash
# Comprueba si se proporciona un índice GPIO
if [ -z "$1" ]; then
echo "Uso: $0 "
exit 1
fi
GPIO=$1
GPIO_PATH="/sys/class/gpio/gpio$GPIO"
EXPORT_PATH="/sys/class/gpio/export"
# Comprueba si el GPIO ya está exportado
if [ ! -d "$GPIO_PATH" ]; then
echo "Exportando GPIO $GPIO..."
echo "$GPIO" > "$EXPORT_PATH"
if [ $? -ne 0 ]; then
echo "Error al exportar GPIO $GPIO. Compruebe los permisos o si está en uso".
exit 1
fi
else
echo "GPIO $GPIO ya está exportado".
fi
# Establece la dirección GPIO a salida
echo "out" > "$GPIO_PATH/direction"
# Establece el valor inicial a bajo
echo 0 > "$GPIO_PATH/valor"
echo "Conmutando GPIO $GPIO cada 1 segundo. Pulse Ctrl+C para parar".
# Iniciar bucle de alternancia
while true; do
echo 1 >"$GPIO_PATH/valor"
sleep 1
echo 0 >"$GPIO_PATH/valor"
sleep 1
hecho
Prueba de funcionamiento: bash led_ejemplo.sh 38
2.2. Ejemplo de prueba de código
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/gpio.h>
#include <errno.h>
#define GPIO_CHIP "/dev/gpiochip1" // Use gpiochip1
#define GPIO_LINE 38%32 // Offset of the GPIO to control within chip1
#define PERIOD_US 500000 // Period time (microseconds)
int main() {
struct gpiohandle_request req;
struct gpiohandle_data data;
int fd, ret;
// Open the GPIO character device
fd = open(GPIO_CHIP, O_RDWR);
if (fd < 0) {
perror("Failed to open GPIO device");
return EXIT_FAILURE;
}
// Configure GPIO request
memset(&req, 0, sizeof(req));
req.lineoffsets[0] = GPIO_LINE; // GPIO line number
req.flags = GPIOHANDLE_REQUEST_OUTPUT; // Set as output mode
req.default_values[0] = 0; // Initial value set to low
strcpy(req.consumer_label, "gpio-toggle"); // Consumer label
req.lines = 1; // Number of GPIO lines to control
// Request GPIO control
ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
if (ret < 0) {
perror("Failed to get GPIO handle");
close(fd);
return EXIT_FAILURE;
}
// Close GPIO character device (we already have line handle)
close(fd);
printf("Controlling GPIO chip1 line %d, period %.1f seconds...\n", GPIO_LINE, PERIOD_US/1000000.0);
// Periodically toggle GPIO level
while (1) {
data.values[0] = 1; // High level
ret = ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data);
if (ret < 0) {
perror("Failed to set GPIO high level");
break;
}
usleep(PERIOD_US/2);
data.values[0] = 0; // Low level
ret = ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data);
if (ret < 0) {
perror("Failed to set GPIO low level");
break;
}
usleep(PERIOD_US/2);
}
// Close GPIO line handle
close(req.fd);
return EXIT_SUCCESS;
}
Compilar: gcc led_ejemplo.c -o led_ejemplo
Prueba de funcionamiento: ./led_ejemplo
3. CAN FD
EC100 dispone de dos interfaces CAN de alta velocidad
| Interfaz de hardware | Interfaz de red |
|---|---|
| CAN1 [H1 L1] | can0 |
| CAN2 [H2 L2] | lata1 |

3.1. Prueba rápida
Conectar can0 y can1, prueba de línea de comandos:
#Inicialice primero can0 y can1, seleccione la velocidad en baudios 500k, utilice canfd, luego seleccione can0 para recibir datos y can1 para enviarlos
ip link set can0 down
ip link set can1 down
ip link set can0 type can bitrate 500000 sample-point 0.8 dbitrate 2000000 sample-point 0.8 fd on
ip link set can1 type can bitrate 500000 sample-point 0.8 dbitrate 2000000 sample-point 0.8 fd on
ip link set can0 up
ip link set can1 up
echo 4096 > /sys/class/net/can0/tx_queue_len
echo 4096 > /sys/class/net/can1/tx_queue_len
candump can0 &
cansend can1 001234EF#00.11.22.33.44.55.66.77
3.2. Ejemplo de prueba de código
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <fcntl.h>
#include <errno.h>
#include <stdint.h>
#define CAN_INTERFACE "can0"
#define BITRATE 500000
#define DATA_BITRATE 2000000
#define SAMPLE_POINT 0.8
#define TX_QUEUE_LEN 4096
// Configure CAN FD interface
int setup_can_fd_interface(const char *ifname) {
char cmd[512];
FILE *fp;
// Bring the interface down
snprintf(cmd, sizeof(cmd), "ip link set %s down", ifname);
system(cmd);
// Set CAN FD parameters
snprintf(cmd, sizeof(cmd),
"ip link set %s type can bitrate %d sample-point %.1f "
"dbitrate %d dsample-point %.1f fd on",
ifname, BITRATE, SAMPLE_POINT, DATA_BITRATE, SAMPLE_POINT);
if (system(cmd) != 0) {
fprintf(stderr, "Failed to configure CAN FD interface %s\n", ifname);
return -1;
}
// Set TX queue length
snprintf(cmd, sizeof(cmd), "/sys/class/net/%s/tx_queue_len", ifname);
fp = fopen(cmd, "w");
if (fp == NULL) {
perror("Failed to open tx_queue_len");
return -1;
}
fprintf(fp, "%d", TX_QUEUE_LEN);
fclose(fp);
// Bring the interface up
snprintf(cmd, sizeof(cmd), "ip link set %s up", ifname);
if (system(cmd) != 0) {
fprintf(stderr, "Failed to bring up CAN interface %s\n", ifname);
return -1;
}
printf("CAN FD interface %s configured:\n", ifname);
printf(" Bitrate: %d\n", BITRATE);
printf(" Data bitrate: %d\n", DATA_BITRATE);
printf(" Sample point: %.1f\n", SAMPLE_POINT);
printf(" TX queue length: %d\n", TX_QUEUE_LEN);
return 0;
}
// Send a CAN FD frame
int send_can_fd_frame(int sock, uint32_t can_id, uint8_t *data, uint8_t len) {
struct canfd_frame frame;
memset(&frame, 0, sizeof(frame));
frame.can_id = can_id;
frame.len = len;
memcpy(frame.data, data, len);
frame.flags = CANFD_BRS; // Enable bit rate switching
int nbytes = write(sock, &frame, sizeof(frame));
if (nbytes != sizeof(frame)) {
perror("CAN FD frame send failed");
return -1;
}
printf("Sent CAN FD frame: ID 0x%08X, data: ", can_id);
for (int i = 0; i < len; i++) {
printf("%02X ", data[i]);
}
printf("\n");
return 0;
}
// Receive CAN messages (supports classic CAN and CAN FD)
void receive_can_messages(int sock) {
struct canfd_frame frame;
int nbytes;
printf("Starting to receive CAN messages (Ctrl+C to stop)...\n");
while (1) {
nbytes = read(sock, &frame, sizeof(frame));
if (nbytes < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
continue;
}
perror("CAN frame read failed");
break;
}
if (nbytes == CAN_MTU) {
// Classic CAN frame
printf("Received CAN frame: ID 0x%08X, DLC %d, data: ",
frame.can_id, frame.len);
}else if (nbytes == CANFD_MTU) {
// CAN FD frame
printf("Received CAN FD frame: ID 0x%08X, DLC %d, data: ",
frame.can_id, frame.len);
}else {
printf("Received frame with unexpected size %d\n", nbytes);
continue;
}
for (int i = 0; i < frame.len; i++) {
printf("%02X ", frame.data[i]);
}
printf("\n");
}
}
int main() {
int s;
struct sockaddr_can addr;
struct ifreq ifr;
// Configure CAN FD interface
if (setup_can_fd_interface(CAN_INTERFACE) < 0) {
return 1;
}
// Create socket
if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
perror("Socket creation failed");
return 1;
}
// Enable CAN FD support
int enable_canfd = 1;
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &enable_canfd, sizeof(enable_canfd)) < 0) {
perror("Failed to enable CAN FD support");
close(s);
return 1;
}
// Specify CAN interface
strcpy(ifr.ifr_name, CAN_INTERFACE);
if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
perror("IOCTL SIOCGIFINDEX failed");
close(s);
return 1;
}
// Bind socket to CAN interface
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
if (bind(s, (struct sockaddr *)&addr, sizeof(addr))< 0) {
perror("Bind failed");
close(s);
return 1;
}
// Send test CAN FD frame (ID 0x001234EF, data 00.11.22.33.44.55.66.77)
uint8_t test_data[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
if (send_can_fd_frame(s, 0x001234EF, test_data, sizeof(test_data)) < 0) {
close(s);
return 1;
}
// Start receiving CAN messages
receive_can_messages(s);
close(s);
return 0;
}
Recopilación: gcc can_ejemplo.c -o can_ejemplo
Prueba de funcionamiento: ./ejemplo_de_can
4. Botones
Botones EC100: Programa interno ocupado, utilizado para reiniciar o restablecer la configuración relacionada con la página web del dispositivo.
Reinicia: Pulsar durante 1 segundo y soltar
Restablecer + reiniciar: Pulsar durante >5 segundos
5. Hardware Watchdog
El hardware watchdog del EC100 está habilitado por defecto y gestionado por el programa interno.
Ciclo de vigilancia: <30 segundos
Nota: Si el programa interno se detiene, debe hacerse cargo manualmente del servicio de alimentación del watchdog; de lo contrario, el dispositivo se reiniciará periódicamente.
6. Puertos de red
Los puertos de red se dividen en puertos WAN y LAN, gestionados por el programa de red interno; la configuración debe realizarse a través de la interfaz web. Para más detalles, consulte:
Esta es una tarjeta de contenido Yuque, haga clic en el enlace para ver: https://iotrouter.yuque.com/zn3vdn/ec/go5fnig7b5xumq79?singleDoc
7. Telefonía móvil
El EC100 soporta comunicación 4G (versión 4G); la identificación del módulo y la marcación son gestionadas por el programa interno, y los usuarios no necesitan preocuparse de esto. Para más detalles, consulte:
Esta es una ficha de contenido de Yueque; haz clic en el enlace para verla: https://iotrouter.yuque.com/zn3vdn/ec/go5fnig7b5xumq79?singleDoc
Aplicaciones informáticas
1. Programa de gestión interna
Para simplificar la experiencia del usuario, el EC100 está equipado con el programa de gestión integrado iotrouter, que se inicia automáticamente al arrancar. El programa de gestión incluye, entre otras, las siguientes funciones:
- Inicialización del dispositivo
- Gestión de redes
- Watchdog
- Control de botones
- Cortafuegos
- Servicio de configuración de dispositivos (puerto 80 por defecto; el puerto de escucha puede cambiarse; archivo: /usr/local/src/iotrouter/web/user-config.js)
- Función de exploración de archivos de usuario (ruta por defecto /home; la ruta puede cambiarse; archivo: /usr/local/src/iotrouter/web/user-config.js)
Nota: Los programas internos deben permanecer activos; de lo contrario, el dispositivo podría no arrancar con normalidad. Si los usuarios deben desactivar los programas de gestión internos, deberán hacerse cargo ellos mismos de los servicios de los programas de gestión mencionados.
2. NeuronEX
El EC100 lleva preinstalado NeuronEX-Lite, que se inicia automáticamente al arrancar y escucha en el puerto 8085. Para más detalles, consulte:
Esta es una tarjeta de contenido Yuque; haga clic en el enlace para verla: https://iotrouter.yuque.com/zn3vdn/ec/hdsb71i79vmfr8wd?singleDoc
- Compruebe el estado del servicio: systemctl status neuronex
- Reinicia el servicio: systemctl restart neuronex
- Parar servicio: systemctl stop neuronex
- Desactivar el inicio del servicio: systemctl disable neuronex
3. Nodo-RED
EC100 tiene incorporado Node-RED, que se inicia automáticamente en el arranque y escucha en el puerto 1880. Para más detalles, consulte:
Esta es una tarjeta de contenido de Yueque. Haga clic en el enlace para ver: https://iotrouter.yuque.com/zn3vdn/ec/hdsb71i79vmfr8wd?singleDoc
- Compruebe el estado del servicio: systemctl status nodo-rojo
- Reinicia el servicio: systemctl restart nodo-red
- Parar servicio: systemctl stop nodo-rojo
- Desactivar el inicio automático del servicio: systemctl disable node-red
4. Programas desarrollados por el usuario
Los programas de usuario son desarrollados libremente por los usuarios y se ejecutan de forma independiente, pero éstos deben gestionar la memoria y el espacio de almacenamiento para evitar anomalías en el sistema. Los programas pueden añadirse al método de arranque automático del sistema:
- /etc/rc.local
- servicio systemd
- /etc/init.d sistema
Nuestra empresa también ofrece servicios de desarrollo de software a medida. Por favor consulte a nuestros comerciales si tiene alguna necesidad.
Quema de imágenes
¿Cuándo se utiliza la grabación de imágenes? Al utilizar el dispositivo, los usuarios pueden borrar accidentalmente archivos del núcleo del sistema, modificar incorrectamente parámetros de configuración del sistema (como entradas críticas del registro) o formatear accidentalmente la partición del sistema, lo que provoca que el sistema no pueda arrancar o funcione de forma anómala. En tales casos, la grabación de la imagen del sistema para el dispositivo correspondiente puede restaurar rápidamente el sistema a su estado normal inicial.
1. Herramientas para quemar
El kit de herramientas de grabación es amplio; póngase en contacto con el servicio de asistencia técnica o con el departamento de ventas para obtenerlo.
Conductor: Conductor
Herramienta: Herramienta de grabación
*.img: Imagen de fábrica

2. Instalación del controlador
Instalar: \DriverDriverInstall.exe

3. Quemando
- Abra \tool\RKDevTool.exe.
- Haga clic en Actualizar Firmware para saltar a la interfaz de grabación.
- Haga clic en Firmware para seleccionar la imagen.

Cortocircuite el watchdog del EC100 (el watchdog debe cortocircuitarse durante el proceso de grabación; el dispositivo se reiniciará indefinidamente).
Mantenga pulsado el botón de descarga para encender el EC100.

Al grabar, aparecerá a continuación “Found One MASKROM Device”, indicando que el dispositivo ha sido reconocido.
Haz clic en “Actualizar” para iniciar la grabación, y el registro de grabación aparecerá en la ventana de registro de la derecha.
La última línea mostrará “Éxito”, indicando que la grabación se ha realizado correctamente.
