新闻中心
PRESS CENTERSSH工具
推荐使用MobaXterm,或者选择自己习惯的SSH工具
https://iotrouter.yuque.com/attachments/yuque/0/2025/zip/40387797/1751447985727-10cb8014-e57d-4f95-85f2-722b2f822d6f.zip
串口调试工具
推荐使用XCOM,或者选择自己习惯的串口调试工具
https://iotrouter.yuque.com/attachments/yuque/0/2025/zip/40387797/1751448098345-cc351ada-aa82-4de7-b0bf-b6a909e637bc.zip
硬件工具
常用的调试工具有:CAN转USB工具 / 485转USB工具 / 网线等,请自行准备
交叉编译工具链
https://iotrouter.yuque.com/attachments/yuque/0/2025/tar/40387797/1751447691686-3001e3bf-2f16-43d3-a4d7-55c4705dff97.tar
软件环境
软件 | 版本 |
OS | Ubuntu 20.04.1;部分裁剪 |
NodeJs | v22.16.0 |
Python | python3.8 |
Shell | bash |
GLIBC | 2.31 |
1. 串口
EC100自带两路自收发RS485
硬件接口 | 设备文件 |
RS485-1 | /dev/ttyS4 |
RS485-2 | /dev/ttyS3 |
注:自收发RS485,用户不需要关心收发切换,硬件会自动处理
1.1. 快速测试
使用minicom工具测试,具体使用方法可以百度或者咨询DeepSeek
1.2. 代码测试样例
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <termios.h> #include <errno.h> #include <sys/select.h> #define BUFFER_SIZE 256 typedef struct { int baud_rate; // 波特率 int data_bits; // 数据位 (5,6,7,8) int stop_bits; // 停止位 (1,2) char parity; // 校验位 (N:无校验, O:奇校验, E:偶校验) } SerialConfig; int set_serial_attr(int fd, SerialConfig *config) { struct termios tty; if (tcgetattr(fd, &tty) < 0) { perror("tcgetattr"); return -1; } // 设置波特率 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; default: fprintf(stderr, "Unsupported baud rate, using 115200\n"); speed = B115200; } cfsetispeed(&tty, speed); cfsetospeed(&tty, speed); // 设置数据位 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; default: fprintf(stderr, "Unsupported data bits, using 8\n"); tty.c_cflag |= CS8; } // 设置停止位 if (config->stop_bits == 2) { tty.c_cflag |= CSTOPB; } else { tty.c_cflag &= ~CSTOPB; } // 设置校验位 switch (config->parity) { case 'N': case 'n': tty.c_cflag &= ~PARENB; // 无校验 break; case 'O': case 'o': tty.c_cflag |= PARENB; // 奇校验 tty.c_cflag |= PARODD; break; case 'E': case 'e': tty.c_cflag |= PARENB; // 偶校验 tty.c_cflag &= ~PARODD; break; default: fprintf(stderr, "Unsupported parity, using N\n"); tty.c_cflag &= ~PARENB; } // 其他设置 tty.c_cflag |= (CLOCAL | CREAD); // 启用接收和本地模式 tty.c_cflag &= ~CRTSCTS; // 无硬件流控 tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 原始输入模式 tty.c_oflag &= ~OPOST; // 原始输出模式 tty.c_cc[VMIN] = 1; // 最小读取字符数 tty.c_cc[VTIME] = 0; // 读取超时时间(单位:0.1秒) if (tcsetattr(fd, TCSANOW, &tty) < 0) { perror("tcsetattr"); return -1; } return 0; } int main(int argc, char *argv[]) { int fd; char *portname; if (argc < 2) { fprintf(stderr, "Usage: %s <serial_port>\n", argv[0]); exit(EXIT_FAILURE); } portname = argv[1]; // 配置串口参数 SerialConfig config = { .baud_rate = 115200, // 波特率 .data_bits = 8, // 数据位 .stop_bits = 1, // 停止位 .parity = 'N' // 校验位 (N:无校验, O:奇校验, E:偶校验) }; fd = open(portname, 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("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; while (1) { FD_ZERO(&readfds); FD_SET(fd, &readfds); // 无限等待数据到达(移除了超时设置) if (select(fd + 1, &readfds, NULL, NULL, NULL) < 0) { perror("select"); break; } if (FD_ISSET(fd, &readfds)) { n = read(fd, buffer, BUFFER_SIZE - 1); if (n > 0) { buffer[n] = '\0'; printf("Received %d bytes: %s\n", n, buffer); // 回显数据 write(fd, buffer, n); } else if (n < 0) { if (errno != EAGAIN && errno != EWOULDBLOCK) { perror("read"); break; } } } } close(fd); return 0; } |
编译: gcc rs485_example.c -o rs485_example
RS485-1测试运行: ./rs485_example/dev/ttyS4
2. LED
EC100 总共4个指示灯,其中2个可用户编程控制
硬件接口 | IO索引 | IO编号 | chip组 | 备注 |
POW | / | / | / | 电源指示灯 |
RUN | 39 | GPIO1_A7 | gpiochip1 | 内部程序占用;不可编程;运行后呈闪烁状态 |
LED1 | 38 | GPIO1_A6 | gpiochip1 | 用户可编程 |
LED2 | 36 | GPIO1_A4 | gpiochip1 | 用户可编程 |
注:IO索引是由IO编号计算得出
2.1. 快速测试
#!/bin/bash # 检查是否传入了GPIO索引 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" # 判断GPIO是否已经导出 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 # 设置GPIO方向为输出 echo "out" > "$GPIO_PATH/direction" # 设置初始值为低电平 echo 0 > "$GPIO_PATH/value" echo "Toggling GPIO $GPIO every 1 second. Press Ctrl+C to stop." # 开始循环翻转 while true; do echo 1 > "$GPIO_PATH/value" sleep 1 echo 0 > "$GPIO_PATH/value" sleep 1 done |
测试运行:bash led_example.sh 38
2.2. 代码测试样例
#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" // 使用gpiochip1 #define GPIO_LINE 38%32 // 要控制的GPIO在chip1上的偏移 #define PERIOD_US 500000 // 周期时间(微秒) int main() { struct gpiohandle_request req; struct gpiohandle_data data; int fd, ret; // 打开GPIO字符设备 fd = open(GPIO_CHIP, O_RDWR); if (fd < 0) { perror("无法打开GPIO设备"); return EXIT_FAILURE; } // 设置GPIO请求 memset(&req, 0, sizeof(req)); req.lineoffsets[0] = GPIO_LINE; // GPIO线号 req.flags = GPIOHANDLE_REQUEST_OUTPUT; // 设置为输出模式 req.default_values[0] = 0; // 初始值设为低电平 strcpy(req.consumer_label, "gpio-toggle"); // 消费者标签 req.lines = 1; // 要控制的GPIO线数量 // 请求GPIO控制 ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req); if (ret < 0) { perror("无法获取GPIO控制权"); close(fd); return EXIT_FAILURE; } // 关闭GPIO字符设备(我们已经获得了线句柄) close(fd); printf("正在控制GPIO chip1 line %d,周期为%.1f秒...\n", GPIO_LINE, PERIOD_US/1000000.0); // 周期切换GPIO电平 while (1) { data.values[0] = 1; // 高电平 ret = ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data); if (ret < 0) { perror("设置GPIO高电平失败"); break; } usleep(PERIOD_US/2); data.values[0] = 0; // 低电平 ret = ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data); if (ret < 0) { perror("设置GPIO低电平失败"); break; } usleep(PERIOD_US/2); } // 关闭GPIO线句柄 close(req.fd); return EXIT_SUCCESS; } |
编译: gcc led_example.c -o led_example
测试运行: ./led_example
3. CAN FD
EC100 有两路高速CAN接口
硬件接口 | 网络接口 |
CAN1 [H1 L1] | can0 |
CAN2 [H2 L2] | can1 |
3.1. 快速测试
将can0和can1互接;命令行测试
#首先初始化 can0 与 can1,波特率选择 500k,使用 canfd,然后选择 can0 接受数据,can1 发送数据 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. 代码测试样例
#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 // 配置CAN FD接口 int setup_can_fd_interface(const char *ifname) { char cmd[512]; FILE *fp;
// 关闭接口 snprintf(cmd, sizeof(cmd), "ip link set %s down", ifname); system(cmd);
// 设置CAN FD参数 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; }
// 设置TX队列长度 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);
// 启用接口 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; } // 发送CAN FD帧 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; // 启用比特率切换
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; } // 接收CAN帧(支持经典CAN和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) { // 经典CAN帧 printf("Received CAN frame: ID 0x%08X, DLC %d, data: ", frame.can_id, frame.len); } else if (nbytes == CANFD_MTU) { // CAN FD帧 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;
// 配置CAN FD接口 if (setup_can_fd_interface(CAN_INTERFACE) < 0) { return 1; }
// 创建socket if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) { perror("Socket creation failed"); return 1; }
// 启用CAN FD支持 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; }
// 指定CAN接口 strcpy(ifr.ifr_name, CAN_INTERFACE); if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { perror("IOCTL SIOCGIFINDEX failed"); close(s); return 1; }
// 绑定socket到CAN接口 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; }
// 发送测试CAN FD帧 (ID 0x001234EF, 数据 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; }
// 开始接收CAN消息 receive_can_messages(s);
close(s); return 0; } |
编译: gcc can_example.c -o can_example
测试运行: ./can_example
4. 按键
EC100按键:内部程序占用,用于重启或者复位设备的web网页相关配置
重启:按下1s抬起
复位+重启:按下>5s
5. 硬件看门狗
EC100默认启用硬件看门狗,由内部程序管理喂狗
喂狗周期:<30s
注:如果停止内部程序,必须自行接管看门狗喂狗服务,否则设备会定期重启
6. 网口
网口分为WAN+LAN口,由内部网络程序管理;需在web网页配置,详情请见:
此处为语雀内容卡片,点击链接查看:https://iotrouter.yuque.com/zn3vdn/ec/go5fnig7b5xumq79?singleDoc
7. 蜂窝无线
EC100支持4G通信(4G版本),模组的识别+拨号由内部程序管理,用户无需关心;详情请见:
此处为语雀内容卡片,点击链接查看:https://iotrouter.yuque.com/zn3vdn/ec/go5fnig7b5xumq79?singleDoc
1. 内部管理程序
EC100为了简化用户使用,内置管理程序iotrouter,开机自启动。管理程序包括但不限于下列功能:
设备初始化
网络管理
看门狗
按键监听
防火墙
设备配置服务(默认80端口,监听端口可更改;文件:/usr/local/src/iotrouter/web/user-config.js)
用户文件浏览功能(默认/home路径;路径可更改;文件:/usr/local/src/iotrouter/web/user-config.js)
注:内部程序必须保活,否则会造成设备开机运行异常。如果用户一定需要关闭内部管理程序,必须自行接管上述管理程序服务。
2. NeuronEX
EC100内置NeuronEX-Lite,服务开机自启动,监听端口8085;介绍详见:
此处为语雀内容卡片,点击链接查看:https://iotrouter.yuque.com/zn3vdn/ec/hdsb71i79vmfr8wd?singleDoc
查看服务状态:systemctl status neuronex
重启服务:systemctl restart neuronex
停止服务:systemctl stop neuronex
关闭服务自启:systemctl disable neuronex
3. Node-Red
EC100内置Node-Red,服务开机自启动,监听端口1880;介绍详见:
此处为语雀内容卡片,点击链接查看:https://iotrouter.yuque.com/zn3vdn/ec/hdsb71i79vmfr8wd?singleDoc
查看服务状态:systemctl status node-red
重启服务:systemctl restart node-red
停止服务:systemctl stop node-red
关闭服务自启:systemctl disable node-red
4. 用户自开发程序
用户程序由用户自由开发,用户程序独立运行,但须注意内存和空间管理避免导致系统异常。软件可加入系统自启动方式:
/etc/rc.local
systemd服务
/etc/init.d系统
我司也提供软件开发定制服务;如有需求请咨询销售人员
什么时候会使用到镜像烧录:用户在使用设备时,可能因误删系统核心文件、错误修改系统配置参数(如注册表关键项),或误执行格式化系统分区等操作,导致系统无法启动、功能异常。此时,烧录对应设备的系统镜像,能快速将系统恢复到初始正常状态。
1. 烧录工具
烧录工具包较大请联系技术支持或销售获取
Driver:驱动
tool:烧录工具
*.img:出厂镜像
2. 驱动安装
安装\DriverDriverInstall.exe
3. 烧录
打开\tool\RKDevTool.exe
点击Upgrade Firmware跳转到烧录界面
点击Firmware选择镜像
短接EC100的看门狗(烧录过程必须短接看门狗否则设备会无限重启)
按住下载按钮给EC100上电
烧录下方会出现Found One MASKROM Device表示已经识别到设备
点击Upgrade开始烧录,右侧日志窗口出现烧录日志
最后一行出现Success表示烧录成功