SEGGER-RTT简介:
如果在MCU开发调试时使用的是jlink,同时SEGGER-RTT支持当前MCU时,我们可以使用SEGGER-RTT代码串口进行打印输出及命令输入,可参考文章:
https://blog.csdn.net/qlexcel/article/details/126633180
需求背景:
SEGGER-RTT提供的接口函数:
1、int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, …)
格式化输出,支持字符、字符串、hex字符打印,但不支持浮点数及hex字符串。
2、unsigned SEGGER_RTT_Read(unsigned BufferIndex, void* pBuffer, unsigned BufferSize)
读取上位机RTT客户端输入字符串,但不支持直接读取hex字符串。
基于以上两点原因,决定对SEGGER-RTT原有接口函数进行封装,增加缺失的功能。
新的接口函数如下:
1、DebugPrintf(Format, …)
格式化打印输出,支持C语言所有格式化数据。
2、DebugHexPrint(const uint8_t aBuf[], const uint16_t Len)
hex字符串打印,在通讯调试时非常实用。
3、uint16_t DebugHexRecv(uint8_t *pBuf,uint16_t BufLen)
读取hex字符串读取,方便调试带参数的函数。
4、uint16_t DebugStrRecv(uint8_t *pBuf,uint16_t BufLen)
字符串读取
5、void JscopeDataUpLoad(uint32_t Data)
Jscope绘制曲线
头文件:
/********************************************************************
FileName : debug.h
Author :
Version :
Date :
Note : 使用打印功能时,必须连接Jlink仿真器,通过J-Link RTT Viewer查看输出
使用J-Scope功能时,必须连接Jlink仿真器,通过J-Scope 上位机查看输出
History :
********************************************************************/
#ifndef __DEBUG_H__
#define __DEBUG_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------*/
#include <stdint.h>
/* Public define -------------------------------------------------*/
//<<< Use Configuration Wizard in Context Menu >>>
// <h>Debug cfg
//<c1>Enable Debug
//<i>Enable Debug
#define D_ENABLE_DEBUG
//</c>
// <o>debug buffer length
// <i>Default: 256
// <1-1024>
#define D_PRINT_BUF_LEN 1024
//<c1>Enable debug time
//<i>Enable debug time
#define D_PRINT_TIME
//</c>
//<c1>Enable Hex Print
//<i>Enable Hex Print
#define D_ENABLE_HEX_PRINT
//</c>
// <o>hex buffer length
// <i>Default: 255
// <1-255>
#define D_HEX_BUF_LEN 200
//<c1>Enable jscope
//<i>Enable jscope
//#define D_ENABLE_JSCOPE
//</c>
// <o>jscope buffer length
// <i>Default: 2048
// <1-65535>
#define D_JSCOPE_BUF_LEN 4096
//<c1>Enable jscope time
//<i>Enable jscope time
//#define D_JSCOPE_TIME
//</c>
//<c1>Enable receive
//<i>Enable receive
#define D_ENABLE_RECV
//</c>
// </h>
//<<< end of configuration section >>>
#ifdef D_ENABLE_DEBUG
#include "SEGGER_RTT.h"
extern void RTT_Printf(const void *pFormat,...);
#define DebugPrintf(Format, ...) RTT_Printf(Format, ##__VA_ARGS__)
#define DebugErr(Format, ...) do {\
SEGGER_RTT_WriteString(0,RTT_CTRL_TEXT_BRIGHT_RED);\
SEGGER_RTT_WriteString(0,__FILE__);\
RTT_Printf("line:%d\n",__LINE__);\
RTT_Printf(Format, ##__VA_ARGS__);\
SEGGER_RTT_WriteString(0,RTT_CTRL_TEXT_BRIGHT_CYAN);\
}while(0)
#else
#define DebugPrintf(format, ...)
#define DebugErr(Format, ...)
#endif
/* Public typedef ------------------------------------------------*/
/* Public constants ----------------------------------------------*/
/* Public variables ----------------------------------------------*/
/* Public function prototypes ------------------------------------*/
extern void DebugInit(void);
extern void DebugHexPrint(const uint8_t aBuf[], const uint16_t Len);
extern void JscopeDataUpLoad(uint32_t Data);
extern uint16_t DebugHexRecv(uint8_t *pBuf,uint16_t BufLen);
extern uint16_t DebugStrRecv(uint8_t *pBuf,uint16_t BufLen);
#ifdef __cplusplus
}
#endif
#endif
/*************************** END OF FILE ***************************/
如果你使用的keil5,可以通过configuration Wizard进行开关、buffer等配置,如图所示:
源文件:
/********************************************************************
FileName : debug.c
Author :
Version :
Date :
Note : 使用打印功能时,必须连接Jlink仿真器,通过J-Link RTT Viewer查看输出
使用J-Scope功能时,必须连接Jlink仿真器,通过J-Scope 上位机查看输出
History :
********************************************************************/
/* Includes ------------------------------------------------------*/
#include "debug.h"
#include <string.h>
#include <stdio.h>
/* Private define ------------------------------------------------*/
/* Private typedef -----------------------------------------------*/
/* Private constants ---------------------------------------------*/
/* Private variables ---------------------------------------------*/
#ifdef D_ENABLE_DEBUG
static uint8_t s_aPrintStrBuf[D_PRINT_BUF_LEN] = {0};
#ifdef D_ENABLE_HEX_PRINT
static uint8_t s_aPrintHexBuf[D_HEX_BUF_LEN] = {0};
#endif
#ifdef D_ENABLE_JSCOPE
static uint8_t s_aJscopeBuf[D_JSCOPE_BUF_LEN] = {0};
#endif
#endif
/* Private function prototypes -----------------------------------*/
/* Public constants ----------------------------------------------*/
/* Public variables ----------------------------------------------*/
/********************************************************************
* name : DebugInit
* description : RTT 初始化
* Input : none
* Output : none
* Return : none
********************************************************************/
void DebugInit(void)
{
#ifdef D_ENABLE_DEBUG
SEGGER_RTT_Init();
SEGGER_RTT_WriteString(0, RTT_CTRL_CLEAR);
SEGGER_RTT_WriteString(0, RTT_CTRL_TEXT_BRIGHT_CYAN);
#ifdef D_ENABLE_JSCOPE
/* J-Scope上行配置,通道1,格式:uint_32*/
#ifdef D_JSCOPE_TIME
SEGGER_RTT_ConfigUpBuffer(1, "JScope_t4u4", s_aJscopeBuf, sizeof(s_aJscopeBuf), SEGGER_RTT_MODE_NO_BLOCK_SKIP);
#else
SEGGER_RTT_ConfigUpBuffer(1, "JScope_u4", s_aJscopeBuf, sizeof(s_aJscopeBuf), SEGGER_RTT_MODE_NO_BLOCK_SKIP);
#endif
#endif
#endif
}
/********************************************************************
* name : RTT_Printf
* description : RTT 格式化打印
* Input : Format 格式化字符串
* Output : RTT print
* Return : none
********************************************************************/
#ifdef D_ENABLE_DEBUG
void RTT_Printf(const void *pFormat, ...)
{
uint16_t Index = 0;
memset(s_aPrintStrBuf, 0, sizeof(s_aPrintStrBuf));
#ifdef D_PRINT_TIME
extern uint32_t HAL_GetTick(void);
//时间戳
Index += sprintf((char *)s_aPrintStrBuf + Index, "(%d)", HAL_GetTick());
#endif
//数据
va_list arg;
va_start(arg, pFormat);
Index += vsprintf((char *)&s_aPrintStrBuf[Index], (char *)pFormat, arg);
va_end(arg);
Index = (Index < D_PRINT_BUF_LEN ? Index : D_PRINT_BUF_LEN);
SEGGER_RTT_Write(0, s_aPrintStrBuf, Index);
}
#endif
/********************************************************************
* name : DebugHexPrint
* description : Hex 数据打印
* Input : aBuf Hex数组
* Input : Len Hex长度
* Output : RTT print
* Return : none
********************************************************************/
void DebugHexPrint(const uint8_t aBuf[], const uint16_t Len)
{
#ifdef D_ENABLE_DEBUG
#ifdef D_ENABLE_HEX_PRINT
uint16_t Index = 0;
memset(s_aPrintHexBuf, 0, sizeof(s_aPrintHexBuf));
Index += sprintf((char *)&s_aPrintHexBuf[Index], "HEX:");
for(uint16_t i = 0; (i < Len) && (Index < D_HEX_BUF_LEN - 5); i++)
{
Index += sprintf((char *)&s_aPrintHexBuf[Index], "%02X ", aBuf[i]);
}
Index += sprintf((char *)&s_aPrintHexBuf[Index], "\n");
SEGGER_RTT_Write(0, s_aPrintHexBuf, Index);
#endif
#endif
}
/********************************************************************
* name : JscopeDataUpLoad
* description : Jscope数据上传
* Input : Data
* Output : none
* Return : none
********************************************************************/
void JscopeDataUpLoad(uint32_t Data)
{
#ifdef D_ENABLE_DEBUG
#ifdef D_ENABLE_JSCOPE
#ifdef D_JSCOPE_TIME
extern uint32_t HAL_GetTick(void);
//注意字节顺序
uint64_t TickUs = HAL_GetTick() * 1000;
uint64_t Temp = (uint64_t)Data << 32;
Temp += TickUs;
SEGGER_RTT_Write(1, &Temp, sizeof(uint64_t));
#else
SEGGER_RTT_Write(1, &Data, sizeof(uint32_t));
#endif
#endif
#endif
}
#ifdef D_ENABLE_RECV
#ifdef D_ENABLE_DEBUG
/********************************************************************
* name : CharToHex
* description : 字符转Hex
* Input : Ch 字符
* Output : Hex
* Return : Hex
********************************************************************/
static int8_t CharToHex(int8_t Ch)
{
if((Ch >= '0') && (Ch <= '9'))
{
return Ch - 0x30;
}
else if((Ch >= 'A') && (Ch <= 'F'))
{
return Ch - 'A' + 10;
}
else if((Ch >= 'a') && (Ch <= 'f'))
{
return Ch - 'a' + 10;
}
else
{
return (0xFF);
}
}
/********************************************************************
* name : Str2HexData
* description : ASCII字符串转hex字符串
* Input : Str ASCII字符串
* Input : Len ASCII字符串长度
* Input : Tag 字符串分隔符
* Output : pHex hex字符串
* Return : hex字符串长度
********************************************************************/
static int32_t Str2HexData(const uint8_t *pStr, uint16_t StrLen, uint8_t *pHex, uint8_t Tag)
{
int32_t HexData = 0;
int32_t LowHexData = 0;
uint16_t HexLen = 0;
for(uint16_t i = 0; i < StrLen; i++)
{
//跳过分隔符
if(!memcmp(&pStr[i], &Tag, 1))
{
continue;
}
int8_t StrH = pStr[i];
i++;
if(i >= StrLen)
{
break;
}
uint8_t strL = pStr[i];
HexData = CharToHex(StrH);
LowHexData = CharToHex(strL);
if((HexData == 16) || (LowHexData == 16))
{
break;
}
else
{
HexData = HexData * 16 + LowHexData;
}
pHex[HexLen] = (char)HexData;
HexLen++;
}
return HexLen;
}
#endif
#endif
/********************************************************************
* name : DebugHexRecv
* description : 从RTT接收HEX数据
* Input : pBuf
* Input : BufLen
* Output : pBuf
* Return : 接收数据长度
********************************************************************/
uint16_t DebugHexRecv(uint8_t *pBuf, uint16_t BufLen)
{
uint16_t DataLen = 0;
#ifdef D_ENABLE_DEBUG
#ifdef D_ENABLE_RECV
uint8_t aDataBuf[128] = {0};
uint16_t StrLen = 0;
uint8_t aStrBuf[256] = {0};
StrLen = (int)SEGGER_RTT_Read(0u, aStrBuf, sizeof(aStrBuf));
if(StrLen > 0)
{
DataLen = Str2HexData(aStrBuf, StrLen, aDataBuf, ' ');
if(DataLen > 0)
{
DataLen = DataLen < BufLen ? DataLen : BufLen;
//黄色字体显示输入
SEGGER_RTT_WriteString(0, RTT_CTRL_TEXT_BRIGHT_YELLOW);
aStrBuf[StrLen] = '\n';
SEGGER_RTT_WriteString(0, (const char *)aStrBuf);
SEGGER_RTT_WriteString(0, RTT_CTRL_TEXT_BRIGHT_CYAN);
memcpy(pBuf, aDataBuf, DataLen);
}
}
#endif
#endif
return DataLen;
}
/********************************************************************
* name : DebugStrRecv
* description : 从RTT接收字符串
* Input : pBuf
* Input : BufLen
* Output : pBuf
* Return : 接收数据长度
********************************************************************/
uint16_t DebugStrRecv(uint8_t *pBuf, uint16_t BufLen)
{
uint16_t StrLen = 0;
#ifdef D_ENABLE_DEBUG
#ifdef D_ENABLE_RECV
static uint8_t aStrBuf[256] = {0};
StrLen = (int)SEGGER_RTT_Read(0u, aStrBuf, sizeof(aStrBuf));
if(StrLen > 0)
{
if(StrLen <= BufLen)
{
//显示输入
SEGGER_RTT_WriteString(0, RTT_CTRL_TEXT_BRIGHT_MAGENTA);
DebugPrintf("%s\n", aStrBuf);
SEGGER_RTT_WriteString(0, RTT_CTRL_TEXT_BRIGHT_CYAN);
memcpy(pBuf, aStrBuf, StrLen);
}
else
{
SEGGER_RTT_WriteString(0, RTT_CTRL_TEXT_BRIGHT_RED);
DebugPrintf("input string is too long!\n");
SEGGER_RTT_WriteString(0, RTT_CTRL_TEXT_BRIGHT_CYAN);
StrLen = 0;
}
}
#endif
#endif
return StrLen;
}
/*************************** END OF FILE ***************************/