有没有可能在没有标准库的情况下写入控制台?c / c++

is it possible write to console without stdlibs? c/c++

本文关键字:控制台 c++ 情况下 有可能 标准      更新时间:2023-10-16

我正在手臂微处理器上编程,并试图通过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_xprintf()为所有变量(printf, sprintf, fprintf等)完成所有艰苦的工作

int do_xprintf(void (*outputfunc)(void *extra, char c), void *extra, const char *fmt, va_list args)
{
    char *ptr = fmt;
    while(1)
    {
       char c = *ptr++;
       if (c == '%')
       {
            c = *ptr++; // Get next character from format string. 
            switch(c)
            {
               case 's': 
                  char *str = va_arg(args, const char *);
                  while(*str)
                  {
                      count++;
                      outputfunc(extra, *str);
                      str++;
                  }
                  break; 
               case 'x': 
                  base = 16;
                  goto output_number;
               case 'd':
                  base = 10;
         output_number:
                  int i = va_arg(args, int);
                  // magical code to output 'i' in 'base'. 
                  break;
               default:
                  count++;
                  outputfunc(extra, c);
                  break;
         }
         else
             count++;
             outputfunc(extra, c);
     }
     return count;
 }                

现在,您所需要做的就是填充上面的一些代码,并编写输出到串行端口的outputfunc()。

请注意,这是一个粗略的草图,我敢肯定代码中有一些错误-如果你想支持浮点数或"宽度",你将不得不在这方面多做一点工作…

(注意额外的参数—对于输出到FILE *的文件指针,对于sprintf,您可以传递缓冲区和缓冲区位置的结构,或者类似的东西)

"控制台"的概念在您正在使用的特定系统的上下文中没有多大意义。通常在嵌入式程序中没有控制台的真正概念。

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

完成这些之后,您可以按照Mats的指示编写自己的printf。

由于通过嵌入式系统中的串行端口打印出信息会修改主程序的时序,因此我发现的最佳解决方案是发送2字节编码的小消息(有时1字节工作得很好),然后使用PC中的程序解码这些消息并提供必要的信息,其中可以包括统计数据和您可能需要的一切。通过这种方式,我只是在主程序中增加了一点开销,而让PC来完成处理消息的繁重工作。也许像这样:

  • 1字节消息:bits 7:4 =模块ID, bits 3:0 =调试信息

  • 2字节消息:bits 15:12 =模块ID, bits 11:8 =调试信息,bits 7:0 = data.

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

也许它不像伪printf函数那样灵活,因为您需要在PC中解码一组固定的消息,但它不会增加太多的开销,正如我之前提到的。

希望有帮助。

费尔南多

我发现在后台调试中,将字符排队到一个循环缓冲区中,然后由art传输寄存器上的轮询例程耗尽,这是我选择的方法。

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

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