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

    关注

    2313

    文章

    11195

    浏览量

    374667
  • 函数
    +关注

    关注

    3

    文章

    4422

    浏览量

    67851
  • 串口打印
    +关注

    关注

    0

    文章

    11

    浏览量

    3353

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

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

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    【RA-Eco-RA2E1-V1.0开发板试用】串口打印例程。

    本实验基于瑞萨 RA 系列单片机完成UART 串口通信与printf 重定向功能实现,通过配置串口引脚、初始化驱动、编写发送回调函数,实现
    的头像 发表于 02-24 16:33 450次阅读
    【RA-Eco-RA2E1-V1.0开发板试用】<b class='flag-5'>串口</b><b class='flag-5'>打印</b>例程。

    keil定义fputc函数

    函数 fputc 是输出字符的底层函数,只需要实现这个函数,类似 printf、puts 等函数也可以正常使用了。 由于存在3种文件类型,这里分别定义3种文件类型的fputc函数,在 fput
    发表于 01-22 08:25

    将C库的printf函数重定向到UART的过程

    这里不用keil自带的microLib这个代码,就是自己重新映射端口。 包含头文件 stdio.h #ifdef __GNUC__ /* With GCC/RAISONANCE, small
    发表于 01-21 07:14

    【瑞萨RA6E2地奇星开发板试用】OLED 屏幕驱动,串口打印

    打印 Hello World OLED 12864 显示屏显示 Hello World 【串口打印】 使用 FPS Smart Configuration 设置串口,原理图如下: 开发
    发表于 12-19 18:27

    什么是KEIL的微库(microlib)

    是以牺牲性能为代价的。为了减少容量,MicroLib去掉了一些函数功能,并对一些函数做了空间上的优化。那么Microlib都有哪些不一样呢? main()函数不能带参数,并且main()不能返回
    发表于 12-10 06:27

    使用Keil MicroLIB时自动设置堆大小

    Keil编译项目,如果使用微库MicroLIB,就可以使用malloc。微库内部位置一个堆管理模块。 芯片的RAM大小是固定了的,前面分为全局变量,后面分给堆和栈,这是一般开发方式。 但是我们在开发
    发表于 12-09 07:04

    NucleiStudio_IDE_201909串口打印浮点型数据时无数据输出,软件该如何配置串口才能打印浮点型数据?

    NucleiStudio_IDE_201909串口打印浮点型数据时无数据输出,软件该如何配置串口才能打印浮点型数据?
    发表于 11-07 07:57

    【CPKCOR-RA8D1】基础串口打印测试

    本文将演示如何为瑞萨CPKCOR-RA8D1开发板配置串口功能,并实现最简单的“Hello World”数据打印串口是嵌入式开发中最常用、
    发表于 10-30 15:23

    【CPKCOR-RA8D1】+ 基础串口打印测试

    本文将演示如何为瑞萨CPKCOR-RA8D1开发板配置串口功能,并实现最简单的“Hello World”数据打印串口是嵌入式开发中最常用、
    发表于 10-30 09:40

    串口通信有哪些方式

    串口通信(Serial Communication)是一种通过串行方式逐位传输数据的通信方式,广泛应用于嵌入式系统、工业控制、仪器仪表等领域。其通信方式可根据不同的分类标准划分为多种类
    的头像 发表于 09-28 18:02 1308次阅读

    【HarmonyOS 5】桌面快捷方式功能实现详解

    【HarmonyOS 5】桌面快捷方式功能实现详解 ##鸿蒙开发能力 ##HarmonyOS SDK应用服务##鸿蒙金融类应用 (金融理财# 一、前言 在移动应用开发中,如何让用户快速触达核心
    的头像 发表于 06-21 16:42 2453次阅读
    【HarmonyOS 5】桌面快捷<b class='flag-5'>方式</b><b class='flag-5'>功能</b><b class='flag-5'>实现</b>详解

    【RA4L1-SENSOR】+ RA4L1-SENSOR开发版之使用Jlink的RTT打印功能代替串口

    上一篇帖子中我已经实现了板子上的串口USART9进行输出打印,这篇帖子我采用另外一种串口打印实现
    发表于 06-09 09:03

    【RA4L1-SENSOR】+ RA4L1-SENSOR开发版串口打印功能printf实现

    很高兴收到瑞萨RA生态工作室给与试用的RA4L1-SENSOR开发板,本期就来讲解使用RA4L1-SENSOR开发板实现串口打印功能! 1。打开原理图 可以知道板载的USB
    发表于 06-08 15:01

    【RA-Eco-RA4M2开发板评测】使用Jlink的RTT来实现串口打印功能

    用。 但是在实际开发如果没有预留串口怎么办?其实我们的下载器是可以用来作为调试打印来用的,只是很多小伙伴不知道这个功能而已,今天就来说一下如何用调试器JLink来打印信息。 1、JLi
    发表于 04-30 12:19

    【RA-Eco-RA4M2开发板评测】RA-Eco-RA4M2 串口通信

    代码指定C标准库输出函数的控制终端设备,也就是使用功能I/O重定向。 下面我们以实现printf打印数据到UART(即重定义fputc函数)的实现
    发表于 04-27 23:23