关注+星标公众号,不错过精彩内容
作者 | strongerHuang
微信公众号 | strongerHuang单片机学习、做项目,经常都会用到类似 printf 这种打印输出的时候。比如:打印输出日志信息打印输出调试信息查看实时数据等而 printf 用的最多的就是UART(重定向串口) 。其实除了串口,也可以使用其他底层接口,I2C、SPI、CAN等这些常见通信接口也是可以的。因为CAN的通信速率相对更高,我之前很多项目不管是传输数据,还是输出信息都用到 CAN 总线进行通信。所以,其实底层也可以“重定向CAN”单片机printf打印输出
单片机 printf 打印输出,最常见的一种是使用UART串口重定向,然后使用微库,比如Keil环境下,只需要在配置界面勾选“微库”即可:
然后串口进行重定向:#include
上面分享的 printf 打印输出都是标准的方法,有些时候,这些标准的方法可能不适合当前的项目。比如内存、Flash不足了,输出的方式不能满足等,这个时候,就需要自定义printf函数了。这里简单分享一下常见的方式。1、底层通信函数UART串口是最常见的一种printf通信接口,其实,CAN这种通信速率更高的接口也是可以的。USART_SendChar((uint8_t)ch);//或者CAN总线作为通信接口CAN_SendChar((uint8_t)ch);2、重定向底层通信接口这里是通过UART串口重定向实现一些基础的字符和字符串输出函数。voidputchar(char c){ USART_SendChar(c);}voidputs(constchar *str){while(*str) {putchar(*str++); }putchar('\n');}3、实现整数输出我们这里使用简单的 itoa(整数转字符串)算法。voidprint_int(int num){char buffer[12];char *ptr = buffer + 11;char is_negative = 0;if (num < 0) { is_negative = 1; num = -num; } *ptr = '\0';do { *--ptr = (num % 10) + '0'; num /= 10; } while (num);if (is_negative) { *--ptr = '-'; }puts(ptr);}4、实现小数点输出如果需要支持小数输出,可以添加一个简单的浮点数打印函数。但是,考虑到有些单片机不支持浮点运算硬件,这里使用定点数(整数和小数部分分离)来实现。voidprint_fixed_point(int num, int fraction_digits){int integer_part = num / (int)pow(10, fraction_digits);int fractional_part = num % (int)pow(10, fraction_digits); print_int(integer_part);putchar('.');for (int i = 0; i < fraction_digits; i++) { fractional_part *= 10;putchar((fractional_part / (int)pow(10, fraction_digits - i)) + '0'); }}5、自定义封装成 printf 风格的函数将以上函数封装成一个类似 printf 的函数。为了简单说明案例,这里只支持 %d 和 %f(使用定点数)格式说明符。voidmy_printf(constchar *format, ...){ va_list args; va_start(args, format);constchar *ptr = format;while (*ptr) {if (*ptr == '%') { ptr++;switch (*ptr) {case'd': {int num = va_arg(args, int); print_int(num);break; }case'f': { // 使用定点数表示int num = va_arg(args, int); // 整数部分和小数部分合并的定点数int fraction_digits = va_arg(args, int); // 小数位数 print_fixed_point(num, fraction_digits);break; }default:putchar('%');putchar(*ptr);break; } } else {putchar(*ptr); } ptr++; } va_end(args);}最后,printf的基本功能就实现了。。。最最后要说明一下,这里举例只是简单给大家说明原理,真正项目,其实还需要添加很多内容,比如:串口发送超时、参数验证等容错设计。
------------ END ------------
●专栏《嵌入式工具》
●专栏《嵌入式开发》
●专栏《Keil教程》
●嵌入式专栏精选教程
关注公众号回复“加群”按规则加入技术交流群,回复“1024”查看更多内容。
点击“阅读原文”查看更多分享。