Guia de desenvolvimento do computador industrial EC100 ARM - IOTROUTER
Animação de pairar

Guia de desenvolvimento do computador industrial EC100 ARM

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, &amp;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

Computador Industrial EC100 ARM - Guia de Desenvolvimento

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

2056697292

2. Instalação do controlador

Instalar: \DriverDriverInstall.exe

Instalação do controlador

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.

Queimadura

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.

EC100xinpiantu

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.

Atualização