STM32F105RCT6 -- ST-Link ITM Trace printf 打印日志

1. STM32 可以配置UASRT,使用串口来打印日志,还有另外一种方式,使用ITM 调试功能来打印日志, 主要使用到的三个函数 core_cm3.h

1.1 发送函数 static __INLINE uint32_t ITM_SendChar(uint32_t ch),相当于串口的发送函数usart_send(), 将参数ch发送到keil 的日志打印窗口,一次只能发送一个字符,字符串需要排队发送,发送速度跟系统时钟主频相关,所以比串口要快很多很多

static __INLINE uint32_t ITM_SendChar(uint32_t ch)
{
    if ((CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk)  && // Trace enabled
        (ITM->TCR & ITM_TCR_ITMENA_Msk) && // ITM enabled
        (ITM->TER & (1ul << 0))) // ITM Port #0 enabled
    {
        while (ITM->PORT[0].u32 == 0);
        ITM->PORT[0].u8 = (uint8_t) ch;
    }
    return (ch);
}

1.2 接收函数 static __INLINE int ITM_ReceiveChar(void),第一次见在头文件中

static __INLINE int ITM_ReceiveChar(void)
{
    int ch = -1; /* no character available */

    if (ITM_RxBuffer != ITM_RXBUFFER_EMPTY)
    {
        ch = ITM_RxBuffer;
        ITM_RxBuffer = ITM_RXBUFFER_EMPTY; /* ready for next character */
    }

    return (ch);
}

1.3 检查标志位函数 static __INLINE int ITM_CheckChar(void), 相当于串口里面的传输完成中断标志位监测

static __INLINE int ITM_CheckChar(void)
{
    if (ITM_RxBuffer == ITM_RXBUFFER_EMPTY)
    {
        return (0); /* no character available */
    }
    else
    {
        return (1); /* character available */
    }
}

2. keil 配置,使用ST-Link 下载器调试, 点击Setting

在这里插入图片描述

3. 点击 Trace

在这里插入图片描述

4. Core Clock 与系统时钟主频相关,不同芯片主频会有差异,我的是STM32F105RCT6,系统时钟配置的是72Mhz

在这里插入图片描述

5. 代码配置,必须要包含系统头文件 #include <stdio.h> 不然会报错的

在这里插入图片描述

6. 我自己写了一个log.h 文件,专门用来管理日志打印的, 可以实现不同等级的日志打印,在华为搞蓝牙耳机项目的时候就是这样搞的,基本都会封装printf 函数,搞高通项目的时候也是,小公司可能就会搞这种操作了,直接就printf()

6.1 log.h

#ifndef __LOG_FILE_
#define __LOG_FILE_

#include <stdio.h>

#define USE_ITM_TRACE_DEBUG // set in keil magic wand -> Debug -> Setting -> Trace -> Trace Enable

// log level
#define ERROR_LEVEL    4
#define WARN_LEVEL    3
#define INFO_LEVEL    2
#define DEBUG_LEVEL    1

/*
 * current log level
 * error level: log only printf erro log
 * warn level: only printf warn and erro log
 * info level: only printf info, warn and error log
 * debug level: printf debug, info, warn and error
 */
#define CURRENT_LOG_LEVEL INFO_LEVEL

#if CURRENT_LOG_LEVEL <= DEBUG_LEVEL
    #define DEBUG_LOG(fmt, ...) printf("[DEBUG]" fmt, ##__VA_ARGS__)
#else
    #define DEBUG_LOG(fmt, ...)
#endif

#if CURRENT_LOG_LEVEL <= INFO_LEVEL
    #define INFO_LOG(fmt, ...) printf("[INFO]" fmt, ##__VA_ARGS__)
#else
    #define INFO_LOG(fmt, ...)
#endif

#if CURRENT_LOG_LEVEL <= WARN_LEVEL
    #define WARN_LOG(fmt, ...) printf("[WARN]" fmt, ##__VA_ARGS__)
#else
    #define WARN_LOG(fmt, ...)
#endif

#if CURRENT_LOG_LEVEL <= ERROR_LEVEL
    #define ERROR_LOG(fmt, ...) printf("[ERROR]" fmt, ##__VA_ARGS__)
#else
    #define ERROR_LOG(fmt, ...)
#endif

#endif // __LOG_FILE_

7. 我是在usart.c 里面配置软件支持ITM 调试功能的

7.1 usart.c 禁用半主机模式,这是很早以前的一种调试手段,开半主机模式的话会影响性能,所以后面ARM 就出台了ITM 功能,代替半主机模式

// when select ARMCC 5 compiler, need define __FILE and disable half host mode
#pragma import(__use_no_semihosting_swi) // 用软件中断的方式实现printf software interrupt

7.2 也可以写成

#pragma import(__use_no_semihosting) // 正点原子的例程就是这样写的

8. 定义文件IO 标准输入输出句柄

// support functions required for standard libraries
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
};

// FILE defined in <stdio.h>
FILE __stdout;
FILE __stdin;

9. 定义系统死循环退出

函数是一个模拟系统退出的函数。它接受一个整数类型的返回码作为参数,但实际上并没有执行任何系统退出的操作,而是通过一个无限循环来使程序陷入死循环状态。
这段代码通常被用于无嵌入式系统或者操作系统环境下的调试目的。通过将程序置于无限循环中,可以使程序停留在某个特定点,方便进行调试和观察程序行为。

void _sys_exit(int return_code)
{
label:
    goto label; // endless loop
}

10. 改写fputc 函数,printf 函数就是调用这个函数实现的打印日志的

int fgetc(FILE *f)
{
    while (ITM_CheckChar() != 1)
    {
        __NOP();
    }
    return (ITM_ReceiveChar());
}

11. 改写fgetc 函数,scanf 函数最终会调用这个函数

int fputc(int ch, FILE *f)
{
    return ITM_SendChar(ch);
}
#endif

12. 初始化接收buffer 为空

volatile int32_t ITM_RxBuffer = ITM_RXBUFFER_EMPTY;

13. 监测文件流是否发生错误,错误处理

int ferror(FILE   *f)
{
    // your implementation of ferror, handle error here

    return EOF;
}

14. 辅助函数,将字符输出到标准输出文件流中

void _ttywrch(int c)
{
    fputc(c, &__stdout);
}

15. 回退函数

int __backspace()
{
    return 0;
}

16. 将上面几行代码拷贝到文件你的.c 文件里面(main.c 或其它的.c 文件)

17. 在main函数里面写测试代码

int main(void)
{
	char c;
	printf("hello world");
	scanf("%c", &c);
	printf("hello world, %c\r\n", c);

	return 0;
}

18. 用我自己的测试代码debug, 点击小红d 进debug 模式

在这里插入图片描述

19. 进debug模式后,把keil 的日志窗口调出来 view -》 serial windows -》debug (printf) Viewer

在这里插入图片描述

20. 刚进debug 模式,停在main函数这里,按一下F5全速跑,日志就出来了

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

分享之python 协程

线程和进程的操作是由程序触发系统接口&#xff0c;最后的执行者是系统&#xff1b;协程的操作则是程序员。 协程存在的意义&#xff1a;对于多线程应用&#xff0c;CPU通过切片的方式来切换线程间的执行&#xff0c;线程切换时需要耗时&#xff08;保存状态&#xff0c;下次继…

CMU 15-445 -- Introduction to Distributed Databases - 19

CMU 15-445 -- Introduction to Distributed Databases - 19 引言System ArchitectureShared MemoryShared DiskShared Nothing Early Distributed Database SystemsDesign IssuesHomogeneous VS. Heterogeneous Database PartitioningNaive Table PartitioningHorizontal Part…

Grafana技术文档--基本安装-docker安装并挂载数据卷-《十分钟搭建》

阿丹&#xff1a; Prometheus技术文档--基本安装-docker安装并挂载数据卷-《十分钟搭建》_一单成的博客-CSDN博客 在正确安装了Prometheus之后开始使用并安装Grafana作为Prometheus的仪表盘。 一、拉取镜像 搜索可拉取版本 docker search Grafana拉取镜像 docker pull gra…

数字万用表测量基础知识--DMM的显示位数

概览 DMM&#xff08;即数字万用表&#xff09;是一种电气测试和测量仪器&#xff0c;可测量直流和交流信号的电压、电流和电阻。本文介绍如何正确使用和理解数字万用表(DMM)。 DMM的显示位数 数字万用表(DMM)可用于进行各种测量。在选择DMM或理解所使用的DMM时&#xff0c;首…

Lecoode有序数组的平方977

题目建议&#xff1a; 本题关键在于理解双指针思想 题目链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 文章讲解&#xff1a;代码随想录 视频讲解&#xff1a; 双指针法经典题目 | LeetCode&#xff1a;977.有序数组的平方_哔哩…

linux配置上网 linux adsl拨号上网设置

Linux里面配置ADSL上网是件很麻烦的事。但配置完成之后就能开机自动拨号上网&#xff0c;可谓十分的方便。支持的系统有Redhat,CentOS,SuSE,FreeBSD,Ubuntu等常见的Linux。 工具/原料 ADSL网络&#xff0c;电信&#xff0c;网通&#xff0c;移动等常见宽带。 Linux系统的安装光…

06-4_Qt 5.9 C++开发指南_MDI应用程序设计

文章目录 1. MDI简介2. 文档窗口类 QFormDoc 的设计3. MDI主窗口设计与子窗口的使用3.1 主窗口界面设计3.2 MDI子窗口的创建与加入3.3 QMdiArea 常用功能函数3.4 MDI的信号 4. 源码4.1 qwmainwindow.h4.2 qwmainwindow.cpp 1. MDI简介 传统的应用程序设计中有多文档界面(Multi…

VBA技术资料MF42:VBA_从Excel中上面的单元格复制公式

【分享成果&#xff0c;随喜正能量】唯有梦想才配让你不安&#xff0c;唯有行动才能解除你的不安.绳锯木断&#xff0c;水滴石穿。也许你现在做的事情很小&#xff0c;只要你能日积月累的坚持下去&#xff0c;才会发现意义非凡。所谓的成功&#xff0c;便是别人失败的时候你还在…

windows永久关闭更新

不要去services.msc 服务里面关闭windowUpdata了&#xff0c;对win11和部分win10根本不管用&#xff0c;下面在教你一招永久关闭&#xff08;原理不是关闭&#xff0c;只是延长更新时间&#xff0c;时间可以设置百年后&#xff0c;所以和关闭差不多&#xff09; windows图形化…

手撕数据结构之栈+例题

目录 一、栈的概念及结构 二、栈的头文件及基本框架 三、接口实现 1、对栈的初始化 2、栈的销毁 3、入栈操作 4、出栈操作 5、判断栈是否为空 6、返回栈顶元素 7、遍历栈 四、有效的括号 - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 思路&#xff…

QT自带PDF库的使用

QT自带PDF库可以方便的打开PDF文件&#xff0c;并将文件解析为QImage&#xff0c;相比网上提供的开源库&#xff0c;QT自带PDF库使用更方便&#xff0c;也更加可靠&#xff0c;然而&#xff0c;QT自带PDF库的使用却不同于其他通用库的使用&#xff0c;具备一定的技巧。 1. 安装…

Session与Cookie的区别(五)

储存状态的方式 小明的故事说完了&#xff0c;该来把上面这一段变成网络的实际案例了。其实在网络世界中问题也是一样的。 前面已经提到过我们会把状态存在 Cookie 里面&#xff0c;让 Request 之间能够变得有关联。 假设我们今天要来做一个会员系统&#xff0c;那我要怎么知道…

UML箭头汇总

参考&#xff1a;http://www.cnblogs.com/damsoft/archive/2016/10/24/5993602.html 1.UML简介 Unified Modeling Language (UML)又称统一建模语言或标准建模语言。 简单说就是以图形方式表现模型&#xff0c;根据不同模型进行分类&#xff0c;在UML 2.0中有13种图&#xff…

青大数据结构【2015】

一、单选 二、简答 5.如果一组关键字&#xff0c;以不同的次序输入后建立起来的二叉排序树是否相同&#xff1f;当中序遍历这些二叉排序树时&#xff0c;其遍历的结果是否相同&#xff1f;为什么&#xff1f; 不同&#xff0c;因为输入次序不同&#xff0c;所放置的位置与上一…

idea打开多个项目需要开多个窗口(恢复询问弹窗)

【版权所有&#xff0c;文章允许转载&#xff0c;但须以链接方式注明源地址&#xff0c;否则追究法律责任】【创作不易&#xff0c;点个赞就是对我最大的支持】 前言 仅作为学习笔记&#xff0c;供大家参考 总结的不错的话&#xff0c;记得点赞收藏关注哦&#xff01; 使用…

【C++】异常exception

文章目录 1. C语言中传统的处理错误方法2. C中的异常3. 异常的使用3.1 异常的抛出和捕获3.2 异常的重新抛出3.3 异常安全3.4 异常规范 4. 自定义异常体系5. 异常的优缺点 &#x1f4dd; 个人主页 &#xff1a;超人不会飞)&#x1f4d1; 本文收录专栏&#xff1a;《C的修行之路》…

拥抱创新:用Kotlin开发高效Android应用

拥抱创新&#xff1a;用Kotlin开发高效Android应用 引言 在当今数字时代&#xff0c;移动应用已经成为人们生活中不可或缺的一部分。无论是社交媒体、电子商务还是健康管理&#xff0c;移动应用已经深刻地影响了我们的生活方式。随着移动设备的普及和功能的增强&#xff0c;A…

无涯教程-Perl - endpwent函数

描述 此功能告诉系统您不再希望使用getpwent从密码文件读取条目。在Windows下,使用Win32API::Net函数从域服务器获取信息。 语法 以下是此函数的简单语法- endpwent返回值 此函数不返回任何值。 例 以下是显示其基本用法的示例代码- #!/usr/bin/perlwhile(($name, $pas…

vr虚拟仿真消防模拟演练提升受训者的安全观念和防范技能

纵观多年来的火灾事故教训得知&#xff0c;火灾发生的原因复杂多样&#xff0c;仅采取单一教育形式无法达到预期效果。消防安全重在预防&#xff0c;VR消防模拟演练系统将火灾安全问题&#xff0c;经采集和汇集处理&#xff0c;以可视化的形式在安全培训平台上进行实时展现&…

Elasticsearch同时使用should和must

问题及解决方法 must和should组合查询&#xff0c;should失效。使用must嵌套查询&#xff0c;将should组成的bool查询包含在其中一个must查询中。 SearchRequest request new SearchRequest(); request.indices("function_log");SearchSourceBuilder sourceBuilde…