新聞中心
PRESS CENTERSSH工具
推薦使用MobaXterm,或者選擇自己習(xí)慣的SSH工具
https://iotrouter.yuque.com/attachments/yuque/0/2025/zip/40387797/1751447985727-10cb8014-e57d-4f95-85f2-722b2f822d6f.zip
串口調(diào)試工具
推薦使用XCOM,或者選擇自己習(xí)慣的串口調(diào)試工具
https://iotrouter.yuque.com/attachments/yuque/0/2025/zip/40387797/1751448098345-cc351ada-aa82-4de7-b0bf-b6a909e637bc.zip
硬件工具
常用的調(diào)試工具有:CAN轉(zhuǎn)USB工具 / 485轉(zhuǎn)USB工具 / 網(wǎng)線等,請自行準(zhǔn)備
交叉編譯工具鏈
https://iotrouter.yuque.com/attachments/yuque/0/2025/tar/40387797/1751447691686-3001e3bf-2f16-43d3-a4d7-55c4705dff97.tar
軟件環(huán)境
軟件 | 版本 |
OS | Ubuntu 20.04.1;部分裁剪 |
NodeJs | v22.16.0 |
Python | python3.8 |
Shell | bash |
GLIBC | 2.31 |
1. 串口
EC100自帶兩路自收發(fā)RS485
硬件接口 | 設(shè)備文件 |
RS485-1 | /dev/ttyS4 |
RS485-2 | /dev/ttyS3 |
注:自收發(fā)RS485,用戶不需要關(guān)心收發(fā)切換,硬件會自動處理
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; // 數(shù)據(jù)位 (5,6,7,8) int stop_bits; // 停止位 (1,2) char parity; // 校驗(yàn)位 (N:無校驗(yàn), O:奇校驗(yàn), E:偶校驗(yàn)) } SerialConfig; int set_serial_attr(int fd, SerialConfig *config) { struct termios tty; if (tcgetattr(fd, &tty) < 0) { perror("tcgetattr"); return -1; } // 設(shè)置波特率 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); // 設(shè)置數(shù)據(jù)位 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; } // 設(shè)置停止位 if (config->stop_bits == 2) { tty.c_cflag |= CSTOPB; } else { tty.c_cflag &= ~CSTOPB; } // 設(shè)置校驗(yàn)位 switch (config->parity) { case 'N': case 'n': tty.c_cflag &= ~PARENB; // 無校驗(yàn) break; case 'O': case 'o': tty.c_cflag |= PARENB; // 奇校驗(yàn) tty.c_cflag |= PARODD; break; case 'E': case 'e': tty.c_cflag |= PARENB; // 偶校驗(yàn) tty.c_cflag &= ~PARODD; break; default: fprintf(stderr, "Unsupported parity, using N\n"); tty.c_cflag &= ~PARENB; } // 其他設(shè)置 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; // 最小讀取字符數(shù) tty.c_cc[VTIME] = 0; // 讀取超時(shí)時(shí)間(單位: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]; // 配置串口參數(shù) SerialConfig config = { .baud_rate = 115200, // 波特率 .data_bits = 8, // 數(shù)據(jù)位 .stop_bits = 1, // 停止位 .parity = 'N' // 校驗(yàn)位 (N:無校驗(yàn), O:奇校驗(yàn), E:偶校驗(yàn)) }; 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); // 無限等待數(shù)據(jù)到達(dá)(移除了超時(shí)設(shè)置) 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); // 回顯數(shù)據(jù) 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測試運(yùn)行: ./rs485_example/dev/ttyS4
2. LED
EC100 總共4個(gè)指示燈,其中2個(gè)可用戶編程控制
硬件接口 | IO索引 | IO編號 | chip組 | 備注 |
POW | / | / | / | 電源指示燈 |
RUN | 39 | GPIO1_A7 | gpiochip1 | 內(nèi)部程序占用;不可編程;運(yùn)行后呈閃爍狀態(tài) |
LED1 | 38 | GPIO1_A6 | gpiochip1 | 用戶可編程 |
LED2 | 36 | GPIO1_A4 | gpiochip1 | 用戶可編程 |
注:IO索引是由IO編號計(jì)算得出
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是否已經(jīng)導(dǎo)出 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 # 設(shè)置GPIO方向?yàn)檩敵?/span> echo "out" > "$GPIO_PATH/direction" # 設(shè)置初始值為低電平 echo 0 > "$GPIO_PATH/value" echo "Toggling GPIO $GPIO every 1 second. Press Ctrl+C to stop." # 開始循環(huán)翻轉(zhuǎn) while true; do echo 1 > "$GPIO_PATH/value" sleep 1 echo 0 > "$GPIO_PATH/value" sleep 1 done |
測試運(yùn)行: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 // 周期時(shí)間(微秒) int main() { struct gpiohandle_request req; struct gpiohandle_data data; int fd, ret; // 打開GPIO字符設(shè)備 fd = open(GPIO_CHIP, O_RDWR); if (fd < 0) { perror("無法打開GPIO設(shè)備"); return EXIT_FAILURE; } // 設(shè)置GPIO請求 memset(&req, 0, sizeof(req)); req.lineoffsets[0] = GPIO_LINE; // GPIO線號 req.flags = GPIOHANDLE_REQUEST_OUTPUT; // 設(shè)置為輸出模式 req.default_values[0] = 0; // 初始值設(shè)為低電平 strcpy(req.consumer_label, "gpio-toggle"); // 消費(fèi)者標(biāo)簽 req.lines = 1; // 要控制的GPIO線數(shù)量 // 請求GPIO控制 ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req); if (ret < 0) { perror("無法獲取GPIO控制權(quán)"); close(fd); return EXIT_FAILURE; } // 關(guān)閉GPIO字符設(shè)備(我們已經(jīng)獲得了線句柄) 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("設(shè)置GPIO高電平失敗"); break; } usleep(PERIOD_US/2); data.values[0] = 0; // 低電平 ret = ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data); if (ret < 0) { perror("設(shè)置GPIO低電平失敗"); break; } usleep(PERIOD_US/2); } // 關(guān)閉GPIO線句柄 close(req.fd); return EXIT_SUCCESS; } |
編譯: gcc led_example.c -o led_example
測試運(yùn)行: ./led_example
3. CAN FD
EC100 有兩路高速CAN接口
硬件接口 | 網(wǎng)絡(luò)接口 |
CAN1 [H1 L1] | can0 |
CAN2 [H2 L2] | can1 |
3.1. 快速測試
將can0和can1互接;命令行測試
#首先初始化 can0 與 can1,波特率選擇 500k,使用 canfd,然后選擇 can0 接受數(shù)據(jù),can1 發(fā)送數(shù)據(jù) 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;
// 關(guān)閉接口 snprintf(cmd, sizeof(cmd), "ip link set %s down", ifname); system(cmd);
// 設(shè)置CAN FD參數(shù) 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; }
// 設(shè)置TX隊(duì)列長度 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; } // 發(fā)送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幀(支持經(jīng)典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) { // 經(jīng)典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; }
// 創(chuàng)建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; }
// 發(fā)送測試CAN FD幀 (ID 0x001234EF, 數(shù)據(jù) 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
測試運(yùn)行: ./can_example
4. 按鍵
EC100按鍵:內(nèi)部程序占用,用于重啟或者復(fù)位設(shè)備的web網(wǎng)頁相關(guān)配置
重啟:按下1s抬起
復(fù)位+重啟:按下>5s
5. 硬件看門狗
EC100默認(rèn)啟用硬件看門狗,由內(nèi)部程序管理喂狗
喂狗周期:<30s
注:如果停止內(nèi)部程序,必須自行接管看門狗喂狗服務(wù),否則設(shè)備會定期重啟
6. 網(wǎng)口
網(wǎng)口分為WAN+LAN口,由內(nèi)部網(wǎng)絡(luò)程序管理;需在web網(wǎng)頁配置,詳情請見:
此處為語雀內(nèi)容卡片,點(diǎn)擊鏈接查看:https://iotrouter.yuque.com/zn3vdn/ec/go5fnig7b5xumq79?singleDoc
7. 蜂窩無線
EC100支持4G通信(4G版本),模組的識別+撥號由內(nèi)部程序管理,用戶無需關(guān)心;詳情請見:
此處為語雀內(nèi)容卡片,點(diǎn)擊鏈接查看:https://iotrouter.yuque.com/zn3vdn/ec/go5fnig7b5xumq79?singleDoc
1. 內(nèi)部管理程序
EC100為了簡化用戶使用,內(nèi)置管理程序iotrouter,開機(jī)自啟動。管理程序包括但不限于下列功能:
設(shè)備初始化
網(wǎng)絡(luò)管理
看門狗
按鍵監(jiān)聽
防火墻
設(shè)備配置服務(wù)(默認(rèn)80端口,監(jiān)聽端口可更改;文件:/usr/local/src/iotrouter/web/user-config.js)
用戶文件瀏覽功能(默認(rèn)/home路徑;路徑可更改;文件:/usr/local/src/iotrouter/web/user-config.js)
注:內(nèi)部程序必須?;?,否則會造成設(shè)備開機(jī)運(yùn)行異常。如果用戶一定需要關(guān)閉內(nèi)部管理程序,必須自行接管上述管理程序服務(wù)。
2. NeuronEX
EC100內(nèi)置NeuronEX-Lite,服務(wù)開機(jī)自啟動,監(jiān)聽端口8085;介紹詳見:
此處為語雀內(nèi)容卡片,點(diǎn)擊鏈接查看:https://iotrouter.yuque.com/zn3vdn/ec/hdsb71i79vmfr8wd?singleDoc
查看服務(wù)狀態(tài):systemctl status neuronex
重啟服務(wù):systemctl restart neuronex
停止服務(wù):systemctl stop neuronex
關(guān)閉服務(wù)自啟:systemctl disable neuronex
3. Node-Red
EC100內(nèi)置Node-Red,服務(wù)開機(jī)自啟動,監(jiān)聽端口1880;介紹詳見:
此處為語雀內(nèi)容卡片,點(diǎn)擊鏈接查看:https://iotrouter.yuque.com/zn3vdn/ec/hdsb71i79vmfr8wd?singleDoc
查看服務(wù)狀態(tài):systemctl status node-red
重啟服務(wù):systemctl restart node-red
停止服務(wù):systemctl stop node-red
關(guān)閉服務(wù)自啟:systemctl disable node-red
4. 用戶自開發(fā)程序
用戶程序由用戶自由開發(fā),用戶程序獨(dú)立運(yùn)行,但須注意內(nèi)存和空間管理避免導(dǎo)致系統(tǒng)異常。軟件可加入系統(tǒng)自啟動方式:
/etc/rc.local
systemd服務(wù)
/etc/init.d系統(tǒng)
我司也提供軟件開發(fā)定制服務(wù);如有需求請咨詢銷售人員
什么時(shí)候會使用到鏡像燒錄:用戶在使用設(shè)備時(shí),可能因誤刪系統(tǒng)核心文件、錯(cuò)誤修改系統(tǒng)配置參數(shù)(如注冊表關(guān)鍵項(xiàng)),或誤執(zhí)行格式化系統(tǒng)分區(qū)等操作,導(dǎo)致系統(tǒng)無法啟動、功能異常。此時(shí),燒錄對應(yīng)設(shè)備的系統(tǒng)鏡像,能快速將系統(tǒng)恢復(fù)到初始正常狀態(tài)。
1. 燒錄工具
燒錄工具包較大請聯(lián)系技術(shù)支持或銷售獲取
Driver:驅(qū)動
tool:燒錄工具
*.img:出廠鏡像
2. 驅(qū)動安裝
安裝\DriverDriverInstall.exe
3. 燒錄
打開\tool\RKDevTool.exe
點(diǎn)擊Upgrade Firmware跳轉(zhuǎn)到燒錄界面
點(diǎn)擊Firmware選擇鏡像
短接EC100的看門狗(燒錄過程必須短接看門狗否則設(shè)備會無限重啟)
按住下載按鈕給EC100上電
燒錄下方會出現(xiàn)Found One MASKROM Device表示已經(jīng)識別到設(shè)備
點(diǎn)擊Upgrade開始燒錄,右側(cè)日志窗口出現(xiàn)燒錄日志
最后一行出現(xiàn)Success表示燒錄成功