为什么 printf() 不适合调试嵌入式系统?

电器工程 C 调试
2022-01-02 20:18:54

我想尝试使用printf().

我可以理解您没有预定义的输出位置,并且它可能会消耗有价值的引脚。同时,我看到人们使用 UART TX 引脚使用自定义DEBUG_PRINT()宏输出到 IDE 终端。

4个回答

我可以提出使用 printf() 的一些缺点。请记住,“嵌入式系统”的范围可以从具有几百字节程序存储器的东西到具有千兆字节 RAM 和 TB 非易失性存储器的成熟机架式 QNX RTOS 驱动系统。

  • 它需要某个地方来发送数据。也许您在系统上已经有一个调试或编程端口,也许您没有。如果您不这样做(或者您拥有的那个不工作),它就不是很方便。

  • 在所有情况下,它都不是轻量级功能。如果你有一个只有几 K 内存的微控制器,这可能是一件大事,因为在 printf 中的链接可能会自己吃掉 4K。如果你有一个 32K 或 256K 的微控制器,这可能不是问题,更不用说如果你有一个大型嵌入式系统。

  • 它对于查找与内存分配或中断相关的某些类型的问题几乎没有用处,并且可以在包含或不包含语句时改变程序的行为。

  • 它对于处理对时间敏感的东西是非常无用的。最好使用逻辑分析仪和示波器或协议分析仪,甚至模拟器。

  • 如果您有一个大程序,并且在更改 printf 语句并更改它们时必须重新编译很多次,那么您可能会浪费很多时间。

它有什么好处 - 它是一种以每个 C 程序员都知道如何使用的预格式化方式输出数据的快速方法 - 零学习曲线。如果您需要为正在调试的卡尔曼滤波器输出一个矩阵,最好以 MATLAB 可以读取的格式输出它。当然比在调试器或仿真器中一次查看一个 RAM 位置更好.

我不认为它是箭袋中的无用箭头,但应谨慎使用,与 gdb 或其他调试器、仿真器、逻辑分析仪、示波器、静态代码分析工具、代码覆盖工具等一起使用。

除了其他一些很好的答案之外,以串行波特率向端口发送数据的行为相对于您的循环时间可能会非常缓慢,并且会影响程序其余部分的运行方式(任何调试都可以)过程)。

正如其他人一直在告诉您的那样,使用这种技术并没有什么“坏处”,但它确实像许多其他调试技术一样,有其局限性。只要您知道并能够处理这些限制,它就可以非常方便地帮助您正确编写代码。

嵌入式系统具有一定的不透明性,通常会使调试成为一个问题。

printf尝试在微控制器上使用会遇到两个主要问题。

首先,将输出通过管道传输到正确的端口可能会很痛苦。不总是。但有些平台比其他平台更难。一些配置文件的文档可能很差,可能需要进行大量实验。

二是记忆。一个完整的printf库可以很大。有时您不需要所有格式说明符,并且可以使用专门的版本。例如,stdio.h AVR 提供的包含三个不同printf大小和功能的不同的。

由于所有提到的功能的完整实现变得相当大,vfprintf()因此可以使用链接器选项选择三种不同的风格。默认vfprintf()实现所有提到的功能,除了浮点转换。有一个最小化版本vfprintf(),它只实现非常基本的整数和字符串转换工具,但只能#使用转换标志指定附加选项(这些标志从格式规范中正确解析,但随后被简单地忽略)。

我有一个没有可用库且内存最少的实例。所以我别无选择,只能使用自定义宏。但是使用printf与否实际上是符合您要求的方法之一。

为了补充 Spehro Pefhany 所说的“时间敏感的东西”:让我们举个例子。假设您有一个陀螺仪,您的嵌入式系统每秒从该陀螺仪进行 1,000 次测量。您想调试这些测量值,因此需要将它们打印出来。问题:将它们打印出来会导致系统太忙而无法每秒读取 1,000 个测量值,这会导致陀螺仪的缓冲区溢出,从而导致读取(和打印)损坏的数据。因此,通过打印数据,您已经破坏了数据,使您认为读取数据时存在错误,而实际上可能没有。所谓的黑森虫。