0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

使用MicroLIB+fputc的方式实现串口打印功能

GReq_mcu168 来源:玩转单片机 2020-08-05 10:52 次阅读

常规打印方法

STM32的应用中,我们常常对printf进行重定向的方式来把打印信息printf到我们的串口助手。

在MDK环境中,我们常常使用MicroLIB+fputc的方式实现串口打印功能,即:

要实现fputc函数的原因是:printf函数依赖于fputc函数,重新实现fputc内部从串口发送数据即可间接地实现printf打印输出数据到串口。

不知道大家有没有看过正点原子裸机串口相关的例程,他们的串口例程里不使用MicroLIB,而是使用标准库+fputc的方式。相关代码如:

#if1 #pragmaimport(__use_no_semihosting) //标准库需要的支持函数 struct__FILE { inthandle; }; FILE__stdout; /** *@brief定义_sys_exit()以避免使用半主机模式 *@paramvoid *@returnvoid */ void_sys_exit(intx) { x=x; } intfputc(intch,FILE*f) { while((USART1->ISR&0X40)==0);//循环发送,直到发送完毕 USART1->TDR=(u8)ch; returnch; } #endif

关于这两种方法的一些说明可以查看Mculover666兄的《重定向printf函数到串口输出的多种方法》这篇文章。这篇文章中不仅包含上面的两种方法,而且也包含着在GCC中使用标准库重定向printf的方法。

自己实现一个打印函数

以上的几种方法基本上是改造C库的printf函数来实现串口打印的功能。其实我们也可以自己实现一个串口打印的功能。

printf本身就是一个变参函数,其原型为:

intprintf(constchar*__format,...);

所以,我们要重新封装的一个串口打印函数自然也应该是一个变参函数。具体实现如下:

1、基于STM32的HAL库

左右滑动查看全部代码>>>

#defineTX_BUF_LEN256/*发送缓冲区容量,根据需要进行调整*/ uint8_tTxBuf[TX_BUF_LEN];/*发送缓冲区*/ voidMyPrintf(constchar*__format,...) { va_listap; va_start(ap,__format); /*清空发送缓冲区*/ memset(TxBuf,0x0,TX_BUF_LEN); /*填充发送缓冲区*/ vsnprintf((char*)TxBuf,TX_BUF_LEN,(constchar*)__format,ap); va_end(ap); intlen=strlen((constchar*)TxBuf); /*往串口发送数据*/ HAL_UART_Transmit(&huart1,(uint8_t*)&TxBuf,len,0xFFFF); }

因为我们使用printf函数基本不使用其返回值,所以这里直接用void类型了。

自定义变参函数需要用到va_start、va_end等宏,需要包含头文件stdarg.h。关于变参函数的一些学习可以查看网上的一些博文,如:

https://www.cnblogs.com/wulei0630/p/9444062.html

这里我们使用的是STM32的HAL库,其给我们提供HAL_UART_Transmit接口可以直接把整个发送缓冲区的内容给一次性发出去。

2、基于STM32标准库

若是基于STM32的标准库,就需要一字节一字节的循环发送出去,具体代码如:

左右滑动查看全部代码>>>

#defineTX_BUF_LEN256/*发送缓冲区容量,根据需要进行调整*/ uint8_tTxBuf[TX_BUF_LEN];/*发送缓冲区*/ voidMyPrintf(constchar*__format,...) { va_listap; va_start(ap,__format); /*清空发送缓冲区*/ memset(TxBuf,0x0,TX_BUF_LEN); /*填充发送缓冲区*/ vsnprintf((char*)TxBuf,TX_BUF_LEN,(constchar*)__format,ap); va_end(ap); intlen=strlen((constchar*)TxBuf); /*往串口发送数据*/ for(inti=0;i< len; i++)   {  while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET);      USART_SendData(USART1, TxBuf[i]);   } }

测试结果:

我们也可以使用我们的MyPrintf函数按照上一篇文章:《C语言嵌入式中几个非常实用的宏技巧》的方式封装一个宏打印函数:

以上就是我们自定义方式实现的一种串口打印函数。

但是,我想说:对于串口打印的使用,我们没必要自己创建一个打印函数。

看到这,是不是有人想要打我了。。。。看了半天,你却跟我说没必要用。。。

哈哈,别急,我们不应用在串口打印调试方面,那可以用在其它方面呀。

(1)应用一:

比如最近我在实际应用中:我们的MCU跑的是我们老大自己写的一个小的操作系统+我们公司自己开发的上位机

我们MCU端与上位机使用的是串口通讯,MCU往上位机发送的数据有两种类型,一种是HEX格式数据,一种是字符串数据。

但是我们下位机的这两种数据,在通过串口发送之前都得统一把数据封包交给那个系统通信任务,然后再由通信任务发出去。

在这里,就不能用printf了。老大也针对他的这个系统实现了一个deb_printf函数用于打印调试。

但是,那个函数既复杂又很鸡肋,稍微复杂一点的数据就打印不出来了。

因此我利用上面的思路给它新封装了一个打印调试函数,很好用,完美地兼容了老大的那个系统。具体代码就不分享了,大体代码、思路如上。

(2)应用二:

我们在使用串口与ESP8266模块通讯时,可利用类似这样的方式封装一个发送数据的函数,这个函数的使用可以像printf一样简单。

可以以很简单的方式把数据透传至服务端,比如我以前的毕设中就有这么应用:

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • STM32
    +关注

    关注

    2265

    文章

    10870

    浏览量

    354694
  • 函数
    +关注

    关注

    3

    文章

    4303

    浏览量

    62411
  • 串口打印
    +关注

    关注

    0

    文章

    10

    浏览量

    3081

原文标题:串口打印知多少?

文章出处:【微信号:mcu168,微信公众号:硬件攻城狮】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    打印针控制机构实现打印针的什么和什么动作

    打印针控制机构实现打印针的 出针 和 收针 动作。这是针式打印打印过程中的关键环节。打印针控制
    的头像 发表于 10-14 15:45 255次阅读

    重定向了fputc及putchar函数,但printf没有输出,为什么?

    重定向了fputc及putchar函数,但printf没有输出 删除了drivers/drv_uart.c drv_uart.h 删除了文件rt-thread\\components
    发表于 07-18 07:44

    单独打印UART_test时串口可以打印,添加以下代码后串口打印,为什么?

    单独打印UART_test时串口可以打印,添加以下代码后串口打印。代码看附件截图
    发表于 06-27 06:21

    串口屏的几种安装方式

    串口屏的几种安装方式
    的头像 发表于 05-10 11:28 1502次阅读

    有谁知道如何在热敏打印机中实现图片的灰阶打印效果吗?

    有谁知道如何在热敏打印机中实现图片的灰阶打印效果。 现在基本上文字打印,图片打印功能都已开发结束
    发表于 04-24 15:43

    串口屏的安装方式方法

    串口屏的安装方式方法
    的头像 发表于 04-02 16:25 1416次阅读

    如何添加microLib库?cubeIDE是否支持添加microLib库?

    如何添加microLib库?cubeIDE是否支持添加microLib库?
    发表于 03-08 08:21

    SPWM调制方式是怎样实现变压功能的?又是怎样实现变频功能的?

    SPWM调制方式是怎样实现变压功能的?又是怎样实现变频功能的? SPWM是一种常见的调制方式,它
    的头像 发表于 02-06 11:09 1507次阅读

    SPWM调制方式是怎样实现变压功能的?

    SPWM调制方式是怎样实现变压功能的? SPWM调制是一种常用的调制方式,用于将直流电压转换为交流电压,同时也可以实现变压
    的头像 发表于 02-06 11:08 1121次阅读

    TLE9854 printf函数无法输出是怎么回事?

    TLE9854 的串口能正常输出,现在想配置成printf,使能了STDOUT和STDIN,选择了MicroLIB,可是没法输出,怀疑是程序里这个函数没被调用,这个函数在哪里调用的? void
    发表于 02-02 16:05

    xmc7200使用cy_retarget_io_init_fc功能初始化串口6,为什么printf功能CAN不打印出数据?

    我使用的是xmc7200开发板,使用cy_retarget_io_init_fc功能初始化串口6,为什么printf功能 CAN 不打印出数据?
    发表于 01-30 06:55

    M487JIDAE如何使用ITM功能实现printf打印?

    M487JIDAE如何使用ITM功能实现printf打印?
    发表于 01-16 08:03

    STM32WB55开发(4)----配置串口打印Debug调试信息

    在STM32WB55系列微控制器上进行开发时,实时监控应用程序的运行情况和调试潜在问题是至关重要的。使用串口(USART/UART)进行Debug信息打印是一种简便、高效的方法。下面是如何在STM32WB55上配置串口
    的头像 发表于 12-01 15:48 1189次阅读
    STM32WB55开发(4)----配置<b class='flag-5'>串口</b><b class='flag-5'>打印</b>Debug调试信息

    STM32H5开发(5)----串口打印配置

    在使用STM32CUBEIDE开发STM32H5项目时,串口打印被证明是一项极其有益的调试工具,能够在开发过程中实时输出信息和调试数据,起到了至关重要的作用。通过充分利用串口打印
    的头像 发表于 12-01 15:04 924次阅读
    STM32H5开发(5)----<b class='flag-5'>串口</b><b class='flag-5'>打印</b>配置

    基于RASC的keil电子时钟制作(瑞萨RA)(2)----配置keil以及使用串口进行打印

    配置。通过详细的步骤和示例,读者将能够了解如何使用RA Smart Configurator这一强大工具来简化串口配置过程,并将其应用于实际项目中,以实现高效的串口通信和打印
    的头像 发表于 12-01 14:47 650次阅读
    基于RASC的keil电子时钟制作(瑞萨RA)(2)----配置keil以及使用<b class='flag-5'>串口</b>进行<b class='flag-5'>打印</b>