C++ 是否可以在没有STDLIB的情况下写入控制台?c/c++;

C++ 是否可以在没有STDLIB的情况下写入控制台?c/c++;,c++,c,microcontroller,uart,C++,C,Microcontroller,Uart,我在arm微处理器上编程,并试图通过UART使用打印语句进行调试。我不想仅仅为了调试而添加stdlibs。是否有一种方法可以在不使用stdio.h/iostream.h的情况下打印到控制台?我是否可以自己编写printf() 或者,我可以使用DMA控制器直接写入UART。然而,我想避免这是可能的。使用内置测试功能“echo”或 “远程环回”我知道我已经正确配置了UART。简短回答:是的,两种解决方案都完全可以实现 如果要支持所有数据类型和格式,printf函数相当复杂。但是,编写能够以几种不同的

我在arm微处理器上编程,并试图通过UART使用打印语句进行调试。我不想仅仅为了调试而添加
stdlibs
。是否有一种方法可以在不使用
stdio.h
/
iostream.h
的情况下打印到控制台?我是否可以自己编写
printf()

或者,我可以使用DMA控制器直接写入UART。然而,我想避免这是可能的。使用内置测试功能“echo”或
“远程环回”我知道我已经正确配置了UART。

简短回答:是的,两种解决方案都完全可以实现

如果要支持所有数据类型和格式,printf函数相当复杂。但是,编写能够以几种不同的基址输出字符串或整数的代码并不难(大多数人只需要十进制和十六进制,但八进制可能只在有了十进制和十六进制后再添加3-4行代码)

通常,printf的编写方式如下:

 int printf(const char *fmt, ...)
 {
     int ret;
     va_list args; 

     va_start(args, fmt)
     ret = do_xprintf(outputfunc, NULL, fmt, args); 
     va_end(args);
     return ret;
}
然后,
do\u xprintf()
完成所有变体(printf、sprintf、fprintf等)的所有艰苦工作

现在,您只需填写上面代码的几位,然后编写一个输出到串行端口的outputfunc()

请注意,这是一个粗略的草图,我确信代码中有一些错误-如果您想支持浮点或“宽度”,您将不得不在这方面做更多的工作

(注意额外参数-对于将作为文件指针的
文件*
的输出,对于
sprintf
,您可以传递缓冲区的结构和缓冲区中的位置,或者类似的内容)

除了您正在使用的特定系统的上下文之外,“控制台”的概念没有太多意义。在嵌入式程序中,通常没有真正的控制台概念

您正在寻找的是一种从系统中获取数据的方法。如果您想使用UART,而不是使用像GNU/linux这样的高级操作系统,则需要编写自己的I/O驱动程序。通常,这意味着首先通过寄存器写入为所需的butrate/奇偶校验/流量控制配置UART。对于任何类型的健壮IO,您都希望它是中断驱动的,因此您需要为使用循环缓冲区的tx和rx编写ISR


完成后,您可以编写自己的printf,如图所示。

我发现,对于后台调试,将字符排队到循环缓冲区中,然后通过uart传输寄存器上的轮询例程将其排空,这是我选择的方法

排队例程基于字符、字符串和变量大小(十六进制或固定宽度十进制)。高级缓冲区例程可以用保留字符指示溢出


这种方法对目标操作的开销/影响最小,可以(小心地)在中断例程中使用,而且这个想法很容易转移,因此我忽略了我使用过的所有系统上的调试器。

因为通过嵌入式系统中的串行端口打印信息会修改主程序的计时,我找到的最好的解决方案是发送一条2字节编码的小消息(有时1字节就可以了),然后使用PC中的程序对这些消息进行解码,并提供必要的信息,包括统计数据和您可能需要的一切。 这样,我只给主程序增加了一点开销,让PC机来处理消息。 也许是这样的:

 int printf(const char *fmt, ...)
 {
     int ret;
     va_list args; 

     va_start(args, fmt)
     ret = do_xprintf(outputfunc, NULL, fmt, args); 
     va_end(args);
     return ret;
}
  • 1字节消息:位7:4=模块ID,位3:0=调试信息

  • 2字节消息:位15:12=模块ID,位11:8=调试信息,位7:0=数据

然后,在PC软件中,您必须声明一个表,其中包含映射到给定模块ID/调试信息对的消息,并使用它们在屏幕上打印

也许它不如pseudo printf函数灵活,因为您需要在PC中使用一组固定的消息来解码,但正如我前面提到的,它不会增加太多开销

希望能有帮助


Fernando

是的,这是可能的-您可以编写自己的输出例程,找到一个小型独立的partial printf()实现,或者编写必要的后端支持,以使这些函数能够从最小的嵌入式libc(可能包含在您的工具链中)在您的平台上运行。谢谢。我听说newlib作为嵌入式libc可以正常工作。不过,我将首先查找部分printf()。@ChrisStratton:这取决于操作系统。本机操作系统例程可能是标准库。非常感谢。我是少数只需要十进制/十六进制的人之一。我正在使用定点表示法,希望验证我的结果。这将使事情变得更容易。我感谢你的帮助!为什么
output\u number
是case语句中的一个标签,而不是普通函数?@Lundin:只是它的键入时间较短。它也可能产生更短的代码,除非编译器非常聪明,并且意识到两个函数调用之间的唯一区别是输入参数。谢谢!我意识到了这一点。我最初是想弄清楚如何避开这个问题,因为我遇到了一些问题。但我发现,在每次写入tx缓冲区后,我必须使用处理器访问状态寄存器。如果我不这样做,它就会停滞不前。我现在处理波特率的问题,但我肯定会使用垫子的东西,一旦我得到的纠结了。谢谢你的帮助