Skip to content

OpenLinux 平台详解

OpenLinux 架构

移远 OpenLinux 基于 Yocto Project 构建,是专为 IoT 模组优化的嵌入式 Linux 发行版。

OpenLinux 软件栈:
  ┌─────────────────────────────────────────┐
  │           用户应用程序                   │
  │  C/C++ / Python / Shell / Node.js       │
  ├─────────────────────────────────────────┤
  │           系统库                         │
  │  glibc / OpenSSL / libcurl / libmosquitto│
  ├─────────────────────────────────────────┤
  │           系统服务                       │
  │  systemd / NetworkManager / udev        │
  ├─────────────────────────────────────────┤
  │           Linux 内核(4.x / 5.x)        │
  │  驱动:USB / UART / SPI / I2C / GPIO    │
  ├─────────────────────────────────────────┤
  │           Bootloader(U-Boot)           │
  └─────────────────────────────────────────┘

文件系统结构

/
├── bin/        # 基本命令(ls, cp, mv 等)
├── dev/        # 设备文件
│   ├── ttyUSB0 # USB 串口
│   ├── ttyHS0  # 硬件串口
│   ├── i2c-0   # I2C 总线
│   └── spidev0.0 # SPI 设备
├── etc/        # 配置文件
│   ├── systemd/ # systemd 服务配置
│   └── network/ # 网络配置
├── lib/        # 系统库
├── opt/        # 用户应用程序(推荐安装位置)
├── proc/       # 进程信息(虚拟文件系统)
├── sys/        # 系统信息(虚拟文件系统)
├── tmp/        # 临时文件
└── usr/        # 用户程序和库

网络配置

蜂窝网络连接

bash
# 方法1:使用 quectel-CM(推荐)
# quectel-CM 是移远提供的连接管理工具
./quectel-CM -s cmnet &  # 后台运行,-s 指定 APN

# 查看网络接口
ip addr show
# 会出现 wwan0 或 usb0 接口

# 查看路由
ip route show

# 测试连通性
ping -c 3 8.8.8.8

# 方法2:使用 ModemManager
mmcli -m 0 --simple-connect="apn=cmnet"

# 方法3:AT 指令手动配置
# 通过 /dev/ttyUSB2(AT 指令端口)
echo -e "AT+CGDCONT=1,\"IP\",\"cmnet\"\r\n" > /dev/ttyUSB2
echo -e "AT+CGACT=1,1\r\n" > /dev/ttyUSB2

开机自动连接

bash
# 创建 systemd 服务
cat > /etc/systemd/system/quectel-cm.service << 'EOF'
[Unit]
Description=Quectel Connection Manager
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/quectel-CM -s cmnet
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF

systemctl enable quectel-cm.service
systemctl start quectel-cm.service

GPIO 操作

sysfs 接口(传统方式)

bash
# 导出 GPIO
echo 10 > /sys/class/gpio/export

# 设置方向
echo out > /sys/class/gpio/gpio10/direction

# 设置值
echo 1 > /sys/class/gpio/gpio10/value  # 高电平
echo 0 > /sys/class/gpio/gpio10/value  # 低电平

# 读取输入
echo in > /sys/class/gpio/gpio11/direction
cat /sys/class/gpio/gpio11/value

libgpiod(现代方式)

c
#include <gpiod.h>
#include <stdio.h>

int main() {
    struct gpiod_chip *chip;
    struct gpiod_line *line;
    
    // 打开 GPIO 芯片
    chip = gpiod_chip_open("/dev/gpiochip0");
    if (!chip) {
        perror("Open chip failed");
        return -1;
    }
    
    // 获取 GPIO 线
    line = gpiod_chip_get_line(chip, 10);  // GPIO 10
    
    // 请求输出
    gpiod_line_request_output(line, "myapp", 0);
    
    // 设置高电平
    gpiod_line_set_value(line, 1);
    
    // 释放资源
    gpiod_line_release(line);
    gpiod_chip_close(chip);
    
    return 0;
}

I2C 操作

c
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>

#define I2C_BUS "/dev/i2c-0"
#define SHT30_ADDR 0x44

int main() {
    int fd = open(I2C_BUS, O_RDWR);
    if (fd < 0) {
        perror("Open I2C failed");
        return -1;
    }
    
    // 设置从设备地址
    ioctl(fd, I2C_SLAVE, SHT30_ADDR);
    
    // 发送测量命令(单次测量,高精度)
    unsigned char cmd[2] = {0x2C, 0x06};
    write(fd, cmd, 2);
    
    usleep(500000);  // 等待 500ms
    
    // 读取 6 字节数据
    unsigned char data[6];
    read(fd, data, 6);
    
    // 解析温度和湿度
    unsigned int raw_temp = (data[0] << 8) | data[1];
    unsigned int raw_hum = (data[3] << 8) | data[4];
    
    float temperature = -45.0 + 175.0 * raw_temp / 65535.0;
    float humidity = 100.0 * raw_hum / 65535.0;
    
    printf("Temperature: %.1f°C, Humidity: %.1f%%\n", temperature, humidity);
    
    close(fd);
    return 0;
}

SPI 操作

c
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>

#define SPI_DEVICE "/dev/spidev0.0"

int main() {
    int fd = open(SPI_DEVICE, O_RDWR);
    
    // 配置 SPI 参数
    uint8_t mode = SPI_MODE_0;
    uint8_t bits = 8;
    uint32_t speed = 1000000;  // 1MHz
    
    ioctl(fd, SPI_IOC_WR_MODE, &mode);
    ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
    ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
    
    // 全双工传输
    uint8_t tx_buf[4] = {0x01, 0x02, 0x03, 0x04};
    uint8_t rx_buf[4] = {0};
    
    struct spi_ioc_transfer transfer = {
        .tx_buf = (unsigned long)tx_buf,
        .rx_buf = (unsigned long)rx_buf,
        .len = 4,
        .speed_hz = speed,
        .bits_per_word = bits,
    };
    
    ioctl(fd, SPI_IOC_MESSAGE(1), &transfer);
    
    printf("Received: %02X %02X %02X %02X\n",
           rx_buf[0], rx_buf[1], rx_buf[2], rx_buf[3]);
    
    close(fd);
    return 0;
}

褚成志的笔记