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


一、背景

在开发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中的如下界面勾选使用微库

并添加如下代码段重定向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);

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

  1. STM32使用printf重定向到USART(串口)并打印数据到串口助手

    STM32使用sprintf打印数据到串口助手 一.背景知识 二. 重定向printf到USART1 三.使用printf打印hello,world到串口助手 3.1 usart.c 3.2 usar ...

  2. Python直接调用C库的printf()函数打印一条消息

    github博客传送门 csdn博客传送门 话不多说直接上代码 # 直接从 C 库中调用 printf()函数打印一条消息 # Windows 中的 C 库位于 C:\WINDOWS\system32 ...

  3. printf函数打印

    程序运行的时候,会自动打开三个文件,分别是stdin.stdout.stderr 这三个文件对应的外设分别是 键盘.显示器.显示器 这三个文件对应的文件描述符为 0.1.2 printf函数在显示器上 ...

  4. printf函数打印(一)—— 过程解析篇

    程序运行的时候,会自动打开三个文件,分别是stdin.stdout.stderr 这三个文件对应的外设分别是 键盘.显示器.显示器 这三个文件对应的文件描述符为 0.1.2 printf函数在显示器上 ...

  5. codeblocks printf函数打印不出来_最全C语言基本程序交互函数之输出到屏幕

    前言 上一栏目主要讲解了各种数据类型的知识,大家先闭眼回顾一下数据类型的知识哦.本章节主要内容是讲解程序的基本交互设计之程序的输出.程序和人交互无非就是通过外设进行输入信息,C语言中基本的交互的基本流 ...

  6. stc单片机使用printf()函数打印

    串口波特率初始化: 利用stc-isp工具生成初始化代码, 在串口初始化函数中添加 **TI=1;**如下图,否则printf()无法输出. void UartInit(void) //9600bps ...

  7. stm32+HTU21D温湿度传感器通过usart1发送温湿度数据在串口助手显示

    stm32+HTU21D温湿度传感器 这里就不拍实物图了,我用的是下面这款HTU21D ic是stm32f103vet6 工程代码是io口模拟i2c和传感器通讯 PB6-SCL,PB7-SDA usa ...

  8. 【STM32学习 自制STM32游戏机】

    2020年科协招新需要出训练题,让新生了解一下单片机,所以我这边打算出一道游戏机的题,让新生用单片机实现一个游戏机,共3个游戏可选,分别为:贪吃蛇,打地鼠和推箱子,由于是针对于0基础新生,所以在指标上 ...

  9. 【stm32学习】stm32最小系统和程序下载方式

    文章目录 前言 一.程序下载 1.USB下载方式 2.J-LINK下载方式 前言 stm32学习过程,是从正点原子的开发板开始的,但是正点原子的开发板实在是太大了,而且不便宜,不适合一些实际项目制作, ...

最新文章

  1. 深入剖析ISAServer 网页缓存及配置
  2. 新的GNSS精度度量是怎样定义的?
  3. 地址栏射击游戏!对,你没看错,就是在地址栏上玩的游戏,有图有真相!
  4. SAP Spartacus B2B功能,只渲染BodyContent position里的UI
  5. SQL 字符 数字 转换字母
  6. gprs模块http mqtt_在GPRS模块(SIM800C)和STM32芯片上实现MQTT协议 | TsonTec:测量解决方案提供者...
  7. mysql active_GitHub - vipshop/drc: MySQL active-active replication solution.
  8. 序列化和反序列化的概念
  9. HDU 1693 Eat the Trees ——插头DP
  10. 第14章 学习scikit-learn文档
  11. 用友U872《合同管理》模块操作手册
  12. PLC编程的5种专用语言 ,学习PLC编程得先了解一下!
  13. javascript手册安卓版_JavaScript 手册
  14. QGIS快速提取建筑和道路矢量
  15. Hexo文章中图片点击实现全屏查看
  16. 计算机组装主机怎么拆,【电脑组装知识网】电脑主机组装教程之戴尔显示器底座拆卸教程...
  17. 画笔Paint及模拟画图工具
  18. 键盘上的按键--键码 对应表
  19. 电机速度曲线规划1:梯形速度曲线设计与实现
  20. 钓鱼网站盯上加油卡充值

热门文章

  1. NumPy最详细入门笔记
  2. scratch lenet(9): C语言实现tanh的计算
  3. 开源! ROS2阿克曼开发平台方案
  4. docear使用教程_如何使用Docear进行学术研究
  5. 【图像分割】基于模糊C均值聚类算法CGFFCM实现彩色图像分割附matlab代码
  6. 2022阿里云金秋云创季年终双十一活-动汇总!
  7. 机器学习实践—基于Scikit-Learn、Keras和TensorFlow2第二版—第4章 训练模型
  8. java模拟商店购买
  9. uni-app - 日历选择器组件(支持日期 “范围选择“ 多选 / 支持单选日期 / 自定义默认选中时间 / 弹框式 / 支持农历 )完美兼容 H5 APP 小程序,最好用的教程完整源代码插件!
  10. 数据链路层——广播信道CSMA/CD协议