STM32程序 关于Semhosting(半主机)和Microlib 以及Printf的关系

server/2024/9/20 9:21:54/ 标签: 单片机, 嵌入式硬件, stm32, c语言

一,Keil中Printf导致程序无法运行到Main函数

在Keil中调试STM32程序,编译烧录后,发现程序不能运行,Main函数中点亮LED灯的语句没起作用,说明没有进入Main函数。用Keil调试的时候,虽然设置了Run to main(),

但发现确实进入不了Main函数。也就是程序烧录后其实无法进入Main函数运行。(这个和Semihosting的机制有关,后面再解释)

想到自己是因为调试的需要,添加了Printf语句,所以怀疑是这个问题,然后倒腾了下,勾选了Use MicroLIB:

烧录后,发现程序就可以运行了,Printf也有输出。(程序里已经有重写fputc重定向到串口的函数)

然后注释掉Printf语句,并且取消勾选Use MicroLIB,程序烧录到开发板上也能正常运行。

小结:

1. 要使用Printf函数,在Keil中,请勾选使用MicroLIB,重定向fputc到串口。

/*!
* @brief       Redirect C Library function printf to serial port.
*              After Redirection, you can use printf function.
*
* @param       ch:  The characters that need to be send.
*
* @param       *f:  pointer to a FILE that can recording all information
*              needed to control a stream
*
* @retval      The characters that need to be send.
*
* @note
*/
int fputc(int ch, FILE* f)
{/* send a byte of data to the serial port */USART_TxData(DEBUG_USART, (uint8_t)ch);/* wait for the data to be send  */while (USART_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == RESET);return (ch);
}

2. 不勾选MicroLIB,即使重写了fputc到串口,使用Printf会使程序无法运行到Main函数。

    再提前加一点解释:

3. 不勾选MicroLIB而使用Printf,无法运行到Main函数,是因为Printf/scanf之类的函数受了Semihosting机制的影响

二,Keil中是必须要使用MicroLIB实现串口打印吗

因为要和同事的代码合并,他是在VSCODE中写的,所以我要迁移代码到VSCODE,但是搜了一圈发现VSCODE没有MicroLIB, 这个微库是Keil独有内置的(也许也有别的类似的,但我没有研究)。既然VSCODE没有Micro LIB,那么一定也有别的方式,那么Keil中是必须要使用MicroLIB来实现串口打印吗?答案是NO

然后突然想起之前了解到的所谓的半主机模式(英文原文Semihosting,这个“半主机”翻译感觉怪怪的,其实意思就是嵌入式设备因为硬件功能受限,而需要借用主机的一部分功能,这主要在调试的时候提供了方便,感觉  “半托管”  更直观贴切)。

Semihosting是一种机制,它允许嵌入式系统与主机计算机的操作系统进行通信,进行输入/输出操作,例如文件I/O,标准I/O(stdio)和其他与系统相关的功能。它使开发人员在开发和调试过程中与嵌入式系统进行交互,而无需额外的硬件或专用通信渠道。

使用半主机时,通常由嵌入式系统硬件处理的某些操作,例如从文件读取或写入文件,被转移(offload)到由主机的操作系统来操作。这使开发人员可以在调试目的时使用主机操作系统提供的熟悉的文件系统和I/O功能。

半主机通常涉及开发工具链提供的一小部分软件函数,这些函数充当嵌入式应用程序和主机操作系统之间的中介,为嵌入式系统与主机计算机之间的通信提供了便利。这些函数允许开发人员执行诸如打印调试消息、从主机读取输入或访问主机文件系统中的文件等任务。

半主机的一个常见用例是调试嵌入式软件应用程序,开发人员可以在其代码中使用标准的printf语句将调试信息输出到主机计算机的控制台,而不是依赖于专用的调试硬件。此外,半主机可用于任务,如将文件加载到嵌入式系统中,执行软件更新或访问主机操作系统提供的系统资源。

总的来说,半主机为开发人员提供了一种方便的方式,在开发和调试过程中与嵌入式系统进行交互,有助于简化开发流程并提高生产力。

所以就搜了一下,在Keil工程添加了以下代码禁用Semihosting :

//加入以下代码,支持printf函数,而不需要选择use MicroLIB#pragma import(__use_no_semihosting)  // 确保没有从 C 库链接使用半主机的函数
void _sys_exit(int  x) //定义 _sys_exit() 以避免使用半主机模式
{x = x;
}
struct __FILE  // 标准库需要的支持函数
{int handle;
};
/* FILE is typedef ’ d in stdio.h. */
FILE __stdout;

然后同时取消勾选MicroLIB,发现程序也能正常运行,能使用串口打印输出。

小结:

Keil中也可以不使用MicroLIB,通过禁用Semihosting,正常使用C库,可以实现串口打印。

三、VSCODE中该怎么通过串口使用Printf

既然KEIL中可以不使用MicroLIB,那么VSCODE中没有MicroLIB也就不是问题了,同样禁用Semihosting,添加重定向fputc。但是却仍然出现问题,没有输出。

搜了一圈,发现在VSCODE中若使用GCC编译器,要重定向的函数不是fputc,而是_write和__io_putchar:

/*!
* @brief       Redirect C Library function printf to serial port.
*              After Redirection, you can use printf function.
*
* @param       ch:  The characters that need to be send.
*
* @param       *f:  pointer to a FILE that can recording all information
*              needed to control a stream
*
* @retval      The characters that need to be send.
*
* @note
*/int __io_putchar(int ch)
{/* send a byte of data to the serial port */USART_TxData(DEBUG_USART, ch);/* wait for the data to be send  */while (USART_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == RESET);return ch;
}int _write(int fd, char* ptr, int len)
{int DataIdx;for (DataIdx = 0; DataIdx < len; DataIdx++){__io_putchar(*ptr++);}return len;
}

注:上述USART相关函数实际上是极海MCU的,而不是STM32,因为我实际上是在极海APM32上做开发,是参照STM32而已。但原理是通的,具体函数名字不同,根据自己是使用标准库还是HAL库,做一下改变就行了。

小结:

不同编译环境下的重定向函数有所不同,

Keil、IAR等 IDE上面,都是用以下方式重定向的:

  • int fputc(int ch, FILE *f)
    int fgetc(FILE *f)

在 GCC 环境下,使用的是如下方式:

int _write(int file, char *ptr, int len)
int _read(int file, char *ptr, int len)

四、完整重定向代码(通用)

最后贴上极海SDK里面的重定向完整代码,供参考:

#if defined (__CC_ARM) || defined (__ICCARM__) || (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))/*!
* @brief       Redirect C Library function printf to serial port.
*              After Redirection, you can use printf function.
*
* @param       ch:  The characters that need to be send.
*
* @param       *f:  pointer to a FILE that can recording all information
*              needed to control a stream
*
* @retval      The characters that need to be send.
*
* @note
*/
int fputc(int ch, FILE* f)
{/* send a byte of data to the serial port */USART_TxData(DEBUG_USART, (uint8_t)ch);/* wait for the data to be send  */while (USART_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == RESET);return (ch);
}#elif defined (__GNUC__)/*!
* @brief       Redirect C Library function printf to serial port.
*              After Redirection, you can use printf function.
*
* @param       ch:  The characters that need to be send.
*
* @retval      The characters that need to be send.
*
* @note
*/
int __io_putchar(int ch)
{/* send a byte of data to the serial port */USART_TxData(DEBUG_USART, ch);/* wait for the data to be send  */while (USART_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == RESET);return ch;
}/*!
* @brief       Redirect C Library function printf to serial port.
*              After Redirection, you can use printf function.
*
* @param       file:  Meaningless in this function.
*
* @param       *ptr:  Buffer pointer for data to be sent.
*
* @param       len:  Length of data to be sent.
*
* @retval      The characters that need to be send.
*
* @note
*/
int _write(int file, char* ptr, int len)
{int i;for (i = 0; i < len; i++){__io_putchar(*ptr++);}return len;
}#else
#warning Not supported compiler type
#endif

根据自己的MCU,修改USART相关的函数即可。


http://www.ppmy.cn/server/2819.html

相关文章

若依前端分离版中使用二维码功能

一、安装 在前端项目工程目录&#xff0c;远端执行如下命令 // npm npm install vue-qr --save // yarn yarn add vue-qr 二、引入组件 在main.js文件中增加如下的内容 // vue2.x import VueQr from vue-qr //注册组件 Vue.component(VueQr, VueQr)// vue3.x import vueQr f…

优化汽车制造中的库存管理

在拥有足够的库存以满足客户需求和最大限度地减少过剩库存之间取得适当的平衡&#xff0c;对于高效运营和正向现金流运营至关重要。我们将探讨如何利用数据见解和预测技术来支持汽车制造商进行精益运营&#xff0c;避免库存过多或不足的缺陷。 销售模式告诉我们什么&#xff1…

开源相机管理库Aravis例程学习(二)——连续采集multiple-acquisition-main-thread

开源相机管理库Aravis例程学习&#xff08;二&#xff09;——连续采集multiple-acquisition-main-thread 简介例程代码函数说明arv_camera_set_acquisition_modearv_camera_create_streamarv_camera_get_payloadarv_buffer_newarv_stream_push_bufferarv_camera_start_acquisi…

【机器学习—聚类】

文章目录 1、前言1.1、定义1.2、数据 2、亲和力传播3、聚合聚类4、BIRCH5、DBSCAN6、K-均值7、Mini-Batch K-均值8、均值漂移聚类9、OPTICS10、光谱聚类11、高斯混合模型12、参考 1、前言 1.1、定义 聚类分析&#xff0c;即聚类&#xff0c;是一项无监督的机器学习任务。它包…

git突然不能更新

【Q】 git 更新经常报这种错 Update failed WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! Someone could be eavesdropping on you right now (man-in-the-middle attack)…

zookeeper与kafka

一、zookeeper介绍&#xff1a; 1.zookeeper简介&#xff1a; Zookeeper&#xff1a;开源分布式的服务&#xff0c;为分布式框架提供协调服务的apache项目 2.zookeeper特点&#xff1a; Zookeeper&#xff1a;一个领导者(Leader) &#xff0c;多个跟随者(Follower) 组成的集…

亚远景科技-如何看待汽车软件开发中的质量管理与传统质量管理的异同?结合ASPICE标准谈谈

汽车软件开发中的质量管理与传统质量管理在某些方面存在异同&#xff0c;而ASPICE&#xff08;Automotive SPICE&#xff09;标准为汽车行业提供了一套针对软件开发过程的专门质量管理框架。下面是对比分析以及ASPICE标准在此背景下的作用&#xff1a; 异同点&#xff1a; 1. 复…

【性能测试】接口测试各知识第3篇:Jmeter 基本使用流程,学习目标【附代码文档】

接口测试完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;接口测试&#xff0c;学习目标学习目标,2. 接口测试课程大纲,3. 接口学完样品,4. 学完课程,学到什么,5. 参考:,1. 理解接口的概念。学习目标&#xff0c;RESTFUL1. 理解接口的概念,2.什么是接口测试…

学习javaEE的日子 Day36 字符流

Day36 1.字符流 应用场景&#xff1a;操作纯文本数据 注意&#xff1a;字符流 字节流编译器 编译器&#xff1a;可以识别中文字符和非中文字符&#xff0c;非中文字符获取1个字节&#xff08;一个字节一个字符&#xff09;&#xff0c;编译器会根据编码格式获取中文字符对应的…

JavaWeb开发03-Mybatis入门-基础操作-XML映射文件-动态SQL

一、Mybatis-入门 Java程序控制数据库 1.入门 定义实体类&#xff1a;一定要和表中的字段一一对应 配置连接数据库数据 建立Mapper层语句&#xff0c;来获取数据库数据以及将其封装到user的list中去。 2.配置SQL提示 为了进行查询数据库中有哪些表&#xff0c;所以得连接数据…

【鸿蒙开发】第二十章 Camera相机服务

1 简介 开发者通过调用Camera Kit(相机服务)提供的接口可以开发相机应用&#xff0c;应用通过访问和操作相机硬件&#xff0c;实现基础操作&#xff0c;如预览、拍照和录像&#xff1b;还可以通过接口组合完成更多操作&#xff0c;如控制闪光灯和曝光时间、对焦或调焦等。 2 …

混合A*算法

混合A算法是一种路径规划算法,它结合了A搜索和采样优化技术。其原理可以简要概括如下: A*搜索:A*算法是一种启发式搜索算法,用于解决图或者网络中的路径规划问题。它通过维护两个列表(开放列表和封闭列表),根据启发式函数(估计函数)和已走过路径的成本来选择下一个状态…

Github 2024-04-15 开源项目日报Top10

根据Github Trendings的统计,今日(2024-04-15统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目4TypeScript项目2HTML项目1JavaScript项目1C++项目1Rust项目1Mojo项目1Fooocus: 图像生成软件 创建周期:188 天开发语言:Python协议…

AI大模型与函数式编程

将AI大型模型与函数式编程融合&#xff0c;是一种激动人心的前景。设计模式是解决特定问题的可重复解决方案&#xff0c;它们可以提高代码的可读性、可维护性和可扩展性。而AI大型模型的出现为我们提供了更加智能的解决方案&#xff0c;能够理解和生成自然语言&#xff0c;从而…

2024年认证杯SPSSPRO杯数学建模A题(第一阶段)保暖纤维的保暖能力全过程文档及程序

2024年认证杯SPSSPRO杯数学建模 A题 保暖纤维的保暖能力 原题再现&#xff1a; 冬装最重要的作用是保暖&#xff0c;也就是阻挡温暖的人体与寒冷环境之间的热量传递。人们在不同款式的棉衣中会填充保暖材料&#xff0c;从古已有之的棉花、羽绒到近年来各种各样的人造纤维。不…

SpringBoot+FTP下载文件,单文件直接下载,多文件进行打包zip下载

直接调用downloadFiles方法即可 package com.demo.utils;import org.apache.commons.io.IOUtils; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPFile; import org.springframework.http.ResponseEntity; import org.springframework.w…

vivado 在硬件管理器中调试 AXI 接口

在硬件管理器中调试 AXI 接口 IP integrator 中的 System ILA IP 支持您在 FPGA 上对设计执行系统内调试。在 Versal 器件上 &#xff0c; System ILA 核已被废 弃。现在 &#xff0c; 在含 AXIS 接口的标准 ILA 中支持接口调试。如需监控 IP integrator 块设计中的…

FluentUI系列 - 1 - 介绍第一个窗口

介绍一个QML的UI库&#xff0c;国人编写&#xff0c;作者也耍知乎。这个UI库确实好用&#xff0c;但是教程基本等于无&#xff0c;个人在使用中顺便记录一下学习内容。这玩意儿也有Pyside6的版本&#xff0c;有需要的可以查看PySide6-FluentUI-QML。 FluentUI库地址​github.c…

Unity Android 2021 Release-Notes

&#x1f308;Unity Android 2021 Release-Notes 本文信息收集来自自动搜集工具&#x1f448; 版本更新内容2021.3.34Android: Google play.core package is replaced with separate plugins including play.asset-delivery 2.1.0 to solve PAD related compatibility problem…

Ubuntu日常配置

目录 修改网络配置 xshell连不上怎么办 解析域名失败 永久修改DNS方法 临时修改DNS方法 修改网络配置 1、先ifconfig确认本机IP地址&#xff08;刚装的机子没有ifconfig&#xff0c;先apt install net-tools&#xff09; 2、22.04版本的ubuntu网络配置在netplan目录下&…