我们在程序中使用printf把需要打印的信息打印到控制台上,那么在嵌入式中如何用printf来输出打印信息呢?
有两种方法:
其一,把fput()函数重新定义
其二,重新定义一个类似printf的函数
首先,介绍把fput()重新定义的方法
1 struct __FILE 2 { 3 int handle; 4 }; 5 FILE __stdout; 6 FILE __stdin; 7 8 int fputc(int ch, FILE * p_file) 9 { 10 assert_param(p_file); 11 12 HAL_UART_Transmit(&UartDebugHandle, (uint8_t *)&ch, 1, 0xFFFF); 13 14 return ch; 15 }
因为printf()会调用fputc()函数向控制台发数据,我们将fputc()重定义,在该函数里边用串口发数据,所以当我们调用printf()时,就可以通过串口把数据发出去。
接下来介绍第二种方法:
1 #include <stdarg.h> 2 #include <stdio.h> 3 4 #define MAX_LENGTH 200 5 static uint8_t debug_buffer[MAX_LENGTH] = {0}; 6 7 void test_printf(const char *fmt, ...) 8 { 9 va_list vlist; 10 11 va_start(vlist, fmt); 12 vsnprintf(debug_buffer, MAX_LENGTH, fmt, vlist); 13 HAL_UART_Transmit_IT(&UartDebugHandle, (uint8_t*)debug_buffer,strlen(debug_buffer)); 14 va_end(vlist); 15 } 16 然后,就可以调用test_printf()往外发数据了。 17 eg:int num = 100; 18 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);
}