Keil环境下CANopenNode移植到STM32问题记录(一)---printf重定向问题

文章目录

    • 问题描述
    • 问题结决
    • 思考:
    • 相关文章

在直接将CANopenSTM32的示例工程直接移植到Keil环境下。
如果移植工程未实现printf函数重定向,则要注释掉log_printf下面的printf函数,使日志打印失效

/* Printf function of CanOpen app */
#define log_printf(macropar_message, ...) //printf(macropar_message, ##__VA_ARGS__)

在未在选项中勾选使用微库的时候,程序会卡死。调试会发现是卡死在了BKAP 0xAB处,网上搜索会有很多说明,是因为使用了printf函数而为实现重定向导致的。解决办法1:勾选上使用微库。办法2:禁用半主机模式。
选择办法1后进行编译,程序可以正常运行了。

问题描述

因为我在其它工程上使用arm clang编译器,因而不能选择勾选微库的方式。因而我尝试办法2,但这时就出现了比较奇怪的问题(两个编译器都会出现这个奇怪的问题,这里是在armcc编译器下的测试)

按照我之前文章中https://blog.csdn.net/xiaoyuanwuhui/article/details/110538555描述的如下方式便可以重定向。

/* ------------------通过重定向将printf函数映射到串口1上-------------------*/
#if !defined(__MICROLIB)#pragma import(__use_no_semihosting)
void _sys_exit(int x) //避免使用半主机模式
{x = x;
}
//__use_no_semihosting was requested, but _ttywrch was 
void _ttywrch(int ch)
{ch = ch;
}
typedef struct __FILE
{int handle;
}FILE;#endif#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif 
PUTCHAR_PROTOTYPE
{/* 实现串口发送一个字节数据的函数 *///serial_write(&serial1, (uint8_t)ch); //发送一个自己的数据到串口//HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1000);return ch;
}

但是在添加了上述内容后,进行编译提示了如下报错:请求禁用半主机模式,但是_sys_open函数未定义
在这里插入图片描述
仿照之前定义_sys_exit()函数的方式定义_sys_open()函数,如下:

void _sys_open(int x)
{x = x;
}

然后进行编译程序又出现了如下报错:_sys_open函数重复定义
在这里插入图片描述
至此,一脸懵逼,到底什么情况:不定义提示缺少定义,定义了又提示重复定义,只能是无语了。期待有大佬可以详细描述下这是怎么回事 ,不胜感激!

问题结决

https://developer.arm.com/documentation/ka002219/latest文章中提供了一种半主机问题的解决方案:使用RTE(Run-Time-Environment)中的Compiler组件重新定位标准C运行时库的I/O函数。
在这里插入图片描述
这里我只针对于解决上面的问题,如上图所示,在STDOUT处选中,并将后面的值改为User。
将程序中之前重定向的代码全部移除掉,然后进行编译,这时仍会有一个报错提示,如下:
在这里插入图片描述
这是因为我们选择了重定向输出,还需要实现对应的stdout_putchar函数(用于打印一个字符到输出设备),一般而言这需要通过串口实现发送一个字符的功能,这里暂时先定义一个空函数:

int stdout_putchar (int ch) {}

然后再进行编译,结果如下:
在这里插入图片描述
此时已经没有报错了,程序下载到单片机上也可以正常运行了。

思考:

为什么这种方式可以解决问题,之前的方式就不可以呢?
这里我们将RTE下的retarget_io.c文件中的内容复制一份到retarget.c文件,并添加到工程中,然后将之前勾选的RTE中的STDOUT的取消,在retarget.c文件的前面添加上如下宏定义并注释掉RTE组件头文件

//#include "RTE_Components.h"
#define RTE_Compiler_IO_STDOUT_User
#define RTE_Compiler_IO_STDOUT

直接进行编译,也没有出现报错,下载到单片机中也可以正常运行。

__attribute__((weak))
FILEHANDLE _sys_open (const char *name, int openmode) {};
__attribute__((weak))
int _sys_close (FILEHANDLE fh) {};
__attribute__((weak))
int _sys_write (FILEHANDLE fh, const uint8_t *buf, uint32_t len, int mode) {};
__attribute__((weak))
int _sys_istty (FILEHANDLE fh) {};
__attribute__((weak))
int _sys_seek (FILEHANDLE fh, long pos) {};
__attribute__((weak))
long _sys_flen (FILEHANDLE fh) {};

上面这6个函数注释掉哪一个都会出现如下报错:
在这里插入图片描述
好像是要将所有的这几个函数都实现了才不会调用C库中的函数。
进一步实验:
将上面的6个函数的空语句添加到main.c的空白位置,然后进行编译,发现不会报错,但程序下载到单片机内依然会卡死。
再在6个函数的前面添加上__stdin_name,__stdout_name,__stderr_name的定义

#include <rt_sys.h>
///* Standard IO device name defines. */
const char __stdin_name[]  = ":STDIN";
const char __stdout_name[] = ":STDOUT";
const char __stderr_name[] = ":STDERR";
__attribute__((weak))
FILEHANDLE _sys_open (const char *name, int openmode) {};
__attribute__((weak))
int _sys_close (FILEHANDLE fh) {};
__attribute__((weak))
int _sys_write (FILEHANDLE fh, const uint8_t *buf, uint32_t len, int mode) {};
__attribute__((weak))
int _sys_istty (FILEHANDLE fh) {};
__attribute__((weak))
int _sys_seek (FILEHANDLE fh, long pos) {};
__attribute__((weak))
long _sys_flen (FILEHANDLE fh) {};

然后再进行编译也不会报错,下载到单片机内也可以正常运行。
初步结论:只有6个函数和3个变量都定义了才能完成完整的重定向功能。
实际应用时还是建议直接使用RTE的组件,这里拆分出来是为了进一步分析。

相关文章

std::mt19937 with ARM Compiler 6 uses sys_open and breaks retarget.c
I/O Retargeting

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/13194.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue3的getCurrentInstance()方法拿到的实例对象中的proxy

getCurrentInstance方法拿到的是当前组件的实例对象 实例对象中的成员proxy是一个代理对象&#xff0c;可以通过访问代理对象来间接访问当前组件的实例对象 这样就不需要this&#xff0c;也可以操作当前组件的实例对象了 proxy对象就相当于当前组件的实例对象 proxy对象会对…

FPGA实验五:信号发生器设计

目录 一、实验目的 二、设计要求 三、实验代码 1.代码原理分析 2.代码设计思路 3.IP核的设计与配置 四、实验结果及分析 1、引脚锁定 2、仿真波形及分析 &#xff08;1&#xff09;关于波形一些指标的介绍 &#xff08;2&#xff09;对波形转换功能的验证 &#xf…

【CPU】关于x86、x86_64/x64、amd64和arm64/aarch64

为什么叫x86和x86_64和AMD64? 为什么大家叫x86为32位系统&#xff1f; 为什么软件版本会注明 for amd64版本&#xff0c;不是intel64呢&#xff1f; x86是指intel的开发的一种32位指令集&#xff0c;从386开始时代开始的&#xff0c;一直沿用至今&#xff0c;是一种cisc指令…

Haskell 入门学习(一)之安装试用 Haskell

Haskell 入门学习&#xff08;一&#xff09;之安装试用 Haskell 文章目录 Haskell 入门学习&#xff08;一&#xff09;之安装试用 Haskell前言&#xff1a;安装Windows 安装Linux、MacOs 使用 VSCode 进行代码编写创建一个简单的项目使用 Cabal 管理项目项目大致结构运行项目…

python验证公网ip与内网ip

公网IP和内网IP都是用于标识网络设备的地址&#xff0c;但它们有着不同的作用和特点。 公网IP是由互联网服务提供商&#xff08;ISP&#xff09;分配给用户设备的唯一标识符。它是全球范围内唯一的&#xff0c;并且可以被其他网络设备使用来寻找和连接特定的设备。公网IP通常用…

python_day2

猜数字-while循环 import randomnum random.randint(1, 10) while True:x int(input("输入&#xff1a;"))if x > num:print("大了")elif x < num:print("小了")else:print("猜对了")break打印九九乘法表-while循环 i 1 wh…

MySQL索引优化整合案例实现

目录 1 JOIN优化1.1 JOIN算法原理1.2 in和exists函数 2 order by优化2.1 索引排序2.2 额外排序2.3 排序优化 3 索引单表优化案例3.1. 建表3.2. 单表索引分析3.1.1 需求3.1.2 优化 4 索引多表优化案例 1 JOIN优化 1.1 JOIN算法原理 1) JOIN回顾 JOIN 是 MySQL 用来进行联表操作…

Spring Boot中的Hibernate是什么,如何使用

Spring Boot中的Hibernate是什么&#xff0c;如何使用 Hibernate是一个流行的Java ORM框架&#xff0c;它提供了一种将Java对象映射到关系数据库表的方法。Spring Boot集成了Hibernate&#xff0c;使得在开发Web应用程序时可以轻松地使用Hibernate操作数据库。本文将介绍Sprin…

插值算法

插值法在较少的数据模型的基础上模拟产生新的靠谱数值&#xff0c;可以用来预测。 利用已知的点建立合适的插值函数 f(x) ,未知点 x_i 由插值函数 f(x) 可以求出函数值 f(x_i) &#xff0c;用求得的 (x_i,f(x_i))近似代替未知点。 基本概念&#xff1a; yf(x)在[a,b]上有定义 x…

机器学习基础之《特征工程(2)—特征工程介绍、特征抽取》

一、什么是特征工程 机器学习领域的大神Andrew Ng(吴恩达)老师说“Coming up with features is difficult, time-consuming, requires expert knowledge. “Applied machine learning” is basically feature engineering. ” 注&#xff1a;业界广泛流传&#xff1a;数据和特…

vue创建项目报错npm install --loglevel error --legacy-peer-deps

vue创建项目报错npm install --loglevel error --legacy-peer-deps 如图所示&#xff1a; 话不多说&#xff0c;直接上解决方法&#xff1a; 1、找到这两个文件&#xff08;每个人的位置不一样&#xff0c;像我是安装在D盘&#xff09; 2、分别点进去&#xff0c;右键—属性…

时间序列预测 | Matlab麻雀算法(SSA)优化极限梯度提升树XGBoost时间序列预测,SSA-XGBoost时间序列预测模型,单列数据输入模型

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 麻雀算法(SSA)优化极限梯度提升树XGBoost时间序列预测,SSA-XGBoost时间序列预测模型,单列数据输入模型 评价指标包括:MAPE、RMSE等,代码质量极高,方便学习和替换数据。要求2018版本及以上。 部分源码