如何让printf在STM32F103上工作?
How to make printf work on STM32F103?
我是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
Look there。这是来自 glib
的 printf
。但是你有微控制器。所以你应该写自己的 printf
,其中 vfprintf
将 return 结果放入缓冲区,接下来你将数据从缓冲区发送到 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
。标准 vsprintf
很重。通常使用 vsprintf
特征的一小部分。
编写自己的 printf
实现是一个选项,而且可能是我最推荐的选项。从标准库实现中获得一些灵感并编写您自己的版本,只为满足您的要求。通常,您要做的是,首先重新定位一个 putc
函数以通过您的串行接口发送 char 。然后使用 putc
自定义实现覆盖 printf
方法。也许,一种非常简单的方法是通过递归调用 putc
函数来按字符发送字符串。
最后但同样重要的是,您可以找到一些轻量级 printf
实现。这些轻量级实现提供的代码大小和功能集介于自定义编写的 printf
函数和常用标准 printf
函数(又名野兽)之间。我最近尝试了这个 Tiny Printf 并且非常满意它在 ARM 内核上的内存占用和所需执行周期数方面的性能。
-PS
前一段时间从我自己的 writings 复制而来。
Link:
尝试像这样劫持 _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 将通过此功能(当然取决于您使用的库)。
通过包含以下链接器标志:
LDFLAGS += --specs=rdimon.specs -lc -lrdimon
您似乎正在尝试使用所谓的 半主机。您是在告诉链接器包含系统调用库。
Semihosting is a mechanism that enables code running on an ARM target to communicate and use the Input/Output facilities on a host computer that is running a debugger.
Examples of these facilities include keyboard input, screen output, and disk I/O. For example, you can use this mechanism to enable functions in the C library, such as printf() and scanf(), to use the screen and keyboard of the host instead of having a screen and keyboard on the target system.
由于您使用开源工具进行 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 接口将适用于任何编译器,但您必须检查每个板的引脚配置。
我是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
Look there。这是来自 glib
的 printf
。但是你有微控制器。所以你应该写自己的 printf
,其中 vfprintf
将 return 结果放入缓冲区,接下来你将数据从缓冲区发送到 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
。标准 vsprintf
很重。通常使用 vsprintf
特征的一小部分。
编写自己的 printf
实现是一个选项,而且可能是我最推荐的选项。从标准库实现中获得一些灵感并编写您自己的版本,只为满足您的要求。通常,您要做的是,首先重新定位一个 putc
函数以通过您的串行接口发送 char 。然后使用 putc
自定义实现覆盖 printf
方法。也许,一种非常简单的方法是通过递归调用 putc
函数来按字符发送字符串。
最后但同样重要的是,您可以找到一些轻量级 printf
实现。这些轻量级实现提供的代码大小和功能集介于自定义编写的 printf
函数和常用标准 printf
函数(又名野兽)之间。我最近尝试了这个 Tiny Printf 并且非常满意它在 ARM 内核上的内存占用和所需执行周期数方面的性能。
-PS
前一段时间从我自己的 writings 复制而来。
Link:
尝试像这样劫持 _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 将通过此功能(当然取决于您使用的库)。
通过包含以下链接器标志:
LDFLAGS += --specs=rdimon.specs -lc -lrdimon
您似乎正在尝试使用所谓的 半主机。您是在告诉链接器包含系统调用库。
Semihosting is a mechanism that enables code running on an ARM target to communicate and use the Input/Output facilities on a host computer that is running a debugger.
Examples of these facilities include keyboard input, screen output, and disk I/O. For example, you can use this mechanism to enable functions in the C library, such as printf() and scanf(), to use the screen and keyboard of the host instead of having a screen and keyboard on the target system.
由于您使用开源工具进行 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 接口将适用于任何编译器,但您必须检查每个板的引脚配置。