完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
调试笔记–keil printf小技巧
单片机开发过程中,大部分项目都离不开printf,printf可以打印系统当前运行的日志信息从而快速定位问题原因,一种极为方便的人家交互手段。使用过printf的都知道,要是有printf前,需要对 fputc 函数进行重定向(printf的本质就是先将用户字符串进行格式化(处理%d、%f等格式),然后调用 fputc 函数将格式化后的字符串一个一个的处理一遍,如果将 fputc 定义为串口输出字符串,则printf最终会将字符串从串口输出,这是最常见的,当然也可以通过适配不同的 fputc 函数到达从spi、can或者屏幕等其他通信口输出。)。从通信口接口输出一般会比较耗时,一些实时性要求比较高的系统并不适用,为了解决实时性,一些大佬就发明将fputc重定向输出到ram,然后利用调试器从ram中读取固定格式的数据的方法。 使用keil的Event Recorder中间件进行打印 缺点: 需要代码中添加Event Recorder中间件,并会占用1KB左右的RAMkeil添加组件 工程添加组件并开启 fputc 重定向至EVR 同时记得勾选使用微库 Event Recorder中间件的 fputc 使用了关键字weak,因此不要在工程中定义自己的 fputc函数,否则会覆盖 Event Recorder中间件的 fputc 初始化组件 并添加一下代码进行初始化组件 #include "EventRecorder.h" /* 初始化 EventRecorder 并开启 */ EventRecorderInitialize(EventRecordAll, 1U); 使用printf打印 这里顺带测量了打印耗时,可以发现使用Event Recorder中间件的printf打印耗时是us级的(和单片机有关,这里使用的是72MHz的stm32f105) 使用jlink-RTT Viewer组件进行打印 缺点:安装jlink驱动 jlink官网 一般下载最新版本即可 安装完驱动后,开始菜单就会有 j-Link RTT Viewer图标 移植RTT组件
RTT组件默认有3个上行(单片机到RTT Viewer软件)缓冲区和3个下行(RTT Viewer软件到单片机)缓冲区,其中缓冲区0 用作printf打印功能,其他缓冲区可以用作波形显示
segger官方测试RTT速度在 STM32F407 168 MHz 情况下,发送一个字符在1个us,当然了官方用的jlink应该是36MHz的
初始化将RTT的控制块名字赋值为"SEGGERRTT",并且将上行通道和下行通道0名字赋值为"Terminal",方便jlink通过扫描内存中的"SEGGERRTT"和"Terminal"找到RTT使用的内存。最重要的是将上行通道0和下行通道0和SEGGER_RTT.c中已经定义好了的缓冲区数组绑定起来(如果想使用其他通道,则需要自己开辟缓冲区数组) RTT组件打印 #include "SEGGER_RTT.h" /* BufferIndex只能是0 sFormat要打印的东西 */ /* 该函数不支持打印中文和浮点型 */ /* 如果想要打印中文和浮点型 可以使用printf函数,然后在 fputc 函数调用该函数 */ int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...); jlink连接目标板,打开 j-Link RTT Viewer图标,设置单片机型号,连接成功后就会显示打印信息 修改Terminal窗口 j-Link RTT Viewer软件上有16个 Terminal窗口(都是利用上行缓冲区0发送数据的),在通过在SEGGER_RTT_printf函数打印前,使用 SEGGER_RTT_SetTerminal 函数设置 Terminal显示窗口,让不同信息显示在不同的Terminal窗口内,例如警告信息显示在一个Terminal窗口,错误信息显示在一个Terminal窗口,正常的log信息显示在一个窗口 /* TerminalId 通道范围 0 - 15 */ int SEGGER_RTT_SetTerminal (unsigned char TerminalId); RTT组件接受数据 打印功能利用了RTT组件的上行缓冲区0,而接受则利用下行缓冲区0,如果要发送多个字符,可以适当改大下行缓冲区0的大小 /* * SEGGER_RTT_GetKey * * 函数描述:从缓冲区0读取一个字符 * * 返回值 * < 0 - 缓冲区没有数据 * >= 0 - 缓冲区字符 */ int SEGGER_RTT_GetKey (void); /* * SEGGER_RTT_HasData * * 函数描述:判断缓冲区是否有数据 * BufferIndex:缓冲区序号 * 返回值 * == 0 - 没有数据 * != 0 - 有数据 */ unsigned SEGGER_RTT_HasData (unsigned BufferIndex); /* * SEGGER_RTT_HasKey * * 函数描述:判断缓冲区0是否有数据 * * 返回值 * == 0 - 缓冲区没有数据 * == 1 - 缓冲区有数据 */ int SEGGER_RTT_HasKey (void); /* * SEGGER_RTT_Read * * 函数描述:从缓冲区读取N个字符 * BufferIndex:缓冲区序号 * pBuffer :存放读取数据 * BufferSize :读取长度 * 返回值 :实际读取的字节数 */ unsigned SEGGER_RTT_Read (unsigned BufferIndex, void* pBuffer, unsigned BufferSize); /* * SEGGER_RTT_ReadNoLock * * 函数描述:从缓冲区读取N个字符 * BufferIndex:缓冲区序号 * pBuffer :存放读取数据 * BufferSize :读取长度 * 返回值 :实际读取的字节数 * 注意 :和SEGGER_RTT_Read的区别是不带临界区保护 */ unsigned SEGGER_RTT_ReadNoLock (unsigned BufferIndex, void* pData, unsigned BufferSize); /* * SEGGER_RTT_GetBytesInBuffer * * 函数描述:获取缓冲区中数据数量 * BufferIndex:缓冲区序号 * 返回值 :数据数量 */ unsigned SEGGER_RTT_GetBytesInBuffer (unsigned BufferIndex); 这些API互相配合,接收数据十分简单 RTT组件临界区保护 RTT组件的临界区保护和freertos一样,使用basepri寄存器关闭中断,也就是说不受RTT组件临界区保护的中断服务函数中不能出现RTT组件的API函数。 默认0x20,在stm32中(stm32只用了高四位)只有中断优先级0和1的不受RTT组件临界区关中断影响,因此中断优先级0和1的中断服务函数中不能出现RTT组件的API函数,否则可能会出现错乱。 后缀带NoLock的函数均不使用关中断临界区保护,一般不要使用 |
|
|
|
只有小组成员才能发言,加入小组>>
imx6ull 和 lan8742 工作起来不正常, ping 老是丢包
3510 浏览 0 评论
3439 浏览 9 评论
3124 浏览 16 评论
3618 浏览 1 评论
9332 浏览 16 评论
1471浏览 3评论
724浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
740浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2528浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
2053浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-4-23 16:44 , Processed in 1.109534 second(s), Total 47, Slave 38 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191