历史上的今天
返回首页

历史上的今天

今天是:2025年01月17日(星期五)

正在发生

2019年01月17日 | stm32实现printf打印log的几种办法

2019-01-17 来源:eefocus

在stm32单片机下,改一些bug的时候,光靠调试还不行,有时候需要打印log来查看某些变量在一段时间内的变化趋势,但是板卡又没有接串口,没办法重定向到串口打印,上网查资料研究了一下,发现以下几种办法可实现单片机像在pc终端一样打印log:


方法1:使用串口重定向,将printf打印的信息输出到串口,再将串口连接pc端串口接收终端,在终端上查看log.主要2个步骤:修改printf函数底层调用到的fputc函数和避免使用semihos TIng(半主机模式)。


a.如果使用mdk作为编译工具,在Target选项框里选Use MicroLib 选项,即为使用微库模式,不会使用半主机模式;


b.工程中添加串口配置代码,方便后续使用串口发送数据


void UART1_Configuration(void)

{

USART_InitTypeDef USART_InitStructure;

USART_ClockInitTypeDef  USART_ClockInitStructure;


RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 |RCC_APB2Periph_USART1, ENABLE  );


USART_ClockInitStructure.USART_Clock = USART_Clock_Disable;   // 时钟低电平活动

USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low;     // 时钟低电平

USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge;  // 时钟第二个边沿进行数据捕获

USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable;  // 最后一位数据的时钟脉冲不从SCLK输出

/* Configure the USART1 synchronous paramters */

USART_ClockInit(USART1, &USART_ClockInitStructure);  // 时钟参数初始化设置

 

USART_InitStructure.USART_BaudRate = 115200;    // 波特率为:115200

USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 8位数据

USART_InitStructure.USART_StopBits = USART_StopBits_1;  // 在帧结尾传输1个停止位

USART_InitStructure.USART_Parity = USART_Parity_No ;   // 奇偶失能

USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 硬件流控制失能


USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 发送使能+接收使能

/* Configure USART1 basic and asynchronous paramters */

USART_Init(USART1, &USART_InitStructure);


  /* Enable USART1 */

USART_ClearFlag(USART1, USART_IT_RXNE); //清中断,以免一启用中断后立即产生中断

USART_ITConfig(USART1,USART_IT_RXNE, ENABLE); //使能USART1中断源

USART_Cmd(USART1, ENABLE); //USART1总开关:开启

}

c.添加串口中断程序 


#define TxBufferSize   (countof(TxBuffer) - 1)

#define RxBufferSize   0x20

 

/* Private macro -------------------------------------------------------------*/

#define countof(a)   (sizeof(a) / sizeof(*(a)))

 

/* Private variables ---------------------------------------------------------*/

u8 TxBuffer[] = "\n\rUSART Hyperterminal Interrupts Example: USART-Hyperterminal\

communication using Interrupt\n\r";

u8 RxBuffer[RxBufferSize];

u8 NbrOfDataToTransfer = TxBufferSize;

u8 NbrOfDataToRead = RxBufferSize;

u8 TxCounter = 0; 

u16 RxCounter = 0;

 

 

/*******************************************************************************

* Function Name  : USART1_IRQHandler

* Description    : This function handles USART1 global interrupt request.

* Input          : None

* Output         : None

* Return         : None

*******************************************************************************/

void USART1_IRQHandler(void)

{

  if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)

  {

    /* Read one byte from the receive data register */

    RxBuffer[RxCounter++] = (USART_ReceiveData(USART1) & 0x7F);

   if(RxCounter == NbrOfDataToRead)

    {

      /* Disable the USART Receive interrupt */

          RxCounter = 0;

      //USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);

    }

  }

 

  if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)

  {   

    /* Write one byte to the transmit data register */

    USART_SendData(USART1, TxBuffer[TxCounter++]);                    

 

   if(TxCounter == NbrOfDataToTransfer)

    {

      /* Disable the USART1 Transmit interrupt */

      USART_ITConfig(USART1, USART_IT_TXE, DISABLE);

    }    

  }           

}

d.修改fputc和fgetc函数


int fputc(int ch, FILE *f)

{

/* 发送一个字节数据到USART1 */

USART_SendData(USART1, (u8) ch);


/* 等待发送完毕 */

while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);


return (ch);

}

 

// 重定向c库函数scanf到USART1

int fgetc(FILE *f)

{

/* 等待串口1输入数据 */

while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);

 

return (int)USART_ReceiveData(USART1);

}

d.现在就可以直接在代码中使用printf就可以在串口连接的pc端看到打印信息了


方法2:利用mdk自带的ITM功能查看log打印,这种办法优点是不占用串口,速度快,但还是依赖mdk来显示,在keil官网有相关的详细介绍http://www.keil.com/support/man/docs/uv4/uv4_db_dbg_printf_viewer.htm,有兴趣的朋友可以试试


方法3:使用Jlink自带的RTT工具打印。相比前2种,速度更快,也不依赖编译工具,只要有JLink即可。步骤如下:


a.需要使用新版的JLINK软件,最低要V4.90版本以上,旧版的jlink没有该功能,这是官方下载链接https://www.segger.com/downloads/jlink/#J-LinkSoftwareAndDocumentationPack、


b.从官网下载的JLINK程序安装后,再找到包里以下4个个文件添加到工程中


å¾ 2  éè¦æ·»å å°å·¥ç¨çæä»¶


c.这就可以直接使用SEGGER_RTT_printf函数打印,函数使用格式如下:


SEGGER_RTT_printf((0,"hello test %d times\r\n",++u32Counter);


d.先启动调试程序,然后可以在安装的Jlink目录找到J-link RTT Client.exe(还有其他查看log工具),打开此程序,打印的信息即可显示在该窗口


å¾3


e.查看RTT输出的工具有三个:


RTTViewer:不支持中文。至少要进入一次Debugger才能正常显示输出。建议进入Debugger之后再打开,否则经常不能正常显示输出


RTTLogger:支持中文,并且可以保存为log文件。使用具体的正确使用方法不清楚。根据手册说明,log只接收RTT通道1的输出,即SEGGER_RTT_printf(1,"字符串",输出格式)。但是实测,只能输出RTT通道0的信息,并且要求代码中要有使用到通道1的语句。否则收不到数据。


RTTClient:必须配合RTTLogger或者keil的Debugger来使用,而RTTLogger也必须配合Debugger使用。Client、Logger和Debugger三个窗口都打开的时候,Client和Logger只有其中一个能正常显示,另外一个会严重丢失数据。


方法4:使用图形化显示数据的调试法宝—JScope。


J-Scope是SEGGER公司推出的,可以在目标MCU运行时,实时分析数据并图形化显示的软件。它不需要像SWO那样需要MCU上面额外的引脚,而是使用标准的调试接口。J-Link驱动4.90之后的版本都有这个软件哦。


推荐阅读

史海拾趣

Dawning Precision Co Ltd公司的发展小趣事

为了进一步提升产品的品质和可靠性,Dawning加强了品质管理体系的建设。公司引进了先进的生产设备和检测仪器,制定了严格的品质检测流程。同时,Dawning还定期对员工进行品质管理培训,提高员工的品质意识和操作技能。这些措施的实施,使得Dawning的产品在品质上得到了极大的提升,赢得了客户的信赖和好评。

BAE Systems公司的发展小趣事

BAE Systems公司一直致力于技术创新,不断推动电子行业的发展。公司投入大量资源进行研发,开发出了一系列先进的电子系统和产品。这些技术成果不仅提升了公司的竞争力,也为全球电子行业的技术进步做出了贡献。例如,公司在军事通信、雷达系统、导弹技术等领域都取得了重要的突破,为国家的安全和防御提供了强有力的支持。

Fuji Teminal Industry Co Ltd公司的发展小趣事

BAE Systems公司的前身可以追溯到多个历史悠久的英国航空与电子企业。1910年成立的布里斯托飞机公司、1918年成立的英格兰电子公司,以及1927年成立的Vickers-Armstrongs,这些企业在各自的领域内都取得了显著的成就。到了1960年,这些企业经过整合,形成了英国飞机公司,这标志着英国航空与电子工业的一次重要合并。这一整合不仅增强了英国在航空领域的实力,也为后来的BAE Systems公司打下了坚实的基础。

Global Mixed-Mode Technology Inc公司的发展小趣事
报警灯的颜色和数量可以根据实际需求来设定。通常,为了区分不同的缺相情况,可以使用不同颜色的报警灯来对应不同的缺相相别。例如,黄色灯表示L1相缺相,绿色灯表示L2相缺相,红色灯表示L3相缺相。数量上,一般至少需要一个报警灯来指示缺相状态,但也可以设置多个报警灯以增加冗余或提供额外的视觉提示。
AD Semiconductor公司的发展小趣事
三相缺相报警灯电路的工作原理基于三相电的平衡性。当三相电中的任意一相缺失时,会导致电路不平衡,从而触发报警机制。通常,该电路会使用中间继电器或专门的缺相检测芯片来监测三相电的电压情况。一旦检测到缺相,就会通过继电器或芯片的控制,使报警灯亮起或发出声音警报,以提醒用户及时处理。
Aptina (ON Semiconductor)公司的发展小趣事

值得一提的是,Aptina曾与索尼达成了一项专利交叉许可协议。这一协议不仅加强了双方的技术合作,还促进了双方在图像传感器领域的共同发展。通过共享专利资源,Aptina得以进一步拓展其产品线,提升产品质量,巩固市场地位。

问答坊 | AI 解惑

女工程师在各大名企求职80天的经历(一)

作者:从11月初回到深圳,就开始着手找工作,拖到05年1月,80天的奔波和忐忑不安的心理终于告一段落。期间面试了好几家公司,有惊喜有失望有抱怨甚至对自己的怀疑,但是我顽固的执着终于有了回报,得到了想要的工作。其中的甘苦与大家分享、共勉, ...…

查看全部问答>

电子设计 (遥控车)

本帖最后由 paulhyde 于 2014-9-15 08:54 编辑 有人猜测会有遥控车的题目 就跟大家分享一下  …

查看全部问答>

求指导

本帖最后由 paulhyde 于 2014-9-15 09:40 编辑 有人知道ad811芯片怎么搭建才能实现功能吗,datasheet上的电路好像不行  …

查看全部问答>

摇摇棒制作

网上这些东西都比较多了,今天也把我做的东东跟大家共享一下,前些日子就送给女朋友了。所以没有照片,真不好意思,这里有原理图,源程序(c语言),和去摸软件,可以自由更换源代码,对于初学单片机的人来说无疑是个不错的选择,而且可以把作品送 ...…

查看全部问答>

生成NK.nb0的大小(CE6.0)

能否让Nk.Nb0的大小自动变化? 现在我的NK.NB0大小都一定会等于config.bib文件中定义的大小。 里边的ROMSIZE等于多大,NK.NB0就一定是多大。 请教…

查看全部问答>

关于对数据总线操作的问题

最近写了个应用程序对数据总线上的数据进行操作,关于物理地址和虚拟地址的映射我知道 假设*vi_adress为映射好的虚拟地址 先是写操作 *vi_adress=tmp  (tmp是数据) 这个操作是成功的 现在我想读取外面从过来的数据 tmp=*vi_adress& ...…

查看全部问答>

Wince 5.0 如何实现 AlphaBlend?

Wince 5.0 如何实现 AlphaBlend? Requirements OS Versions: Microsoft? Windows CE? 5.0 and later. Header: Windows.h. Link Library: Coredll.lib. 加入以上 lib后,编译仍出错。 应如何处理,找了些算法来代替,但速度太慢。 谢谢。…

查看全部问答>

问一个比较傻子的问题!硬件中断如何跳转到软件代码

偶菜鸟, 问一个傻子问题,硬件中断如何跳转到软件代码 例如,我有一个键盘,按一下, CPU是如何通过中断服务程序跳转到程序中的代码中? …

查看全部问答>

像迷一样的问题

想控制驱动程序,使用 CreateFile 取驱动句柄, 为什么有些驱动程序能够取到,有些取不到?驱动名称和路径是肯定正确的。 比较了代码,也没找出什么区别。 关键在哪里? 请高手帮助一下。 谢谢 。…

查看全部问答>

wince 图形绘制问题

不知道wince 支持 DirectX么? 支持 gdi+么? 各位大虾:不知道wince上,你们是怎么绘制图形?…

查看全部问答>