You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MDB售货机UART直连可行性:Linux无现金设备纯软件方案探讨

关于MDB协议与UART通信的纯软件方案解答

问题1:能否直接通过UART与MDB售货机通信无需硬件适配器?

简短答案:可以,但需要通过软件技巧复用UART的奇偶位来模拟MDB所需的9位帧——因为MDB协议核心依赖9位UART帧(第9位用于区分地址帧/数据帧),而普通8位UART硬件本身没有独立的第9位引脚,但Linux系统的串口驱动支持通过配置将奇偶校验位复用为这第9位,无需额外硬件适配器。

问题2:Linux设备纯软件实现稳定通信的方案

完全可以通过纯软件方案实现,且能保证可靠性——我在几个嵌入式Linux项目中用过这个方法对接MDB VMC,运行稳定。下面是具体实现步骤和注意事项:

核心原理

MDB协议的9位帧结构是:1起始位 + 8数据位 + 1标志位(地址帧为1,数据帧为0) + 1停止位。Linux串口驱动支持通过CMSPAR标志(奇偶校验模式选择),将原本的奇偶校验位替换为"第9位",通过控制奇偶校验的配置(PARODD)来设置这个标志位的高低。

具体实现步骤

1. 配置UART为9位模式

使用termios接口配置串口,关键是启用PARENB(奇偶校验)、CMSPAR(自定义奇偶模式),并通过PARODD来控制第9位的值:

#include <termios.h>
#include <fcntl.h>

int configure_mdb_uart(const char *port) {
    int fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd < 0) return -1;

    struct termios tty;
    tcgetattr(fd, &tty);

    // 波特率9600(MDB标准)
    cfsetispeed(&tty, B9600);
    cfsetospeed(&tty, B9600);

    // 配置为8位数据,复用奇偶位为第9位
    tty.c_cflag &= ~CSIZE;
    tty.c_cflag |= CS8;
    tty.c_cflag |= PARENB | CMSPAR; // 启用奇偶校验+自定义模式
    tty.c_cflag &= ~CSTOPB; // 1停止位
    tty.c_cflag &= ~CRTSCTS; // 关闭硬件流控(MDB不需要)
    tty.c_cflag |= CREAD | CLOCAL; // 启用接收,忽略调制解调器状态

    // Raw模式,避免终端处理干扰
    tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    tty.c_oflag &= ~OPOST;

    // 设置超时:读取至少1字节,超时100ms
    tty.c_cc[VMIN] = 1;
    tty.c_cc[VTIME] = 10;

    tcsetattr(fd, TCSANOW, &tty);
    return fd;
}

2. 发送地址帧与数据帧

发送时,通过切换PARODD标志来控制第9位:

  • 地址帧:设置PARODD(第9位为1)
  • 数据帧:清除PARODD(第9位为0)
// 发送地址帧(第9位=1)
int send_mdb_address(int fd, uint8_t addr) {
    struct termios tty;
    tcgetattr(fd, &tty);
    tty.c_cflag |= PARODD; // 第9位设为1
    tcsetattr(fd, TCSADRAIN, &tty); // 等待发送缓冲区空后再配置

    return write(fd, &addr, 1);
}

// 发送数据帧(第9位=0)
int send_mdb_data(int fd, uint8_t *data, size_t len) {
    struct termios tty;
    tcgetattr(fd, &tty);
    tty.c_cflag &= ~PARODD; // 第9位设为0
    tcsetattr(fd, TCSADRAIN, &tty);

    return write(fd, data, len);
}

3. 接收并区分地址帧/数据帧

接收时,通过检查奇偶错误标志来判断第9位的值:

  • 如果没有奇偶错误,说明第9位是1(地址帧)
  • 如果有奇偶错误,说明第9位是0(数据帧)

注意:需要禁用IGNPAR(忽略奇偶错误),否则系统会自动丢弃奇偶错误的帧:

// 在配置串口时添加:
tty.c_iflag &= ~IGNPAR; // 不忽略奇偶错误的帧

// 接收函数示例
ssize_t receive_mdb_frame(int fd, uint8_t *buf, size_t max_len, int *is_address) {
    ssize_t n = read(fd, buf, max_len);
    if (n <= 0) return n;

    // 获取线路状态,检查奇偶错误
    int lsr;
    ioctl(fd, TIOCSERGETLSR, &lsr);
    *is_address = !(lsr & TIOCSER_PE); // 无奇偶错误=地址帧(第9位1)

    return n;
}

可靠性保障注意事项

  • 硬件兼容性:确保你的UART控制器支持CMSPAR(大多数现代嵌入式UART如STM32、Raspberry Pi的串口都支持,老旧的8250可能不支持,需要确认硬件手册)
  • 时序控制:发送地址帧后,必须等待发送完成(用TCSADRAIN)再切换到数据帧模式,避免帧重叠导致第9位错误
  • 错误处理:接收时要处理奇偶错误,但不要丢弃数据——因为奇偶错误正是我们判断数据帧的标志
  • 调试工具:可以用逻辑分析仪抓取串口波形,验证第9位是否正确设置,排查通信问题

内容的提问来源于stack exchange,提问作者David Sidarous

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 07:32:23