STM--KEIL printf打印--ITM机制(亲测成功)

本文介绍如何利用STM32的SWO接口进行调试,通过Keil实现简单的信息输出及输入功能,适用于无串口可用的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Jlink/STLink自带一个SWO接口,使用这个接口配合keil可以输出一些简单的调试信息,在没有串口可以使用的时候,SWO也可很方便的打印一些信息,比如F303RE这个板子在我的电脑上一直没法安装虚拟串口的驱动,所以我可以用这个SWO输出调试信息。论坛送的STM32F303RE上自带的stlink正好有这个SWO口,而且也接到了MCU上,所以正好可以使用,好像有的ST的板子也带了这个接口,但是其中桥接电阻并没有贴到板子上,如果要使用的话,就要自己连接起来(比如STM32F429DISCO好像就没有接上)。



对于stlink的驱动好像也有一些要求,我使用keil4带的有点旧的stlink驱动就会提示驱动不支持,后来使用keil5带的stlink驱动据可以了。


如果硬件和软件都没有问题了,还需要设置下kei:
首先打开Micro LIB

然后打开keil的Trace功能,具体设置如下: 时钟一定要对应上,否则是乱码。

然后就是一些重定向printf的函数了,如果之前将printf重定向了串口,那么要修改并添加如下代码:

  1. #define ITM_Port8(n)    (*((volatile unsigned char *)(0xE0000000+4*n)))
  2. #define ITM_Port16(n)   (*((volatile unsigned short*)(0xE0000000+4*n)))
  3. #define ITM_Port32(n)   (*((volatile unsigned long *)(0xE0000000+4*n)))

  4. #define DEMCR           (*((volatile unsigned long *)(0xE000EDFC)))
  5. #define TRCENA          0x01000000

  6. struct __FILE { int handle; /* Add whatever needed */ };
  7. FILE __stdout;
  8. FILE __stdin;

  9. int fputc(int ch, FILE *f) {
  10.   if (DEMCR & TRCENA) {
  11.     while (ITM_Port32(0) == 0);
  12.     ITM_Port8(0) = ch;
  13.   }
  14.   return(ch);
  15. }

复制代码

打开调试即可得到调试信息:

输出调试信息

测试代码:
F303RE_SWO.rar(394.54 KB, 下载次数: 307)


*******************************************一天过去了***************************************
上面说了输出的功能,其实如果需要的话,重定向下scanf()函数即可完成从Debug Viewer向程序输入参数的,这在调试某些需要动态调整参数的程序里面应该有帮助,比如按下某个按键,激活输入功能,重新配置下参数,然后继续运行程序。
调试的时候有个变量在一直检测是否有数据输入,如果有数据输入,那么输入的数据就传到这个变量,这个接口在内核的头文件有相关的定义,我们只需要定义这个变量即可。
将下面的main.c代码完整的替换掉上面的mian.c就可以使用了。
  1. #include "main.h"
  2. #include "string.h"
  3. //SWV test
  4. //2015-6-15
  5. //by creep
  6. #define ITM_Port8(n)    (*((volatile unsigned char *)(0xE0000000+4*n)))
  7. #define ITM_Port16(n)   (*((volatile unsigned short*)(0xE0000000+4*n)))
  8. #define ITM_Port32(n)   (*((volatile unsigned long *)(0xE0000000+4*n)))

  9. #define DEMCR           (*((volatile unsigned long *)(0xE000EDFC)))
  10. #define TRCENA          0x01000000

  11. struct __FILE { int handle; /* Add whatever needed */ };
  12. FILE __stdout;
  13. FILE __stdin;

  14. volatile int32_t ITM_RxBuffer=ITM_RXBUFFER_EMPTY;

  15. int fputc(int ch, FILE *f) {
  16.   if (DEMCR & TRCENA) {
  17.     while (ITM_Port32(0) == 0);
  18.     ITM_Port8(0) = ch;
  19.   }
  20.   return(ch);
  21. }
  22. int fgetc(FILE *f)
  23. {
  24.         while(ITM_CheckChar() == 0)
  25.         {               
  26.         }
  27.         return ITM_ReceiveChar();
  28. }

  29. u8 Write_buff[30] = "\n\r\n\rPlease enter your name:\n\r";
  30. u8 read_buff[50]= "";
  31. u8 name[100]="\n\rYour name is : ";
  32. int main(void)
  33. {
  34.         static u8 led_sta = ON;
  35.     LED_Init();
  36.     delay_init();
  37.                 delay_ms(1000);
  38.     while(1)
  39.     {
  40.                                 //将数据发送到Debug Viewer
  41.                                 printf((const char*)Write_buff);
  42.                                 memset(read_buff,0,50);
  43.                                 //等待输入
  44.                                 scanf("%s",read_buff);
  45.                                 //将姓名输出
  46.                                 printf((const char*)name);
  47.                                 printf((const char*)read_buff);
  48.                                 LED(led_sta);
  49.                                 led_sta = !led_sta;
  50.         delay_ms(1000);
  51.     }
  52. }



复制代码
直接在debug viewer窗口输入内容然后回车即可,输入的内容不会回显在窗口中,输入也支持中文。运行结果如下:



### 如何在 Keil IDE 中使用 `printf` 函数 当尝试在嵌入式开发环境中使用标准 C 库中的 `printf` 函数时,可能会遇到一些挑战。这是因为嵌入式系统通常不具备完整的标准输入输出设备。为了使 `printf` 正常工作,在 Keil IDE 下需完成特定配置。 #### 配置重定向标准输出到调试接口或其他外设 由于默认情况下,`printf` 尝试向控制台写数据而许多微控制器平台并没有连接实际的终端设备,所以需要将此功能重新导向至可用通信端口比如 UART 或者通过 SWO 输出用于 ITM 调试机制[^1]。 对于 STM32 系列单片机而言,一种常见做法是利用串行线调试(SWD)协议下的 ITM (Instrumentation Trace Macrocell),它允许实时发送字符流给主机电脑显示出来而不影响程序执行性能。这可以通过修改 `_write` 函数来实现: ```c #include "stm32f4xx_hal.h" // 定义 _write 方法以便于 printf 可以正常工作 int __attribute__((weak)) _write(int file, char *ptr, int len){ HAL_StatusTypeDef status; for(int i=0; i<len; ++i){ while(ITM_SendChar(*((unsigned char *) ptr++))); // 发送直到成功 } return len; } ``` 这段代码片段展示了如何定义弱符号 `_write` 来覆盖默认行为并让其适配硬件特性。这里假设已经初始化好 ITM 和 DWT 单元,并启用了 TRCENA 位以及设置了正确的波特率等参数。 另外,如果希望简单地把消息打印到计算机上的窗口而不是依赖特殊的硬件支持,则可以选择安装像 Keil 这样的集成开发环境(IDE)[^2]。这类工具提供了模拟的标准输出窗口供开发者查看运行期间产生的日志信息。 最后值得注意的是,在某些项目设置里还需要调整链接器选项排除不必要的库文件从而减小程序体积;同样也可以按照一定方法指定不包含某些源码单元或目录[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值