【STM32学习5】STM32使用printf函数 打印到电脑串口助手
本文所使用的方法与代码参考自正点原子,如果想要详细了解这方面的知识,请阅读正点原子官方提供的文档。
一、背景
在开发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有两种方法:
- 通过代码取消ARM的半主机工作模式,并重定向printf函数
- 使用微库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函数 打印到电脑串口助手相关推荐
- STM32使用printf重定向到USART(串口)并打印数据到串口助手
STM32使用sprintf打印数据到串口助手 一.背景知识 二. 重定向printf到USART1 三.使用printf打印hello,world到串口助手 3.1 usart.c 3.2 usar ...
- Python直接调用C库的printf()函数打印一条消息
github博客传送门 csdn博客传送门 话不多说直接上代码 # 直接从 C 库中调用 printf()函数打印一条消息 # Windows 中的 C 库位于 C:\WINDOWS\system32 ...
- printf函数打印
程序运行的时候,会自动打开三个文件,分别是stdin.stdout.stderr 这三个文件对应的外设分别是 键盘.显示器.显示器 这三个文件对应的文件描述符为 0.1.2 printf函数在显示器上 ...
- printf函数打印(一)—— 过程解析篇
程序运行的时候,会自动打开三个文件,分别是stdin.stdout.stderr 这三个文件对应的外设分别是 键盘.显示器.显示器 这三个文件对应的文件描述符为 0.1.2 printf函数在显示器上 ...
- codeblocks printf函数打印不出来_最全C语言基本程序交互函数之输出到屏幕
前言 上一栏目主要讲解了各种数据类型的知识,大家先闭眼回顾一下数据类型的知识哦.本章节主要内容是讲解程序的基本交互设计之程序的输出.程序和人交互无非就是通过外设进行输入信息,C语言中基本的交互的基本流 ...
- stc单片机使用printf()函数打印
串口波特率初始化: 利用stc-isp工具生成初始化代码, 在串口初始化函数中添加 **TI=1;**如下图,否则printf()无法输出. void UartInit(void) //9600bps ...
- stm32+HTU21D温湿度传感器通过usart1发送温湿度数据在串口助手显示
stm32+HTU21D温湿度传感器 这里就不拍实物图了,我用的是下面这款HTU21D ic是stm32f103vet6 工程代码是io口模拟i2c和传感器通讯 PB6-SCL,PB7-SDA usa ...
- 【STM32学习 自制STM32游戏机】
2020年科协招新需要出训练题,让新生了解一下单片机,所以我这边打算出一道游戏机的题,让新生用单片机实现一个游戏机,共3个游戏可选,分别为:贪吃蛇,打地鼠和推箱子,由于是针对于0基础新生,所以在指标上 ...
- 【stm32学习】stm32最小系统和程序下载方式
文章目录 前言 一.程序下载 1.USB下载方式 2.J-LINK下载方式 前言 stm32学习过程,是从正点原子的开发板开始的,但是正点原子的开发板实在是太大了,而且不便宜,不适合一些实际项目制作, ...
最新文章
- 深入剖析ISAServer 网页缓存及配置
- 新的GNSS精度度量是怎样定义的?
- 地址栏射击游戏!对,你没看错,就是在地址栏上玩的游戏,有图有真相!
- SAP Spartacus B2B功能,只渲染BodyContent position里的UI
- SQL 字符 数字 转换字母
- gprs模块http mqtt_在GPRS模块(SIM800C)和STM32芯片上实现MQTT协议 | TsonTec:测量解决方案提供者...
- mysql active_GitHub - vipshop/drc: MySQL active-active replication solution.
- 序列化和反序列化的概念
- HDU 1693 Eat the Trees ——插头DP
- 第14章 学习scikit-learn文档
- 用友U872《合同管理》模块操作手册
- PLC编程的5种专用语言 ,学习PLC编程得先了解一下!
- javascript手册安卓版_JavaScript 手册
- QGIS快速提取建筑和道路矢量
- Hexo文章中图片点击实现全屏查看
- 计算机组装主机怎么拆,【电脑组装知识网】电脑主机组装教程之戴尔显示器底座拆卸教程...
- 画笔Paint及模拟画图工具
- 键盘上的按键--键码 对应表
- 电机速度曲线规划1:梯形速度曲线设计与实现
- 钓鱼网站盯上加油卡充值
热门文章
- NumPy最详细入门笔记
- scratch lenet(9): C语言实现tanh的计算
- 开源! ROS2阿克曼开发平台方案
- docear使用教程_如何使用Docear进行学术研究
- 【图像分割】基于模糊C均值聚类算法CGFFCM实现彩色图像分割附matlab代码
- 2022阿里云金秋云创季年终双十一活-动汇总!
- 机器学习实践—基于Scikit-Learn、Keras和TensorFlow2第二版—第4章 训练模型
- java模拟商店购买
- uni-app - 日历选择器组件(支持日期 “范围选择“ 多选 / 支持单选日期 / 自定义默认选中时间 / 弹框式 / 支持农历 )完美兼容 H5 APP 小程序,最好用的教程完整源代码插件!
- 数据链路层——广播信道CSMA/CD协议