USMART调试组件学习

USMART调试组件学习日记

写于2024/9/24日晚

文章目录

  • USMART调试组件学习日记
    • 1. 简介
    • 2. 调试组件组成
    • 3.程序流程图
    • 4. 移植解析
    • 5. 实验效果
    • 5. 实验效果

1. 简介

USMART 是由正点原子开发的一个灵巧的串口调试互交组件,通过它你可以通过串口助手调用程序里面的任何函数,并执行。因此,你可以随意更改函数的输入参数(支持数字(10/16进制,支持负数)、字符串、函数入口地址等作为参数),单个函数最多支持 10 个输入参数,并支持函数返回值显示。

实现效果

image-20240924204852707

USMART 的特点如下:

  1. 可以调用绝大部分用户直接编写的函数。

  2. 资源占用极少(最少情况:FLASH:4K;SRAM:72B)。

  3. 支持参数类型多(数字(包含 10/16 进制,支持负数)、字符串、函数指针等)。

  4. 支持函数返回值显示。

  5. 支持参数及返回值格式设置。

  6. 支持函数执行时间计算(V3.1 及以后的版本新特性)。

  7. 使用方便。

2. 调试组件组成

USMART 文件说明
usmart.cUSMART 核心文件,用于处理命令以及对外交互
usmart.hUSMART 核心文件头文件,定义结构体,宏定义、函数声明等
usmart_str.cUSMART 字符串处理文件,用于字符串转换、参数获取等
usmart_str.hUSMART 字符串处理头文件,用于函数声明
usmart_port.cUSMART 移植文件,用于 USMART 移植
usmart_port.hUSMART 移植头文件,定义用户配置参数、宏定义、函数声明等
usmart_config.cUSMART 函数管理文件,用于添加用户需要 USMART 管理的函数

3.程序流程图

image-20240924205619957

我们拿LED0翻转函数进行测试USMART

4. 移植解析

USMART 的移植非常简单,我们只需要修改usmart_port.c 里面的 5 个函数即可完成移植。至于usmart.c等核心代码不用详细解析。

/**
* @brief 获取输入数据流(字符串)
* @note USMART 通过解析该函数返回的字符串以获取函数名及参数等信息
* @param 无
* @retval
* @arg 0, 没有接收到数据
* @arg 其他,数据流首地址(不能是 0)
*/
char *usmart_get_input_string(void)
{uint8_t len;char *pbuf = 0;if (g_usart_rx_sta & 0x8000) /* 串口接收完成? */{len = g_usart_rx_sta & 0x3fff; /* 得到此次接收到的数据长度 */g_usart_rx_buf[len] = '\0'; /* 在末尾加入结束符. */pbuf = (char*)g_usart_rx_buf;g_usart_rx_sta = 0; /* 开启下一次接收 */}return pbuf;
}

该函数通过 SYSTEM 文件夹默认的串口接收来实现输入数据流获取。SYSTEM 文件夹里面的串口接收函数,最大可以一次接收 200 字节,用于从串口接收函数名和参数等。大家如果在其他平台移植,请参考 SYSTEM 文件夹串口接收的实现方式进行移植

第二个是 usmart_timx_init 函数,该函数的实现代码如下:

/**
* @brief 定时器初始化函数
* @param arr:自动重装载值
* psc:定时器分频系数
* @retval 无
*/
void usmart_timx_init(uint16_t arr, uint16_t psc)
{USMART_TIMX_CLK_ENABLE();g_timx_usmart_handle.Instance = USMART_TIMX; /* 通用定时器 4 */g_timx_usmart_handle.Init.Prescaler = psc; /* 分频系数 */g_timx_usmart_handle.Init.CounterMode = TIM_COUNTERMODE_UP; /* 向上计数器 */g_timx_usmart_handle.Init.Period = arr; /* 自动装载值 */g_timx_usmart_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;HAL_TIM_Base_Init(&g_timx_usmart_handle);HAL_TIM_Base_Start_IT(&g_timx_usmart_handle); /* 使能定时器和定时器中断 */HAL_NVIC_SetPriority(USMART_TIMX_IRQn, 3, 3); /* 抢占优先级 3,子优先级 3 */HAL_NVIC_EnableIRQ(USMART_TIMX_IRQn); /* 开启 TIM 中断 */
}

该函数只有在:USMART_ENTIMX_SCAN 值为 1 时,才需要实现,用于定时器初始化,利用定时器完成对 usmart_scan 函数的周期性调用,并实现函数运行时间计时(runtime)功能。

第三和第四个函数仅用于服务 USMART 的函数执行时间统计功能(串口指令:runtime 1),分别是:usmart_timx_reset_time 和 usmart_timx_get_time,这两个函数代码如下:

/**
* @brief 复位 runtime
* @note 需要根据所移植到的 MCU 的定时器参数进行修改
* @param 无
* @retval 无
*/
void usmart_timx_reset_time(void)
{__HAL_TIM_CLEAR_FLAG(&g_timx_usmart_handle, TIM_FLAG_UPDATE);/* 清中断标志 */__HAL_TIM_SET_AUTORELOAD(&g_timx_usmart_handle, 0XFFFF); /* 重载值设置最大 */__HAL_TIM_SET_COUNTER(&g_timx_usmart_handle, 0); /* 清定时器 CNT */usmart_dev.runtime = 0;
}
/**
* @brief 获得 runtime 时间
* @note 需要根据所移植到的 MCU 的定时器参数进行修改
* @param 无
* @retval 执行时间,单位:0.1ms,最大延时时间为定时器 CNT 值的 2 倍*0.1ms
*/
uint32_t usmart_timx_get_time(void)
{
/* 在运行期间,产生了定时器溢出 */if (__HAL_TIM_GET_FLAG(&g_timx_usmart_handle, TIM_FLAG_UPDATE) == SET) {usmart_dev.runtime += 0XFFFF;}usmart_dev.runtime += __HAL_TIM_GET_COUNTER(&g_timx_usmart_handle);return usmart_dev.runtime; /* 返回计数值 */
}

usmart_timx_reset_time 函数在每次 USMART 调用函数之前执行,清除定时器的计数器,然后在函数执行完之后,调用 usmart_timx_get_time 获取计数器值,从而得到整个函数的运行时间。由于 usmart 调用的函数,都是在中断里面执行的,所以我们不太方便再用定时器的中断功能来实现定时器溢出统计,因此,USMART 的函数执行时间统计功能,最多可以统计定时器溢出 1 次的时间,对 STM32F103 的 TIM4 来说,该定时器是 16 位的,最大计数是 65535,而由于我们定时器设置的是 0.1ms 一个计时周期(10Khz),所以最长计时时间是:65535 * 2 * 0.1ms = 13.1 秒

也就是说,如果函数执行时间超过 13.1 秒,那么计时将不准确。

最后一个是 USMART_TIMX_IRQHandler 函数,该函数的实现代码如下:

/**
* @brief USMART 定时器中断服务函数
* @param 无
* @retval 无
*/
void USMART_TIMX_IRQHandler(void)
{
/* 溢出中断 */if(__HAL_TIM_GET_IT_SOURCE(&g_timx_usmart_handle,TIM_IT_UPDATE)==SET){usmart_dev.scan(); /* usmart 扫描 */__HAL_TIM_SET_COUNTER(&g_timx_usmart_handle, 0);; /* 清定时器 CNT */__HAL_TIM_SET_AUTORELOAD(&g_timx_usmart_handle, 100); /* 恢复原来的设置 */}__HAL_TIM_CLEAR_IT(&g_timx_usmart_handle, TIM_IT_UPDATE); /* 清除中断标志位 */
}

该函数是定时器 TIMX 的中断服务函数,也是一个宏定义函数,同样是在 usmart_port.h 里面定义,方便大家修改。该函数主要用于周期性调用 usmart 扫描函数(实际函数:usmart_scan),完成对输入数据流的处理。同时,清除定时器的 CNT 值,并设置自动重装载值。完成这几个函数的移植,就可以使用 USMART 了。不过,需要注意的是,usmart 同外部的互交,一般是通过 usmart_dev 结构体实现,所以 usmart_init 和 usmart_scan 的调用分别是通过:usmart_dev.init 和 usmart_dev.scan 实现的。

/* usmart控制管理器 */
struct _m_usmart_dev
{struct _m_usmart_nametab *funs;     /* 函数名指针 */void (*init)(uint16_t tclk);        /* 初始化 */uint8_t (*cmd_rec)(char *str);      /* 识别函数名及参数 */void (*exe)(void);                  /* 执行  */void (*scan)(void);                 /* 扫描 */uint8_t fnum;                       /* 函数数量 */uint8_t pnum;                       /* 参数数量 */uint8_t id;                         /* 函数id */uint8_t sptype;                     /* 参数显示类型(非字符串参数):0,10进制;1,16进制; */uint16_t parmtype;                  /* 参数的类型 */uint8_t  plentbl[MAX_PARM];         /* 每个参数的长度暂存表 */uint8_t  parm[PARM_LEN];            /* 函数的参数 */uint8_t runtimeflag;                /* 0,不统计函数执行时间;1,统计函数执行时间,注意:此功能必须在USMART_ENTIMX_SCAN使能的时候,才有用 */uint32_t runtime;                   /* 运行时间,单位:0.1ms,最大延时时间为定时器CNT值的2倍*0.1ms */
};

此外我们还需要在 usmart_config.c 文件里面添加想要被 USMART 调用的函数。打开usmart_config.c 文件

#include "./USMART/usmart.h"
#include "./USMART/usmart_str.h"/******************************************************************************************/
/* 用户配置区* 这下面要包含所用到的函数所申明的头文件(用户自己添加)*/#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/delay/delay.h"
//#include "./BSP/LCD/lcd.h"extern void led_set(uint8_t sta);
extern void test_fun(void(*ledset)(uint8_t), uint8_t sta);/* 函数名列表初始化(用户自己添加)* 用户直接在这里输入要执行的函数名及其查找串*/
struct _m_usmart_nametab usmart_nametab[] =
{
#if USMART_USE_WRFUNS == 1      /* 如果使能了读写操作 */(void *)read_addr, "uint32_t read_addr(uint32_t addr)",(void *)write_addr, "void write_addr(uint32_t addr,uint32_t val)",
#endif(void *)delay_ms, "void delay_ms(uint16_t nms)",(void *)delay_us, "void delay_us(uint32_t nus)",(void *)led_set, "void led_set(uint8_t sta)",};/******************************************************************************************/
/* 函数控制管理器初始化* 得到各个受控函数的名字* 得到函数总数量*/
struct _m_usmart_dev usmart_dev =
{usmart_nametab,usmart_init,usmart_cmd_rec,usmart_exe,usmart_scan,sizeof(usmart_nametab) / sizeof(struct _m_usmart_nametab), /* 函数数量 */0,      /* 参数数量 */0,      /* 函数ID */1,      /* 参数显示类型,0,10进制;1,16进制 */0,      /* 参数类型.bitx:,0,数字;1,字符串 */0,      /* 每个参数的长度暂存表,需要MAX_PARM个0初始化 */0,      /* 函数的参数,需要PARM_LEN个0初始化 */
};

这里的添加函数很简单,只要把函数所在头文件添加进来,并把函数名添加到usmart_nametab[]中

主程序初始化

/* LED状态设置函数 */
void led_set(uint8_t sta)
{LED1(sta);
}/* 函数参数调用测试函数 */
void test_fun(void(*ledset)(uint8_t), uint8_t sta)
{ledset(sta);
}int main(void)
{HAL_Init();                         /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72);                     /* 延时初始化 */usart_init(115200);                 /* 串口初始化为115200 */usmart_dev.init(72);                /* 初始化USMART */led_init();                         /* 初始化LED */lcd_init();                         /* 初始化LCD */lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);lcd_show_string(30, 70, 200, 16, 16, "USMART TEST", RED);lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);while (1){LED0_TOGGLE();                  /* LED0(RED) 闪烁 */delay_ms(500);}
}

usmart_dev.init(72)通过此函数进行USMART初始化,并usart_init(115200)初始化串口

5. 实验效果

微信图片_20240924211408

image-20240924211451299

image-20240924211504079

发送led_set(0x0),led亮起,实验完成。

,并usart_init(115200)初始化串口

5. 实验效果

微信图片_20240924211408

[外链图片转存中…(img-B8ACaJDK-1727183958931)]

[外链图片转存中…(img-HEwCgvSW-1727183958931)]

发送led_set(0x0),led亮起,实验完成。

微信图片_20240924211624

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1549566.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

SigLIP技术小结

paperhttps://arxiv.org/abs/2303.15343githubhttps://github.com/google-research/big_vision个人博客位置http://myhz0606.com/article/siglip 1 背景 CLIP[1]自提出以来在zero-shot分类、跨模态搜索、多模态对齐等多个领域得到广泛应用。得益于其令人惊叹的能力&#xff0…

备考中考的制胜法宝 —— 全国历年中考真题试卷大全

在中考这场重要的战役中,每一分都至关重要。为了帮助广大考生更好地备考,我们精心整理了这份全国历年中考真题试卷大全,旨在为大家提供最全面、最权威的备考资料。 文章目录 1. 全科覆盖,无遗漏2. 历年真题,权威可靠3.…

数据结构——“AVL树”的四种数据旋转的方法

因为上次普通的二叉搜索树在极端情况下极容易造成我们的链式结构(这会导致我们查询的时间复杂度变为O(n)),然而AVL树就很好的解决了这一问题(归功于四种旋转的方法),它让我们的树的查询的时间复杂度变得接近…

QT--基础

将默认提供的程序都注释上意义 0101.pro QT core gui #QT表示要引入的类库 core:核心库 gui:图形化界面库 #如果要使用其他库类中的相关函数,则需要加对应的库类后,才能使用 greaterThan(QT_MAJOR_VERSION, 4): QT wid…

关于frp Web界面-----frp Server Dashboard 和 frp Client Admin UI

Web 界面 官方文档:https://gofrp.org/zh-cn/docs/features/common/ui/ 目前 frpc 和 frps 分别内置了相应的 Web 界面方便用户使用。 客户端 Admin UI 服务端 Dashboard 服务端 Dashboard 服务端 Dashboard 使用户可以通过浏览器查看 frp 的状态以及代理统计信…

GD32片内flash读写数据

如有技术问题及技术需求请加作者微信! GD32片内Flash的读写数据是微控制器编程中的常见任务,主要用于存储程序代码、配置参数或用户数据等。以下将详细介绍GD32片内Flash的读写数据方法和程序。 一、GD32 Flash的基本特性 存储空间划分:GD32的Flash存储空间通常分为主存储块…

罕见 P0 故障!上交所崩了 ~

大家好啊,我是董董灿。 昨天(9月27号)很多朋友可能都刷到一个消息:上交所崩了。 原因是在近期经济政策的刺激下,我大A股市场出现反弹,很多投资者纷纷涌入大A进行交易。 A 股反弹本来是件好事&#xff0c…

常见网络服务搭建之SSH服务搭建

SSH为Secure Shell的缩写,由IETF的网络小组(Network Working Group)所制定的建立在应用层基础上的安全协议。SSH是较可靠,专为远程登录会话和其他网络服务提供安全性的协议,利用SSH协议可以有效防止远程管理过程中的信…

计算机毕业设计 招生宣传管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍:✌从事软件开发10年之余,专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ 🍅文末获取源码联系🍅 👇🏻 精…

代码随想录算法训练营第十七天|654.最大二叉树 617.合并二叉树 700.二叉搜索树中的搜索 98.验证二叉搜索树

654.最大二叉树 给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下: 二叉树的根是数组中的最大元素。左子树是通过数组中最大值左边部分构造出的最大二叉树。右子树是通过数组中最大值右边部分构造出的最大二叉树。 通过给定的数组构建最大二…

番外篇 | 复现AC-YOLOv5,进行自动化织物缺陷检测

前言:Hello大家好,我是小哥谈。我们提出了一种基于AC-YOLOv5的新型纺织缺陷检测方法。将空洞空间金字塔池化(ASPP)模块引入YOLOv5主干网络中,提出了squeeze-and-excitation(CSE)通道注意力模块,并将其引入到YOLOv5主干网络中。🌈 目录 🚀1.基础概念 🚀2.添…

Chrome浏览器如何修改语言(修改成英文、中文)

一、背景 有的时候需要修改chrome浏览器的语言,比如如下是中文,我要修改成英文 二、下面的方法已经无效了 在语言里添加"英语"并且置顶,试了很久,设置完后重启浏览器什么的,都无法改成英文。 这个可能…

ECMAScript 与 JavaScript 的区别详解

ECMAScript 与 JavaScript 的区别详解 在前端开发的学习过程中,很多开发者会遇到两个常见的术语:ECMAScript 和 JavaScript。这两个术语常常被混淆,因为它们密切相关,甚至有时被认为是同一件事。本文将详细解析 ECMAScript 和 Ja…

青动CRM V3.2.1

全面解决企业销售团队的全流程客户服务难题旨在助力企业销售全流程精细化、数字化管理,全面解决企业销售团队的全流程客户服务难题,帮助企业有效盘活客户资源、量化销售行为,合理配置资源、建立科学销售体系,提升销售业绩。标准授…

【面试题】软件测试实习(含答案)

软件测试实习常见面试题,主要是功能测试相关的基础问题 目录 一、软件测试基础 1、介绍一下你最近的项目,以及工作职责 2、软件项目的测试流程? 3、黑盒测试与白盒测试的区别? 4、黑盒测试常见的设计方法?怎么理解等价类方法和边界值方法 1&…

言语理解(2)

B B出现在文章中的第一句话,属于转折前的内容非重点 在这一过程中,属于对前面的指代,后面可以引出文章中的中心内容 A D没有提及到农村,C选项和文段中的最后一句话是相契合的 B 色彩是文章中的主题词,不过属于转折&…

SpringBoot搭建

第一种创建方式 第二种创建方式 第三种创建 第四种手动创建 最后把controller写好

解决Windows远程桌面 “为安全考虑,已锁定该用户账户,原因是登录尝试或密码更改尝试过多,请稍后片刻再重试,或与系统管理员或技术支持联系“问题

根本原因就是当前主机被通过远程桌面输入了过多的错误密码,被系统锁定。这种情况多数是你的服务器远程桌面被人试图攻击了,不建议取消系统锁定策略。如果阿里云或者腾讯云主机,只需要在管理后台通过管理终端或者VNC登陆一次,锁定即…

RTA-OS Port Guide学习(三)-基于S32K324 OS

文章目录 前言HardwareSupported DevicesRegister UsageInitializationModificationRequired OS resourcesInterruptsInterrupt Priority LevelsAllocation of ISRs to Interrupt VectorsVector TableWriting Category 1 Interrupt HandlersWriting Category 2 Interrupt Handl…

【Echarts】折线图和柱状图如何从后端动态获取数据?

🚀个人主页:一颗小谷粒 🚀所属专栏:Web前端开发 很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~ 目录 1.1 前端数据分析 1.2 数据库表分析 1.3 后端数据处理 1.4 前端接收数据 继上一篇文章&…