OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 11065|回复: 15

【ALIENTEK 战舰STM32开发板例程系列连载+教学】第十九章 USMART调试组件实验

[复制链接]

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-1-27 18:24:44 | 显示全部楼层 |阅读模式

第十九章 USMART调试组件实验

本章,我们将向大家介绍一个十分重要的辅助调试工具:USMART调试组件。该组件由ALIENTEK 开发提供,功能类似linuxshellRTTfinsh也属于此类)。USMART最主要的功能就是通过串口调用单片机里面的函数,并执行,对我们调试代码是很有帮助的。本章分为如下几个部分:

19.1 USMART调试组件简介

19.2 硬件设计

19.3 软件设计

19.4 下载验证

19.1 USMART调试组件简介

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

USMART的特点如下:

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

2,  资源占用极少(最少情况:FLASH:4KSRAM:72B)。

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

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

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

6,  使用方便。

有了USMART,你可以轻易的修改函数参数、查看函数运行结果,从而快速解决问题。比如你调试一个摄像头模块,需要修改其中的几个参数来得到最佳的效果,普通的做法:写函数->修改参数->下载->看结果->不满意->修改参数->下载->看结果->不满意….不停的循环,直到满意为止。这样做很麻烦不说,单片机也是有寿命的啊,老这样不停的刷,很折寿的。而利用USMART,则只需要在串口调试助手里面输入函数及参数,然后直接串口发送给单片机,就执行了一次参数调整,不满意的话,你在串口调试助手修改参数在发送就可以了,直到你满意为止。这样,修改参数十分方便,不需要编译、不需要下载、不会让单片机折寿。

USMART支持的参数类型基本满足任何调试了,支持的类型有:10或者16进制数字、字符串指针(如果该参数是用作参数返回的话,可能会有问题!)、函数指针等。因此绝大部分函数,可以直接被USMART调用,对于不能直接调用的,你只需要重写一个函数,把影响调用的参数去掉即可,这个重写后的函数,即可以被USMART调用了。

USMART的实现流程简单概括就是:第一步,添加需要调用的函数(在usmart_config.c里面的usmart_nametab数组里面添加);第二步,初始化串口;第三步,初始化USMART(通过usmart_init函数实现);第四步,轮询usmart_scan函数,处理串口数据。

 经过以上简单介绍,我们对USMART有了个大概了解,接下来我们来简单介绍下USMART组件的移植。

USMART组件总共包含6文件如图19.1.1所示:




19.1.1 USMART组件代码

       其中redeme.txt是一个说明文件,不参与编译。其他五个文件,usmart.c负责与外部互交等。usmat_str.c主要负责命令和参数解析。usmart_config.c主要由用户添加需要由usmart管理的函数。

usmart.husmart_str.h是两个头文件,其中usmart.h里面含有几个用户配置宏定义,可以用来配置usmart的功能及总参数长度(直接和SRAM占用挂钩)、是否使能定时器扫描、是否使用读写函数等。

       USMART的移植,只需要实现3个函数。其中两个函数都在usmart.c里面,另外一个是串口接收函数,必须由用户自己实现,用于接收串口发送过来的数据。

第一个函数,串口接收函数。该函数,我们是通过SYSTEM文件夹默认的串口接收来实现的,该函数在5.3.1节有介绍过,我们这里就不列出来了。SYSTEM文件夹里面的串口接收函数,最大可以一次接收200字节,用于从串口接收函数名和参数等。大家如果在其他平台移植,请参考SYSTEM文件夹串口接收的实现方式进行移植。

第二个是void usmart_init(void)函数,该函数的实现代码如下:

//初始化串口控制器

//sysclk:系统时钟(Mhz

void usmart_init(u8 sysclk)

{

#if USMART_ENTIMX_SCAN==1

       Timer2_Init(1000,(u32)sysclk*100-1);//分频,时钟为10K ,100ms中断一次

#endif

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

}

该函数有一个参数sysclk,就是用于定时器初始化。另外USMART_ENTIMX_SCAN是在usmart.h里面定义的一个是否使能定时器中断扫描的宏定义。如果为1,就初始化定时器中断,并在中断里面调用usmart_scan函数。如果为0,那么需要用户需要自行间隔一定时间(100ms左右为宜)调用一次usmart_scan函数,以实现串口数据处理。

最后一个是usmart_scan函数,该函数用于执行usmart扫描,该函数需要得到两个参量,第一个是从串口接收到的数组(USART_RX_BUF),第二个是串口接收状态(USART_RX_STA)。接收状态包括接收到的数组大小,以及接收是否完成。该函数代码如下:

//usmart扫描函数

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

//以及时执行从串口发过来的各个函数.

//本函数可以在中断里面调用,从而实现自动管理.

//ALIENTEK开发板用户,USART_RX_STAUSART_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;//状态寄存器清空         

       }

}

该函数的执行过程:先判断串口接收是否完成(USART_RX_STA的最高位是否为1),如果完成,则取得串口接收到的数据长度(USART_RX_STA的低14位),并在末尾增加结束符,再执行解析,解析完之后清空接收标记(USART_RX_STA置零)。如果没执行完成,则直接跳过,不进行任何处理。

       完成这三个函数的移植,你就可以使用USMART了。不过,需要注意的是,usmart同外部的互交,一般是通过usmart_dev结构体实现,所以usmart_initusmart_scan的调用分别是通过:usmart_dev.initusmart_dev.scan实现的。

       下面,我们将在第十八章实验的基础上,移植USMART,并通过USMART调用一些TFTLCD的内部函数,让大家初步了解USMART的使用。

      

19.2 硬件设计

本实验用到的硬件资源有:

1)  指示灯DS0DS1

2)  串口

3)  TFTLCD模块

这三个硬件在前面章节均有介绍,本章不再介绍。

19.3 软件设计

打开上一章的工程,复制USMART文件夹(该文件夹可以在光盘的本章实验例程里面找到)到本工程文件夹下面,如图19.3.1所示:


19.3.1 复制USMART文件夹到工程文件夹下

接着,我们打开工程,并新建USMART组,添加USMART组件代码,同时把USMART文件夹添加到头文件包含路径,在主函数里面加入includeusmart.h”如图19.3.2所示:


19.3.2 添加USMART组件代码

由于USMART默认提供了STM32TIM2中断初始化设置代码,我们只需要在usmart.h里面设置USMART_ENTIMX_SCAN1,即可完成TIM2的设置,通过TIM2的中断服务函数,调用usmart_dev.scan()(就是usmart_scan函数),实现usmart的扫描。此部分代码我们就不列出来了,请参考usmart.c

      此时,我们就可以使用USMART了,不过在主程序里面还得执行usmart的初始化,另外还需要针对你自己想要被USMART调用的函数在usmart_config.c里面进行添加。下面先介绍如何添加自己想要被USMART调用的函数,打开usmart_config.c,如图19.3.3所示:


19.3.3添加需要被USMART调用的函数

这里的添加函数很简单,只要把函数所在头文件添加进来,并把函数名按上图所示的方式增加即可,默认我们添加了两个函数:delay_msdelay_us。另外,read_addrwrite_addr属于usmart自带的函数,用于读写指定地址的数据,通过配置USMART_USE_WRFUNS,可以使能或者禁止这两个函数。

这里我们根据自己的需要按上图的格式添加其他函数,添加完之后如图19.3.4所示:


19.3.4 添加函数后

上图中,我们添加了lcd.h,并添加了很多LCD函数,最后我们还添加了led_settest_fun两个函数,这两个函数在test.c里面实现,代码如下:

//LED状态设置函数

void led_set(u8 sta)

{

       LED1=sta;

}

//函数参数调用测试函数

void test_fun(void(*ledset)(u8),u8 sta)

{

       ledset(sta);

}

       led_set函数,用于设置LED1的状态,而第二个函数test_fun则是测试USMART对函数参数的支持的,test_fun的第一个参数是函数,在USMART里面也是可以被调用的。

在添加完函数之后,我们修改main函数,如下:

int main(void)

{                     

      Stm32_Clock_Init(9);    //系统时钟设置

       delay_init(72);                     //延时初始化

       uart_init(72,9600);      //串口1初始化为9600

       LED_Init();                         //初始化与LED连接的硬件接口

      LCD_Init();                         //初始化LCD

       usmart_dev.init(72);     //初始化USMART                          

       POINT_COLOR=RED;

       LCD_ShowString(30,50,200,16,16,"WarShip STM32 ^_^");    

       LCD_ShowString(30,70,200,16,16,"USMART TEST");    

       LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");

       LCD_ShowString(30,110,200,16,16,"2012/9/7");         

      while(1)

       {                   

              LED0=!LED0;                                  

              delay_ms(500);     

       }                                                                              

}    

此代码显示简单的信息后,就是在死循环等待串口数据。

至此,整个usmart的移植就完成了。编译成功后,就可以下载程序到开发板,开始USMART的体验。

19.4 下载验证

将程序下载到战舰STM32后,可以看到DS0不停的闪烁,提示程序已经在运行了。同时,屏幕上显示了一些字符(就是主函数里面要显示的字符)。

我们打开串口调试助手,选择正确的串口号,并选择发送新行(即发送回车键)选项。如下图所示(点击扩展->隐藏,显示扩展界面):


19.4.1 驱动串口调试助手

       上图中listid、?、helphexdec都属于usmart自带的系统命令。下面我们简单介绍下这几个命令:

list,该命令用于打印所有usmart可调用函数。发送该命令后,串口将受到所有能被usmart调用得到函数如图19.4.2所示:


19.4.2 list指令执行结果

       id,该指令用于获取各个函数的入口地址。比如前面写的test_fun函数,就有一个函数参数,我们需要先通过id指令,获取ledset函数的id(即入口地址),然后将这个id作为函数参数,传递给test_fun

       ?和help,这两个指令的功能是一样的。发送该指令后,串口将打印usmart使用的帮助信息。

hexdec,这两个指令可以带参数,也可以不带参数。当不带参数的时候,hexdec分别用于设置串口显示数据格式为16进制/10进制。当带参数的时候,hexdec就执行进制转换,比如输入:hex 1234,串口将打印:HEX:0X4D2,也就是将1234转换为16进制打印出来。又比如输入:dec 0X1234,串口将打印:DEC:4660,就是将0X1234转换为10进制打印出来。 

大家可以亲自体验下这几个系统指令,不过要注意,所有的指令都是大小写敏感的,不要写错哦。

       接下来,我们将介绍如何调用list所打印的这些函数,先来看一个简单的delay_ms的调用,我们分别输入delay_ms(1000)delay_ms(0x3E8),如图19.4.3所示:


19.4.3 串口delay_ms函数

       从上图可以看出,delay_ms(1000)delay_ms(0x3E8)的调用结果是一样的,都是延时1000ms,因为usmart默认设置的是hex显示,所以看到串口打印的参数都是16进制格式的,大家可以通过发送dec指令切换为十进制显示。另外,由于usmart对调用函数的参数大小写不敏感,所以参数写成:0X3E8或者0x3e8都是正确的。

       我们再看另外一个函数,LCD_ShowString函数,该函数用于显示字符串,我们通过串口输入:LCD_ShowString(20,200,200,100,16,"This is a test for usmart!!"),如图19.4.4所示:


19.4.4 串口调用LCD_ShowString函数

该函数用于在指定区域,显示指定字符串,发送给开发板后,我们可以看到LCD在我们指定的地方显示了:This is a test for usmart!! 这个字符串。

其他函数的调用,也都是一样的方法,这里我们就不多介绍了,最后说一下带有函数参数的函数的调用。我们将led_set函数作为 test_fun的参数,通过在test_fun里面调用led_set函数,实现对DS1(LED1)的控制。前面说过,我们要调用带有函数参数的函数,就必须先得到函数参数的入口地址(id),通过输入id指令,我们可以得到led_set的函数入口地址是:0X08000281,所以,我们在串口输入:test_fun(0X08000281,0),就可以控制DS1亮了。如图19.4.5所示:


19.4.5 串口调用test_fun函数

在开发板上,我们可以看到,收到串口发送的test_fun(0X08000281,0)后,开发板的DS1亮了,然后大家可以通过发送test_fun(0X08000281,1),来关闭DS1。说明我们成功的通过test_fun函数调用led_set,实现了对DS1的控制。也就验证了USMART对函数参数的支持。

USMART调试组件的使用,就为大家介绍到这里。USMART是一个非常不错的调试组件,希望大家能学会使用,可以达到事半功倍的效果。

 

《STM32开发指南》第十九章 USMART调试组件实验.rar

975.78 KB, 下载次数: 944

实验14 USMART调试实验.rar

96.28 KB, 下载次数: 967

我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

21

帖子

0

精华

初级会员

Rank: 2

积分
54
金钱
54
注册时间
2013-3-30
在线时间
0 小时
发表于 2013-4-13 22:21:42 | 显示全部楼层
原子哥,我的战舰用这移植的方法,为什么每次出现
..\OBJ\LCD.axf: Error: L6218E: Undefined symbol TIM_ClearITPendingBit (referred from usmart.o).
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
 楼主| 发表于 2013-4-13 22:49:23 | 显示全部楼层
回复【2楼】jacksee:
---------------------------------
你用的库函数?这是寄存器版本的。。。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

3

主题

21

帖子

0

精华

初级会员

Rank: 2

积分
54
金钱
54
注册时间
2013-3-30
在线时间
0 小时
发表于 2013-4-14 09:03:20 | 显示全部楼层
库函数版本的
回复 支持 反对

使用道具 举报

3

主题

21

帖子

0

精华

初级会员

Rank: 2

积分
54
金钱
54
注册时间
2013-3-30
在线时间
0 小时
发表于 2013-4-14 09:44:42 | 显示全部楼层
原子哥,我知道了,原来是在用LCD做模板的,在fwlib中少了.c文件。
回复 支持 反对

使用道具 举报

50

主题

201

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
423
金钱
423
注册时间
2013-4-9
在线时间
1 小时
发表于 2013-6-10 22:25:45 | 显示全部楼层
为啥我的tim2中断不执行啊- -
回复 支持 反对

使用道具 举报

16

主题

69

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
212
金钱
212
注册时间
2013-3-17
在线时间
13 小时
发表于 2013-8-27 17:24:37 | 显示全部楼层
原子哥这里红框里的1000改为999是不是更精确???




回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
 楼主| 发表于 2013-8-27 18:16:34 | 显示全部楼层
是的
回复 支持 反对

使用道具 举报

86

主题

983

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1848
金钱
1848
注册时间
2013-4-15
在线时间
163 小时
发表于 2014-5-15 13:41:14 | 显示全部楼层
为啥我通过USMART不能设置当前时间呢
合肥-文盲
回复 支持 反对

使用道具 举报

0

主题

5

帖子

0

精华

新手上路

积分
27
金钱
27
注册时间
2015-3-7
在线时间
0 小时
发表于 2015-3-7 15:22:22 | 显示全部楼层
原子哥,我用tim3定时0.5ms中断一次执行adc出理,为啥usmart失效了?
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
 楼主| 发表于 2015-3-7 22:58:04 | 显示全部楼层
回复【10楼】yangtkzc:
---------------------------------
说明你的adc中断太频繁了,影响了usmart代码。具体的,你得仿真看问题了。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

3

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
62
金钱
62
注册时间
2015-3-15
在线时间
4 小时
发表于 2015-5-31 17:42:11 | 显示全部楼层
回复【11楼】正点原子:
---------------------------------
原子哥,请问一下,USMART初始化的时候为什么是usmart_dev.init(SystemCoreClock/1000000);而不直接用usmart_init(SystemCoreClock/1000000);在源代码里面没找到usmart_dev.init(SystemCoreClock/1000000)函数呢!
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
 楼主| 发表于 2015-5-31 19:08:07 | 显示全部楼层
回复【12楼】QKX607:
---------------------------------
都可以,一个是做成结构体成员的函数指针了。
一个是直接一个函数。
好好学习下结构体吧。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

15

主题

78

帖子

0

精华

初级会员

Rank: 2

积分
180
金钱
180
注册时间
2012-11-21
在线时间
9 小时
发表于 2015-7-19 10:37:06 | 显示全部楼层
回复【5楼】jacksee:
---------------------------------
少了哪个。c文件?
回复 支持 反对

使用道具 举报

32

主题

183

帖子

0

精华

高级会员

Rank: 4

积分
617
金钱
617
注册时间
2013-1-16
在线时间
131 小时
发表于 2015-10-19 23:38:31 | 显示全部楼层
想请问下,怎样实现点亮等函数的调用的,具体实现的过程还不是很懂,求大神指导。
回复 支持 反对

使用道具 举报

1

主题

4

帖子

0

精华

初级会员

Rank: 2

积分
66
金钱
66
注册时间
2017-12-25
在线时间
11 小时
发表于 2017-12-26 08:44:33 | 显示全部楼层
目测只支持32位机,32位模式。8位机和16位机可能会出错吧。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-18 09:11

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表