# 工程操作 ## 1.1 各类文件含义 | 文件 | 作用功能 | | ------------------- | ------------------------------------------------------------ | | `.eww`工作空间文件 | 顶层容器,管理**多个相关联的工程** | | `.ewp`工程文件 | 存储单个工程的**完整配置** | | `.cspy`工程配置文件 | 保存调试会话的**具体硬件配置**(仅调试相关)。 | | `.ewd`调试会话文件 | | | `.dep`依赖文件 | | | `.icf`链接脚本 | 代码数据在芯片芯片内存中的物理布局,设置栈和堆其实地址及大小 | | `.ewt`模板文件 | | | .s汇编源文件 | 经汇编器生成.o文件**1. 芯片启动初始化** **2. 硬件底层操作****中断服务函数 | | .a二进制静态库 | | | .map | 看内存存储地址, | | | | ## 1.2 新建项目 * 新建项目 ![](pictures\图片2.png) * 选择空模板 ![](pictures\图片3.png) * 保存工作区 ![](pictures\图片4.png) * 添加文件夹 ![](pictures\图片5.png) * 添加所有文件 ![](pictures\图片7.png) * 添加库文件路径(**相对路径**) ![](pictures\图片8.png) # 工程配置 ## 2.1设备配置 > ![](pictures\图片10.png) ## 2.2 编译配置 ### 2.2.1优化等级 ​ ![](pictures\图片9.png) | 等级 | 行为 | 场景 | | -------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | **None(无优化)** | 完全不优化,代码按原始顺序逐行编译。 | 初级调试阶段(变量未被优化,便于观察) 排查编译器行为异常问题 | | **Low(低优化)** | 基础优化:删除无操作指令、合并重复加载操**保持函数栈帧完整** | 日常调试开发,对执行速度要求不高的模块 | | **Medium(中优化)** | 开启函数内联(小函数直接展开)循环展开,寄存器复用加强 | 需要兼顾速度和体积的应用,发布版本的预备测试阶段,**影响调试**时局部变量观察 | | **High(高优化)** | 激进策略:向量化指令、分支预测优化,**大幅调整代码结构**(如重排指令流水线) | 对实时性要求高的场景(电机控制、信号处理)资源宽裕但性能吃紧的模块; **可能暴露隐藏的时序BUG 调试时变量可能(被优化掉)** | ### 2.2.2 硬件浮点 > ![](pictures\图片12.png) ### 2.2.3 文件路径 > - **设置位置**: > `Project > Options > C/C++ Compiler > Preprocessor`(相对路径) > - `Additional include directories`头文件 > - `Defined symbols`(预定义全局宏) > > 预编译处理 > > * 定义STM32F401xx,预编译宏识别芯片型号 > * .h中寄存器映射结构被激活 > > ![](pictures\图片8.png) ### 2.3.4 库文件路径 > `Project > Options > Linker > Library` > > ![](pictures\图片20.png) ### 2.2.5 输出. 1. 编译输出 `Project > Options > General Output` **Output directory**生成 .o/.d 文件的目录 **Intermediate files directory**临时文件目录 2. 可执行文件 ![](pictures\图片21.png) 3. 输出hex文件 * ![](pictures\图片11.png) ## 2.3 调试器配置 ![](pictures\图片17.png) ## 2.4 库相关配置 ### 2.4.1 库类型 | **库类型** | **文件格式** | **使用场景** | **配置入口** | | :--------------: | :----------: | :---------------: | :------------------------------: | | **静态库** | `.a` | 核心算法/驱动封装 | Linker > Library | | **运行时库** | 内置 | 标准C/C++函数支持 | General Options > Library Config | | **第三方源码库** | `.c`/`.h` | 开源组件集成 | C/C++ Compiler > Preprocessor | | **系统库** | `.lib` | 操作系统接口 | Linker > Extra Library Search | ![](pictures\图片22.png) ## 2.5 静态库封装 ### 创建库工程 1. 建项目`Project > Create New Project...` → 选择 **Library** 模板 → 输入库名称(如 `MyLib`)→ 指定芯片型号。 2. 右键工程名 → `Add` → 添加库功能的源文件(`.c`/`.cpp`)和头文件(`.h`)。 * 排除不要生成的库文件 ![](pictures\图片23.png) ![](pictures\图片14.png) --- ## 2.6 调用 1. 将静态库头文件(.h)复制到inc目录 2. **添加头文件路径** `Project > Options > C/C++ Compiler > Preprocessor` → 填写头文件路径(如 `$PROJ_DIR$\inc`)。 3. 链接库文件 * `Project > Options > Linker > Library` → 添加库搜索路径(如 `$PROJ_DIR$\..\MyLib\Output\Release`)。 * 在 **Additional libraries** 中填写库名(如 `MyLib`,**不带扩展名**)。 * 若有多个库,用空格分隔(`MyLib1 MyLib2`)。 4. 代码调用 ~~~ c #include "mylib_functions.h" // 静态库头文件 int main() { lib_init(); // 调用库的初始化函数 int result = calculate(3, 5); // 调用库的计算函数 while(1); return 0; } ~~~ # iar功能 ## 图标 ![](pictures\图片29.png) > 1. 搜索功能 > 2. 替换内容 > 3. 跳转到指定行 > 4. 书签(在光标所指处,进行书签添加删除) > 5. 进行书签跳转 ![](pictures\图片30.png) > 1. 编译当前文件 > 2. 编译所有文件 > 3. 在光标出添加断点 > 4. 下载并进入调试 > 5. 直接进行调试 # 工程调试 ## 断点 ![](pictures\图片15.png) 1. 设置断点,--点击代码左侧 2. 禁用断点,---右键disable 3. 启用断点,---右键Enable 4. 删除断点,再次点击 5. 条件断点 ![](pictures\图片16.png) ### 数据断点 全局变量可以打数据断点,局部变量不可以. ![](pictures\图片32.png) | **特性** | 数据断点 | 条件断点 | | :----------: | :--------------: | :-------------------: | | **触发条件** | 内存访问 | 代码位置 + 自定义条件 | | **硬件依赖** | 是(DWT单元) | 否 | | **数量限制** | 4个(Cortex-M) | 无 | | **性能影响** | 零开销 | 条件计算引入延迟 | | **典型场景** | 全局变量篡改监控 | 循环内定点检查 | 1. **数据断点** → 用于捕获 **不可预测** 的内存篡改 2. **条件断点** → 用于 **可预测逻辑错误** 的定位 3. **性能敏感时**:用 `if(cond){bkpt;}` 替代复杂条件断点 4. **多地址监控**:采用分组轮换策略 * 监控信息 `查看变量值,和存储所在的寄存器值` ![](pictures\图片28.png) | **工具类型** | 数据刷新机制 | 显示格式控制 | 适用场景 | | :-------------: | :--------------------: | :----------: | :------------------: | | **Watch** | 手动刷新(暂停时) | ✅ 支持 | 分析暂停时的变量快照 | | **Live Watch** | 自动实时刷新(运行中) | ❌ 不支持 | 监控运行时动态变化 | | **Quick Watch** | 单次快照 | ✅ 支持 | 快速查看复杂表达式 | | **Locals** | 局部变量窗口 | | | | .Auto | 自动显示表达式/变量窗 | | | | static | 静态变量窗口 | | | * 寄存器信息 ![](pictures\图片26.png) ​ * 内存信息 ![](pictures\图片25.png) ![](pictures\图片31.png) | 普通内存 | 简单内存 | | ------------ | ------------ | | 使用地址索引 | 变量名称索引 | ___ * 汇编窗口 ​ ![](pictures\图片27.png) * 栈信息汇编信息 ![](pictures\图片24.png) * 单步调试 ![](pictures\图片19.png) * 编译 * 全编译(make) * | **编译 (Compile)** | Ctrl+F7 | **当前文件**((`.c/.cpp/.s`)) | 生成 `.o` 对象文件 | | ---------------------- | ------- | -------------------------------- | --------------------------- | | **全编译 (Make)** | F7 | 全部文件 | 增量编译+链接 → 生成 `.out` | | **重建 (Rebuild All)** | - | **所有文件** | 全量编译+链接 → 完整输出 | 编译-下载调试 * 在光标处添加断点 * 下载调试 * 调试 * 停止调试 | 图标 | 作用 | | -------------- | ------------------------------------------------------------ | | step over | 不进入内部直接得到结果 | | step into | 执行下一条语句,若遇到函数调用则进入该函数内部 | | step out | 立即执行完当前函数,并返回到调用该函数的位置 | | Run to Cursor | 全速执行到光标所在行暂停临时断点 | | Next Statement | **强制修改程序计数器(PC)**,将下条执行语句重定向到光标位置,程序暂停时执行 | # 拓展 ## 调试器 stlink启动三种模式 | **复位模式** | **操作原理** | **适用场景** | **IAR 配置路径** | | :---------------------: | :---------------------------------: | :------------------------------: | :----------------------------------: | | **硬件复位 (Hardware)** | 拉低目标芯片的 **NRST 引脚** | 1. 芯片完全卡死 2. Flash锁死 | `Debugger > Setup > Reset: Hardware` | | **内核复位 (Core)** | 通过 **Cortex-M 调试端口** 复位内核 | 1. 保留外设状态 2. 快速重启调试 | `Debugger > Setup > Reset: Core` | | **系统复位 (System)** | 触发 **SYSRESETREQ 信号** | 1. 复位内核+外设 2. 模拟上电复位 | `Debugger > Setup > Reset: System` | | **软件复位 (Software)** | 写 **AIRCR 寄存器** | 1. 无NRST引脚设计 2. 远程复位 | `Debugger > Setup > Reset: Software` | | ST-link | j-link | I-Jet Trace | | -------- | ------------ | ----------- | | 低速5M | 较高 | 高速50M | | 便宜 | | 贵 | | | | iar深度绑定 | | SWD/JTAG | JTAG/SWD/SWO | 多ETM | ## 上电启动 * 硬件启动,启动 ## 寄存器相关 | **寄存器** | **别名** | **位宽** | **核心作用** | **是否可自由使用** | | :--------: | :------------------: | :------: | :----------------------------: | :----------------: | | **R0-R12** | 通用寄存器 | 32-bit | 数据存储与运算 | ✅ 是 | | **R13** | SP (Stack Pointer) | 32-bit | 栈指针(管理函数调用栈) | ⚠️ 受限 | | **R14** | LR (Link Register) | 32-bit | 保存函数返回地址 | ⚠️ 受限 | | **R15** | PC (Program Counter) | 32-bit | 程序计数器(指向下条指令地址) | ❌ 不可直接修改 | | **xPSR** | 程序状态寄存器 | 32-bit | 记录运算状态(零/负/进位等) | ⚠️ 受限 | 单片机启动项 ## **Debugger和Download** | **特性** | **Debugger(调试器)** | **Download(下载)** | | :----------: | :------------------------: | :------------------------: | | **核心目标** | **实时监控与分析**程序行为 | **单向传输**固件到目标芯片 | | | 需支持调试协议的接口 | 只需物理连接 | | | 开发/测试 | 量产/维护 | ## 栈使用空间大小分析 ### 1.静态分析 `project-->options-->linker-->list-->Generate linker map file-->stack usage analysis` ```yaml A[Project > Options] --> B[Linker] B --> C[List] C --> D[勾选 Generate linker map file] D --> E[勾选 Generate stack usage analysis] ``` ![](pictures\图片33.png) | **选项名称** | **作用** | **推荐场景** | | :-------------------------------: | :----------------------------------------: | :----------------------: | | **✓ Generate linker map file** | 生成 `.map` 文件(内存布局详情+符号地址) | **必选**(内存分析必备) | | **✓ Generate log file** | 生成链接日志(库引用/段合并记录) | 调试链接问题时启用 | | **▢ Automatic library selection** | 自动选择依赖库(跳过未使用的库) | 启用可减小固件体积 | | **▢ Initialization decisions** | 记录全局变量初始化顺序(C++中关键) | C++多模块初始化调试 | | **▢ Module selections** | 列出所有被链接的 `.o/.a` 文件 | 检查冗余模块/库依赖 | | **▢ Redirected symbols** | 显示重定向符号(如 `printf` 重定向到串口) | 自定义库函数调试 | | **▢ Section selections** | 输出每个段(section)的详细地址分配 | 手动优化内存布局时 | | **▢ Stack usage call graph** | **栈使用调用图**(函数调用链+最大栈消耗) | **栈溢出分析必备** | | **▢ Unused section fragments** | 标记被丢弃的未使用段(如未调用的函数) | 清理死代码优化 Flash | | **▢ Veneer statistics** | 统计中断桥接(veneer)数量(跨域调用开销) | 长跳转指令优化 | > 编译生成静态文件然后进行分析 ### 2.动态分析 ## .icf文件分析 ### 2.为变量分配固定内存块 #### 1. **定义内存块** ```c define block MY_DATA_BLOCK with size = 256, alignment = 4 { }; ``` #### 2. **分配区域** ```c place in RAM_region { block MY_DATA_BLOCK }; ``` #### 3. **C 代码中使用** ```c #pragma location = "MY_DATA_BLOCK" __no_init uint8_t sensorBuffer[256]; // 分配到自定义块 ``` #### 4. **高级用法:绝对地址分配** ```c // 强制变量到0x20001000 #pragma location = 0x20001000 __no_init volatile uint32_t systemFlags; ```