Guia de desenvolvimento do computador industrial EC100 ARM - O EC100 vem pré-instalado com o Node-RED 4.0 e o NeuronEX-Lite, o que o torna pronto para o desenvolvimento de aplicações de ponta.
O Node-RED fornece uma interface de programação visual, do tipo arrastar e soltar, para a construção rápida de lógica comercial, enquanto o NeuronEX-Lite serve como uma plataforma de computação de borda leve que suporta conetividade de dispositivos de nível de milissegundos por meio de compatibilidade multiprotocolo. Esta combinação simplifica muito o desenvolvimento e permite a rápida implementação de soluções IoT industriais.
Preparação do desenvolvimento
1. Ferramentas SSH
Recomendamos a utilização do MobaXterm, ou pode escolher o seu Ferramenta SSH.
2. Ferramenta de depuração da porta série
Recomendamos que utilize o XCOM ou escolha o seu ferramenta de depuração da porta de série.
3. Ferramentas de hardware
As ferramentas de depuração comuns incluem: Ferramentas CAN-para-USB / ferramentas 485-para-USB/cabos de rede, etc. É favor prepará-las por sua conta.
4. Cadeia de ferramentas de compilação cruzada
Cadeia de ferramentas de compilação cruzada
Ambiente de software
SO: Embedded Linux 20.04.1; parcialmente cortado
NodeJs: v22.16.0
Python: python3.8
Concha: bash
GLIBC: 2.31
Interfaces periféricas
1. Porta de série
O EC100 é fornecido com dois transceptores RS485 incorporados.
| Interface de hardware | Ficheiro do dispositivo |
|---|---|
| RS485-1 | /dev/ttyS4 |
| RS485-2 | /dev/ttyS3 |
Nota: Com a transmissão e receção RS485, os utilizadores não precisam de se preocupar em alternar entre a transmissão e a receção, uma vez que o hardware tratará disso automaticamente.
1.1. Teste rápido
Utilizar a ferramenta minicom para testar. Para obter instruções de utilização específicas, pesquise no Baidu ou consulte o DeepSeek.
1.2. Exemplo de teste de código
#include
#include
#include
#include
#include
#include
#include
#include
#define BUFFER_SIZE 256
typedef struct {
int baud_rate; // Taxa de baud
int data_bits; // Bits de dados (5,6,7,8)
int stop_bits; // Bits de paragem (1,2)
char parity; // Paridade (N: Nenhuma, O: Ímpar, E: Par)
} SerialConfig;
int set_serial_attr(int fd, SerialConfig *config)
{
struct termios tty;
if (tcgetattr(fd, &tty) < 0) { perror("tcgetattr"); return -1; } // Set baud rate speed_t speed;
switch (config->baud_rate) {
case 9600: speed = B9600; break;
case 19200: speed = B19200; break;
case 38400: speed = B38400; break;
case 57600: speed = B57600; break;
case 115200: speed = B115200; break;
por defeito:
fprintf(stderr, "Unsupported baud rate, using 115200\n");
velocidade = B115200;
}
cfsetispeed(&tty, speed);
cfsetospeed(&tty, speed);
// Definir dados
bits tty.c_cflag &= ~CSIZE;
switch (config->data_bits) {
case 5: tty.c_cflag |= CS5; break;
case 6: tty.c_cflag |= CS6; break;
case 7: tty.c_cflag |= CS7; break;
case 8: tty.c_cflag |= CS8; break;
por defeito:
fprintf(stderr, "Unsupported data bits, using 8\n");
tty.c_cflag |= CS8;
}
// Definir bits de paragem
se (config->stop_bits == 2) {
tty.c_cflag |= CSTOPB; } else {
tty.c_cflag &= ~CSTOPB; }
// Definir paridade
switch (config->parity) {
case 'N':
case 'n': tty.c_cflag &= ~PARENB; // No parity
pausa;
case 'O':
case 'o': tty.c_cflag |= PARENB; // Odd parity
tty.c_cflag |= PARODD; break;
case 'E':
case 'e': tty.c_cflag |= PARENB; // Even parity
tty.c_cflag &= ~PARODD; break;
por defeito:
fprintf(stderr, "Unsupported parity, using N\n");
tty.c_cflag &= ~PARENB;
}
// Outras definições
tty.c_cflag |= (CLOCAL | CREAD); // Ativar o recetor e o modo local
tty.c_cflag &= ~CRTSCTS; // Desativar controlo de fluxo de hardware
tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // Modo de entrada bruta
tty.c_oflag &= ~OPOST; // Modo de saída bruta
tty.c_cc[VMIN] = 1; // Número mínimo de caracteres a ler
tty.c_cc[VTIME] = 0; // Tempo limite de leitura (unidade: 0,1s)
se (tcsetattr(fd, TCSANOW, &tty) < 0) {
perror("tcsetattr");
return -1; }
retorno 0;
}
int main(int argc, char *argv[]) {
int fd;
char *nome do porto;
se (argc < 2) {
fprintf(stderr, "Usage: %s <serial_port>\n", argv[0]);
exit(EXIT_FAILURE);
}
portname = argv[1]; // Configuração da porta serial
SerialConfig config = { .baud_rate = 115200, // Taxa de transmissão
.data_bits = 8, // Bits de dados
.stop_bits = 1, // Bits de paragem
.parity = 'N' // Parity (N: None, O: Odd, E: Even)
};
fd = open(nome da porta, O_RDWR | O_NOCTTY | O_NONBLOCK);
se (fd < 0) {
perror("open");
exit(EXIT_FAILURE);
}
se (set_serial_attr(fd, &config)) {
close(fd);
exit(EXIT_FAILURE);
}
printf("Serial port echo test running on %s\n", portname);
printf("Configuration: %d baud, %d data bits, %d stop bit, %c parity\n", config.baud_rate, config.data_bits, config.stop_bits, config.parity);
printf("Press Ctrl+C to exit.\n");
fd_set readfds;
char buffer[BUFFER_SIZE];
int n;
enquanto (1) {
FD_ZERO(&readfds);
FD_SET(fd, &readfds); // Espera indefinidamente pelos dados de entrada (sem tempo limite)
se (select(fd + 1, &readfds, NULL, NULL, NULL) < 0) {
perror("select");
break; }
se (FD_ISSET(fd, &readfds)) {
n = read(fd, buffer, BUFFER_SIZE - 1);
se (n > 0) {
buffer[n] = '\0';
printf("Received %d bytes: %s\n", n, buffer); // Echo data back
write(fd, buffer, n); } else if (n < 0) {
se (errno != EAGAIN && errno != EWOULDBLOCK) {
perror("read");
pausa;
}
}
}
}
close(fd);
retorno 0;
}
Compilar: gcc rs485_exemplo.c -o rs485_exemplo
Teste de funcionamento do RS485-1: ./rs485_example/dev/ttyS4
2. LED
O EC100 tem um total de 4 luzes indicadoras, 2 das quais podem ser programadas pelo utilizador.
| Interface de hardware | Índice IO | Número IO | Grupo Chip | Notas |
|---|---|---|---|---|
| POW | / | / | / | LED indicador de alimentação. |
| CORRER | 39 | GPIO1_A7 | gpiochip1 | Reservado pelo firmware interno; não programável pelo utilizador; pisca durante o funcionamento normal. |
| LED1 | 38 | GPIO1_A6 | gpiochip1 | Programável pelo utilizador. |
| LED2 | 36 | GPIO1_A4 | gpiochip1 | Programável pelo utilizador. |
Nota: O índice IO é calculado com base no número IO.
2.1. Teste rápido
#!/bin/bash
# Check if a GPIO index is provided
if [ -z "$1" ]; then
echo "Usage: $0 <gpio_number>"
exit 1
fi
GPIO=$1
GPIO_PATH="/sys/class/gpio/gpio$GPIO"
EXPORT_PATH="/sys/class/gpio/export"
# Check if the GPIO is already exported
if [ ! -d "$GPIO_PATH" ]; then
echo "Exporting GPIO $GPIO..."
echo "$GPIO" > "$EXPORT_PATH"
if [ $? -ne 0 ]; then
echo "Failed to export GPIO $GPIO. Check permissions or if it's in use."
exit 1
fi
else
echo "GPIO $GPIO is already exported."
fi
# Set GPIO direction to output
echo "out" > "$GPIO_PATH/direction"
# Set the initial value to low
echo 0 > "$GPIO_PATH/value"
echo "Toggling GPIO $GPIO every 1 second. Press Ctrl+C to stop."
# Start toggle loop
while true; do
echo 1 >"$GPIO_PATH/value"
sleep 1
echo 0 >"$GPIO_PATH/value"
sleep 1
done
Teste de funcionamento: bash led_exemplo.sh 38
2.2. Exemplo de teste 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_exemplo.c -o led_exemplo
Teste de funcionamento: ./exemplo_led
3. CAN FD
O EC100 tem duas interfaces CAN de alta velocidade
| Interface de hardware | Interface de rede |
|---|---|
| CAN1 [H1 L1] | can0 |
| CAN2 [H2 L2] | can1 |

3.1. Teste rápido
Ligar can0 e can1, teste da linha de comando:
#Initialize can0 and can1 first, select baud rate 500k, use canfd, then select can0 to receive data and can1 to send data
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. Exemplo de teste 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;
}
Compilação: gcc can_exemplo.c -o can_exemplo
Teste de funcionamento: ./exemplo_de_can
4. Botões
Botões EC100: Programa interno ocupado, utilizado para reiniciar ou repor a configuração relacionada com a página Web do dispositivo
Reiniciar: Premir durante 1 segundo e soltar
Repor + reiniciar: Premir durante >5 segundos
5. Cão de guarda do hardware
O watchdog de hardware do EC100 é ativado por defeito e gerido pelo programa interno.
Ciclo de vigilância: <30 segundos
Nota: Se o programa interno for interrompido, é necessário assumir manualmente o serviço de alimentação do watchdog; caso contrário, o dispositivo será reiniciado periodicamente.
6. Portas de rede
As portas de rede estão divididas em portas WAN e LAN, geridas pelo programa de rede interno; a configuração deve ser efectuada através da interface Web. Para obter detalhes, consulte:
Este é um cartão de conteúdo Yuque, clique na ligação para o visualizar: https://iotrouter.yuque.com/zn3vdn/ec/go5fnig7b5xumq79?singleDoc
7. Telemóveis sem fios
O EC100 suporta comunicação 4G (versão 4G); a identificação do módulo e a marcação são geridas pelo programa interno e os utilizadores não precisam de se preocupar com isso. Para mais pormenores, consulte:
Este é um cartão de conteúdo de Yueque; clique no link para ver: https://iotrouter.yuque.com/zn3vdn/ec/go5fnig7b5xumq79?singleDoc
Aplicações de software
1. Programa de gestão interna
Para simplificar a experiência do utilizador, o EC100 está equipado com o programa de gestão integrado iotrouter, que é iniciado automaticamente no arranque. O programa de gestão inclui, mas não se limita a, as seguintes funções:
- Inicialização do dispositivo
- Gestão de redes
- Cão de guarda
- Monitorização de botões
- Firewall
- Serviço de configuração do dispositivo (porta predefinida 80; a porta de escuta pode ser alterada; ficheiro: /usr/local/src/iotrouter/web/user-config.js)
- Função de navegação nos ficheiros do utilizador (caminho predefinido /home; o caminho pode ser alterado; ficheiro: /usr/local/src/iotrouter/web/user-config.js)
Nota: Os programas internos devem permanecer activos; caso contrário, o dispositivo pode não arrancar normalmente. Se os utilizadores tiverem de desativar os programas de gestão interna, devem assumir eles próprios os serviços dos programas de gestão acima mencionados.
2. NeuronEX
O EC100 vem pré-instalado com o NeuronEX-Lite, que se inicia automaticamente no arranque e escuta na porta 8085. Para mais pormenores, consulte:
Este é um cartão de conteúdo Yuque; clique na ligação para ver: https://iotrouter.yuque.com/zn3vdn/ec/hdsb71i79vmfr8wd?singleDoc
- Verificar o estado do serviço: systemctl status neuronex
- Reiniciar o serviço: systemctl restart neuronex
- Parar o serviço: systemctl stop neuronex
- Desativar o arranque do serviço: systemctl disable neuronex
3. Nó-RED
EC100 tem o Node-RED embutido, que inicia automaticamente na inicialização e escuta na porta 1880. Para mais detalhes, veja:
Este é um cartão de conteúdo Yueque. Clique no link para ver: https://iotrouter.yuque.com/zn3vdn/ec/hdsb71i79vmfr8wd?singleDoc
- Verificar o estado do serviço: systemctl status node-red
- Reiniciar o serviço: systemctl restart node-red
- Parar o serviço: systemctl stop node-red
- Desativar o arranque automático do serviço: systemctl disable node-red
4. Programas desenvolvidos pelo utilizador
Os programas de utilizador são desenvolvidos livremente pelos utilizadores e executados de forma independente, mas os utilizadores devem gerir a memória e o espaço de armazenamento para evitar anomalias no sistema. O software pode ser adicionado ao método de arranque automático do sistema:
- /etc/rc.local
- serviço systemd
- /etc/init.d sistema
A nossa empresa também presta serviços de desenvolvimento de software personalizado. Por favor consultar o nosso pessoal comercial se tiver alguma necessidade.
Queima de imagem
Quando é que a gravação de imagens é utilizada? Ao utilizar o dispositivo, os utilizadores podem eliminar acidentalmente os ficheiros principais do sistema, modificar incorretamente os parâmetros de configuração do sistema (tais como entradas de registo críticas) ou formatar acidentalmente a partição do sistema, o que faz com que o sistema não consiga arrancar ou funcione de forma anormal. Nesses casos, gravar a imagem do sistema para o dispositivo correspondente pode restaurar rapidamente o sistema para o seu estado normal inicial.
1. Ferramentas de queima
O kit de ferramentas de gravação é grande; contacte o apoio técnico ou as vendas para o obter.
Driver: Driver
Tool: Burning tool
*.img: Factory image

2. Instalação do controlador
Instalar: \DriverDriverInstall.exe

3. Queimadura
- Abrir \tool\RKDevTool.exe.
- Clique em Upgrade Firmware para saltar para a interface de gravação.
- Clique em Firmware para selecionar a imagem.

Short-circuit the watchdog of EC100 (the watchdog must be short-circuited during the burning process; the device will restart indefinitely).
Prima e mantenha premido o botão de transferência para ligar o EC100.

Ao gravar, aparece a mensagem “Found One MASKROM Device”, indicando que o dispositivo foi reconhecido.
Clique em “Upgrade” (Atualizar) para iniciar a gravação e o registo de gravação aparecerá na janela de registo à direita.
A última linha mostrará “Success” (Sucesso), indicando que a gravação foi bem sucedida.
