您的位置:首页 > 科技 > 能源 > html教程菜鸟_贵州企业网站建设招商_网站关键字优化_企业网站优化服务公司

html教程菜鸟_贵州企业网站建设招商_网站关键字优化_企业网站优化服务公司

2024/11/17 5:32:03 来源:https://blog.csdn.net/dianfu233/article/details/142500598  浏览:    关键词:html教程菜鸟_贵州企业网站建设招商_网站关键字优化_企业网站优化服务公司
html教程菜鸟_贵州企业网站建设招商_网站关键字优化_企业网站优化服务公司

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

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com