keil 异常处理

本文解析了Keil编译器中的几个常见警告及错误,包括未调用函数导致的内存浪费、输入文件类型未知的问题,以及STM32外接晶振更换后程序无法正常运行的原因和解决方案。

问题1

*** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS
SEGMENT: ?PR?_TIMER2_INIT?TIMER2

说明

程序中有些函数例如_TIMER2_INIT(或片段)以前(调试过程中)从未被调用过,或者根本没有调用它的语句。这条警告信息前应该还有一条信息指示出是哪个函数导致了这一问题。只要做点简单的调整就可以。不理它也没什么大不了的。但是,我们知道,即使没有调用这个函数,Keil仍然把它编译连接进整个程序,不过浪费点ROM。最主要的是,在这个函数中的变量,不会被列入覆盖分析范围内,也就是说这些变量占的空间不能被回收,这对于为数不多的RAM资源可是巨大的浪费!

解决方法

  1. 删除或注释掉COMPARE()函数
  2. 利用条件编译#if……#endif,可保留该函数并不编译。如果你一定要考虑可移植性的话,就这样做,否则还是采取方法1
  3. 想不显示这些提示:则可对keil进行如下设置:
    option for target
    —>bl51 misc—>disable warning == 这里写入16

问题2

keil Error: C4065E: type of input file “…” unknown

解决方法

keil包含路径中,添加的路径在文件夹名称中包含一些空格,将面临此错误。

问题3

在STM32F427上,外接晶振25M换成8M,下载程序出现下图1提示:
在这里插入图片描述

分析

晶振频率修改错误导致程序超频锁死。

解决办法

  1. 调整软件工程晶振频率;
  2. BOOT1置0,把BOOT0置1(3.3V),整片擦除程序下载,随后拉低BOOT0(默认状态),重新上电解决。
Keil 开发环境中实现日志处理函数,通常是为了提升嵌入式系统的调试效率和运行时监控能力。通过将日志信息输出到特定的接口(如串口、SWO 或 RTT),可以动态获取系统状态、变量值或异常信息,从而辅助定位问题。 ### 日志处理函数的基本结构 为了统一日志输出的方式并提高可扩展性,可以定义一个包含初始化和打印功能的日志操作结构体。例如: ```c typedef struct { uint8_t (*init)(void* arg); uint8_t (*print)(uint8_t ch); uint8_t (*print_dma)(uint8_t* buffer, uint32_t len); } log_func; ``` 该结构体支持不同的底层传输方式,如阻塞式发送、DMA 异步发送等。接着可以定义一个日志设备结构体来管理日志缓冲区和当前使用的日志函数集: ```c typedef struct { volatile uint8_t type; uint8_t* buffer; volatile uint32_t write_idx; volatile uint32_t read_idx; log_func* log_func; } log_dev; ``` 上述结构允许在运行时切换不同的日志输出方式,例如从串口切换到 SWO 或 RTT[^2]。 ### 在 Keil 中使用 SWO 输出日志 Keil 支持通过 SWO(Serial Wire Output)接口进行非侵入式的调试信息输出。启用 SWO 需要配置芯片的 ITM(Instrumentation Trace Macrocell)模块,并确保调试器支持 SWO 功能。 1. **初始化 SWO 输出** 在系统初始化阶段,需要配置 ITM 和相关寄存器以启用 SWO 输出。以下是一个示例函数: ```c void swo_init(void) { CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; // Enable trace ITM->LAR = 0xC5ACCE55; // Unlock access to ITM registers ITM->TER = 1 << 0; // Enable stimulus port 0 ITM->TCR = ITM_TCR_TraceBusID_Msk | // Enable ITM ITM_TCR_DWT_Interface_CLK_enable_Msk | ITM_TCR_ITM_interface_CLK_enable_Msk; } ``` 2. **实现 SWO 打印函数** 定义一个用于向 SWO 发送单个字符的函数: ```c uint8_t swo_print(uint8_t ch) { while (ITM->PORT[0].u32 == 0); // Wait until ready ITM->PORT[0].u8 = ch; // Send character return 0; } ``` 3. **集成到日志系统** 将 `swo_init` 和 `swo_print` 绑定到 `log_func` 结构中,并设置为当前日志函数: ```c log_func swo_logger = { .init = swo_init, .print = swo_print, .print_dma = NULL // 不支持 DMA 的情况下设为 NULL }; log_dev logger = { .type = LOG_TYPE_SWO, .buffer = NULL, .write_idx = 0, .read_idx = 0, .log_func = &swo_logger }; ``` 4. **调用日志函数** 在应用程序中可以通过封装函数调用日志输出: ```c void log_putc(uint8_t ch) { if (logger.log_func && logger.log_func->print) { logger.log_func->print(ch); } } void log_puts(const char* str) { while (*str) { log_putc(*str++); } } ``` ### 使用 Segger RTT 提升实时性 如果项目对实时性要求较高,推荐使用 Segger RTT(Real-Time Transfer)。RTT 是一种高效的双向通信机制,适用于调试和数据传输。它不需要暂停 CPU 即可读取缓冲区内容,且对系统性能影响极小。 在 Keil 中使用 RTT,需完成以下步骤: 1. 下载并集成 Segger RTT 库; 2. 初始化 RTT 控制块; 3. 使用 `SEGGER_RTT_Write` 等函数输出日志信息; 例如: ```c #include "SEGGER_RTT.h" void rtt_log_init(void) { SEGGER_RTT_Init(); } void rtt_log_putc(uint8_t ch) { SEGGER_RTT_Write(0, &ch, 1); } ``` 随后可在任意位置调用 `rtt_log_putc` 输出日志信息,而不会显著影响程序执行流程[^3]。 ### 调试技巧与注意事项 - **避免频繁写入日志**:过多的日志输出会影响系统性能,建议在关键路径或异常处理中使用。 - **使用缓冲区**:将日志写入环形缓冲区再异步输出,可减少对主流程的干扰。 - **结合断点动作**:在 Keil 中可以设置断点触发日志输出,无需手动插入打印语句。 - **利用 DWT 计数器分析耗时**:在日志中记录时间戳有助于分析代码执行效率[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值