我正在使用arm微处理器进行编程,并尝试通过UART使用print语句进行调试。我不想仅为调试添加stdlibs
。有没有办法在没有stdio.h
/ iostream.h
的情况下打印到控制台?我可以自己编写printf()
吗?
或者我可以使用DMA控制器直接写入UART。但是,我想避免这是可能的。使用内置的测试功能“echo”或 “远程环回”我知道我已正确配置UART。
答案 0 :(得分:9)
简短回答:是的,完全可以同时完成两种解决方案。
如果要支持所有数据类型和格式,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()。
请注意,这是粗略的草图,我确信代码中有一些错误 - 如果你想支持浮点或“宽度”,你将需要更多地工作...... < / p>
(关于额外参数的注意事项 - 输出到FILE *
将成为文件指针,对于sprintf
,您可以传递缓冲区的结构和缓冲区中的位置,或类似的东西)
答案 1 :(得分:2)
&#34; console&#34;的概念在您使用的特定系统的上下文之外没有太多意义。通常在嵌入式程序中没有控制台的真实概念。
您正在寻找的是一种从系统中获取数据的方法。如果您想使用UART,并且您没有使用像GNU / linux这样的高级操作系统,则需要编写自己的I / O驱动程序。通常,这意味着首先通过寄存器写操作将UART配置为所需的分配/奇偶校验/流控制。对于任何类型的强大IO,您都希望它是中断驱动的,因此您需要为使用循环缓冲区的tx和rx编写ISR。
完成后,您可以编写自己的printf,如Mats所示。
答案 2 :(得分:1)
我找到了后台调试,将字符排入循环缓冲区,然后通过uart传输寄存器上的轮询程序排出,这是我选择的方法。
排队例程基于字符,字符串和可变大小(十六进制或固定宽度十进制)。豪华缓冲程序可以指示溢出的保留字符。
该方法对目标操作的开销/影响最小,可以在中断例程中使用(小心),并且这个想法很容易转移,所以我忽略了我使用过的所有系统上的调试器。
答案 3 :(得分:1)
由于通过嵌入式系统中的串口打印信息会修改主程序的时序,我发现的最佳解决方案是发送一个以2个字节编码的小消息(有时1个字节工作正常),然后使用PC中的程序解码这些消息并提供必要的信息,其中包括统计数据和您可能需要的所有信息。 这样,我只是在主程序中添加了一点开销,让PC完成了处理消息的艰苦工作。 也许是这样的:
1字节消息:位7:4 =模块ID,位3:0 =调试信息。
2字节消息:位15:12 =模块ID,位11:8 =调试信息,位7:0 =数据。
然后,在PC软件中,您必须声明一个表格,其中包含映射到给定模块ID /调试信息对的消息,并使用它们在屏幕上打印。
也许它不像伪printf函数那么灵活,因为你需要一组固定的消息来解码,但它并没有增加太多的开销,正如我之前提到的那样。
希望它有所帮助。
费尔南多