【STM32学习5】STM32使用printf函数 打印到电脑串口助手

2023-05-16


本文所使用的方法与代码参考自正点原子,如果想要详细了解这方面的知识,请阅读正点原子官方提供的文档。


一、背景

在开发STM32应用时,将一些信息通过串口打印到电脑上是常用的调试手段。C语言标准库中的printf函数是我们常用的打印函数。但是在STM32应用下一般无法直接使用这个函数,正点原子给出的解释如下,有兴趣可以详细了解一下。

标准库下的 printf 为调试属性的函数,如果直接使用,会使单片机进入半主机模式(semihosting),这是一种调试模式,直接下载代码后出现程序无法运行,但是在连接调试器进行 Debug 时程序反而能正常工作的情况。半主机是 ARM 目标的一种机制,用于将输入/输出请求从应用程序代码通信到运行调试器的主机。例如,此机制可用于允许 C 库中的函数(如 printf()和 scanf())使用主机的屏幕和键盘,而不是在目标系统上设置屏幕和键盘。这很有用,因为开发硬件通常不具有最终系统的所有输入和输出设备,如屏幕、键盘等。半主机是通过一组定义好的软件指令(如 SVC)SVC 指令(以前称为 SWI 指令)来实现的,这些指令通过程序控制生成异常。应用程序调用相应的半主机调用,然后调试代理处理该异常。调试代理(这里的调试代理是仿真器)提供与主机之间的必需通信。也就是说使用半主机模式必须使用仿真器调试。
如果想在独立环境下运行调试功能的函数,我们这里是 printf,printf 对字符 ch 处理后写入文件 f,最后使用 fputc 将文件 f 输出到显示设备。对于 PC 端的设备,fputc 通过复杂的源码,最终把字符显示到屏幕上。那我们需要做的,就是把 printf 调用的 fputc 函数重新实现,重定向fputc 的输出,同时避免进入半主模式。

目前想要在SMT32上使用printf有两种方法:

  1. 通过代码取消ARM的半主机工作模式,并重定向printf函数
  2. 使用微库MicroLib,并重定向printf函数。

由于微库裁剪了许多标准库的功能,如果注重功能完整性建议使用第一种方法。

二、取消ARM的半主机工作模式

添加stdio.h头文件,并在程序中加入以下代码段即可(代码引自正点原子)

/******************************************************************************************/

/* 在合适的位置引用下面头文件 */
#include <stdio.h>

/* 加入以下代码, 支持printf函数, 而不需要选择use MicroLIB */

#if 1
#if (__ARMCC_VERSION >= 6010050)                    /* 使用AC6编译器时 */
__asm(".global __use_no_semihosting\n\t");          /* 声明不使用半主机模式 */
__asm(".global __ARM_use_no_argv \n\t");            /* AC6下需要声明main函数为无参数格式,否则部分例程可能出现半主机模式 */

#else
/* 使用AC5编译器时, 要在这里定义__FILE 和 不使用半主机模式 */
#pragma import(__use_no_semihosting)

struct __FILE
{
    int handle;
    /* Whatever you require here. If the only file you are using is */
    /* standard output using printf() for debugging, no file handling */
    /* is required. */
};

#endif

/* 不使用半主机模式,至少需要重定义_ttywrch\_sys_exit\_sys_command_string函数,以同时兼容AC6和AC5模式 */
int _ttywrch(int ch)
{
    ch = ch;
    return ch;
}

/* 定义_sys_exit()以避免使用半主机模式 */
void _sys_exit(int x)
{
    x = x;
}

char *_sys_command_string(char *cmd, int len)
{
    return NULL;
}

/* FILE 在 stdio.h里面定义. */
FILE __stdout;

/* 重定义fputc函数, printf函数最终会通过调用fputc输出字符串到串口 
其中串口可根据实际使用情况调整 */
int fputc(int ch, FILE *f)
{
    while ((USART1->SR & 0X40) == 0);             /* 等待上一个字符发送完成 */

    USART1->DR = (uint8_t)ch;                     /* 将要发送的字符 ch 写入到DR寄存器 */
    return ch;
}
#endif
/***********************************************END*******************************************/

上面代码段使用的是串口1(USART1),可根据实际使用情况调整。

三、使用微库MicroLib

直接在Keil中的如下界面勾选使用微库
Keil中使用MicroLib
并添加如下代码段重定向fputc

/* 在合适的位置引用下面头文件 */
#include <stdio.h>

/* 重定义 fputc 函数, printf 函数最终会通过调用 fputc 输出字符串到串口 */
/* 串口可根据实际使用情况调整 */
int fputc(int ch, FILE *f)
{
 while ((USART1->ISR & 0X40) == 0); /* 等待上一个字符发送完成 */
 USART1->TDR = (uint8_t)ch; /* 将要发送的字符 ch 写入到 DR 寄存器 */
 return ch;
}

微库由于裁剪掉了一些功能,有着如下特点:

  • 微库会优化代码空间,但会降低某些程序的执行效率(比如: memcpy()),效率换空间
  • 微库不支持浮点运算,所以在有FPU单元的MCU上,使用MicroLIB并开启FPU会让程序死机或跑飞
  • 微库不支持C++,在使用C++开发MCU时不能使用MicroLib
  • 微库不支持操作系统函数

更详细的讲解可参见博文STM32程序不运行与MicroLIB讲解

四、应用

采用了上面任意一种方法设置后,我们便可在程序中使用printf,并通过串口打印在电脑端的串口助手上。

		printf("123\r\n");
		
		HAL_Delay(500);

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【STM32学习5】STM32使用printf函数 打印到电脑串口助手 的相关文章

随机推荐

  • UART通信协议

    UART通信协议 一 UART是什么 xff1f 1 同步串口通信 vs 异步串口通信2 串行通信 二 通信协议三 工作原理四 特点 一 UART是什么 xff1f 通用异步收发传输器 xff08 Universal Asynchronou
  • win10右下角的通知区域

    属性 gt 通知和操作 gt 选择在任务栏上显示哪些图标 gt
  • UART一对多通信的方法

    通常 xff0c uart为单对单通信 xff0c 当用到一对多时可以用RS485 然而有时候我们MCU的uart口只剩一个 xff0c 又要接多个uart的外围芯片 xff0c 这时如果转成RS485需要加多个485收发器 xff0c 成
  • 全网最全的 postman 工具使用教程

    正文如下 xff0c 如果觉得有用欢迎点赞 关注 postman是一款支持http协议的接口调试与测试工具 xff0c 其主要特点就是功能强大 xff0c 使用简单且易用性好 无论是开发人员进行接口调试 xff0c 还是测试人员做接口测试
  • 星际争霸1终于可以在win10上运行了

    win7的时候 xff0c 星际争霸1就不能运行 xff0c 只好装了个虚拟机 xff0c 在虚拟机里玩 刚刚更新到了win10 xff0c 总觉得在虚拟机里玩不是个事 xff0c 就去网上搜索 xff0c 终于发现了办法 在 StarCr
  • windows下编译opencv 3.4.0

    为了方便后期的调试 xff0c 自己动手编译opencv3 4 0 xff0c 这样有需要的时候还可以自己修改修改源代码 通常来说 xff0c 编译32位比较简单 xff0c 直接用cmake生成编译的工程就行了 xff0c 但64位就比较
  • opencv添加的新接口clearVec()的实现

    自己编译的opencv xff0c 之前文章有说添加了这个接口 xff0c 也有上传3 3 0版本添加这个接口之后编译好的库 xff0c 但是没有把实现过程展现出来 xff0c 导致有些朋友问我如何实现的 xff0c 今天把这个实现放出来
  • 苏泊尔电饭煲不工作的维修

    本篇文章与其说是维修 xff0c 倒不如说成是 拆 xff0c 因为维修相对容易 xff0c 但想拆开却很艰难 xff0c 大部分的时间都花在了拆的工作上面 老家伙的样子如下 型号为 xff1a CYSB50FC99 100 xff0c 铭
  • 萨克斯吹不响的解决办法

    刚开始吹萨克斯 xff0c 发现总是吹不响 看各种入门的文章 xff0c 很多都强调口型的重要性 xff0c 各文章说得也都差不多 xff0c 我仔细捉摸 xff0c 不断尝试 xff0c 似乎还是不得要领 特别是安装好之后 xff0c 很
  • vs2010制作安装工程

    这里的安装工程 xff0c 是指制作安装包 xff0c 而不是vs2010的安装包 用向导生成一个安装工程 xff0c 通常会直接打开一个文件编辑窗口 xff1a 这个窗口很容易编辑 xff0c 把所有要安装的文件拖到 应用程序文件夹 上
  • windows下编译ffmpeg源代码

    由于工作原因 xff0c 需要使用ffmpeg在windows下进行代码跟踪 于是 xff0c 上网找相关文章 xff0c 搜索出来有很多 xff0c 经过查看 xff0c 其中的一个英文网站是最好的 xff0c 网址 xff1a http
  • 注册控件失败之一:提示0x80040200错误的处理办法

    今天有客户反馈说控件无法注册 xff0c 晕 xff0c 这问题好容易困扰开发者以及客服人员 xff0c 但是环境千差万别 xff0c 很难做到完全自动化 出现的错误号码有很多 xff0c 但相对的0x80040200这个号码出现的概率较其
  • win10+ubuntu23.04双系统安装

    win10 win10先安装好 xff08 确保主板上各个螺丝稳定 xff0c 至少4对螺丝 43 铜柱 xff0c 否则会各种蓝屏 xff09 如果双系统安装失败了 xff0c 连win10都进不去了 xff0c 用原版ISO刻录的U盘或
  • 冷门指标移中平均线和多空指数的完美结合(一定要看)

    注 xff0c 原贴地址 xff1a http blog sina com cn s blog 7f0a6fa50101hyls html 在此谨以记录防止原帖无法打开为忧 冷门指标移中平均线和多空指数的完美结合 一定要看 xff09 20
  • LINUX下安装QT的惨痛经历

    安装QT的惨痛经历 目标 xff1a 2012 4月下旬 xff0c 计划开始在linux上安装QT和ffmpeg xff0c 准备摸索一下视频客户端的开发 以下是安装过程 由于没有额外的电脑 xff0c 所以使用了虚拟机安装 电脑上刚好有
  • Linux下CAN总线速率设置,socketCAN。

    背景 xff1a 飞思卡尔Freescale的ARM9处理器i MX25系列 socketCAN对于在Linux下操作CAN总线非常的快捷方便 xff0c 其配置方法和在Linux下对网卡的配置相似 xff0c 方法如下 xff1a 1 i
  • c++在Linux环境下的套接字Tcp通信例子(demo)

    demo包括服务端和客户端的通信 xff0c 发送端发送格式为先发送长度为5的字符串数据 xff0c 告知对方接下来的数据长度 xff0c 接收端首先接收到消息长度 xff0c 再根据消息长度接受接下来的消息 服务端 xff1a inclu
  • yolo_mark工具的使用

    之前自己编译了一下yolo mark用来标注样本 我编译时yolo mark依赖了opencv3 2 0 当时为了方便直接把yolo mark exe放到编译yolo的文件夹 现在要在其他地方使用 xff0c 就把所有文件整理出来 其中op
  • GStreamer与opencv实现rtsp推流

    文章目录 前言安装库代码总结 前言 最近工作遇到瓶颈了呀 xff01 xff01 xff01 公司分配给我的任务是deepstream部署 xff0c 太难了 xff0c gstreamer语言学的我头皮发麻 xff01 xff01 xff
  • 【STM32学习5】STM32使用printf函数 打印到电脑串口助手

    本文所使用的方法与代码参考自正点原子 xff0c 如果想要详细了解这方面的知识 xff0c 请阅读正点原子官方提供的文档 一 背景 在开发STM32应用时 xff0c 将一些信息通过串口打印到电脑上是常用的调试手段 C语言标准库中的prin