我们在程序中使用printf把需要打印的信息打印到控制台上,那么在嵌入式中如何用printf来输出打印信息呢?
有两种方法:
其一,把fput()函数重新定义: 因为printf()会调用fputc()函数向控制台发数据,我们将fputc()重定义,在该函数里边用串口发数据,所以当我们调用printf()时,就可以通过串口把数据发出去。
其二,重新定义一个类似printf的函数
首先,介绍把fput()重新定义的方法
struct __FILE
{
int handle;
};
FILE __stdout;
FILE __stdin;int fputc(int ch, FILE * p_file)
{
assert_param(p_file);HAL_UART_Transmit(&UartDebugHandle, (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
因为printf()会调用fputc()函数向控制台发数据,我们将fputc()重定义,在该函数里边用串口发数据,所以当我们调用printf()时,就可以通过串口把数据发出去。
接下来介绍第二种方法:
#include <stdarg.h>
#include <stdio.h>#define MAX_LENGTH 200
static uint8_t debug_buffer[MAX_LENGTH] = {0};void test_printf(const char *fmt, ...)
{
va_list vlist;va_start(vlist, fmt);
vsnprintf(debug_buffer, MAX_LENGTH, fmt, vlist);
HAL_UART_Transmit_IT(&UartDebugHandle, (uint8_t*)debug_buffer,strlen(debug_buffer));
va_end(vlist);
}
然后,就可以调用test_printf()往外发数据了。
eg:int num = 100;
test_printf(“This is test num: %d”,num);
注:
1、在C中,当我们无法列出传递函数的所有实参的类型和数目时,可以用省略号指定参数表。
eg:void test_printf(const char *fmt, ...)
2、函数参数的传递原理
我们知道,函数的参数再内存中是存在栈中的,形参的存入顺序是从右向左存入的,void func(int x, float y, long z),在调用函数时,形参入栈的顺序是z > y >x,即z先入栈。
栈是从上往下增长的,即从内存地址高的位置开始增长,往内存地址低的方向上增长。因此,我们只要知道形参中任一变量的内存地址,就可以得到其它变量的内存地址。
3、介绍下test_printf()的实现
在<stdarg.h>中定义了如下:
typedef char * va_list;
void va_start ( va_list ap, prev_param );
void va_end ( va_list ap );
void test_printf(const char *fmt, ...)
{
//定义指针vlist
va_list vlist;
//让vlist指向形参的第一个变量
va_start(vlist, fmt);
//把fmt和不定长的参数(vlist指向参数列表)复制到debug_buffer中
vsnprintf(debug_buffer, MAX_LENGTH, fmt, vlist);
HAL_UART_Transmit_IT(&UartDebugHandle, (uint8_t*)debug_buffer, strlen(debug_buffer));
//在使用完指针之后,需要把指针关掉,以防出现危险。
va_end(vlist);
}