跳转至

ymodem文件传输(Air780EPM不支持)

一、Ymodem 协议概述

Ymodem 是一种基于串行通信的文件传输协议,由 Chuck Forsberg 于 1980 年代初期在 Xmodem 协议基础上改进而来。其设计目标是解决 Xmodem 在大文件传输效率低(仅支持 128 字节数据块)、缺乏批处理能力等问题,通过引入 1024 字节数据块和批量文件传输机制,显著提升传输效率与可靠性,成为早期嵌入式系统和计算机间文件交换的核心技术之一。

1.1 核心特性

特性
说明
数据块大小
支持 128 字节(SOH 模式)和 1024 字节(STX 模式)
错误检测
使用 CRC-16 循环冗余校验,校验范围包含数据块内容
批处理传输
可一次性发送多个文件,支持文件名和文件大小元数据传递
流量控制
通过 ACK/NAK 机制实现自动重传,防止数据溢出
填充规则
数据不足时用 0x1A 填充,结束帧用 0x00 填充

1.2 帧格式说明

1.2.1 起始帧(133 字节)

字段
字节数

描述
SOH
1
0x01
起始符(固定为 SOH)
块编号
1
0x00
固定为 00
块编号反码
1
0xFF
块编号的二进制反码
文件名
变长
foo.bin
以 0x00 结尾的字符串
文件大小
变长
1024
十进制数值 + 0x00 结尾
填充区
剩余
0x00
补满至 128 字节
CRC 校验码
2
CRCH CRCL
高字节在前,低字节在后

1.2.2 数据帧(1029/133 字节)

字段
字节数

描述
STX/SOH
1
0x02/0x01
1024 字节用 STX,128 用 SOH
块编号
1
0x01
从 01 递增
块编号反码
1
0xFE
块编号的二进制反码
数据区
1024/128
原始数据
不足时用 0x1A 填充
CRC 校验码
2
CRCH CRCL
校验数据区内容

1.2.3 结束帧(133 字节)

字段
字节数

描述
SOH
1
0x01
固定为 SOH
块编号
1
0x00
固定为 00
块编号反码
1
0xFF
固定为 FF
填充区
128
0x00
全 0 填充
CRC 校验码
2
0x0000
固定为 0

1.3 控制字符表

字符
ASCII 码
功能描述
SOH
0x01
128 字节数据块起始标志
STX
0x02
1024 字节数据块起始标志
EOT
0x04
传输结束标志
ACK
0x06
确认接收成功
NAK
0x15
请求重传(校验失败/超时)
CAN
0x18
取消传输
‘C’
0x43
接收方发起传输请求

1.4 传输流程

二、演示功能概述

本篇文章演示的内容为:使用 Air780EHM 核心板的 UART1 连接 PC 端的串口调试仿真工具 SecureCRT,通过 Ymodem 协议接收文件传输。

三、准备硬件环境

参考:硬件环境清单第二章节内容,准备以及组装好硬件环境。

3.1 准备一块 Air780EHM 核心板:点击购买

3.2 连线对应表

Air780EPM开发板
USB 转 TTL 线
uart1_tx
白线
uart1_rx
绿线
gnd
黑线

3.3 硬件连接图

使用 USB 转 TTL 线连接 780EHM 核心板的 U1TX、U1RX 和 GND

四、准备软件环境

烧录工具:Luatools 工具

Air780EPM 烧录需要的固件和脚本文件:

LuatOS 运行所需要的 lib 文件:

使用 Luatools 烧录时,勾选 添加默认 lib 选项,使用默认 lib 脚本文件

PC 端工具 SecureCRT:下载链接

五、代码 API 和代码解析

5.1 代码 API

ymodem - 合宙模组资料中心

5.2 代码解析

1.定义一个 ymodem_to 函数,用于发送 C 字符,并重置 ymodem 处理程序

--  定义一个ymodem_to函数,用于发送C字符,并重置ymodem处理程序
local function ymodem_to() 
    while true do
        --  如果ymodem协议没有在运行,则发送请求;并重置ymodem处理程序
        if not ymodem_running then 
            uart.write(uartid, "C")
            ymodem.reset(ymodem_handler) 
        end
        sys.wait(500)
    end
end

2.定义一个 ymodem_rx 函数,用于接收数据

--  定义一个ymodem_rx函数,用于接收数据
local function ymodem_rx(id,len) 
    --  从uart接收数据到缓冲区
    uart.rx(id,rxbuff) 
    --  打印缓冲区已使用的大小
    log.info(rxbuff:used()) 
    --  调用ymodem.receive函数,接收数据
    local result,ack,flag,file_done,all_done = ymodem.receive(ymodem_handler,rxbuff) 
    ymodem_running = result
    log.info("result:",ymodem_running,ack,flag,file_done,all_done)
    rxbuff:del()
    if result then
        rxbuff:copy(0, ack,flag)
        uart.tx(id, rxbuff)
    end

    --  所有数据都接收完毕
    if all_done then 
        -- 判断/save.bin文件是否存在
        local exists=io.exists("/save.bin") 

        -- 判断/save.bin文件是否存在,存在则打印日志,显示/save.bin文件大小;不存在则打印日志,显示/save.bin文件不存在
        if exists then
            log.info("io", "save.bin file exists:", exists) 
            log.info("io", "save.bin file size:", io.fileSize("/save.bin")) 
        else
            log.info("io", "save.bin file not exists") 
        end

        --ymodem_running置为false,再次开始接收
        ymodem_running = false 
    end
    rxbuff:del()
end

六、运行结果展示

6.1 完整代码

--[[
@module  main
@summary ymodem 接收文件应用功能模块 
@version 1.0
@date    2025.07.01
@author  杨鹏
@usage
本文件为Air780EHM核心板演示ymodem功能的代码示例,核心业务逻辑为:
1. 初始化串口通信
2. 创建Ymodem处理对象
    local ymodem_handler = ymodem.create("/","save.bin")
3. 启动请求发送任务
    uart.write(uartid, "C")
4. 监听串口数据接收
    uart.on(uartid, "receive", ymodem_rx)
5. 处理Ymodem数据包
    local function ymodem_rx(id,len)
]]

-- 根据实际设备选取不同的uartid
local uartid = 1 

--初始化
local result = uart.setup(
    uartid,--串口id
    115200,--波特率
    8,--数据位
    1--停止位
)
local taskName = "ymodem_to"

-- 处理未识别的消息
local function ymodem_to_cb(msg)
    log.info("ymodem_to_cb", msg[1], msg[2], msg[3], msg[4])
end

--  定义一个局部变量,用于表示Ymodem协议是否正在运行
local ymodem_running = false 

--  创建一个缓冲区,大小为1024 + 32
local rxbuff = zbuff.create(1024 + 32) 

--  创建一个ymodem处理程序,保存路径为"/",文件名为"save.bin"
local ymodem_handler = ymodem.create("/","save.bin")

--  定义一个ymodem_to函数,用于发送C字符,并重置ymodem处理程序
local function ymodem_to() 
    while true do
        --  如果ymodem协议没有在运行,则发送请求;并重置ymodem处理程序
        if not ymodem_running then 
            uart.write(uartid, "C")
            ymodem.reset(ymodem_handler) 
        end
        sys.wait(500)
    end
end

--  定义一个ymodem_rx函数,用于接收数据
local function ymodem_rx(id,len) 
    --  从uart接收数据到缓冲区
    uart.rx(id,rxbuff) 
    --  打印缓冲区已使用的大小
    log.info(rxbuff:used()) 
    --  调用ymodem.receive函数,接收数据
    local result,ack,flag,file_done,all_done = ymodem.receive(ymodem_handler,rxbuff) 
    ymodem_running = result
    log.info("result:",ymodem_running,ack,flag,file_done,all_done)
    rxbuff:del()
    if result then
        rxbuff:copy(0, ack,flag)
        uart.tx(id, rxbuff)
    end

    --  所有数据都接收完毕
    if all_done then 
        -- 判断/save.bin文件是否存在
        local exists=io.exists("/save.bin") 

        -- 判断/save.bin文件是否存在,存在则打印日志,显示/save.bin文件大小;不存在则打印日志,显示/save.bin文件不存在
        if exists then
            log.info("io", "save.bin file exists:", exists) 
            log.info("io", "save.bin file size:", io.fileSize("/save.bin")) 
        else
            log.info("io", "save.bin file not exists") 
        end

        --ymodem_running置为false,再次开始接收
        ymodem_running = false 
    end
    rxbuff:del()
end

--  监听串口接收事件
uart.on(uartid, "receive", ymodem_rx) 

--  监听串口发送事件
uart.on(uartid, "sent", function(id) 
    log.info("uart", "sent", id) 
end)

--创建并且启动一个task
--运行这个task的主函数ymodem_to
sysplus.taskInitEx(ymodem_to, taskName,ymodem_to_cb)

6.2 结果展示

6.2.1 SecureCRT 使用指南:

6.2.2 1k 文件数据传输:

发送端:传输完成

模组接收端:

6.2.3 10K 文件数据传输:

发送端:传输完成

模组接收端:

七、总结

本文演示如何在 Air780EHM 核心板上面,通过 UART1 连接 PC 端的串口调试工具 SecureCRT,进行 Ymodem 协议的文件传输测试。