在我们实际的项目里,很多时候都没有串口留出来用于调试,这样增加了调试的难度,做一些测试也没有预留的接口可以修改,很麻烦,因此我这边整合了RTT-view和lettershell,提供了一套只需要使用jlink即可使用shell工具调试代码的功能。

1.RTT-View如何使用

【嵌入式小技巧】STM32 实现 SEGGER RTT 打印(超详细)-CSDN博客

基本移植我就不再赘述,我这边介绍一些一个如何快速上手

1.1RTT-View初始化

#define  SEGGER_UP_BUFF_SIZE		(256)
#define  SEGGER_DOWN_BUFF_SIZE	    (256)
#define  SEGGER_INDEX_LINE			(0)

uint8_t g_ucaRTTUp0Buffer[SEGGER_UP_BUFF_SIZE] = {0};
uint8_t g_ucaRTT_BufferDown0Buffer[SEGGER_DOWN_BUFF_SIZE] = {0};

void SeggerInit(void)
{
	SEGGER_RTT_ConfigUpBuffer(SEGGER_INDEX_LINE, "Terminal", g_ucaRTTUp0Buffer, sizeof(g_ucaRTTUp0Buffer), SEGGER_RTT_MODE_NO_BLOCK_SKIP);
	SEGGER_RTT_ConfigDownBuffer(SEGGER_INDEX_LINE, "Terminal", g_ucaRTT_BufferDown0Buffer, sizeof(g_ucaRTT_BufferDown0Buffer), SEGGER_RTT_MODE_NO_BLOCK_SKIP);
	SEGGER_RTT_SetTerminal(SEGGER_INDEX_LINE);
}

初始化代码很简单,只需要指定指定发送的端口,并且设置收发的缓冲区即可,但事实上,我指定rtt-view发出的端口无效,最终内容输出在All Terminals,但是无伤大雅。

SEGGER_RTT_Write(SEGGER_INDEX_LINE, buff, size)

RTT发送十分简单,直接调用SEGGER_RTT_Write即可

	if(SEGGER_RTT_HasKey())
	{
		uint8_t ucGetChar;
		ucGetChar = SEGGER_RTT_GetKey();
		buff[0] = ucGetChar;
		return 1;
	}
	

RTT的接受有多种方式,我这边通过SEGGER_RTT_HasKey和SEGGER_RTT_GetKey组合即可,SEGGER_RTT_HasKey判断接受的缓冲是否有内容,SEGGER_RTT_GetKey读取一个字节

2.Letter-shell如何使用

STM32HAL 移植功能强大letter-shell开源库(裸机开发)_裸机 letter shell-CSDN博客

介绍letter-shell的文章也很多,我这边简述以下

void log_write(char *buff,short len);

Shell shell;
char shellBuffer[512];
Log uartLog = {
    .write = log_write,
    .active = LOG_ENABLE,
    .level = LOG_DEBUG
};
    
signed short shell_read(char *buff, unsigned short len) 
{
	if(SEGGER_RTT_HasKey())
	{
		uint8_t ucGetChar;
		ucGetChar = SEGGER_RTT_GetKey();
		buff[0] = ucGetChar;
		return 1;
	}
	
	return 0;

}

signed short shell_write(char *buff, unsigned short len)
{
	SEGGER_OUT(buff, len);
  return len;
}

void log_write(char *buff,short len)
{
	SEGGER_OUT(buff, len);
}

void userShellInit(void)
{
    shell.write = shell_write;
    shell.read = shell_read;
    shellInit(&shell, shellBuffer, 512);
    logRegister(&uartLog, &shell);
}


实际上letter-shell的移植也就三个部分,实现shell的读,写,以及日志的读写,如果不需要使用日志,有关日志注册的内容可以删除,我这边就保留了

简单介绍以下代码shell_write直接调用SEGGER_OUT,将内容打印到RTT-View上,shell_read通过读取一个字节,并返回给shell,log部分的内容我就不介绍了

注意,letter-shell有两种使用办法,第一种办法是在接受到字符的中断中调用 shellHandler,第二种办法实在主循环中调用shellTask(&shell),其中的shell是我们注册的shell结构体。

以上我们就能将letter-shell和RTT-View结合到一起

3.快速入手

我这边已经将所需要的文件打包好,并且写了注册有关代码,只需要调用几个初始化函数即可使用,我简单的介绍一些文件文件结构

tool.c中集成了我一些平时用的常见的模块,可以不用理会

在tool.h中有USE_SEGGER_RTT 的宏定义,需要设置为1,其他设为0即可

letter_shell文件夹下除了user_shell以外的内容都是letter-shell本身自带的文件,包括log文件夹下的内容,user_shell则是注册letter-shell读写的内容,就是上面第二部分的内容

RTT文件夹下是RTT—View所移植的文件,直接添加到编译即可,无需修改

另外两个文件夹的内容是用于单元测试,不用处理

我现在总结使用流程

1.将tool.h tool.c letter_shell文件夹 RTT文件夹下的内容添加到编译中

2.设置 USE_SEGGER_RTT 为 1

3.调用初始,初始化RTT-View和letter-shell

	SeggerInit();
	userShellInit();

4.在主循环中调用    shellTask(&shell);

5.打开j-link RTT Viewer

6.选择对应的芯片

7.点击OK,打开

8.点击input ->Sending->send on Enter 

9.输入help,点击enter查看是否正常工作

4.仓库地址

以上代码我提交在gitee仓库,需要的自取

zxy/GeneralTool

5.Unity 单元测试框架

基于以上 RTT-Viewer输如输出结合Letter-shell 管理框架,在此基础上可以添加Uniyt单元测试框架,用于进行单元测试,方便修改参数

Unity单元测试框架是由UNITY_OUTPUT_CHAR 宏定义来实现输出接口函数,因此只要将该宏定义修改成RTT-Viewer的输出即可,代码如下

在此基础上,只需要完成测试样例,并且将测试函数定向到外部指令,则可以通过shell工具调用单元测试样例。

编写测试样例

调用测试样例

将测试样例定向到shell指令

调用单元测试指令

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐