STM32F4_USMART调试组件

news2024/11/24 0:49:25

目录

1. USMART是什么?

2. USMART的特点

3. USMART实现流程

4. USMART组件

5. 在usmart_config.c中添加想要被USMART调用的函数

6. 实验程序

6.1 main.c

6.2 usmart.c

6.3 usmart.h

7. USMART调试的优越性说明 


1. USMART是什么?

        USMART 是 ALIENTEK 开发的一种十分重要的辅助调试工具。功能类似于 Linux 中的 shell(RTT 的 finsh)。USMART 是一种灵巧的串口调试互交组件,所以使用该功能必须搭配 usart 串口,通过 USMART,我们借助串口助手可以调用程序中的任何函数,并执行。因此,我们可以随意的更改函数输入参数(支持数字(10/16进制),支持负数、字符串、函数入口地址等作为参数),单个函数最多支持 10 个输入参数,并支持函数返回值显示。

2. USMART的特点

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

2. 资源占用极少(最少情况下:Flash:4K,SRAM:72B)

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

4. 支持函数返回值显示

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

6. 支持函数执行时间计算

7. 使用方便

总之:  有了USMART,我们可以轻易的修改参数,查看函数运行结果,从而快速的解决问题。

        比如说:我们通常写完一个程序,需要在MDK中编译,查看编译是否有错误,然后DowmLoad下载到单片机,如果现象不符合我们的预期,那么就需要一次一次的重复上述步骤,直到单片机显示出我们预期的现象;我们都知道,单片机也是有其使用寿命的,这样一次又一次的编译,下载,非常损耗单片机的寿命;此时我们可以借助USMART,通过串口将函数及参数发送给单片机,要知道,这样通过串口发送给单片机,是不用进行编译和下载的,现象不符合预期,直接在串口修改参数即可,这样一来,对单片机来说是非常友好的。

3. USMART实现流程

USMART的实现流程简单来说包括以下4步:

1. 添加需要调用的函数(在usmart_config.c里面的usmart_nametab数组里面添加)

2. 初始化串口

3. 初始化USMART(通过usmart_init函数实现)

4. 借助usmart_scan函数,处理串口数据

4. USMART组件

USMART文件共包含以下6个文件;其中 readme.txt 是一个说明文件; 

usmart.c负责与外部互交; usmart.h是usmart.c的头文件。该文件中含有几个用户配置宏定义,可以用来配置usmart的功能及总参数长度(直接和SRAM占用挂钩)、是否使能定时器扫描、是否使用读写函数等。

usmart_str.c主要负责命令和参数解析;usmart_str.h是usmart_str.c的头文件;

根据USMART实现流程中的第一步可知:usmart_config主要由用户添加需要由usmart管理的函数;

USMART的移植需要5个函数来实现。其中4个函数位于usmart.c中,另外一个串口接收函数,必须用户自己定义实现。

一、串口接收函数;最大可以一次接收200个字节,用于从串口接收函数名和参数。

二、初始化串口控制器;

//sysclk:系统时钟Mhz

void usmart_init(u8 sysclk)// 初始化串口控制器
{
#if USMART_ENTIMX_SCAN==1 //是否使能定时器中断扫描,如果USMART_ENTIMX_SCAN为1,则使能定时器中断
//扫描;如果为0,则需要用户自行间隔一段时间调用usmart_scan函数
    
    Timer4_Init(1000,(u32)sysclk*100-1);//初始化定时器4,设置自动重装载值和预分频值,保证时间为0.1ms


#endif
    
    usmart_dev.sptype=1;  //十六进制显示参数
}


//如果要使用函数执行时间统计功能(runtime 1),则必须设置USMART_ENTIMX_SCAN为1。
//为了让时间精确到0.1ms,定时器的计数时钟频率必须设置10Khz

三(四)、用于服务函数USMART的函数执行时间统计功能(串口指令:runtime 1);

//复位runtime

void usmart_reset_runtime(void)
{
    TIM_ClearFlag(TIM4,TIM_FLAG_Updata); //清空中断标志位
    TIM_SetAutorload(TIM4,0xFFFF);//将重装载值设置到最大
    TIM_SetCounter(TIM4,0);  //清空定时器的计数值CNT
    usmart_dev.runtime=0;
}
//获得runtime时间
//返回值:执行时间,单位:0.1ms,最大延迟时间为定时器CNT值的2倍*0.1ms

u32 usmart_get_runtime(void)
{
    if(TIM_GetFlagStatus(TIM4,TIM_FLAG_Update)==SET)//在运行时间,产生了定时器中断
   {
        usmart_dev.runtime+=0xFFFF;
    }
    usmart_dev.runtime+=TIM_GetCounter(TIM4);
    return usmart_dev.runtime;   
}

五、usmart扫描函数;usmart_scan函数,该函数用于执行usmart扫描;函数的第一个参数是从串口接收到的数组USART_RX_BUF,第二个参数是串口接收的状态USART_RX_STA

//usmart扫描函数
//通过调用该函数,实现usmart的各个控制,该函数每隔一段时间需要被调用一次

void usmart_scan(void) 
	{  
		u8 sta,len;  
		if(USART_RX_STA&0x8000) //串口接收完成?  
			{  len=USART_RX_STA&0x3fff; //得到此次接收到的数据长度  
				USART_RX_BUF[len]='\0'; //在末尾加入结束符.   
				sta=usmart_dev.cmd_rec(USART_RX_BUF);//得到函数各个信息  
				if(sta==0)usmart_dev.exe(); //执行函数  
				else  
					{  
						len=usmart_sys_cmd_exe(USART_RX_BUF);  
						if(len!=USMART_FUNCERR)sta=len;  
						if(sta)  
							{  
								witch(sta)  
								{  
									case USMART_FUNCERR:  printf("函数错误!\r\n");  break;  
									case USMART_PARMERR:  printf("参数错误!\r\n");  break;  
									case USMART_PARMOVER:  printf("参数太多!\r\n");  break;  
									case USMART_NOFUNCFIND:  printf("未找到匹配的函数!\r\n");  break;  
									}  
									}  
									}  
					USART_RX_STA=0;//状态寄存器清空  
					} 
	} 

5. 在usmart_config.c中添加想要被USMART调用的函数

通过以上使用USMART的步骤,我们知道自己想要被调用的函数需要手动添加到usmart_config.c中;

在上图示意的地方添加想要的函数及函数定义的头文件即可;

6. 实验程序

6.1 main.c

#include "stm32f4xx.h"
#include "delay.h"
#include "usart.h"
#include "LED.h"
#include "lcd.h"
#include "usmart.h"

//LCD状态设置函数
void led_set(u8 sta)
{
	LED1=sta;
}
//函数参数调用测试函数
void test_fun(void(*ledset)(u8),u8 sta)
{
	led_set(sta);
}
int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	delay_init(168);
	uart_init(115200);
	usmart_dev.init(84);
	LED_Init();
	LCD_Init();
	POINT_COLOR=RED;
	LCD_ShowString(30,50,200,16,16,"Hello Friend");
	LCD_ShowString(30,70,200,16,16,"welcome");
	LCD_ShowString(30,90,200,16,16,"to");
	LCD_ShowString(30,110,200,16,16,"2023");
	LCD_ShowString(30,130,200,16,16,"2023/1/22");
	while(1)
	{
		LED0=!LED0;
		delay_ms(500);
	}
	
}

6.2 usmart.c

#include "usmart.h"
#include "usart.h"
#include "sys.h" 

u8 *sys_cmd_tab[]=
{
	"?",
	"help",
	"list",
	"id",
	"hex",
	"dec",
	"runtime",	   
};	    
//处理系统指令
//0,成功处理;其他,错误代码;
u8 usmart_sys_cmd_exe(u8 *str)
{
	u8 i;
	u8 sfname[MAX_FNAME_LEN];//存放本地函数名
	u8 pnum;
	u8 rval;
	u32 res;  
	res=usmart_get_cmdname(str,sfname,&i,MAX_FNAME_LEN);//得到指令及指令长度
	if(res)return USMART_FUNCERR;//错误的指令 
	str+=i;	 	 			    
	for(i=0;i<sizeof(sys_cmd_tab)/4;i++)//支持的系统指令
	{
		if(usmart_strcmp(sfname,sys_cmd_tab[i])==0)break;
	}
	switch(i)
	{					   
		case 0:
		case 1://帮助指令
			printf("\r\n");
#if USMART_USE_HELP
			printf("------------------------USMART V3.1------------------------ \r\n");
			printf("    USMART是由ALIENTEK开发的一个灵巧的串口调试互交组件,通过 \r\n");
			printf("它,你可以通过串口助手调用程序里面的任何函数,并执行.因此,你可\r\n");
			printf("以随意更改函数的输入参数(支持数字(10/16进制)、字符串、函数入\r\n");	  
			printf("口地址等作为参数),单个函数最多支持10个输入参数,并支持函数返 \r\n");
			printf("回值显示.新增参数显示进制设置功能,新增进制转换功能.\r\n");
			printf("技术支持:www.openedv.com\r\n");
			printf("USMART有7个系统命令:\r\n");
			printf("?:      获取帮助信息\r\n");
			printf("help:   获取帮助信息\r\n");
			printf("list:   可用的函数列表\r\n\n");
			printf("id:     可用函数的ID列表\r\n\n");
			printf("hex:    参数16进制显示,后跟空格+数字即执行进制转换\r\n\n");
			printf("dec:    参数10进制显示,后跟空格+数字即执行进制转换\r\n\n");
			printf("runtime:1,开启函数运行计时;0,关闭函数运行计时;\r\n\n");
			printf("请按照程序编写格式输入函数名及参数并以回车键结束.\r\n");    
			printf("--------------------------ALIENTEK------------------------- \r\n");
#else
			printf("指令失效\r\n");
#endif
			break;
		case 2://查询指令
			printf("\r\n");
			printf("-------------------------函数清单--------------------------- \r\n");
			for(i=0;i<usmart_dev.fnum;i++)printf("%s\r\n",usmart_dev.funs[i].name);
			printf("\r\n");
			break;	 
		case 3://查询ID
			printf("\r\n");
			printf("-------------------------函数 ID --------------------------- \r\n");
			for(i=0;i<usmart_dev.fnum;i++)
			{
				usmart_get_fname((u8*)usmart_dev.funs[i].name,sfname,&pnum,&rval);//得到本地函数名 
				printf("%s id is:\r\n0X%08X\r\n",sfname,usmart_dev.funs[i].func); //显示ID
			}
			printf("\r\n");
			break;
		case 4://hex指令
			printf("\r\n");
			usmart_get_aparm(str,sfname,&i);
			if(i==0)//参数正常
			{
				i=usmart_str2num(sfname,&res);	   	//记录该参数	
				if(i==0)						  	//进制转换功能
				{
					printf("HEX:0X%X\r\n",res);	   	//转为16进制
				}else if(i!=4)return USMART_PARMERR;//参数错误.
				else 				   				//参数显示设定功能
				{
					printf("16进制参数显示!\r\n");
					usmart_dev.sptype=SP_TYPE_HEX;  
				}

			}else return USMART_PARMERR;			//参数错误.
			printf("\r\n"); 
			break;
		case 5://dec指令
			printf("\r\n");
			usmart_get_aparm(str,sfname,&i);
			if(i==0)//参数正常
			{
				i=usmart_str2num(sfname,&res);	   	//记录该参数	
				if(i==0)						   	//进制转换功能
				{
					printf("DEC:%lu\r\n",res);	   	//转为10进制
				}else if(i!=4)return USMART_PARMERR;//参数错误.
				else 				   				//参数显示设定功能
				{
					printf("10进制参数显示!\r\n");
					usmart_dev.sptype=SP_TYPE_DEC;  
				}

			}else return USMART_PARMERR;			//参数错误. 
			printf("\r\n"); 
			break;	 
		case 6://runtime指令,设置是否显示函数执行时间
			printf("\r\n");
			usmart_get_aparm(str,sfname,&i);
			if(i==0)//参数正常
			{
				i=usmart_str2num(sfname,&res);	   		//记录该参数	
				if(i==0)						   		//读取指定地址数据功能
				{
					if(USMART_ENTIMX_SCAN==0)printf("\r\nError! \r\nTo EN RunTime function,Please set USMART_ENTIMX_SCAN = 1 first!\r\n");//报错
					else
					{
						usmart_dev.runtimeflag=res;
						if(usmart_dev.runtimeflag)printf("Run Time Calculation ON\r\n");
						else printf("Run Time Calculation OFF\r\n"); 
					}
				}else return USMART_PARMERR;   			//未带参数,或者参数错误	 
 			}else return USMART_PARMERR;				//参数错误. 
			printf("\r\n"); 
			break;	    
		default://非法指令
			return USMART_FUNCERR;
	}
	return 0;
}

//移植注意:本例是以stm32为例,如果要移植到其他mcu,请做相应修改.
//usmart_reset_runtime,清除函数运行时间,连同定时器的计数寄存器以及标志位一起清零.并设置重装载值为最大,以最大限度的延长计时时间.
//usmart_get_runtime,获取函数运行时间,通过读取CNT值获取,由于usmart是通过中断调用的函数,所以定时器中断不再有效,此时最大限度
//只能统计2次CNT的值,也就是清零后+溢出一次,当溢出超过2次,没法处理,所以最大延时,控制在:2*计数器CNT*0.1ms.对STM32来说,是:13.1s左右
//其他的:TIM4_IRQHandler和Timer4_Init,需要根据MCU特点自行修改.确保计数器计数频率为:10Khz即可.另外,定时器不要开启自动重装载功能!!

#if USMART_ENTIMX_SCAN==1
//复位runtime
//需要根据所移植到的MCU的定时器参数进行修改
void usmart_reset_runtime(void)
{
 
	TIM_ClearFlag(TIM4,TIM_FLAG_Update);//清除中断标志位 
	TIM_SetAutoreload(TIM4,0XFFFF);//将重装载值设置到最大
	TIM_SetCounter(TIM4,0);		//清空定时器的CNT
	usmart_dev.runtime=0;	
}
//获得runtime时间
//返回值:执行时间,单位:0.1ms,最大延时时间为定时器CNT值的2倍*0.1ms
//需要根据所移植到的MCU的定时器参数进行修改
u32 usmart_get_runtime(void)
{
	if(TIM_GetFlagStatus(TIM4,TIM_FLAG_Update)==SET)//在运行期间,产生了定时器溢出
	{
		usmart_dev.runtime+=0XFFFF;
	}
	usmart_dev.runtime+=TIM_GetCounter(TIM4);
	return usmart_dev.runtime;		//返回计数值
}  
//下面这两个函数,非USMART函数,放到这里,仅仅方便移植. 
//定时器4中断服务程序	 
void TIM4_IRQHandler(void)
{ 		    		  			    
	if(TIM_GetITStatus(TIM4,TIM_IT_Update)==SET)//溢出中断
	{
		usmart_dev.scan();	//执行usmart扫描	
		TIM_SetCounter(TIM4,0);		//清空定时器的CNT
		TIM_SetAutoreload(TIM4,100);//恢复原来的设置		    				   				     	    	
	}				   
	TIM_ClearITPendingBit(TIM4,TIM_IT_Update);  //清除中断标志位    
}
//使能定时器4,使能中断.
void Timer4_Init(u16 arr,u16 psc)
{
	NVIC_InitTypeDef   NVIC_InitStructure;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);  ///使能TIM4时钟

	TIM_TimeBaseInitStructure.TIM_Prescaler=psc;  //定时器分频
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
	TIM_TimeBaseInitStructure.TIM_Period=arr;   //自动重装载值
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
	
	TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure);//初始化定时器4
	
	TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE); //允许定时器4更新中断
	TIM_Cmd(TIM4,ENABLE); //使能定时器4
 
	NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;//外部中断4
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x03;//抢占优先级3
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;//子优先级3
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道
  NVIC_Init(&NVIC_InitStructure);//配置NVIC
	 							 
}
#endif

//初始化串口控制器
//sysclk:系统时钟(Mhz)
void usmart_init(u8 sysclk)
{
#if USMART_ENTIMX_SCAN==1
	Timer4_Init(1000,(u32)sysclk*100-1);//分频,时钟为10K ,100ms中断一次,注意,计数频率必须为10Khz,以和runtime单位(0.1ms)同步.
#endif
	usmart_dev.sptype=1;	//十六进制显示参数
}		
//从str中获取函数名,id,及参数信息
//*str:字符串指针.
//返回值:0,识别成功;其他,错误代码.
u8 usmart_cmd_rec(u8*str) 
{
	u8 sta,i,rval;//状态	 
	u8 rpnum,spnum;
	u8 rfname[MAX_FNAME_LEN];//暂存空间,用于存放接收到的函数名  
	u8 sfname[MAX_FNAME_LEN];//存放本地函数名
	sta=usmart_get_fname(str,rfname,&rpnum,&rval);//得到接收到的数据的函数名及参数个数	  
	if(sta)return sta;//错误
	for(i=0;i<usmart_dev.fnum;i++)
	{
		sta=usmart_get_fname((u8*)usmart_dev.funs[i].name,sfname,&spnum,&rval);//得到本地函数名及参数个数
		if(sta)return sta;//本地解析有误	  
		if(usmart_strcmp(sfname,rfname)==0)//相等
		{
			if(spnum>rpnum)return USMART_PARMERR;//参数错误(输入参数比源函数参数少)
			usmart_dev.id=i;//记录函数ID.
			break;//跳出.
		}	
	}
	if(i==usmart_dev.fnum)return USMART_NOFUNCFIND;	//未找到匹配的函数
 	sta=usmart_get_fparam(str,&i);					//得到函数参数个数	
	if(sta)return sta;								//返回错误
	usmart_dev.pnum=i;								//参数个数记录
    return USMART_OK;
}
//usamrt执行函数
//该函数用于最终执行从串口收到的有效函数.
//最多支持10个参数的函数,更多的参数支持也很容易实现.不过用的很少.一般5个左右的参数的函数已经很少见了.
//该函数会在串口打印执行情况.以:"函数名(参数1,参数2...参数N)=返回值".的形式打印.
//当所执行的函数没有返回值的时候,所打印的返回值是一个无意义的数据.
void usmart_exe(void)
{
	u8 id,i;
	u32 res;		   
	u32 temp[MAX_PARM];//参数转换,使之支持了字符串 
	u8 sfname[MAX_FNAME_LEN];//存放本地函数名
	u8 pnum,rval;
	id=usmart_dev.id;
	if(id>=usmart_dev.fnum)return;//不执行.
	usmart_get_fname((u8*)usmart_dev.funs[id].name,sfname,&pnum,&rval);//得到本地函数名,及参数个数 
	printf("\r\n%s(",sfname);//输出正要执行的函数名
	for(i=0;i<pnum;i++)//输出参数
	{
		if(usmart_dev.parmtype&(1<<i))//参数是字符串
		{
			printf("%c",'"');			 
			printf("%s",usmart_dev.parm+usmart_get_parmpos(i));
			printf("%c",'"');
			temp[i]=(u32)&(usmart_dev.parm[usmart_get_parmpos(i)]);
		}else						  //参数是数字
		{
			temp[i]=*(u32*)(usmart_dev.parm+usmart_get_parmpos(i));
			if(usmart_dev.sptype==SP_TYPE_DEC)printf("%lu",temp[i]);//10进制参数显示
			else printf("0X%X",temp[i]);//16进制参数显示 	   
		}
		if(i!=pnum-1)printf(",");
	}
	printf(")");
	usmart_reset_runtime();	//计时器清零,开始计时
	switch(usmart_dev.pnum)
	{
		case 0://无参数(void类型)											  
			res=(*(u32(*)())usmart_dev.funs[id].func)();
			break;
	    case 1://有1个参数
			res=(*(u32(*)())usmart_dev.funs[id].func)(temp[0]);
			break;
	    case 2://有2个参数
			res=(*(u32(*)())usmart_dev.funs[id].func)(temp[0],temp[1]);
			break;
	    case 3://有3个参数
			res=(*(u32(*)())usmart_dev.funs[id].func)(temp[0],temp[1],temp[2]);
			break;
	    case 4://有4个参数
			res=(*(u32(*)())usmart_dev.funs[id].func)(temp[0],temp[1],temp[2],temp[3]);
			break;
	    case 5://有5个参数
			res=(*(u32(*)())usmart_dev.funs[id].func)(temp[0],temp[1],temp[2],temp[3],temp[4]);
			break;
	    case 6://有6个参数
			res=(*(u32(*)())usmart_dev.funs[id].func)(temp[0],temp[1],temp[2],temp[3],temp[4],\
			temp[5]);
			break;
	    case 7://有7个参数
			res=(*(u32(*)())usmart_dev.funs[id].func)(temp[0],temp[1],temp[2],temp[3],temp[4],\
			temp[5],temp[6]);
			break;
	    case 8://有8个参数
			res=(*(u32(*)())usmart_dev.funs[id].func)(temp[0],temp[1],temp[2],temp[3],temp[4],\
			temp[5],temp[6],temp[7]);
			break;
	    case 9://有9个参数
			res=(*(u32(*)())usmart_dev.funs[id].func)(temp[0],temp[1],temp[2],temp[3],temp[4],\
			temp[5],temp[6],temp[7],temp[8]);
			break;
	    case 10://有10个参数
			res=(*(u32(*)())usmart_dev.funs[id].func)(temp[0],temp[1],temp[2],temp[3],temp[4],\
			temp[5],temp[6],temp[7],temp[8],temp[9]);
			break;
	}
	usmart_get_runtime();//获取函数执行时间
	if(rval==1)//需要返回值.
	{
		if(usmart_dev.sptype==SP_TYPE_DEC)printf("=%lu;\r\n",res);//输出执行结果(10进制参数显示)
		else printf("=0X%X;\r\n",res);//输出执行结果(16进制参数显示)	   
	}else printf(";\r\n");		//不需要返回值,直接输出结束
	if(usmart_dev.runtimeflag)	//需要显示函数执行时间
	{ 
		printf("Function Run Time:%d.%1dms\r\n",usmart_dev.runtime/10,usmart_dev.runtime%10);//打印函数执行时间 
	}	
}
//usmart扫描函数
//通过调用该函数,实现usmart的各个控制.该函数需要每隔一定时间被调用一次
//以及时执行从串口发过来的各个函数.
//本函数可以在中断里面调用,从而实现自动管理.
//如果非ALIENTEK用户,则USART_RX_STA和USART_RX_BUF[]需要用户自己实现
void usmart_scan(void)
{
	u8 sta,len;  
	if(USART_RX_STA&0x8000)//串口接收完成?
	{					   
		len=USART_RX_STA&0x3fff;	//得到此次接收到的数据长度
		USART_RX_BUF[len]='\0';	//在末尾加入结束符. 
		sta=usmart_dev.cmd_rec(USART_RX_BUF);//得到函数各个信息
		if(sta==0)usmart_dev.exe();	//执行函数 
		else 
		{  
			len=usmart_sys_cmd_exe(USART_RX_BUF);
			if(len!=USMART_FUNCERR)sta=len;
			if(sta)
			{
				switch(sta)
				{
					case USMART_FUNCERR:
						printf("函数错误!\r\n");   			
						break;	
					case USMART_PARMERR:
						printf("参数错误!\r\n");   			
						break;				
					case USMART_PARMOVER:
						printf("参数太多!\r\n");   			
						break;		
					case USMART_NOFUNCFIND:
						printf("未找到匹配的函数!\r\n");   			
						break;		
				}
			}
		}
		USART_RX_STA=0;//状态寄存器清空	    
	}
}

#if USMART_USE_WRFUNS==1 	//如果使能了读写操作
//读取指定地址的值		 
u32 read_addr(u32 addr)
{
	return *(u32*)addr;//	
}
//在指定地址写入指定的值		 
void write_addr(u32 addr,u32 val)
{
	*(u32*)addr=val; 	
}
#endif

6.3 usmart.h

#ifndef __USMART_H
#define __USMART_H	  		  
#include "usmart_str.h"
 
#define MAX_FNAME_LEN 		30	//函数名最大长度,应该设置为不小于最长函数名的长度。											   
#define MAX_PARM 			10	//最大为10个参数 ,修改此参数,必须修改usmart_exe与之对应.
#define PARM_LEN 			200	//所有参数之和的长度不超过PARM_LEN个字节,注意串口接收部分要与之对应(不小于PARM_LEN)


#define USMART_ENTIMX_SCAN 	1	//使用TIM的定时中断来扫描SCAN函数,如果设置为0,需要自己实现隔一段时间扫描一次scan函数.
								//注意:如果要用runtime统计功能,必须设置USMART_ENTIMX_SCAN为1!!!!
								
#define USMART_USE_HELP		1	//使用帮助,该值设为0,可以节省近700个字节,但是将导致无法显示帮助信息。
#define USMART_USE_WRFUNS	1	//使用读写函数,使能这里,可以读取任何地址的值,还可以写寄存器的值.
///END///

#define USMART_OK 			0  //无错误
#define USMART_FUNCERR 		1  //函数错误
#define USMART_PARMERR 		2  //参数错误
#define USMART_PARMOVER 	3  //参数溢出
#define USMART_NOFUNCFIND 	4  //未找到匹配函数

#define SP_TYPE_DEC      	0  //10进制参数显示
#define SP_TYPE_HEX       	1  //16进制参数显示


 //函数名列表	 
struct _m_usmart_nametab
{
	void* func;			//函数指针
	const u8* name;		//函数名(查找串)	 
};
//usmart控制管理器
struct _m_usmart_dev
{
	struct _m_usmart_nametab *funs;	//函数名指针

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


void usmart_init(u8 sysclk);//初始化
u8 usmart_cmd_rec(u8*str);	//识别
void usmart_exe(void);		//执行
void usmart_scan(void);     //扫描
u32 read_addr(u32 addr);	//读取指定地址的值
void write_addr(u32 addr,u32 val);//在指定地址写入指定的值
u32 usmart_get_runtime(void);	//获取运行时间
void usmart_reset_runtime(void);//复位运行时间

#endif

7. USMART调试的优越性说明 

通过上述程序的执行,在串口助手上会显示出想要调用的函数; 

其中串口助手XCOM中

        list是用于打印所有usmart可调用函数;

        id用于获取各个函数的入口地址;

        help用于打印usmart使用的帮助信息;

        hex和dec:

                        hex串口打印16进制

                        dec串口打印出10进制

        runtime指令用于函数执行时间统计功能的开启和关闭

                        runtime 0,开启函数执行时间统计功能

                        runtime 1,关闭函数执行时间统计功能

通过多条发送中的6和7可以看到开发板上的LED1会亮,这也就是USMART的优越性所在,并不需要通过MDK调试下载程序到单片机的Flash中,只需要借助USMART通过串口助手即可将调试程序发送给单片机,大大增强了单片机寿命;

如下图所示:只需要在主函数中调用test_fun函数即可控制LED1的亮灭,当然这是一个很简单的例子;同样的,我们也可以在主函数中测试其他功能,只需要写一个其他的功能函数即可;主函数的test_fun的第一个参数是所要调用函数的地址,第二个参数是根据具体情况具体设置;

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

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

相关文章

压力测试工具Jmeter安装及使用

1.安装Jmeter Jmeter依赖于JDK&#xff0c;所以必须确保当前计算机上已经安装了JDK&#xff0c;并且配置了环境变量。 1.1.下载 可以Apache Jmeter官网下载&#xff0c;地址&#xff1a;http://jmeter.apache.org/download_jmeter.cgi 1.2.解压 因为下载的是zip包&#xff…

三次样条曲线CubicSpline

本文参考老张在上海轨迹规划 之 三次样条曲线&#xff08;概念性质&#xff09; - 知乎 (zhihu.com) 什么是三次样条曲线 之 三次 样条是一种数据插值的方式&#xff0c;在多项式插值中&#xff0c;多项式是给出的单一公式来尽可能满足所有的数据点&#xff0c;而样条则使用多…

刷题刷题。

租用游艇 1.格式化输入二维数组&#xff1a;1-2&#xff0c;1-3&#xff0c;1-4&#xff0c;2-3&#xff0c;2-4&#xff0c;3-4... ... for(int i1; i<n-1; i) for(int ji1; j<n; j) 2.三重for循环枚举路径&#xff1a;第…

D. Unique Palindromes(回文串/构造)

题目 题意 给定字符串的长度&#xff0c;以及k个条件。 对于每个条件&#xff0c;给定x和c&#xff0c;表示原字符串的长度为x的前缀字符串&#xff0c;存在c个互不相同的回文子串。 原字符串由26个小写字母组成。 构造出长度为n&#xff0c;且满足上述k个条件的字符串。如果…

不黑艺术学社京藏行——参观五台山孙溟㠭为五台山红英师治印

不黑学社社长孙溟㠭先生与五台山菩萨顶主事红英师 不黑学社京藏行&#xff0c;路经五台把佛拜。 巍巍五台清凉境&#xff0c;参访伊始菩萨顶。 感恩“天珠”刘诗语&#xff0c;芬芳佛语满香华。 感恩慈悲红英师&#xff0c;带众参拜大白塔。 菩萨顶上如意宝&#xff0c;莲…

springboot+vue口腔管理平台(源码+文档)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的口腔管理平台。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 &#x1f495;&#x1f495;作者&#xff1a;风歌&a…

微服务---分布式多级缓存集群实现方案(Caffeine+redis+nginx本地缓存+Canal数据同步)

分布式多级缓存集群实现方案 1.什么是多级缓存 传统的缓存策略一般是请求到达Tomcat后&#xff0c;先查询Redis&#xff0c;如果未命中则查询数据库&#xff0c;如图&#xff1a; 存在下面的问题&#xff1a; •请求要经过Tomcat处理&#xff0c;Tomcat的性能成为整个系统的…

DJ5-1/2 输入输出系统(第一节课)

目录 5.1 I/O 系统的功能、模型和接口 5.1.1 I/O 系统的基本功能 5.1.2 I/O 系统的层次结构和模型 5.1.3 I/O 系统接口 5.2 I/O 设备和设备控制器 5.2.1 I/O 设备 5.2.2 设备控制器 5.2.3 I/O 通道 5.2.4 总线系统 5.1 I/O 系统的功能、模型和接口 5.1.1 …

Python进阶篇(五)-- 邮件客户端实现与电子邮件发送

1 SMTP 通过完成本实验&#xff0c;我们将更加了解SMTP协议。还将学到使用Python实现标准协议的经验。 主要任务是开发一个简单的邮件客户端&#xff0c;将邮件发送给任意收件人。客户端将需要连接到邮件服务器&#xff0c;使用SMTP协议与邮件服务器进行对话&#xff0c;并向邮…

【P5】JMeter HTTP Cookie管理器

文章目录 一、测试网站二、Cookie 设置规则2.1、无配置元件时&#xff0c;Cookie 不会自动设置&#xff08;与线程组设置无关&#xff09;2.2、有配置元件&#xff0c;不选任何参数时&#xff0c;Cookie 自动设置&#xff08;与线程组设置无关&#xff09;2.3、有配置元件&…

【iOS KVO(上)实现过程】

前言 KVO 也适用于传值&#xff0c;在之前的学习只是学习了KVO的传值&#xff0c;今天详细学习 监听和实现 源码放在下一节学习 1.1 KVO KVO&#xff08;Key-Value Observing&#xff09;是Objective-C语言中一种观察者模式的实现&#xff0c;可以用来监听对象属性值的变化…

Kafka基础概念介绍

背景 Kafka是我们项目用的最多的消息中间件&#xff0c;但里面也有很多存在的问题&#xff0c;如重复消费、带宽瓶颈、部分分区消费不下来的异常场景。 重复消费问题有些让人头疼&#xff08;reblance导致offset提交失败&#xff09;&#xff0c;这里会持续更新&#xff08;基…

UML简介与类图详解

1 UML简介 1.1 UML是什么 UML&#xff0c;全称为Unified Model Language&#xff0c;即统一建模语言&#xff0c;是由一整套图表组成的&#xff0c;为面向对象系统的产品进行说明、可视化和编制文档的一种标准语言。UML 代表了一组最佳工程实践&#xff0c;这些实践已被证明在…

【路径规划】基于哈里斯鹰优化算法的栅格法路径规划 机器人路径规划【Matlab代码#20】

文章目录 1. 原始HHO算法2. 机器人路径规划环境创建3. 路径规划模型建立4. 部分代码展示5. 仿真结果展示6. 资源获取方式 1. 原始HHO算法 详细介绍此处略&#xff0c;可参考HHO算法介绍 2. 机器人路径规划环境创建 对机器人工作空间的进行环境建模是机器人路径规划研究的重要…

【电源专题】案例:拆一个早期用的万能充看看内部状况

说到万能充,可能存在80/90后的记忆里。以前手机都可以更换电池的,所有往往都是买两块,一块在手机内部使用,另一块在万能充充电。 万能充的外观也是大同小异的,从网上找了一些图片: 这东西现在日常生活已经都看不到了,关键因素之一应该是现在的手机电池都是不可拆…

多维图像去噪方法研究

一、背景介绍 由于传感器技术的快速发展&#xff0c;高光谱&#xff08;HS&#xff09;遥感&#xff08;RS&#xff09;成像为飞机等数据采集设备远距离观测和分析地球表面提供了大量的空间和光谱信息&#xff0c;航天器和卫星。 HS RS 技术的最新进展甚至革命为实现各种应用的…

【ONE·C++ || set和map(一)】

总言 主要介绍set和map的基本框架和使用 文章目录 总言1、部分接口介绍和使用举例1.1、序列式容器和关联式容器、键值对1.1.2、pair键值对 1.2、set基本介绍1.2.1、set::set、遍历1.2.2、set::insert、set::erase、set::find1.2.3、set::count、set::lower_bound、set::upper_…

数据结构与算法基础(青岛大学-王卓)(1)

士别三日当刮目相待&#xff0c;不好意思鸽了好久了&#xff0c;因为学习的时间不连续&#xff0c;所以我一直攒着&#xff0c;我又回来继续更新了 没有继续学习浙大的数据结构了&#xff0c;对比了青岛大学的王老师的这个教程我觉得更适合我一些&#xff0c;更入门&#xff0…

【Spring篇】Spring整合

&#x1f353;系列专栏:Spring系列专栏 &#x1f349;个人主页:个人主页 目录 一、Spring整合 1.Spring整合Mybatis思路分析 1.环境准备 2.整合思路分析 2.Spring整合Mybatis 3.Spring整合Junit 1.环境准备 2.整合Junit步骤 二、图书推荐 1.《元宇宙Ⅱ&#xff1a;图…

Ubuntu安装MySQL

一.安装MySQL服务器 安装MySQL服务器&#xff1a; apt-get install mysql-server 对MySQL进行初始化&#xff0c;设置密码&#xff1a; mysql_secure_installation 注意&#xff0c;这里要设置密码的最低长度为8位&#xff0c;如果你设的密码小于8位&#xff0c;则会提示&am…