如何让 printf 在 STM32F103 上工作?
Posted
技术标签:
【中文标题】如何让 printf 在 STM32F103 上工作?【英文标题】:How to make printf work on STM32F103? 【发布时间】:2017-02-01 12:12:50 【问题描述】:我是 STM32F103 世界的新手。我有一个 STM32F103 的演示代码,我正在使用 arm-none-eabi 来编译它。
我尝试了可以在 Google 上找到的内容,但到目前为止没有任何效果。我已经花了三天时间解决这个问题。
谁能给我一个运行良好的 printf 演示代码?
我的 makefile 的一部分:
CFLAG = -mcpu=$(CPU) -mthumb -Wall -fdump-rtl-expand -specs=nano.specs --specs=rdimon.specs -Wl,--start-group -lgcc -lc -lm -lrdimon -Wl,--end-group
LDFLAG = -mcpu=$(CPU) -T ./stm32_flash.ld -specs=nano.specs --specs=rdimon.specs -Wl,--start-group -lgcc -lc -lm -lrdimon -Wl,--end-group
【问题讨论】:
“它不起作用”是什么意思?它是一个微控制器,您希望在哪里打印文本?通常在为嵌入式目标编程时,您会创建自己的print
使用 UART(或其他通信协议)的函数集。查找一些 UART 库,或者一些使用您的调试器的调试库(例如,如果您有 Segger 调试器,则在您的 PC 上使用带有 JLink Viewer 的 Segger RTT)
我使用 arm-none-eabi- 来编译。那就是问题所在。我知道如何在 keil 项目中使用 printf。我使用 USART1 输出。您是否尝试使用此编译器构建 bin 文件。
【参考方案1】:
通过包含以下链接器标志:
LDFLAGS += --specs=rdimon.specs -lc -lrdimon
您似乎正在尝试使用所谓的 semihosting。您是在告诉链接器包含系统调用库。
Semihosting 是一种机制,它使运行在 ARM 目标上的代码能够通信并使用运行调试器的主机上的输入/输出工具。
这些工具的示例包括键盘输入、屏幕输出和磁盘 I/O。例如,您可以使用这种机制来启用 C 库中的函数,例如 printf() 和 scanf(),以使用主机的屏幕和键盘,而不是目标系统上的屏幕和键盘。
由于您使用开源工具进行 STM32 开发(Makefile 和 arm-none-eabi),我假设您也使用 openOCD 对微控制器进行编程。 openOCD 要求您也使用以下命令启用半主机:
arm semihosting enable
您可以在 openOCD 脚本的命令中确保终止配置阶段并使用“init”命令进入运行阶段。下面是一个 openOCD 脚本示例(适用于 STM32F103):
source [find target/stm32f1x.cfg]
init
arm semihosting enable
此处提到的将fputc()
函数重新定位到UART 接口的其他解决方案也将起作用并且可能会起作用。半主机将适用于所有最新的 ARM Cortex-M,但需要一些编译器和调试器配置(见上文)。将fputc()
函数重定向到 UART 接口将适用于任何编译器,但您必须检查每个板的引脚配置。
【讨论】:
【参考方案2】:编写自己的printf
实现是一种选择,在我看来,这可能是最推荐的选择。从标准库实现中获得一些灵感并编写您自己的版本,以满足您的要求。通常,您要做的是,首先重新定位putc
函数以通过您的串行接口发送 char 。然后使用putc
自定义实现覆盖printf
方法。也许,一种非常简单的方法是通过递归调用putc
函数来逐字符发送字符串。
最后但同样重要的是,您可以找到一些轻量级的printf
实现。这些轻量级实现提供的代码大小和功能集介于自定义编写的printf
函数和标准的printf
函数(又名野兽)之间。我最近尝试了这个Tiny Printf,对它在 ARM 内核上的内存占用和所需执行周期数方面的性能非常满意。
-PS
从我自己的writings 复制过来。
【讨论】:
【参考方案3】:Look there。这是来自glib
的printf
。但是你有微控制器。所以你应该写自己的printf
,vfprintf
会将结果返回到缓冲区,接下来你将从缓冲区发送数据到 UART。种
void printf( const char * format, ... )
char buffer[256];
va_list args;
va_start (args, format);
vsprintf (buffer,format, args);
send_via_USART1 (buffer);
va_end (args);
你也可以写自己的vsprintf
。 Standart vsprintf
很重。通常会使用一小部分 vsprintf
功能。
【讨论】:
【参考方案4】:链接:How to retarget printf() on an STM32F10x?
尝试像这样劫持 _write 函数:
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
int _write(int file, char *ptr, int len)
switch (file)
case STDOUT_FILENO: /*stdout*/
// Send the string somewhere
break;
case STDERR_FILENO: /* stderr */
// Send the string somewhere
break;
default:
return -1;
return len;
原来的 printf 会经过这个函数(当然取决于你使用什么库)。
【讨论】:
我在 STM32F072 上使用这种方法。详情在这里。 electronics.stackexchange.com/questions/206113/…以上是关于如何让 printf 在 STM32F103 上工作?的主要内容,如果未能解决你的问题,请参考以下文章
Arduino STM32F103如何让pa11输出高电平?