STM32 程序不开机问题解决方案

【投稿赢 iPhone 17】「我的第一个开源项目」故事征集:用代码换C位出道! 10w+人浏览 1.6k人参与

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 初始化编译器指令
fputcprintf 底层实现注释掉(可选择重定向到UART)
_sys_open/_sys_close文件操作返回 -1(不支持)
_sys_write/_sys_read读写操作返回 -1(不支持)
_sys_exit程序退出空实现(避免卡死)

适用场景

  • C++ 项目(MicroLIB 不支持)
  • 使用 TensorFlow Lite Micro 等包含标准库调用的第三方库
  • 需要独立运行的嵌入式应用

使用步骤

  1. 在项目中创建 retarget_io.c 文件
  2. 将上述代码复制到文件中
  3. 确保文件被添加到编译列表
  4. 重新编译并下载程序
  5. 断开调试器,重启设备验证程序能够独立运行

注意事项

  • 如果需要 printf 输出,可以取消注释 fputc 函数并配置相应的 UART
  • 对于使用大量标准库的项目(如 TensorFlow Lite Micro),此方案是必需的
  • 确保栈和堆大小配置合理(建议栈 4KB,堆 2KB)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值