STM32嵌入式:如何使用keil 来获取flash块数据并转换成可视化的数据 来判断源头数据是否错误

STM32嵌入式:如何使用keil 来获取flash块数据并转换成可视化的数据 来判断源头数据是否错误

比较实用的实战步骤,分三部分讲:

  • 在 Keil 里怎么看到/导出 Flash 数据
  • 怎么把原始 16 位补码数据"转成"我们能看懂的波形
  • 怎么对比"Flash 源头数据"和"你解析出来的数据",判断解析是否错误
    中间用一点伪命令,你按自己芯片型号和工程改一下就行。

一、整体流程示意(先有个整体感)

简单来说,你可以按下面这个思路来:

  1. Keil 进入调试模式 2. 在 Memory 窗口查看 Flash 数据 3. 用 SAVE 命令导出 Flash 块到 HEX 文件 4. HEX 转 数组/CSV 5. 用脚本做补码转换(16 位) 6. 用 Excel/Matlab/Python 画波形 7. 对比 Flash 源头数据 与 代码解析后数据
    判断源头/解析是否错误

二、在 Keil 中查看并导出 Flash 数据

1. 调试状态下打开 Memory 窗口

  • 在 Keil 中:
    • 点击 "Debug" → "Start/Stop Debug Session"(或 Ctrl+F5)进入调试
    • 菜单 "View" → "Memory Windows" → "Memory 1/2/3/4",打开一个内存窗口
  • 在 Memory 窗口的 "Address" 输入栏里填你要看的那块 Flash 地址,例如:
    • 0x08000000(STM32 的 Flash 起始地址,按你芯片的实际情况来)
  • 回车后,下面就会显示一段原始字节内容,形如:
    • 0x08000000 03 1F 03 3B 01 AD 01 15 ...
      如果你的 Flash 数据已经是一些"采样数据"写死在里面(比如 const 数组),你会在 Memory 窗口里看到它们以字节形式排布。

2. 确认数组/变量的地址

如果数据是以某个常量数组存在代码里,比如:

  • 代码中定义:
    • const int16_t flash_wave[128] = { ... };
      那么在调试时:
  • 打开 "View" → "Watch Windows" → "Watch 1"
  • 在 Watch 窗口里输入 flash_wave,Keil 会显示:
    • 这个数组的起始地址(比如 0x08001234
    • 数组里各个位置的值(如果显示格式对的话)
      你可以记下这个起始地址和长度,然后直接用 Memory 窗口看同一块区域。

3. 使用 SAVE 命令导出一段 Flash 到文件(重点)

Keil 的调试命令行(Debug → Command 窗口)支持 SAVE 命令,可以把一段内存内容导出为 Intel HEX 文件:

  • 在 Command 窗口输入(示例):

    text 复制代码
    SAVE flash_block.hex 0x08000000, 0x08000400

    参数含义:

    • flash_block.hex:你要保存的文件名(默认在工程目录)
    • 0x08000000:起始地址
    • 0x08000400:结束地址(导出 0x08000000~0x080003FF 这一段)
      注意:这里写的是"结束地址",不是"长度"。
  • SAVE 命令说明文档里讲的是:将内存区域以 HEX386 格式写入文件。
    这样你就有了一份"从 Flash 里原封不动导出来"的数据文件。


三、把 HEX 转成数组/CSV,并做 16 位补码转换

现在你拿到了 flash_block.hex,但它是 HEX 格式,不方便直接画图,一般做法是:

  • 要么用在线工具 / 小工具把 HEX 转成二进制 / C 数组 / CSV
  • 要么直接用 Python/C 脚本解析 HEX 文件并做补码转换
    这里给你一个最通用、可自动化的做法:用 Python 脚本一次性做完"解析 HEX + 补码转换 + 生成 CSV"。
    假设:
  • 你的原始采样数据是 16 位,按"小端模式(Little Endian)"存在 Flash 中(STM32 这类常见)
  • 地址 0x08000000 开始是:
    • 0x03 0x1F 0x03 0x3B 0x01 0xAD ...
  • 对应的 16 位有符号值是:
    • 0x1F030x3B030xAD01 ...

示例:Python 脚本解析 HEX + 转 16 位有符号 + 生成 CSV

你可以建一个 parse_hex.py

python 复制代码
import intelhex
import csv
# 输入 Keil 导出的 HEX 文件
hex_file = "flash_block.hex"
csv_file = "flash_wave.csv"
start_addr = 0x08000000
end_addr   = 0x08000400  # 和 SAVE 命令的结束地址一致
ih = intelhex.IntelHex(hex_file)
values = []
addr = start_addr
while addr < end_addr:
    # 小端模式:低字节在前,高字节在后
    low  = ih[addr]
    high = ih[addr + 1]
    u16 = (high << 8) | low   # 组合成 16 位无符号整数
    # 转为 16 位有符号(补码)
    if u16 & 0x8000:
        i16 = u16 - 0x10000
    else:
        i16 = u16
    values.append(i16)
    addr += 2  # 每次跳 2 字节
# 写入 CSV(只有一列,就是转换后的值)
with open(csv_file, "w", newline="") as f:
    writer = csv.writer(f)
    writer.writerow(["Index", "Value"])  # 表头
    for i, v in enumerate(values):
        writer.writerow([i, v])
print(f"Done. Written {len(values)} samples to {csv_file}.")

需要先安装 intelhex 库:

bash 复制代码
pip install intelhex

运行脚本后,你会得到 flash_wave.csv,里面形如:

text 复制代码
Index,Value
0,192
1,315
2,429
3,533
...

这个 Value 就是你"Flash 源头数据 + 16 位补码转换"之后的真实波形值。

四、可视化成波形,和你的解析结果对比

有了 CSV 之后,你可以用三种常用方式可视化。

1)用 Excel 快速看趋势

  • 直接用 Excel 打开 flash_wave.csv
  • 选中两列数据,插入"折线图"
  • 看一下:
    • 波形是否类似正弦/三角/你预期的信号
    • 有没有奇怪的跳变(比如从几百突然跳到几千)
      这一步主要用来判断"源头数据本身是不是就乱"。

2)用 Python + Matplotlib 画更漂亮的波形

python 复制代码
import csv
import matplotlib.pyplot as plt
xs = []
ys = []
with open("flash_wave.csv") as f:
    reader = csv.DictReader(f)
    for row in reader:
        xs.append(int(row["Index"]))
        ys.append(int(row["Value"]))
plt.figure(figsize=(10, 4))
plt.plot(xs, ys, marker='o', markersize=3, linestyle='-')
plt.title("Flash Waveform (signed 16-bit)")
plt.xlabel("Sample Index")
plt.ylabel("Amplitude")
plt.grid(True)
plt.tight_layout()
plt.show()

这样你可以很清楚地看到:

  • 是否是连续平滑的波形
  • 在 0 附近是否正确跨越正负(例如从几十到负几十,而不是从几十跳到 65471)

3)和"你的代码解析结果"对比(判断是否解析错误)

你前面有一段从 data 里解析通道数据并做 twos_comp 的代码。你可以:

  • 在 Keil 调试时:
    • 在 Watch 窗口添加 wavedata.channelValue[curchanneltmp][0]lenOfChannel 等,实时查看解析后的数组。
    • 或在调试过程中执行类似的 SAVE 命令,把解析后的数组所在内存也导出一份 HEX/CSV。
  • 然后画在同一张图上对比:
    • 曲线 A:直接从 Flash 导出 + 正确补码转换("标准答案")
    • 曲线 B:你的代码解析出来的数据
      对比时看几个点:
  • 形状是否一致(正弦/方波/三角等)
  • 幅值是否一致
  • 有没有"多出一些奇怪的点"或"整体平移/翻转"
  • 特别检查从正到负的过渡区域(例如你之前那组 60 → 65471)
    如果形状明显不一样,大部分是你代码里:
  • 通道号/索引用错
  • 数据长度算错
  • 高低位字节搞反
  • 没有做补码转换或转换方式不对

五、几个常见坑和检查点

1)大小端模式

  • 很多 ARM MCU(STM32 等)是小端:
    • 低字节在低地址,高字节在高地址
  • 如果你误用大端解析,波形会变得完全不对(幅值、噪声都异常)
  • 可以在 Memory 窗口先看几个典型点的字节分布:
    • 如果 Flash 中是 01 FC,预期值大概是 0xFC01
    • 如果你解析出 0x01FC,说明大小端反了

2)数据类型 & 步长

  • 如果你的数据实际是:
    • 16 位有符号:用 int16_t,步长 = 2 字节
    • 32 位有符号/浮点:步长 = 4 字节
  • 步长错了,会导致解析错位(比如把高/低字拼到相邻采样上)

3)数组边界 / 通道切换

  • 你之前的代码里 curchanneltmpmaxchannel 等逻辑,如果在 Flash 里有多个通道连续排布:
    • 需要确认每个通道的起始地址和长度
    • 不然容易把两个通道的数据拼在一起,看起来像奇怪的折线

4)如果只是简单确认 Flash 数据是不是"写死"得对

  • 直接在 Keil 里:
    • 打开 Watch 窗口,添加数组变量
    • 看它的值是不是你预期
    • 再对比一下 Memory 窗口同一位置的字节
  • 如果两者都对,那问题基本就出在"接收/解析"逻辑,而不是 Flash 源头。

六、小结:推荐的实战步骤

给出一个简单可照抄的流程:

  1. 在 Keil 里调试,Memory 窗口定位到你的 Flash 数组起始地址(比如 0x08001000

  2. 用 Command 窗口执行:

    text 复制代码
    SAVE flash_block.hex 0x08001000 0x08001200

    导出这块数据到 HEX 文件

  3. 用 Python 解析这个 HEX 文件,按 16 位小端 + 补码转换,生成 flash_wave.csv

  4. 用 Excel/Matlab/Python 画出波形,确认是否像你预期的正弦/三角等信号

  5. 同时,在 Keil 调试中导出你代码解析出来的数组(也可以用 SAVE 或 watch+复制),按相同方式画出来

  6. 把两张图叠在一起对比:

    • 完全一致:说明解析没问题,源头数据也 OK
    • 不一致:根据差异点反推:
      • 波形整体平移/翻转 → 大小端或符号位有问题
      • 多出跳变、毛刺 → 通道/长度/索引处理有误
      • 某一段完全乱掉 → 可能是多通道混在一起或数组指针错
相关推荐
qqssss121dfd5 小时前
STM32H750XBH6的ETH模块移植LWIP
网络·stm32·嵌入式硬件
想放学的刺客6 小时前
单片机嵌入式试题(第27期)设计可移植、可配置的外设驱动框架的关键要点
c语言·stm32·单片机·嵌入式硬件·物联网
天昊吖6 小时前
stc8H启用DMA发送后 卡住【踩坑日志】
单片机
李永奉7 小时前
杰理芯片SDK开发-ENC双麦降噪配置/调试教程
人工智能·单片机·嵌入式硬件·物联网·语音识别
BackCatK Chen7 小时前
第 1 篇:软件视角扫盲|TMC2240 软件核心特性 + 学习路径(附工具清单)
c语言·stm32·单片机·学习·电机驱动·保姆级教程·tmc2240
兆龙电子单片机设计7 小时前
【STM32项目开源】STM32单片机多功能电子秤
stm32·单片机·开源·毕业设计·智能家居
切糕师学AI7 小时前
ARM 架构中的复位(Reset)与复位流程
arm开发·单片机·嵌入式·复位
wotaifuzao7 小时前
STM32多协议网关-FreeRTOS事件驱动架构实战
stm32·嵌入式硬件·can·freertos·uart·modbus·spi
llilian_167 小时前
信号发生器 多通道多功能脉冲信号发生器应用解决方案 多功能脉冲发生器
功能测试·单片机·嵌入式硬件·测试工具
yuanmenghao8 小时前
Classic AUTOSAR深入浅出系列 - 【第十六篇】MCAL:为什么 MCU 换了,上层几乎不用动
单片机·嵌入式硬件·autosar