我正在努力使用GCC从newlib到我的esp32中正确实现printf。
我已经阅读了newlib文档,它为我提供了有关如何调用printf的一般信息,但没有向我解释后端实现。
根据我目前的研究,我确定printf将格式化的字符串输出到STDOUT。在PC上,这对我来说比较容易理解,因为有一个控制台窗口可以显示printf的格式化输出,但是在嵌入式系统上,我知道您必须告诉库将printf的格式化输出重定向到何处,这就是我想弄清楚。
再次,根据我的研究,我了解到要实现此功能需要一些功能,特别是功能_write
。
我发现如何弥合printf与利用_write
函数之间的差距非常困难。我希望这里的人可以帮助我了解如何正确实现printf。
如果我错过了一些清楚地说明此问题的文档,请重定向到该文档。我尝试阅读newlib文档以及与GCC相关的文档,但是并没有真正提到如何使用printf,但是有很多关于如何调用printf和格式化字符串的文档,但这很简单。我需要知道如何从MCU的STDOUT获取格式化的字符串。
谢谢大家!
答案 0 :(得分:0)
在Newlib中,您没有实现库中包含的printf()
。您只需实现最少的syscall集即可支持该库。流设备sycall API由open
,close
,read
和write
(或后缀为_r
的可重入版本)组成-在此重入非常有用如果您正在使用多线程并且需要每个线程errno
(在任何实现特定的重新进入要求中)。
如果您仅实现stdout
(printf()
,putchar()
,puts()
等使用的流)并且仅支持单个设备(通常是UART) )并且不关心重定向或重新进入的能力,那么open
,close
和read
可以为空,而write
可以直接将提供的缓冲区直接输出到您的低级串行I / O API:
int _write(int handle, char *data, int size )
{
int count ;
handle = handle ; // unused
for( count = 0; count < size; count++)
{
outputByte( data[count] ) ; // Your low-level output function here.
}
return count;
}
请注意,这里handle
尚未使用。对于stdout
,它将为1(stdin
= 0且stderr
= 2)。如果您想为handle
和stdout
使用单独的输出设备,或者如果您正在支持其他设备或文件系统以及stderr
或{{1},则使用fopen
参数重定向。它用于标识stdout
打开的蒸汽。通过忽略它,所有流输出(例如open
都将以相同的方式处理并输出到同一设备);在许多情况下(fprintf()
只是获取调试输出的一种方法,或者您的应用程序没有不需要的文件系统。
考虑到printf()
函数write
将“正常工作”(以最简单的方式),因为所有stdio输出函数都在后台调用printf()
。建议使用具有缓冲且无阻塞的低级输出功能(例如,中断驱动的UART驱动程序)。
很显然,如果您也想在write
上接受 input ,则可以实现类似的stdin
函数。
如果您要堆(read
等),则还需要实现malloc()
/ sbrk
。我建议您至少在Newlib syscalls中没有其他实现。
Bill Gaitliff在Porting and Using Newlib in Embedded Systems中讨论了对系统调用实现的更复杂处理,而在here中讨论了基本实现,而{{3}中提供了与上面类似的示例性最小实现存根。 }本身。