📌 一、概述
S19 文件,也叫 Motorola S-record 文件,是一种使用 ASCII 文本表示程序代码和数据的文件格式。
它常用于:
- 单片机程序下载
- Flash 烧写
- BootLoader 升级
- 不同平台之间传输程序代码和数据
很多 Freescale / NXP 系列 MCU 工程在编译后,会生成类似:
*.s19
*.asb.s19
这样的文件。
🧱 二、S19 整体结构
S19 文件由多行 S Record 组成。
每一行都是一条记录,基本结构如下:
Sx LL AAAA... DD...DD CC
其中:
| 字段 | 大小 | 说明 |
|---|---|---|
| Record Type | 2字符 | 记录类型,如 S0 / S1 / S2 / S3 / S9 |
| Record Length | 1 Byte | 后续字节数 |
| Address | 2 / 3 / 4 Bytes | 数据写入的起始地址 |
| Data | 0 ~ N Bytes | 代码或数据内容 |
| Checksum | 1 Byte | 校验和 |
🧩 三、字段详解
1. Record Type
Record Type 用于描述当前记录的用途。
例如:
S1
S2
S3
S9
其中 S 是固定起始字符,后面的数字表示记录类型。
2. Record Length
Record Length 表示当前记录中剩余的字节数。
计算方式:
Record Length = Address字节数 + Data字节数 + Checksum字节数
注意:
Record Length 本身不参与长度统计
Record Type 也不参与长度统计
3. Address
Address 表示数据应该写入 MCU / Flash 的起始地址。
不同记录类型的 Address 长度不同:
| 类型 | Address长度 |
|---|---|
| S1 | 2 Bytes |
| S2 | 3 Bytes |
| S3 | 4 Bytes |
| S7 | 4 Bytes |
| S8 | 3 Bytes |
| S9 | 2 Bytes |
4. Data
Data 表示真正需要写入 Flash / ROM 的数据。
特点:
- 每 1 Byte 数据用 2 个十六进制字符表示
- Data 长度由 Record Length 和 Address 长度反推
- S0 / S5 / S7 / S8 / S9 通常不需要下载到 MCU
5. Checksum
Checksum 是 1 Byte 校验和。
计算方式:
Checksum = 0xFF - (Record Length + Address + Data 的所有字节之和的低8位)
也可以理解为:
Record Length + Address + Data + Checksum 的低8位 = 0xFF
注意:校验的是实际二进制字节,不是 ASCII 字符本身。
🗂 四、Record Type 类型表
| 类型 | Address长度 | 作用 | 是否下载到 MCU |
|---|---|---|---|
| S0 | 2 Bytes | 文件头 / 文件名 / 注释信息 | 否 |
| S1 | 2 Bytes | 数据记录,16-bit 地址 | 是 |
| S2 | 3 Bytes | 数据记录,24-bit 地址 | 是 |
| S3 | 4 Bytes | 数据记录,32-bit 地址 | 是 |
| S5 | 2 Bytes | S1 / S2 / S3 记录数量统计 | 否 |
| S7 | 4 Bytes | 程序入口地址,结束记录 | 否 |
| S8 | 3 Bytes | 程序入口地址,结束记录 | 否 |
| S9 | 2 Bytes | 程序入口地址,结束记录 | 否 |
📝 五、S0 文件头记录
作用
S0 通常是 S19 文件的第一条记录,用于保存文件名、路径或注释信息。
它不需要下载到 MCU。
结构
S0 LL AAAA DATA CC
| 字段 | 说明 |
|---|---|
| S0 | 文件头记录 |
| LL | 后续字节数 |
| AAAA | 通常为 0000 |
| DATA | 文件名 / 路径 / 注释 |
| CC | 校验和 |
示例
S01F0000443A5C50726F6A6563745F335C62696E5C50726F6A6563742E61627371
解析:
| 字段 | 值 | 说明 |
|---|---|---|
| Type | S0 | 文件头 |
| Length | 1F | 后续 31 Bytes |
| Address | 0000 | 未使用 |
| Data | 443A5C…616273 | ASCII 字符串 |
| Checksum | 71 | 校验和 |
Data 转 ASCII 后大致表示:
D:\Project_3\bin\Project_3.abs
💾 六、S1 数据记录
作用
S1 是数据记录,地址长度为 2 Bytes。
适合 16-bit 地址空间。
结构
S1 LL AAAA DATA CC
| 字段 | 大小 | 说明 |
|---|---|---|
| S1 | 2字符 | 记录类型 |
| LL | 1 Byte | 后续字节数 |
| AAAA | 2 Bytes | 起始地址 |
| DATA | N Bytes | 数据 |
| CC | 1 Byte | 校验和 |
示例
S123C000CF2100C6055B134A800BFE4A8000FE0000C015C031000000000000000000000092
解析:
| 字段 | 值 | 说明 |
|---|---|---|
| Type | S1 | 16-bit 地址数据记录 |
| Length | 23 | 后续 0x23 Bytes |
| Address | C000 | 写入起始地址 |
| Data | CF2100…00000000 | 需要写入的数据 |
| Checksum | 92 | 校验和 |
数据会从地址:0xC000 开始连续写入。
💾 七、S2 数据记录
作用
S2 是数据记录,地址长度为 3 Bytes。
适合 24-bit 地址空间。
结构
S2 LL AAAAAA DATA CC
| 字段 | 大小 | 说明 |
|---|---|---|
| S2 | 2字符 | 记录类型 |
| LL | 1 Byte | 后续字节数 |
| AAAAAA | 3 Bytes | 起始地址 |
| DATA | N Bytes | 数据 |
| CC | 1 Byte | 校验和 |
示例
S218FE8020F2FEC013EC31270BED31180A30700434F920F10A0B
解析:
| 字段 | 值 | 说明 |
|---|---|---|
| Type | S2 | 24-bit 地址数据记录 |
| Length | 18 | 后续 0x18 Bytes |
| Address | FE8020 | 写入起始地址 |
| Data | F2FEC013EC31270BED31180A30700434F920F10A | 数据内容 |
| Checksum | 0B | 校验和 |
数据写入起始地址:0xFE8020
💾 八、S3 数据记录
作用
S3 是数据记录,地址长度为 4 Bytes。
适合 32-bit 地址空间。
结构
S3 LL AAAAAAAA DATA CC
| 字段 | 大小 | 说明 |
|---|---|---|
| S3 | 2字符 | 记录类型 |
| LL | 1 Byte | 后续字节数 |
| AAAAAAAA | 4 Bytes | 起始地址 |
| DATA | N Bytes | 数据 |
| CC | 1 Byte | 校验和 |
地址计算
S3 记录不需要像 Intel HEX 那样依赖扩展线性地址记录。
它本身就包含完整 32-bit 地址:
实际写入地址 = Address + DataIndex
🔢 九、S5 记录数量统计
作用
S5 用于记录前面 S1 / S2 / S3 数据记录的数量。
它不是必须存在的记录。
结构
S5 LL CCCC CC
| 字段 | 说明 |
|---|---|
| S5 | 记录数量统计 |
| LL | 通常为 03 |
| CCCC | 数据记录数量 |
| CC | 校验和 |
注意:
S5 只是校验辅助信息
不表示程序结束不需要写入
MCU不是每个 S19 文件都有
🚀 十、S7 / S8 / S9 程序入口记录
S7 / S8 / S9 都表示文件结束,同时指定程序入口地址。
区别在于入口地址长度不同。
类型区别
| 类型 | Address长度 | 常用于 |
|---|---|---|
| S7 | 4 Bytes | 对应 S3 数据记录 |
| S8 | 3 Bytes | 对应 S2 数据记录 |
| S9 | 2 Bytes | 对应 S1 数据记录 |
S7 结构
S7 LL AAAAAAAA CC
表示 32-bit 程序入口地址。
S8 结构
S8 LL AAAAAA CC
表示 24-bit 程序入口地址。
S9 结构
S9 LL AAAA CC
表示 16-bit 程序入口地址。
示例
S9030000FC
解析:
| 字段 | 值 | 说明 |
|---|---|---|
| Type | S9 | 结束记录 |
| Length | 03 | Address 2 Bytes + Checksum 1 Byte |
| Address | 0000 | 程序入口地址 |
| Checksum | FC | 校验和 |
含义:
程序入口地址 = 0x0000文件结束
🧮 十一、Checksum 校验示例
以 S2 记录为例:
S218FE8020F2FEC013EC31270BED31180A30700434F920F10A0B
取出需要参与计算的字节:
18 FE 80 20 F2 FE C0 13 EC 31 27 0B ED 31 18 0A 30 70 04 34 F9 20 F1 0A
计算:
sum = 所有字节相加checksum = 0xFF - (sum & 0xFF)
最终得到:0B
🧠 十二、开发时怎么解析 S19
解析步骤:
1. 逐行读取
2. 判断是否以 'S' 开头
3. 读取 Record Type
4. 读取 Record Length
5. 根据 Type 判断 Address 长度
6. 解析 Address
7. 根据 Length 反推出 Data 长度
8. 解析 Data
9. 校验 Checksum
10. 根据 Type 决定是否写入 Flash
Data 长度计算
DataLength = RecordLength - AddressLength - 1
其中:
1 = Checksum长度
🛠 十三、写 Flash 时注意事项
1. Flash 需要先擦除再写入
已经写入过的 Flash 地址,通常不能直接覆盖。
正确流程:
擦除 Sector / Page↓写入数据↓校验数据
2. 不要把所有记录都写入 Flash
需要写入 Flash 的通常只有:S1 / S2 / S3
不应写入:S0 / S5 / S7 / S8 / S9
3. 调试器窗口不一定可靠
有时候内存监视窗口不能实时显示 Flash 状态。
可以通过指针读取目标地址,确认是否写入成功:
uint8_t value = *(volatile uint8_t*)address;
4. 注意芯片锁定问题
在某些 Freescale / NXP MCU 上,通过自定义 BootLoader 或串口下载 S19 后,可能导致芯片进入安全锁定状态。
如果被锁定,需要执行:
Unsecure
之后才能再次通过 BDM 或串口下载。
📌 十四、S19 与 Intel HEX 对比
| 对比项 | S19 | Intel HEX |
|---|---|---|
| 厂商来源 | Motorola / Freescale | Intel |
| 行起始符 | Sx | : |
| 地址长度 | 由 S1/S2/S3 决定 | 依赖记录类型扩展 |
| 数据记录 | S1/S2/S3 | Type 00 |
| 结束记录 | S7/S8/S9 | Type 01 |
| 校验方式 | 0xFF 补码 | 0x100 补码 |
| 常见场景 | Freescale / NXP MCU | STM32 / AVR / 通用 MCU |
✅ 十五、快速记忆
最常见组合
S0 文件头S1/S2/S3 数据记录S7/S8/S9 结束与入口地址
真正要写入 Flash 的记录
S1 / S2 / S3
校验公式
Checksum = 0xFF - (sum & 0xFF)
数据长度公式
DataLength = RecordLength - AddressLength - 1
写入地址
实际地址 = Address + DataIndex
