你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

MiniPro STM32H750 开发指南_V1.1-USMART调试组件实验

[复制链接]
STMCU小助手 发布时间:2022-10-7 18:27
USMART调试组件实验
; i( y6 i3 U* g. a$ |本章,我们将向大家介绍一个十分重要的辅助调试工具:USMART调试组件。该组件由正点原子开发提供,功能类似linux的shell(RTT的finsh也属于此类)。USMART最主要的功能就是通过串口调用单片机里面的函数,并执行,对我们调试代码是很有帮助的。8 L9 c, M. t6 Z9 b3 M# F1 J; w, E
26.1 USMART调试组件简介
8 f5 X7 K* W2 ]% ^* v+ V& n- }3 e4 WUSMART是由正点原子开发的一个灵巧的串口调试互交组件,通过它你可以通过串口助手调用程序里面的任何函数,并执行。因此,你可以随意更改函数的输入参数(支持数字(10/16进制,支持负数)、字符串、函数入口地址等作为参数),单个函数最多支持10个输入参数,并支持函数返回值显示,目前最新版本为V3.5。( J' H$ s# m- K, d$ y# l
USMART的特点如下:
: l! }8 Z! I3 f1,可以调用绝大部分用户直接编写的函数。
3 B2 [5 w6 F) p2 u2,资源占用极少(最少情况:FLASH:4K;SRAM:72B)。
6 T8 S, R5 q' x* b! c2 \3,支持参数类型多(数字(包含10/16进制,支持负数)、字符串、函数指针等)。. p- A! `- q. C2 d* g. j. H
4,支持函数返回值显示。
& P# M3 C# {( z( t0 X3 ~+ ?; G5,支持参数及返回值格式设置。
! K* ?/ t4 ^. e/ O6,支持函数执行时间计算(V3.1及以后的版本新特性)。
6 H% ]. n" L1 x. U. W1 }7,支持AC6编译器。
1 Y; D3 w" M$ N/ J5 d有了USMART,你可以轻易的修改函数参数、查看函数运行结果,从而快速解决问题。比如你调试一个摄像头模块,需要修改其中的几个参数来得到最佳的效果,普通的做法:写函数修改参数下载看结果不满意修改参数下载看结果不满意….不停的循环,直到满意为止。这样做很麻烦不说,单片机也是有寿命的啊,老这样不停的刷,很折寿的。而利用USMART,则只需要在串口调试助手里面输入函数及参数,然后直接串口发送给单片机,就执行了一次参数调整,不满意的话,你在串口调试助手修改参数在发送就可以了,直到你满意为止。这样,修改参数十分方便,不需要编译、不需要下载、不会让单片机折寿。
+ j9 e# b, }# ^/ n( ]( y, S# _USMART支持的参数类型基本满足任何调试了,支持的类型有:10或者16进制数字、字符串指针(如果该参数是用作参数返回的话,可能会有问题!)、函数指针等。因此绝大部分函数,可以直接被USMART调用,对于不能直接调用的,你只需要重写一个函数,把影响调用的参数去掉即可,这个重写后的函数,即可以被USMART调用了。
9 R& ~6 ~9 d! c3 yUSMART的实现流程简单概括就是:第一步,添加需要调用的函数(在usmart_config.c里面的usmart_nametab数组里面添加);第二步,初始化串口;第三步,初始化USMART(通过usmart_init函数实现);第四步,轮询usmart_scan函数,处理串口数据。6 ^* g8 H$ M- K! `, U9 c9 Q
经过以上简单介绍,我们对USMART有了个大概了解,接下来我们来简单介绍下USMART组件的移植。USMART组件总共包含8文件如图26.1.1所示:& s# ~6 `8 `' G+ R4 h% a: F$ r

  C- Q" R: y5 f! h; j) h  t2 { 4f56a0cc3b2d462ba340f6288e742c48.png 1 x" p4 A: D7 @1 q! Q
8 b% n, q, k8 g$ j  b; [* M8 P7 B
图26.1.1 USMART组件代码9 X. d& [/ h$ r" Y2 }. m
USMART每个文件的作用如表26.1.1所示:& C0 H! J9 }: j1 |

1 @) ]3 D# m9 A! K b3fe3a0b3c17468b957564ef69962b99.png
- L6 _1 u$ |" q, c
) B/ {8 o4 {" b表26.1.1 USMART文件介绍0 O& @, o5 S' _& x4 K: |) M
经过以上简单介绍,我们对USMART有了个大概了解,接下来我们将在下一小节给大家介绍USMART组件的移植和使用。
" I# }( ^  x& C. _: I* d
. |/ L) c1 [& r+ w26.2 硬件设计: z0 T4 C! k4 K! H& [1 [- c
1.例程功能: ?& T/ `! y  n) w6 ^
本实验通过usmart调用单片机里面的函数,实现对LCD显示和LED以及延时的控制。LED0闪烁用于提示程序正在运行。3 t/ }2 [- G3 K
2.硬件资源( E5 @" P1 ]: q3 S% f# x
1)RGB灯$ p6 k0 \! t! A& n. y2 c3 l. O
RED :LED0 - PB4
/ m5 j& Q6 @1 s# i# \4 j3 |& BGREEN :LED1 - PE6
. }3 U* j  |5 ?! e; D2)串口1(PA9/PA10连接在板载USB转串口芯片CH340上面)9 t8 Y: u% H. P7 a; w3 m
3)定时器4
4 O5 f, ?0 ^8 J4)正点原子2.8/3.5/4.3/7/10寸TFTLCD模块(仅限MCU屏,16位8080并口驱动)
- g5 V) ~7 d- g9 A3 U2 q' H
7 S1 A4 D* I9 E5 s9 g0 z26.3 程序设计
: A8 D! `7 K9 K6 e. Y26.3.1 程序流程图

% n4 N' {# ^+ H
/ h- w7 N* r/ s  C% c& Z( w c7e8856dc98547fb997dc29230c86a6d.png
& ]% u6 M8 w9 q) l& m4 ^# U6 a  D- u, h/ d
图26.3.1.1 USMART调试组件实验程序流程图2 ?9 e' L- _! V! {' u6 \3 R# s3 f
6 e' M3 D9 `+ M( `; J9 }
26.3.2 程序解析
* A# D- W% V9 \1 I$ e; l1.USMART驱动代码9 y; F4 }( v  U! E/ l
这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。USMART驱动源码包括七个文件:usmart.h、usmart_port.c、usmart_port.h、usmart_str.c、usmart.c、usmart_config.c和usmart_str.h。
! t- g* ~4 E3 k3 R, d要使用USMART,我们先得进行代码移植,USMART的移植非常简单,我们只需要修改usmart_port.c里面的5个函数即可完成移植。
% u6 x; ?# [1 o第一个函数,USMART输入数据流获取函数,该函数的实现代码如下:
6 J/ v" Z2 j+ T& f# e+ H9 w' `
  1. /**
    ' l# @: T7 y4 C
  2. * @brief             获取输入数据流(字符串)
    6 k0 W7 x$ P9 x+ s
  3. *   @note             USMART通过解析该函数返回的字符串以获取函数名及参数等信息' l7 c5 K/ _( n/ Y0 {
  4. * @param              无
      c" f/ p, v2 p# @
  5. * @retval
    6 J& V& [; x: t; L8 N( {, Z2 m& _
  6. *   @arg              0,  没有接收到数据8 S1 J+ k: C' ^5 c; J
  7. *   @arg              其他,数据流首地址(不能是0)
    * w" z- p6 U, J/ O6 i2 v) h
  8. */
    # j/ R8 G! [8 ?/ e! ^+ t
  9. char *usmart_get_input_string(void)
    # n) y9 p& [% Q7 b! g9 F$ _: ~
  10. {/ p  E: X) \" }3 }! ?3 p: K# k
  11.     uint8_t len;
    + @7 @9 \8 |9 k# a: Q: e
  12.     char *pbuf = 0;
    1 f3 A, j2 o' T5 _7 K' Z  W
  13.     if (g_usart_rx_sta & 0x8000)                /* 串口接收完成? */
    8 A- _) H; A3 ~; g/ x: C! N! m& \) Z
  14.     {
    ' z) }" A* j- `# p
  15.         len = g_usart_rx_sta & 0x3fff;          /* 得到此次接收到的数据长度 */% v, P# Q: X- L2 p& g
  16.         g_usart_rx_buf[len] = '\0';             /* 在末尾加入结束符. */% U* h/ R* `6 K2 l! p
  17.         pbuf = (char*)g_usart_rx_buf;& s+ I1 X/ k' V7 j4 g0 ~9 C0 J0 G
  18.         g_usart_rx_sta = 0;                     /* 开启下一次接收 */& f; W0 r8 Z2 z
  19.     }
    & e/ J' I, p7 B# V" S  Q
  20.     return pbuf;
    9 Z9 B7 B% N: u% T) c
  21. }
复制代码
1 Z: Z8 R% d- y! D( d
该函数通过SYSTEM文件夹默认的串口接收来实现输入数据流获取。SYSTEM文件夹里面的串口接收函数,最大可以一次接收200字节,用于从串口接收函数名和参数等。大家如果在其他平台移植,请参考SYSTEM文件夹串口接收的实现方式进行移植(详细接收原理请参考:串口通信实验)。
0 g( ?* t7 x# {4 [$ u8 p4 D
' I1 \, ^9 x+ l第二个是usmart_timx_init函数,该函数的实现代码如下:; j: b6 y- w3 K2 Z

# ~( L( L* s6 w/ e, w( q% ~, S$ Q
  1. /**, O" E2 A9 W' L/ L, a! ^. p2 V
  2. * @brief             定时器初始化函数% O" n0 ^/ x" m* U
  3. * @param              arr:自动重装载值
    ! `: e2 I* l/ u8 W: G9 R& `
  4. *                      psc:定时器分频系数
    # Q, p# G, t2 l
  5. * @retval            无( Y  J/ \+ e0 U2 Y  F1 @6 ]: Q
  6. */
    4 Y1 |! R9 U/ e/ ?8 }! x
  7. void usmart_timx_init(uint16_t arr, uint16_t psc): B% b4 [. F7 x# ]" j3 M( Z
  8. {
    * C  ]2 P6 ^2 ?  k" J. a
  9.     USMART_TIMX_CLK_ENABLE();! v! H/ T5 B% ]. ^$ c
  10.     g_timx_usmart_handle.Instance = USMART_TIMX;    /* 通用定时器4 */
    ' B8 D, \/ s* @& U1 P
  11.     g_timx_usmart_handle.Init.Prescaler = psc;              /* 分频系数 */
    3 @! O% i- F% w  i% h; _
  12.     g_timx_usmart_handle.Init.CounterMode = TIM_COUNTERMODE_UP;  /* 向上计数器 */
    ! n+ T- s: q" N8 O1 T
  13.     g_timx_usmart_handle.Init.Period = arr;          /* 自动装载值 */
    # C) J, n" D  t" [
  14.     g_timx_usmart_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;' t- X  D% h/ I; n
  15.     HAL_TIM_Base_Init(&g_timx_usmart_handle);4 G/ D4 R* e/ S0 @6 p
  16.     HAL_TIM_Base_Start_IT(&g_timx_usmart_handle);          /* 使能定时器和定时器中断 */
    $ Z' I  f* ^+ {) A) m$ ~+ p1 |
  17.     HAL_NVIC_SetPriority(USMART_TIMX_IRQn,3,3);            /* 抢占优先级3,子优先级3 */
    0 n8 s  T8 w% ^  _$ {6 |
  18.     HAL_NVIC_EnableIRQ(USMART_TIMX_IRQn);                    /* 开启TIM中断 */ ) n0 W: @& J. f* U
  19. }
复制代码
& F! N1 D( L8 d& v5 l
该函数只有在:USMART_ENTIMX_SCAN值为1时,才需要实现,用于定时器初始化,利用定时器完成对usmart_scan函数的周期性调用,并实现函数运行时间计时(runtime)功能。该函数里面的:USMART_TIMX_CLK_ENABLE、USMART_TIMX和USMART_TIMX_IRQn等定时器相关宏定义我们在usmart_prot.h里面定义,方便大家修改。本实验我们用的TIM4。
( l- F$ [* c' ]) f6 l9 L" V注意:usmart_timx_init函数是在usmart.c里面,被usmart_init调用,usmart_init源码如下:! e7 q# g: i% j/ X, f
1 I( O4 D: Y# l. _0 G  I) |4 b
  1. /**
    & G" `' C5 G6 B! I
  2. * @brief              初始化USMART6 n$ l( y2 N. O; @/ r& `
  3. * @param              tclk: 定时器的工作频率(单位:Mhz)
    " R+ g! {" |- R0 C
  4. * @retval             无5 n4 t7 w& @9 N) L% p
  5. */( e! y2 D2 w& c: i
  6. void usmart_init(uint16_t tclk)
    1 B* i  X' I# R6 s3 D% K4 C% }1 f8 ~" O
  7. {& E  {* h* w/ ]. p8 S/ Z
  8. #if USMART_ENTIMX_SCAN == 1
    ( E; [* i8 ]+ L6 E+ ]
  9.     usmart_timx_init(1000, tclk * 100 - 1);+ e: d3 n7 c% H. L) y
  10. #endif; _5 P) Z- K3 v
  11.     usmart_dev.sptype = 1;          /* 十六进制显示参数 */
    8 d7 H9 E, L. z& ^
  12. }
复制代码
: r0 j; L: g* x* m( `! T2 O# U
该函数有一个参数tclk,就是用于定时器初始化。注意:这里的tclk是指所选TIM的时钟频率,而非系统主频!这里我们用的TIM4,对于STM32H750来说,TIM4的时钟源来自2倍的APB1,频率为:240Mhz。
# N' B4 s3 L" g" D另外,USMART_ENTIMX_SCAN是在usmart_port.h里面定义的一个是否使能定时器中断扫描的宏定义。如果为1,就初始化定时器中断,并在中断里面调用usmart_scan函数。如果为0,那么需要用户需要自行间隔一定时间(100ms左右为宜)调用一次usmart_scan函数,以实现串口数据处理。注意:如果要使用函数执行时间统计功能(runtime 1),则必须设置USMART_ENTIMX_SCAN为1。另外,为了让统计时间精确到0.1ms,定时器的计数时钟频率必须设置为10Khz,否则时间就不是0.1ms了。+ |5 ~: Q/ y, z* Q* B+ p% a
第三和第四个函数仅用于服务USMART的函数执行时间统计功能(串口指令:runtime 1),分别是:usmart_timx_reset_time和usmart_timx_get_time,这两个函数代码如下:
8 t) j& a' q: r" q8 q
0 G( U% s# c5 {* R( q, T8 ?
  1. /**8 u8 |/ ?7 c8 l' u8 ~
  2. * @brief            复位runtime
    3 _: P+ m) u5 s/ M% a  d
  3. *   @note             需要根据所移植到的MCU的定时器参数进行修改8 ]/ }+ O2 t2 A9 r- x- `5 n: C
  4. * @param              无& h7 f" f7 q2 D" D
  5. * @retval             无
    0 e$ W) ~5 }: [$ x
  6. */
    0 \- X% Z8 }5 I: u& a: {! `
  7. void usmart_timx_reset_time(void)/ r- e9 P# b* X' U
  8. {
    3 y; o9 l- q. T' ~, t( P" p
  9.     __HAL_TIM_CLEAR_FLAG(&g_timx_usmart_handle,TIM_FLAG_UPDATE);/* 清除中断标志 */
    : a4 f4 T. j8 r
  10.     __HAL_TIM_SET_AUTORELOAD(&g_timx_usmart_handle,0XFFFF);        /*重载值设置最大*/
    & |8 z- c: m2 B0 J4 N
  11.     __HAL_TIM_SET_COUNTER(&g_timx_usmart_handle, 0);                        /* 清定时器CNT */
    1 [6 C7 I1 J! e) E, o
  12.     usmart_dev.runtime = 0;
    " C5 `2 V; X1 A: G4 D$ z
  13. }& H! Z4 E: }) O; ~: n" g
  14. 8 }2 i+ U$ ]! l: O4 R
  15. /**
    * ]  o1 @# A  G, D) B5 c5 R
  16. * @brief             获得runtime时间$ G6 W( F/ P7 s8 z' d- x2 t; ~$ K4 d
  17. *   @note             需要根据所移植到的MCU的定时器参数进行修改# e( R3 f2 U' I, e( z, ?8 c4 H
  18. * @param              无
    8 b4 A7 ~, y3 e% G( M. x8 t7 J: A
  19. * @retval             执行时间,单位:0.1ms,最大延时时间为定时器CNT值的2倍*0.1ms7 h; k- T8 L  \- o5 w$ X# @
  20. */
    6 j' P! G/ `/ }2 z: i
  21. uint32_t usmart_timx_get_time(void)
    0 a% L( m3 d/ c$ D. L9 {6 \8 ^
  22. {
    6 ?9 P. t' b- X) k( A7 }$ J; `. F2 \
  23. /* 在运行期间,产生了定时器溢出 */
    ; \, F( m9 A0 K4 F& N# W" ]
  24.     if (__HAL_TIM_GET_FLAG(&g_timx_usmart_handle, TIM_FLAG_UPDATE) == SET)  
    ) ]( m/ \' T; L4 q" g
  25.     {
    ) u& ?4 }. D1 E) N1 G- J8 M1 R
  26.         usmart_dev.runtime += 0XFFFF;& E$ b( {1 i* J
  27.     }$ V0 w1 m  D+ w* p6 {4 W4 r
  28.     usmart_dev.runtime += __HAL_TIM_GET_COUNTER(&g_timx_usmart_handle);! K; `9 U5 _- A) {9 f4 p. {; S
  29.     return usmart_dev.runtime;                                 /* 返回计数值 */
    8 e) w' y: F) }" I' L$ C
  30. }/ W- o, c6 t# k- Z# A" p( r9 n
复制代码

* f' R7 H/ d. I; j; q, F; ]usmart_timx_reset_time函数在每次USMART调用函数之前执行,清除定时器的计数器,然后在函数执行完之后,调用usmart_timx_get_time获取计数器值,从而得到整个函数的运行时间。由于usmart调用的函数,都是在中断里面执行的,所以我们不太方便再用定时器的中断功能来实现定时器溢出统计,因此,USMART的函数执行时间统计功能,最多可以统计定时器溢出1次的时间,对STM32H750的定时器4,该定时器是16位的,最大计数是65535,而由于我们定时器设置的是0.1ms一个计时周期(10Khz),所以最长计时时间是:( _, c% N/ ~6 H# p
6553520.1ms=13.1秒
/ B# A! s; r1 W" v& F4 W, _1 p也就是说,如果函数执行时间超过13.1秒,那么计时将不准确。4 H4 X  G5 U7 R; [9 L( L
最后一个是USMART_TIMX_IRQHandler函数,该函数的实现代码如下:2 Q3 n9 l: k  c3 m, L
5 M8 i; d3 A! k  F& r* Z9 T
  1. /**# |& K- J2 j% M) t" k9 p
  2. * @brief              USMART定时器中断服务函数* L7 b& F  x3 ]$ }
  3. * @param              无1 I! y0 M3 ^1 H0 L7 N9 i. R
  4. * @retval             无
    6 Z: L8 _; H6 f0 h! z' p. T4 }, L* t
  5. */
    , M3 b0 h. Q9 U+ x" B' a* M, F; K
  6. void USMART_TIMX_IRQHandler(void)
    2 R. P- K2 A3 \% ?5 i4 D
  7. {
    1 Y& {2 @2 E7 x% b+ c
  8. /* 溢出中断 */
    " _0 ~* B9 S$ B2 [4 e
  9.     if(__HAL_TIM_GET_IT_SOURCE(&g_timx_usmart_handle,TIM_IT_UPDATE)==SET)* G0 b( I) d3 m4 W1 H
  10.     {
    & R: W: c) i# X& `
  11.         usmart_dev.scan();                                                           /* usmart扫描 */
    1 f5 }/ N$ K0 X
  12.         __HAL_TIM_SET_COUNTER(&g_timx_usmart_handle, 0);;            /* 清定时器CNT */6 g7 w: T/ q* I8 f+ Q
  13.         __HAL_TIM_SET_AUTORELOAD(&g_timx_usmart_handle, 100);        /* 恢复原来的设置 */
    : \/ M1 |6 G1 o+ L/ g3 J# J! H
  14.     }
    ( V4 Z7 b: p5 d* [
  15.     __HAL_TIM_CLEAR_IT(&g_timx_usmart_handle, TIM_IT_UPDATE);        /* 清除中断标志位 */
    7 j: F! s& C* l. A/ s4 x* r
  16. }
复制代码

; q) H" Z) d8 s, R  M, U该函数是定时器TIMX的中断服务函数,也是一个宏定义函数,同样是在usmart_port.h里面定义,方便大家修改。该函数主要用于周期性调用usmart扫描函数(实际函数:usmart_scan),完成对输入数据流的处理。同时,清除定时器的CNT值,并设置自动重装载值。
- s0 M7 b8 r  e9 {! B  {完成这几个函数的移植,就可以使用USMART了。不过,需要注意的是,usmart同外部的互交,一般是通过usmart_dev结构体实现,所以usmart_init和usmart_scan的调用分别是通过:usmart_dev.init和usmart_dev.scan实现的。
  P% p, f# ]6 p( b另外我们还需要在usmart_config.c文件里面添加想要被USMART调用的函数。打开usmart_config.c文件,如图26.3.2.1所示:5 O: F& h% `" F5 w
3 ]9 L) ?! ~$ R* W+ i
2a0bebf941ea4614b93e686f075559ce.png
  Z0 w! z( z" X  I3 I; ]& m; L2 Z% T7 Y
图26.3.2.1 添加需要被USMART调用的函数
2 V  F( E8 X7 _, e3 K+ R, O8 R. G这里的添加函数很简单,只要把函数所在头文件添加进来,并把函数名按上图所示的方式增加即可,默认我们添加了两个函数:delay_ms和delay_us。另外,read_addr和write_addr属于usmart自带的函数,用于读写指定地址的数据,通过配置USMART_USE_WRFUNS宏定义,可以使能或者禁止这两个函数。
, E) _1 ?# \" u3 w% l6 k这里我们根据自己的需要按上图的格式添加其他函数,usmart_config.c文件中我们已经添加了LCD的相关函数,大家可以查看本实验的usmart_config.c文件,并可在串口助手中调用。具体的调用方法26.4小节有具体讲解。1 g# I5 g# o3 j8 {4 C5 s" w
2. main.c代码! c5 D; j' F2 P2 B* h- T
在main函数之前,我们添加了led_set和test_fun两个函数,代码如下:
  1. /* LED状态设置函数 */
    ' p8 ?- `4 F0 ?" K0 f" y
  2. void led_set(uint8_t sta)
    9 O+ O2 n8 ^' k; V2 b6 z" i
  3. {
    8 ?. m6 f  t' p  C- i5 }7 Q& P1 v
  4.     LED1(sta);
    " M7 y& T3 d0 J# b1 P
  5. }! M7 G/ }: Q: C: a" V

  6. , q" V+ E$ Q: _+ v7 j, s
  7. /* 函数参数调用测试函数 */
    ! n) B8 ]+ g1 g: _# |
  8. void test_fun(void(*ledset)(uint8_t), uint8_t sta)
    : _3 e2 ]# Z% h; p3 G
  9. {* m5 R& t% i7 [6 t
  10.     ledset(sta);& t- E/ k; o  B+ f; R
  11. }
复制代码
: H+ Z% U6 K3 s+ _: j4 K7 I
led_set函数,用于设置LED1的状态,而第二个函数test_fun则是测试USMART对函数参数的支持的,test_fun的第一个参数是函数,在USMART里面也是可以被调用的。
# v8 [' ~1 u9 ^( a9 f, W" X  @9 _6 \4 |" n- B- c  J5 x
main函数代码如下:9 \8 h5 t; y6 i
3 g9 O  a7 \- P- g! |: j
  1. int main(void)
    ; M; n% V6 J* J
  2. {
    6 D' \- j8 ^8 d7 P4 |1 Q
  3.     sys_cache_enable();                            /* 打开L1-Cache */
    5 F! w. A/ D1 h: ^) I
  4.     HAL_Init();                                      /* 初始化HAL库 */$ }( h, c, S8 s
  5.     sys_stm32_clock_init(240, 2, 2, 4);         /* 设置时钟, 480Mhz */8 c) t9 D8 m6 C
  6.     delay_init(480);                                /* 延时初始化 */
    " z, G. p, w2 {
  7.     usart_init(115200);                            /* 串口初始化为115200 */
    ( r) W. G9 Y! z) C2 ?7 o6 ?! W
  8.     usmart_dev.init(240);                          /* 初始化USMART */3 E7 @2 }- s, t0 i% b7 ~  I$ s; }
  9.     led_init();                                      /* 初始化LED */
    * _/ G; P. E1 J
  10.     mpu_memory_protection();                      /* 保护相关存储区域 */
    ) j* V5 T% i8 f2 b# F* q
  11.     lcd_init();                                             /* 初始化LCD */
    8 y7 N4 Y3 U( d6 A# k0 W
  12.     lcd_show_string(30,50,200,16,16,"STM32", RED);- }' f# s, T" J
  13.     lcd_show_string(30,70,200,16,16,"USMART TEST", RED);; n* ^  d) {' P6 N! ]3 @( w
  14.     lcd_show_string(30,90,200,16,16,"ATOM@ALIENTEK", RED);' R1 X# s5 H8 t( ?
  15.     while(1)
    ( m( M1 K% ?" ^1 q$ o) ^
  16.     {; H2 L) |  M/ K" Z- p, M9 y! Y
  17.         LED0_TOGGLE();  /* LED0(RED) 闪烁 */
    - [4 f( M9 z) v$ D" E4 |
  18.         delay_ms(500);. w0 i$ ]. u" w+ x8 c: E! T$ ^$ B
  19.     }+ P  w$ H4 S" ?9 V! I
  20. }
复制代码
& j3 _. T! {0 A) A; |- j/ ]/ W
此部分代码功能如下:经过一系列初始化,显示使用信息后,就是在无限循环中LED0翻转延时,并等待串口数据。+ q, j* m8 W+ o2 r1 C3 A/ X
$ ]$ p& ?- ?0 J7 [, {
26.4 下载验证- w- T* y- e1 r- B, m
将程序下载到开发板后,可以看到LED0不停的闪烁,提示程序已经在运行了。同时,屏幕上显示了一些字符(就是主函数里面要显示的字符)。
( E% g9 p: x. w# |3 `0 @我们打开串口调试助手XCOM,选择正确的串口号多条发送勾选发送新行(即发送回车键)选项,然后发送list指令,即可打印所有usmart可调用函数。如下图所示:
& g5 u1 Q$ r# X& J% I8 [$ {/ j- ^7 m: }9 u, @4 Z) Z
068b21617c73489fae059aca4f27992e.png
% `7 j6 g8 D- I& u, b7 [* G
& J2 ?' F+ F9 |; J. s' P* B7 z图26.4.1 驱动串口调试助手
; w+ k' k+ g4 F+ L6 \' A上图中list、id、help、hex、dec、?和runtime都属于usmart自带的系统命令,点击后方的数字按钮,即可发送对应的指令。下面我们简单介绍下这几个命令:
7 c; J. S0 T  Y" Rlist,该命令用于打印所有usmart可调用函数。发送该命令后,串口将受到所有能被usmart调用得到函数,如图26.4.1所示。
) Z4 e( C6 U& o9 P/ l4 Eid,该指令用于获取各个函数的入口地址。比如前面写的test_fun函数,就有一个函数参数,我们需要先通过id指令,获取led_set函数的id(即入口地址),然后将这个id作为函数参数,传递给test_fun。
/ z5 h  n: }' p9 j- Ghelp(或者‘?’也可以),发送该指令后,串口将打印usmart使用的帮助信息。, x2 H, |& U6 {7 M, G+ S
hex和dec,这两个指令可以带参数,也可以不带参数。当不带参数的时候,hex和dec分别用于设置串口显示数据格式为16进制/10进制。当带参数的时候,hex和dec就执行进制转换,比如输入:hex 1234,串口将打印:HEX:0X4D2,也就是将1234转换为16进制打印出来。又比如输入:dec 0X1234,串口将打印:DEC:4660,就是将0X1234转换为10进制打印出来。4 E; T1 L# A3 D
runtime指令,用于函数执行时间统计功能的开启和关闭,发送:runtime 1,可以开启函数执行时间统计功能;发送:runtime 0,可以关闭函数执行时间统计功能。函数执行时间统计功能,默认是关闭的。' O' O2 z- \( c6 a( G4 J4 w
大家可以亲自体验下这几个系统指令,不过要注意,所有的指令都是大小写敏感的,不要写错哦。" G( ~7 o9 u' y8 w9 H: K; ]4 f' B! r: t
接下来,我们将介绍如何调用list所打印的这些函数,先来看一个简单的delay_ms的调用,我们分别输入delay_ms(1000)和delay_ms(0x3E8),如图26.4.2所示:
# R/ ?3 D& ]/ p) k+ W# D8 J& h! _8 N1 n
2d932bc28ff9482088f35ff10de1fdac.png . j  @4 _  u+ q) W( n8 G) N
' M8 v3 s8 d" v, d3 K
图26.4.2 串口调用delay_ms函数& L' i1 i$ P3 ^9 J, e, P5 {' q
从上图可以看出,delay_ms(1000)和delay_ms(0x3E8)的调用结果是一样的,都是延时1000ms,因为usmart默认设置的是hex显示,所以看到串口打印的参数都是16进制格式的,大家可以通过发送dec指令切换为十进制显示。另外,由于USMART对调用函数的参数大小写不敏感,所以参数写成:0X3E8或者0x3e8都是正确的。另外,发送:runtime 1,开启运行时间统计功能,从测试结果看,USMART的函数运行时间统计功能,是相当准确的。
( h# R" w  i" c! w4 h我们再看另外一个函数,lcd_show_string函数,该函数用于显示字符串,我们通过串口输入:lcd_show_string(30,200,200,16,16," This is a test for usmart!!", 0xF800),如图26.4.3所示:. b2 J. B$ V7 J
3 O, C" K- W/ r& D2 s6 g
d35713fe2c734e519632cba9bbbe5b5f.png * a2 ^  ^0 k) s
# O9 O) J9 L) B- ^
图26.4.3 串口调用lcd_show_string函数6 r3 V* d+ H2 Z, |* |# j! i! S
该函数用于在指定区域,显示指定字符串,发送给开发板后,我们可以看到LCD在我们指定的地方显示了:This is a test for usmart!! 这个字符串。
3 t% K9 d( I4 i其他函数的调用,也都是一样的方法,这里我们就不多介绍了,最后说一下带有函数参数的函数的调用。我们将led_set函数作为 test_fun的参数,通过在test_fun里面调用led_set函数,实现对LED1的控制。前面说过,我们要调用带有函数参数的函数,就必须先得到函数参数的入口地址(id),通过输入id指令,我们可以得到led_set的函数入口地址是:0X0800321D,所以,我们在串口输入:test_fun(0X0800321D,0),就可以控制LED1亮了。如图26.4.4所示:9 \* F$ l* S6 V1 \+ ^
* I3 y' {9 `- R3 P9 P0 y
18a2a8e872ff48099bef4482abc2ec86.png $ ]. _1 ]' E# `. u$ I2 `

" ]  Y9 R* y* v+ P( Z/ W. p3 s9 W; }8 Y图26.4.4 串口调用test_fun函数
/ p- H7 B& J/ V2 `, P2 Z  E在开发板上,我们可以看到,收到串口发送的test_fun(0X0800321D,0)后,开发板的LED1亮了,然后大家可以通过发送test_fun(0X0800321D,1),来关闭LED1。说明我们成功的通过test_fun函数调用led_set,实现了对LED1的控制。也就验证了USMART对函数参数的支持。
; O$ y3 I! K. ?  v5 A0 }- E1 `0 kUSMART调试组件的使用,就为大家介绍到这里。USMART是一个非常不错的调试组件,希望大家能学会使用,可以达到事半功倍的效果。) Z: a2 J- F' r& \/ g
————————————————
: W3 W- _0 K, Y( V$ v1 F8 g版权声明:正点原子
2 F( [  w" ]9 g( Q% }: z! ^9 V
5 u/ m$ K% ^- [3 h% k3 \
" g# o, L$ t: X! W& g
1 e, {# ^1 `5 a/ n: `, y( z
赞 收藏 评论0 发布时间:2022-10-7 18:27

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版