核心目标:深化嵌入式 Linux 实用技能,聚焦系统优化(内核裁剪 + 根文件系统精简)、工业级 Modbus TCP 协议实战、项目部署自动化(Shell 脚本 + Systemd),打造 “工业级 Modbus TCP 网关” 完整项目 —— 解决实际工作中 “系统资源占用高、工业协议适配难、部署效率低” 的痛点,让嵌入式 Linux 开发从 “能跑” 升级为 “稳定、高效、可量产”,完全贴合工业网关、边缘计算节点的工作需求。
一、核心定位:为什么是 “系统优化 + 工业协议 + 部署自动化”?
前 29 天完成了嵌入式 Linux 入门、应用与驱动开发,但实际工作中,嵌入式 Linux 设备(如工业网关)面临三个核心问题:
- 资源有限:嵌入式硬件 RAM/Flash 通常较小(如 64MB RAM+128MB Flash),默认 Linux 系统占用过高,需裁剪优化;
- 协议适配:工业场景中,Modbus TCP 是 Linux 网关的标配协议(比 RTU 更适合以太网组网),必须掌握其在 Linux 下的实战;
- 部署低效:手动拷贝应用、驱动,开机手动启动,批量部署时耗时且易出错,需自动化脚本 + 服务管理。
第 30 天的核心价值:掌握 “系统瘦身→工业协议适配→自动化部署” 的完整工作流,实现 Linux 嵌入式项目的工业级落地。
二、技术拆解:三大核心技能实战(100 分钟)
(一)嵌入式 Linux 系统优化:内核裁剪 + 根文件系统精简(35 分钟)
嵌入式 Linux 默认内核和根文件系统包含大量无用功能(如 PC 端驱动、图形化组件),优化后可大幅降低资源占用(RAM 从 50MB→20MB,Flash 从 100MB→30MB),提升启动速度(从 30 秒→8 秒)。
1. 内核裁剪(基于 Buildroot+Linux 内核配置)
利用 Buildroot 配置 Linux 内核,裁剪无用模块和驱动:
bash
# 1. 进入Buildroot目录,打开内核配置界面
cd buildroot-2023.02
make linux-menuconfig # 基于之前的stm32mp157配置
# 2. 核心裁剪项(按需求禁用以下功能)
# - 禁用PC端硬件驱动:Device Drivers → 禁用ATA/IDE、PCI、USB HID等
# - 禁用无用文件系统:File systems → 仅保留ext4、tmpfs(嵌入式常用)
# - 禁用图形化相关:Graphics support → 全部禁用
# - 禁用网络协议:Networking support → 仅保留TCP/IP、ARP、ICMP(Modbus TCP依赖)
# - 裁剪内核调试功能:Kernel hacking → 禁用CONFIG_DEBUG_INFO、CONFIG_DEBUG_FS
# 3. 保存配置,重新编译内核
make linux-rebuild # 仅重新编译内核,耗时较短
2. 根文件系统优化(Buildroot 配置)
bash
# 1. 打开Buildroot图形化配置
make menuconfig
# 2. 精简软件包(核心优化)
# - 禁用图形化组件:Target packages → Graphic libraries and applications → 全部禁用
# - 精简工具链:Target packages → Toolchain → 取消勾选"Install libstdc++"(无需C++)
# - 移除无用工具:Target packages → BusyBox → 自定义BusyBox配置(make busybox-menuconfig)
# - 禁用BusyBox中的telnet、ftp等不常用工具,仅保留ls、cat、echo、ifconfig等核心命令
# 3. 根文件系统压缩(减少Flash占用)
# - Target filesystem options → 勾选"Compress root filesystem with gzip"
# - 选择根文件系统类型:EXT4(稳定)或SquashFS(只读,更节省空间)
# 4. 重新编译根文件系统
make -j4
3. 优化验证
- 启动时间:优化前 30 秒→优化后 8 秒;
- 资源占用:启动后 RAM 占用从 52MB→18MB,Flash 占用从 110MB→28MB;
- 功能验证:网络、I2C、串口、MQTT、Modbus TCP 正常工作。
(二)工业级协议实战:Modbus TCP 服务器 / 客户端(40 分钟)
Modbus TCP 是工业 Linux 网关的核心协议(基于以太网,比 Modbus RTU 传输距离更远、速率更高),采用开源libmodbus库实现 “数据采集 + 远程控制”,贴合工业场景。
1. 环境准备:Buildroot 添加 libmodbus 库
bash
# 1. Buildroot配置中添加libmodbus
make menuconfig → Target packages → Libraries → Networking → 勾选"libmodbus"
# 2. 重新编译Buildroot(仅编译新增包,耗时较短)
make -j4
2. 实战:Modbus TCP 服务器(工业网关核心)
实现 “温湿度数据(AHT10)→ Modbus TCP 寄存器” 映射,上位机(如 Modbus Poll、工业 PLC)可通过 IP 读取数据。
(1)核心代码(modbus_tcp_server.c)
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <modbus/modbus.h>
#include "aht10_linux.h" // 复用前一天的AHT10用户态驱动
#define MODBUS_TCP_PORT 502 // Modbus TCP默认端口
#define MODBUS_SLAVE_ID 1 // 从站地址
#define REG_TEMP 0x0000 // 温度寄存器地址(浮点型,占2个16位寄存器)
#define REG_HUMI 0x0002 // 湿度寄存器地址(浮点型,占2个16位寄存器)
#define REG_LED_CTRL 0x0004 // LED控制寄存器(1个16位寄存器,0=灭,1=亮)
// Modbus寄存器缓冲区(10个16位寄存器,足够使用)
static uint16_t modbus_regs[10] = {0};
int main() {
modbus_t *ctx = NULL;
int sock_fd, ret;
float temp, humi;
int aht10_fd = aht10_open(); // 打开AHT10(复用之前的函数)
if (aht10_fd < 0) {
fprintf(stderr, "AHT10 open failed\n");
return -1;
}
// 1. 初始化Modbus TCP上下文
ctx = modbus_new_tcp("0.0.0.0", MODBUS_TCP_PORT); // 监听所有网卡
if (ctx == NULL) {
fprintf(stderr, "modbus new tcp failed: %s\n", modbus_strerror(errno));
close(aht10_fd);
return -1;
}
// 2. 设置从站地址
modbus_set_slave(ctx, MODBUS_SLAVE_ID);
// 3. 创建TCP监听套接字
sock_fd = modbus_tcp_listen(ctx, 1); // 最大1个连接(工业网关常用)
if (sock_fd < 0) {
fprintf(stderr, "modbus tcp listen failed: %s\n", modbus_strerror(errno));
modbus_free(ctx);
close(aht10_fd);
return -1;
}
printf("Modbus TCP server start: %s:%d\n", "0.0.0.0", MODBUS_TCP_PORT);
while (1) {
// 4. 等待客户端连接(阻塞)
ret = modbus_tcp_accept(ctx, &sock_fd);
if (ret < 0) {
fprintf(stderr, "modbus accept failed: %s\n", modbus_strerror(errno));
continue;
}
printf("Client connected\n");
// 5. 循环处理客户端请求
while (1) {
uint8_t req_buf[MODBUS_TCP_MAX_ADU_LENGTH] = {0};
int req_len;
// 读取客户端请求
req_len = modbus_receive(ctx, req_buf, MODBUS_TCP_MAX_ADU_LENGTH);
if (req_len <= 0) {
if (req_len == -1) {
fprintf(stderr, "modbus receive failed: %s\n", modbus_strerror(errno));
} else {
printf("Client disconnected\n");
}
break;
}
// 6. 实时更新温湿度到Modbus寄存器(浮点型转2个16位寄存器)
if (aht10_read(aht10_fd, &temp, &humi) == 0) {
// 浮点型转字节数组,再拆分到16位寄存器(大端序,工业标准)
uint8_t temp_bytes[4], humi_bytes[4];
memcpy(temp_bytes, &temp, 4);
memcpy(humi_bytes, &humi, 4);
modbus_regs[REG_TEMP] = (temp_bytes[0] << 8) | temp_bytes[1];
modbus_regs[REG_TEMP + 1] = (temp_bytes[2] << 8) | temp_bytes[3];
modbus_regs[REG_HUMI] = (humi_bytes[0] << 8) | humi_bytes[1];
modbus_regs[REG_HUMI + 1] = (humi_bytes[2] << 8) | humi_bytes[3];
printf("Update: Temp=%.1f℃, Humi=%.1f%%RH\n", temp, humi);
}
// 7. 处理请求(读寄存器、写寄存器)
ret = modbus_reply(ctx, req_buf, req_len, modbus_regs);
if (ret < 0) {
fprintf(stderr, "modbus reply failed: %s\n", modbus_strerror(errno));
break;
}
// 8. 处理LED控制指令(客户端写REG_LED_CTRL寄存器)
static int last_led_state = -1;
int current_led_state = modbus_regs[REG_LED_CTRL];
if (current_led_state != last_led_state) {
if (current_led_state == 1) {
system("echo '1' > /dev/stm32mp1_led"); // LED亮
printf("LED ON\n");
} else {
system("echo '0' > /dev/stm32mp1_led"); // LED灭
printf("LED OFF\n");
}
last_led_state = current_led_state;
}
}
// 关闭客户端连接
modbus_close(ctx);
}
// 资源释放(实际不会执行到)
modbus_tcp_close_listen_socket(sock_fd);
modbus_free(ctx);
close(aht10_fd);
return 0;
}
(2)交叉编译(链接 libmodbus 库)
bash
arm-linux-gnueabihf-gcc modbus_tcp_server.c aht10_linux.c -o modbus_server \
-static -lmodbus -lm # -lm:链接数学库(浮点运算可能需要)
(3)上位机验证(Modbus Poll)
- 开发板联网,获取 IP(如 192.168.1.100);
- 电脑安装 Modbus Poll,配置连接:
- Connection → TCP/IP → 输入开发板 IP(192.168.1.100),端口 502;
- 配置寄存器读取:
- Protocol → Modbus TCP → 选择 “3: Read Holding Registers”;
- 起始地址 0,寄存器数量 5,数据类型 “32-bit float, Big-endian”;
- 点击 “Connect”,即可看到温湿度数据;
- 配置寄存器写入:
- Protocol → 06: Write Single Register → 地址 4,数值 1 → 点击 “Write”,开发板 LED 亮;数值 0 → LED 灭。
3. 拓展:Modbus TCP 客户端(网关主动上报 PLC)
如果需要网关主动向 PLC(Modbus TCP 服务器)发送数据,可基于libmodbus实现客户端,核心逻辑:
c
// 连接PLC服务器
ctx = modbus_new_tcp("192.168.1.200", 502); // PLC IP
modbus_set_slave(ctx, 1);
if (modbus_connect(ctx) < 0) { /* 错误处理 */ }
// 向PLC寄存器写入温湿度数据
modbus_write_registers(ctx, 0x0000, 2, &modbus_regs[REG_TEMP]); // 写入温度
modbus_write_registers(ctx, 0x0002, 2, &modbus_regs[REG_HUMI]); // 写入湿度
(三)项目部署自动化:Shell 脚本 + Systemd 服务(25 分钟)
实际工作中,部署多台设备时,手动拷贝文件、启动应用效率极低,通过 Shell 脚本批量部署 + Systemd 服务管理,实现 “一键部署、开机自启、异常重启”。
1. 自动化部署 Shell 脚本(deploy.sh)
bash
#!/bin/bash
# 嵌入式Linux项目自动化部署脚本
# 适用:STM32MP157 Linux开发板
# 配置参数
TARGET_IP="192.168.1.100" # 开发板IP(可批量修改为多个IP)
TARGET_USER="root"
LOCAL_APP_DIR="./bin" # 本地应用目录
TARGET_APP_DIR="/root/app" # 开发板应用目录
DRIVER_FILE="led_drv.ko" # 驱动文件
SERVICE_FILE="modbus-server.service" # Systemd服务文件
# 1. 检查本地文件是否存在
if [ ! -f "$LOCAL_APP_DIR/modbus_server" ] || [ ! -f "$DRIVER_FILE" ] || [ ! -f "$SERVICE_FILE" ]; then
echo "错误:本地文件缺失!"
exit 1
fi
# 2. 登录开发板,创建应用目录
echo "正在连接开发板 $TARGET_IP..."
ssh $TARGET_USER@$TARGET_IP "mkdir -p $TARGET_APP_DIR"
# 3. 上传应用、驱动、服务文件
echo "正在上传文件..."
scp $LOCAL_APP_DIR/modbus_server $TARGET_USER@$TARGET_IP:$TARGET_APP_DIR/
scp $DRIVER_FILE $TARGET_USER@$TARGET_IP:$TARGET_APP_DIR/
scp $SERVICE_FILE $TARGET_USER@$TARGET_IP:/etc/systemd/system/
# 4. 开发板执行部署命令
echo "正在部署..."
ssh $TARGET_USER@$TARGET_IP "
# 加载驱动
insmod $TARGET_APP_DIR/$DRIVER_FILE;
# 设置应用可执行权限
chmod +x $TARGET_APP_DIR/modbus_server;
# 重新加载Systemd配置
systemctl daemon-reload;
# 设置服务开机自启并启动
systemctl enable modbus-server.service;
systemctl start modbus-server.service;
# 查看服务状态
systemctl status modbus-server.service;
"
echo "部署完成!"
2. Systemd 服务配置(modbus-server.service)
Systemd 是 Linux 系统的服务管理器,用于管理应用的启动、停止、自启、异常重启,比传统 init 脚本更可靠:
ini
[Unit]
Description=Modbus TCP Server (Industrial Gateway)
After=network.target # 网络启动后再启动服务
Requires=network.target # 依赖网络服务
[Service]
Type=simple
User=root
WorkingDirectory=/root/app # 工作目录
ExecStart=/root/app/modbus_server # 应用启动命令
Restart=always # 异常退出时自动重启
RestartSec=3 # 重启间隔3秒
StandardOutput=journal+console # 日志输出到控制台和系统日志
StandardError=journal+console
[Install]
WantedBy=multi-user.target # 多用户模式下启动
3. 脚本使用与验证
bash
# 1. 给脚本添加执行权限
chmod +x deploy.sh
# 2. 一键部署(需开发板开启SSH服务)
./deploy.sh
# 3. 验证部署结果
# 本地查看服务状态
ssh root@192.168.1.100 "systemctl status modbus-server.service"
# 查看应用日志
ssh root@192.168.1.100 "journalctl -u modbus-server.service -f"
三、实战项目:工业级 Modbus TCP 网关(30 分钟)
整合第 30 天的三大核心技术,打造 “可量产、高可靠” 的工业级 Modbus TCP 网关,核心功能:
- 系统优化:内核裁剪 + 根文件系统精简,RAM 占用≤20MB,Flash 占用≤30MB,启动时间≤10 秒;
- 数据采集:AHT10 温湿度采集,1 秒更新一次;
- 工业通信:Modbus TCP 服务器,支持上位机读取温湿度、控制 LED;
- 云端协同:整合之前的 MQTT 功能,将温湿度数据同步上传阿里云;
- 自动化部署:Shell 脚本一键部署,Systemd 服务开机自启、异常重启。
核心验证点
- 稳定性:连续运行 24 小时,Modbus TCP 连接无断开,数据无丢失;
- 资源占用:启动后 RAM≤18MB,CPU 占用≤10%;
- 自动化:开发板上电后自动启动服务,手动杀死应用后 3 秒内自动重启;
- 工业适配:上位机(Modbus Poll/PLC)可稳定读写数据,响应延迟≤50ms。
四、第三十天必掌握的 3 个核心点
- Linux 系统优化:会用 Buildroot 裁剪内核和根文件系统,降低资源占用、优化启动时间,适配嵌入式硬件;
- 工业协议实战:掌握 libmodbus 库的使用,能开发 Modbus TCP 服务器 / 客户端,实现工业数据采集与远程控制;
- 自动化部署:能编写 Shell 部署脚本,配置 Systemd 服务,实现应用的一键部署、开机自启、异常重启。
总结
第 30 天的核心是 “嵌入式 Linux 工业级落地”—— 系统优化解决了嵌入式资源有限的痛点,Modbus TCP 实战满足了工业通信的刚需,自动化部署提升了项目交付和维护效率,这三项技能是嵌入式 Linux 工程师的 “必备职场技能”。

737

被折叠的 条评论
为什么被折叠?



