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

news2024/11/18 1:45:45

文章目录

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

在直接将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.coloradmin.cn/o/730115.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Django_环境配置(一)

目录 一、安装Django 二、创建项目 三、创建应用 四、注册应用 五、使用mysql数据库 六、视图 七、开发服务器 源码等资料获取方法 一、安装Django # 在CMD中运行 pip install django # 查看djangp版本 python manage.py version 二、创建项目 # 在CMD中运行 django-a…

工业物联网安全监测解决方案:工业安全节能管理

工业自动化和工业化的快速发展&#xff0c;工厂安全问题越来越受到重视。工厂安全监测是保障工厂安全运行的关键技术之一&#xff0c;它可以及时发现并处理潜在的安全问题&#xff0c;防止事故的发生&#xff0c;保障员工的安全和工厂的正常运转。智能改造成为广大企业关注的热…

idea配置本地maven保姆级教程

一、说在前面 idea默认会带有maven插件&#xff0c;原则上是可以不需要配置的。但有个缺点&#xff0c;他是把本地仓库直接安装在了系统盘里面&#xff0c;随着时间的推移&#xff0c;仓库越来越大&#xff0c;笔记本的压力会比较大。 本文是下载自己的maven包&#xff0c;集…

DAY41:动态规划(一)动态规划理论基础

文章目录 DP概念以及和贪心的区别动规问题分类基础问题背包问题打家劫舍股票问题子序列问题 DP注意点解题步骤&#xff1a;五步debug考虑方向 视频课程&#xff1a;从此再也不怕动态规划了&#xff0c;动态规划解题方法论大曝光 &#xff01;| 理论基础 |力扣刷题总结| 动态规划…

3.1.cuda运行API-概述

目录 前言1. Runtime API概述总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记。 本次课程学习精简 CUDA 教程-Runtime API 概述 课程大纲可…

MachineLearningWu_3_LinearRegression

3 Linear Regression Linear Regression即是根据数据做出预测&#xff0c;如下&#xff0c; training set 如下&#xff1a; 在Linear Regression中你可以将(x&#xff0c; y)看做如下&#xff0c;每一行是一个sample&#xff0c;而每一列除最后一列是一个feature&#xff0c…

ESP32(掌控板) RGB灯控制

ESP32&#xff08;掌控板&#xff09; RGB灯控制 本程序实现了RGB灯亮度和颜色调节&#xff0c;通过触摸按键分别调节RGB值&#xff0c;通过机械按键选择要调节的灯或使用预设均通过调整变量的值加上判断实现。预设包含随机颜色和流水灯&#xff0c;各有高亮度和低亮度两种版本…

《Kali渗透基础》07. 弱点扫描(一)

kali渗透 1&#xff1a;漏洞发现1.1&#xff1a;Exploit-DB1.2&#xff1a;searchsploit1.3&#xff1a;nmap 2&#xff1a;漏洞管理3&#xff1a;弱点扫描类型4&#xff1a;漏洞基本概念4.1&#xff1a;CVSS4.2&#xff1a;CVE4.3&#xff1a;OVAL4.4&#xff1a;CCE4.5&#…

TCP概念

文章目录 1.TCP1.1 为什么需要 TCP 协议&#xff1f;TCP 工作在哪一层&#xff1f;1.2 什么是 TCP &#xff1f;1.3 什么是 TCP 连接&#xff1f;1.4 如何唯一确定一个 TCP 连接&#xff1f;1.5 有一个 IP 的服务器监听了一个端口&#xff0c;它的 TCP 的最大连接数是多少&…

nginx的权限问题(13: Permission denied)解决办法

1、查看nginx启动用户和使用用户是否一致 ps aux | grep nginx 如图&#xff1a; 一个是www,一个是root用户 2、打开nginx配置文件 打开 nginx.conf 文件 查找nginx.conf的位置 ps -aux | grep nginx 3、把 nginx 改为 root 4、重启nginx服务 service nginx restart …

性能监控平台 | Prometheus+InfluxDB + Grafana!

在本文中&#xff0c;我将把几个常用的监控部分给梳理一下。前面我们提到过&#xff0c;在性能监控图谱中&#xff0c;有操作系统、应用服务器、中间件、队列、缓存、数据库、网络、前端、负载均衡、Web 服务器、存储、代码等很多需要监控的点。显然这些监控点不能在一个专栏中…

USG6000V 防火墙的策略应用

将G1/0/0划入TRUST区 firewall zone trustadd interface GigabitEthernet1/0/0 将G1/0/1划入UNTRUST区 firewall zone untrustadd interface GigabitEthernet1/0/1在防火墙上配置放行策略 security-policyrule name 1source-zone trustdestination-zone localdestination-z…

2023年船舶、海洋与海事工程国际会议(NAOME 2023) | Ei Scopus双检索

会议简介 Brief Introduction 2023年船舶、海洋与海事工程国际会议(NAOME 2023) 会议时间&#xff1a;2023年10月20日-22日 召开地点&#xff1a;中国镇江 大会官网&#xff1a;NAOME 2023-2023 International Conference on Naval Architecture and Ocean & Marine Engine…

Yolov8方法笔记

目录 1、安装yolov8的虚拟环境 &#xff08;1&#xff09;创建虚拟环境 &#xff08;2&#xff09;安装pytorch ​编辑 2、下载yolov8模型 3、解压缩&#xff0c;解压后的文件 4、将转换数据集&#xff08;以口罩检测为准&#xff09; 5、配置和执行 6、验证 7、测试 1、…

14-C++基本算法-深度优先搜索

&#x1f4da; 从递归阶乘到深度优先搜索 在学习深度优先搜索之前&#xff0c;我们先回顾一下递归阶乘的实现。递归阶乘是一种典型的递归算法&#xff0c;它通过将问题分解为更小的子问题来解决。 #include <iostream> using namespace std;int factorial(int n) {if (…

【PCIE】协议分析之-hot-reset热复位

被上游指定热复位整个通路 当高层&#xff08;higher Layer&#xff09;指示某些通道进行热复位&#xff08;Hot Reset&#xff09;时&#xff0c;以下操作将被执行&#xff1a; 所有在配置的链路中的通道都会发送带有热复位位&#xff08;Hot Reset bit&#xff09;和配置的…

IntelliJ IDEA运行bat脚本,自动taskkill端口进程

在idea运行完程序后&#xff0c;再次重新运行时如果之前的程序仍然占用着端口会导致报错&#xff1a;端口被占用。 因此每次重新运行都需要移除之前的端口所在的进程&#xff0c;这对于调试开发过程是非常频繁的操作。 需要一个快速的办法直接移除端口进程&#xff0c;如下&a…

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

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

Verilog学习笔记3:与非门

1位的与非门 代码&#xff1a; timescale 1ns/10ps module nand_gate( A, B, Y);input A; input B; output Y;assign Y~(A&B);endmodule//testbenchmodule nand_gate_tb; reg A; reg B; wire Y;nand_gate nand_gate(.A(A),.B(B),.Y(Y));initial begin A<0;B<0;#10 …

Ubuntu创建Git项目并push到远程Github

首先在本地创建git仓库 jasminelhl:~/prj$ mkdir Github-test jasminelhl:~/prj$ cd Github-test jasminelhl:~/prj/Github-test$ git init 提示&#xff1a;使用 master 作为初始分支的名称。这个默认分支名称可能会更改。要在新仓库中 提示&#xff1a;配置使用初始分支名&a…