STM32 程序不开机问题解决方案
问题描述
下载程序后即使断电重启设备,程序也无法运行(已在Flash Download中设置Reset and Run)。只有在Debug模式下多次点击全速运行才能把程序跑起来。
根本原因
标准 C/C++ 库启用了 semihosting 机制,导致程序在没有调试器时卡在初始化阶段:
- 任何调用标准库 I/O 函数的代码(如 printf、putchar、getchar、fopen 等)都会触发 semihosting
- Semihosting 需要调试器连接,独立运行时会卡死在
_sys_write或__main等函数 - 程序会在初始化阶段触发硬故障(HardFault)或进入死循环
解决方案
方案一:使用 MicroLIB(仅适用于纯C项目)
在 Keil 项目的Project -> Options for Target -> Target设置中开启 Use MicroLIB:
- MicroLIB 默认禁用 semihosting
- 提供简化的 I/O 实现,程序可以独立运行
-限制:不支持 C++ 项目

方案二:禁用 semihosting + 重定向 I/O(推荐用于C++项目)
通过添加 retarget_io.c 文件来禁用 semihosting 并重定向 I/O 操作。
retarget_io.c 完整代码
#include<stdio.h>
#include<rt_misc.h>
// 禁用 semihosting (ARM Compiler 6)
extern void __ARM_use_no_argv(void);
// 重定向 stdout 和 stdin (可选择重定向到 UART,这里注释掉)
//int fputc(int ch, FILE *f) {
// 这里可以重定向到 UART,例如 USART1:
// while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
// USART_SendData(USART1, (uint8_t)ch);
// return ch; // 返回字符,表示成功
//}
int fgetc(FILE *f) {
return -1; // 不支持输入,返回 EOF
}
void _ttywrch(int ch) {
fputc(ch, stdout);
}
// 实现空的 syscalls (避免链接错误,防止卡死)
int _sys_open(const char *name, int openmode) {
return -1;
}
int _sys_close(int handle) {
return -1;
}
int _sys_write(int handle, char *buf, int len) {
return -1;
}
int _sys_read(int handle, char *buf, int len) {
return -1;
}
int _sys_istty(int handle) {
return 0;
}
int _sys_seek(int handle, long pos) {
return -1;
}
int _sys_ensure(int handle) {
return -1;
}
long _sys_flen(int handle) {
return -1;
}
void _sys_exit(int return_code) {
// while (1); // 避免死循环
}
retarget_io.c 实现原理
核心机制
1.禁用 semihosting 初始化
-extern void __ARM_use_no_argv(void); 告诉 ARM Compiler 6 链接器禁用 semihosting
- 避免程序启动时尝试与调试器通信
2.重定向 I/O 操作
- 实现空的
_sys_*函数,防止调用未定义的 semihosting 函数 - 返回 -1 表示不支持文件操作,避免程序卡死
3.安全退出处理
- 空的
_sys_exit实现避免异常退出时的无限循环或硬故障
函数说明
| 函数 | 作用 | 实现方式 |
|---|---|---|
__ARM_use_no_argv | 禁用 semihosting 初始化 | 编译器指令 |
fputc | printf 底层实现 | 注释掉(可选择重定向到UART) |
_sys_open/_sys_close | 文件操作 | 返回 -1(不支持) |
_sys_write/_sys_read | 读写操作 | 返回 -1(不支持) |
_sys_exit | 程序退出 | 空实现(避免卡死) |
适用场景
- C++ 项目(MicroLIB 不支持)
- 使用 TensorFlow Lite Micro 等包含标准库调用的第三方库
- 需要独立运行的嵌入式应用
使用步骤
- 在项目中创建
retarget_io.c文件 - 将上述代码复制到文件中
- 确保文件被添加到编译列表
- 重新编译并下载程序
- 断开调试器,重启设备验证程序能够独立运行
注意事项
- 如果需要 printf 输出,可以取消注释
fputc函数并配置相应的 UART - 对于使用大量标准库的项目(如 TensorFlow Lite Micro),此方案是必需的
- 确保栈和堆大小配置合理(建议栈 4KB,堆 2KB)
3025

被折叠的 条评论
为什么被折叠?



