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
    +关注

    关注

    2240

    文章

    10675

    浏览量

    348855
  • 函数
    +关注

    关注

    3

    文章

    3904

    浏览量

    61310
  • 串口打印
    +关注

    关注

    0

    文章

    10

    浏览量

    3047

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

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

收藏 人收藏

    评论

    相关推荐

    串口屏的安装方式方法

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

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

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

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

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

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

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

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

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

    串口接收数据的两种方式是什么

    RXNE位的状态来确定数据是否接收。 中断方式就是通过配置接收输出控制通道,配置NVIC,在中断服务子函数里进行数据的接收。 1. 需要更改的地方 既然我们要实现串口的接收,那么就要配置串口
    的头像 发表于 11-10 16:20 979次阅读
    <b class='flag-5'>串口</b>接收数据的两种<b class='flag-5'>方式</b>是什么

    基于STM32F407的USB转串口功能实现

    实现USB转串口功能,需要将单片机真实串口(这里以USART1为例)的收发数据与USB口进行交互。用过USB虚拟串口的朋友可能知道,要
    发表于 10-16 16:04 1198次阅读
    基于STM32F407的USB转<b class='flag-5'>串口</b><b class='flag-5'>功能</b><b class='flag-5'>实现</b>

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

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

    基于IAR搭建RA MCU串口与RTT Viewer打印(下)

    基于IAR搭建RA MCU串口与RTT Viewer打印
    的头像 发表于 08-14 09:50 176次阅读
    基于IAR搭建RA MCU<b class='flag-5'>串口</b>与RTT Viewer<b class='flag-5'>打印</b>(下)

    基于IAR搭建RA MCU串口与RTT Viewer打印(上)

    基于IAR搭建RA MCU串口与RTT Viewer打印
    的头像 发表于 08-14 09:49 194次阅读
    基于IAR搭建RA MCU<b class='flag-5'>串口</b>与RTT Viewer<b class='flag-5'>打印</b>(上)

    RA4M2开发(1)----使用串口进行打印

    本篇文章主要介绍如何使用e2studio对瑞萨RA4M2开发板进行串口打印配置。
    的头像 发表于 07-27 10:00 1010次阅读
    RA4M2开发(1)----使用<b class='flag-5'>串口</b>进行<b class='flag-5'>打印</b>

    串口接收不定长数据的实现方式

    使用串口进行数据的收发在嵌入式产品中是很常用的一种通信方式,因为串口的简单使用,很容易就被选为产品中数据交互的通信手段。
    的头像 发表于 07-04 15:23 1420次阅读
    <b class='flag-5'>串口</b>接收不定长数据的<b class='flag-5'>实现</b><b class='flag-5'>方式</b>

    NDA102EC1中更改UUART1作为调试串口打印输出调试信息未能成功的原因?

    参考网上STM32修改fputc(int ch, FILE *f),把串口打印函数printf()重定向到UUART1模块的端口输出,最终未成功。 但循着类似解决问题的思路,直接在工程中查找有关
    发表于 06-27 07:11

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

    M487JIDAE如何使用ITM功能实现printf打印?
    发表于 06-13 06:30

    Keil微库和标准C库的区别

    初学者使用 Keil 学习单片机,用串口printf打印输出时,通常都会使能Keil工具自带的微库(MicroLib)。
    发表于 06-05 10:09 1217次阅读
    Keil微库和标准C库的区别