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

MiniPro STM32H750 开发指南_V1.1- STM32初体验

[复制链接]
STMCU小助手 发布时间:2022-10-4 17:56
STM32初体验
0 b5 g$ h! v$ C. \  A本章,我们不介绍如何编写代码,而是向大家介绍如何编译、串口下载、仿真器下载、仿真调试开发板例程,体验一下STM32的开发流程,并介绍MDK5的一些使用技巧,通过本章的学习,将对STM32的开发流程和MDK5使用有个大概了解,为后续深入学习打好基础。
- r. U- B+ ]9 U1 r0 j" N
/ K8 ], Q6 y# h) h5 Q& r4.1 使用MDK5编译例程1 ^$ R4 G8 @3 e5 t
我们在编写完代码以后,需要对代码进行编译,编译成功以后,才能下载到开发板进行验证、调试等操作。正点原子MiniPRO STM32H750开发板标准例程源码路径:A盘4,程序源码,如图4.1.1所示:0 W, X9 m5 h" B5 _) t3 G

: @) _* Q4 ^  J) v3 l  j4 v, I 2ced11fcda574832ac95cb533bbdf610.png
% _* O/ {9 G3 L7 A9 ~$ R8 E, \$ W" l+ l
图4.1.1 正点原子MiniPRO STM32H750开发板例程源码
# e" E/ ^3 \5 e4 R这7个压缩包说明如表4.1.1:
) g4 G8 N/ @, V$ E; K8 ~1 i' Z0 J, A# E/ H# K' J; n
51f46f703a65499f9d8edb4411e6a3dc.png
/ y" x$ f0 e2 E2 f1 W4 r2 V2 ^4 j
表4.1.1 源码压缩包说明
; h  v2 g" t: A& m( h% X) l! n  W本书主要针对“标准例程-HAL库版本”源码进行讲解,所以,这里我们先解压该压缩包,得到HAL库版本的标准例程源码如图4.1.2所示:9 u- W* c( L5 E3 e9 k3 R7 ?
( v* v9 e$ G. u" k  B
63781288b27149a5bb26b453e18f9859.png / c( `+ e6 O% u  o  S2 }) a
' L# j5 y% }" a( n
图4.1.2 标准例程-HAL库版本. o9 ?& U( c/ U8 f; P4 Q* X3 P
正点原子MiniPRO STM32H750开发板总共有51个实验的标准例程,部分实验有多个例程,比如:通用定时器实验、高级定时器实验、ADC实验等,实际上我们的总例程数达到了68个。这里我们没有把实验0统计进来,因为实验0主要是新建工程等MDK使用基础教学例程。
5 {6 {+ S: Z. q秉着简单易懂的原则,我们选择:实验1,跑马灯实验 作为STM32入门体验,例程目录如图4.1.3所示:
2 C2 H5 \  V: M) c6 j: P
3 P5 ?# @+ B4 T3 z 7f15c6c67238450bb92525c017ee8afa.png
* _6 ]( z# J& j8 S- T9 Q, J! @
0 {) I, J- x3 ?+ O; W图4.1.3 跑马灯例程工程目录结构
! U; ]/ R! V! E8 l工程目录下有5个文件夹,我们将在后续“新建HAL库版本MDK工程”这一章给大家详细介绍其作用(其实看文件夹名字的字面意思基本就知道是做啥用的了),这里我们不多说。例程MDK工程文件的路径为:ProjectsMDK-ARM atk_h750.uvprojx,如图4.1.4所示:
% G# C8 |$ I1 W8 z: d5 y6 F/ ?: j( v$ H
5bf3d0d1f62344a68689df0c7ae7cd7e.png
- r; }0 e4 t( Q6 O$ q" ?7 z
" G3 {6 ?0 v% H- t/ E6 e& i# R图4.1.4 跑马灯实验例程MDK工程+ x! D: Y+ p3 j% @" U
注意:一定要先安装MDK5(详见第三章),否则无法打开该工程文件!
) S% D# w" q" H! A' B双击atk_h750.uvprojx打开该工程文件,进入MDK IDE界面,如图4.1.5所示:/ u% J- y' _7 q% n/ z, [  D

5 W5 g( b' {$ C 2477b8f75aaf4188b081bc30c39c6db1.png 3 q' E( y4 n2 y3 ]+ K) N
- y7 ^% v. I0 G( K2 Y* P/ W8 r* n, ~
图4.1.5 MDK打开跑马灯实验例程
: y; B  J% W9 Y- e/ b; q0 A①是编译按钮,表示编译当前工程项目文件,如果之前已经编译过了,则只会编译有改动的文件。所以一般第一次会比较耗时间,后续因为只编译改动文件,从而大大缩短了编译时间。该按钮可以通过F7快捷键进行操作。- A" H* ^; P( x+ p: m
②是重新编译当前工程所有文件按钮,工程代码较多时全部重新编译会耗费比较多的时间,建议少用。
( G2 R& k; i5 ~, ~' I+ q按①处的按钮,编译当前项目,在编译完成后,可以看到如图4.1.6所示的编译提示信息:
  ~$ k5 f/ g3 J8 B) J! V. f# I% P! {4 F% b* c- X8 {
bcffb58bdc3e4400b768f57ef00e8357.png
2 i" m4 i* Z- ?0 q0 c7 E
1 g- b2 u8 w4 H5 |图4.1.6 编译提示信息
- [5 |. Z: k7 U. K图中:
3 Z% f/ {+ z- ]3 R  X3 JCode:表示代码大小,占用12652字节。
4 F9 D" i$ z. sRO-Data:表示只读数据所占的空间大小,一般是指const修饰的数据大小。
4 R* @8 K0 E9 s! J( g* ^2 HRW-Data:表示有初值(且非0)的可读写数据所占的空间大小,它同时占用FLASH(存放其初始值)和RAM空间。
' ?0 c+ O7 I4 C+ P  lZI-Data:表示初始化为0的可读写数据所占空间大小,它只占用RAM空间。& t3 Q2 i2 }9 W* X) @2 r, F
因此图4.1.6的提示信息表示:代码总大小(Porgram Size)为:FLASH占用13396字节(Code + RO + RW),SRAM占用2424字节(RW + ZI);成功创建了Hex文件(可执行文件,放在Output目录下);编译0错误,0警告;编译耗时5秒钟。
- n+ w# `$ j3 l9 n5 ~) z编译完成以后,会生成Hex可执行文件,默认输出在Output文件夹下,如图4.1.7所示:
  @" `4 k6 F  O0 V% H* p$ y7 D% B$ _8 o& C2 V8 y; w% C. R% B
3758697c06634a58aec0fe584a7be374.png / p4 _% O5 Z3 `3 W" o

9 N: ?1 T7 N( |! k1 N% l图4.1.7 Hex可执行文件- `& A4 U" g7 u6 D) `
注意:必须编译成功,才会生成Hex可执行文件,否则是不会有这个文件的 !!
8 B& V' {1 Y1 DOutput文件夹下除了.hex文件还有很多其他文件(.axf、.htm、.dep、.lnp、.o、.d、.lst等),这些文件是编译过程所产生的中间文件,我们将在后续的.map文件分析给大家详细介绍这些文件的作用。至此,例程编译完成。其他实验例程,大家可以用同样的方法进行编译。4 U" U0 G* b& r1 V  W0 R

4 V4 G: g, M; u  I1 R4 q- V4.2 STM32H7程序下载方法介绍
/ }& ~+ C! t9 q, Z; d7 S8 OSTM32H7的程序下载有多种方法:USB、串口、JTAG、SWD 等,这几种方式,都可以用来给 STM32H7下载代码。由于 STM32H7 暂时没有比较好的串口下载软件,因此,我们强烈推荐大家购买一个仿真器(如DAP、ST LINK、JLINK等),可以极大的方便学习和开发。下面重点介绍JTAG和SWD两种通信接口,具体如下表所示:
1 H8 r, b2 j) i% T& e2 I
7 h( A' H; F0 U* j+ `8 \( ] 2d400c0685814b29abf397692484ba87.png
& p3 J& Y* @$ P' }& H2 a3 `2 ?# e( S$ X( \7 O8 b# ]
表4.2.1 JTAG和SWD下载方式对比# M6 @9 \5 R$ u+ a- R2 Y. C; r& o
- I$ F7 s% W8 _1 m+ d' P
4.3 使用DAP下载与调试程序* a* d$ M9 `# q$ W) z
上一节我们主要介绍了JTAG和SWD两种通信接口,以及提到了三种仿真器,本节我们将给大家介绍如何使用仿真器给STM32下载代码,并调试代码。
6 C: U# b0 A- D( z# s. f6 y4 \8 T5 v
这里我们以DAP仿真器为例给大家进行讲解,如果你用的是其他仿真器,基本上也是一样的用法,只是选择仿真器的时候,选择对应的型号即可。# H+ w# S& j" v) h5 c5 k
DAP与开发板连接如图4.3.1所示:5 _6 T  t& N  K+ K

& v) N' E# C. k* O) W  A4 M5 L
: Y6 p! N0 x5 q1 G% p! e! {% K. ^+ V  N
图4.3.1 DAP与开发板连接! w( Z5 M6 W  c( ?4 |
①确保开发板已经正常供电,蓝色电源灯常亮。6 M; e8 |1 K8 W3 u/ E. C- F
②B0接GND。
9 f% |, y$ g: l$ a# }+ |③开发板USB供电。% D; C) Q% W3 i) D
④ DAP通过20P排线连接开发板,另一端则连接到电脑,仿真器指示灯蓝灯常亮为正常。6 A" r/ ~( ~$ v5 D3 L- j  ?

$ v, x0 i: j' z5 i8 x5 x4.3.1 使用DAP下载程序
2 d! l; T$ ]8 x# C5 `! ?9 L5 i* B在4.1节的跑马灯例程MDK IDE界面下,点击按钮,打开Options for Target选项卡,在Debug栏选择仿真工具为use:ST-Link Debugger,如图4.3.1.1所示:, ~+ T' A  o0 b2 e$ ]" ~) j/ ~
3 R; ^4 v7 `; P  t
9a3e9c9ea2ae4b59adf4902f832ff2fc.png
$ i; k: g! i) d# b4 u  M
- U  b, i9 J1 Y8 R图4.3.1.1 Debug选项卡设置
( R* g& H, u( ~! ^; R①选择使用CMSIS-DAP Debugger仿真器仿真调试代码。如果你使用的是其他仿真器,比如STLINK、JLINK等,请在这里选择对应的仿真器型号。
! h* A0 [8 m+ i: |; x0 M②该选项选中后,只要点击仿真就会直接运行到main函数,如果没选择这个选项,则会先执行startup_stm32h750xx.s文件的Reset_Handler,再跳到main函数。
  M$ k) l8 o; N然后我们点击Settings,设置DAP的一些参数,如图4.3.1.2所示:
3 \0 A+ B' R- |3 `$ M6 J- k, A$ g  R5 @- H- _
72234b31e0b148779915ffc3dc8ae22a.png 8 v. O. a& t- k+ C3 o" k; m

  `, L4 Q+ e1 q) e4 T图4.3.1.2 DAP仿真器参数设置; _, i7 i* m( R3 w/ @+ D5 T* u9 c
①表示MDK找到了ATK CMSIS-DAP仿真器,如果这里显示为空,则表示没有仿真器被找到,请检查你的电脑是否接了仿真器?并安装了对应的驱动?
' K+ V( j9 `$ b) n1 \②设置接口方式,这里选择SW(比JTAG省IO),通信速度设置为10Mhz(实际上大概只有4M的速度,MDK会自动匹配)。' L7 G0 [5 g6 c2 H
③表示MDK通过仿真器的SW接口找到了目标芯片,ID为:0x6BA02477。如果这里显示:No target connected,则表示没找到任何器件,请检查仿真器和开发板连接是否正常?开发板是否供电了?1 e/ i2 J! d% a& o
其他部分使用默认设置,设置完成以后单击“确定”按钮,完成此部分设置,接下来我们还需要在Utilities选项卡里面设置下载时的目标编程器,如图4.3.1.3所示:
1 G0 }3 L! q, v. G- R3 h0 l5 m) o+ R" x5 Q# b6 j( k
c4bfd243f53b4022a4f2626ee183a12d.png
$ A! c1 J4 B9 i  N, |" N4 g/ c% C  E  T  V3 V
图4.3.1.3 FLASH编程器选择
! s( u+ u  _+ \: y0 ?上图中,我们直接勾选Use Debug Driver,即和调试一样,选择DAP来给目标器件的FLASH编程,然后点击Settings,进入FLASH算法设置,设置如图4.3.1.4所示:5 E  [* [. {% t( |
2 S# [& W$ A+ K2 ]4 a1 `( n
e91decd4876249d2a135fdfefc36cc81.png
2 f7 M5 t' A) q. q: Y; Q9 @0 n
& n* n: N" r. \3 v8 R6 \) c+ m图4.3.1.4 FLASH算法设置
4 K1 K2 d4 z8 ]6 J- }" b8 e. k这里MDK5会根据我们新建工程时选择的目标器件,自动设置flash算法。我们使用的是STM32H750VBT6,FLASH容量为128K字节,所以Programming Algorithm里面默认会有128K的STM32H750xx内部Flash下载算法。! a2 Y) p. n. D3 J
由于我们的工程还有一部分代码是存放在外部 SPI FLASH 的(后面会详细讲解),因此需要添加外部 SPI FLASH 的下载算法,即 3.2小节提到的下载算法。另外,如果这里没有外部SPI Flash下载算法STM32H750VB_25QXX@ALIENTEK.FLM,大家可以点击Add按钮,自行添加即可(注意,必须先将该算法拷贝到MDK安装路径ARMFlash文件夹下,否则是无法选择该算法的!,参见图3.2.4!)。添加好算法后,设置算法使用的 RAM 地址和大小,这里设置的起始地址为:0X2000 0000(DTCM),大小为:0X3000。必须按这个大小设置,否则下载会出错(无法加载算法)。% _* I- j" Q, @( c$ Z0 o- t+ A' a) n
最后,选中Reset and Run选项,以实现在编程后自动运行,其他默认设置即可。
+ r1 R9 U; x5 {& s* Q2 S3 S+ I在设置完之后,点击“确定”,然后再点击“OK”,回到IDE界面,编译(可按F7快捷键)一下工程,编译完成以后(0错误,0警告),我们按(快捷键:F8)这个按钮,就可以将代码通过仿真器下载到开发板上,在IDE下方的Build Output窗口就会提示相关信息,如图4.3.1.5所示:  y9 O7 ?6 k8 f
' W% X) k# G2 {9 I" ~3 |
c460fc02d023487e89ae6c11c933a14b.png 1 d% M4 ~( n  n% e9 w; Q& P" ?
/ q9 E2 Q* r& Q  @% q
图4.3.1.5 仿真器下载代码) c8 Y5 ^6 `5 z- c" C
下载完后,可以看到LED0、LED1和LED2交替闪烁了,说明代码下载成功。
+ t: ?5 @- @  e" q* e, {* t3 A4 @1 T; T3 Y4 X& p" ^7 K
4.3.2 使用DAP仿真调试程序
8 d2 Y9 @6 o8 R! Y在正常编译完例程以后(0错误,0警告),点击: (开始/停止仿真按钮),开始仿真(如果开发板的代码没被更新过,则会先更新代码(即下载代码),再仿真),如图4.3.2.1所示:
2 Q# q( g' G4 u* u( n) O1 {( `. p. z: z( ?# Q$ A+ b5 R# ]: @; D& D
f2e4518a0e63461ba317a49c567c6278.png ; u( M8 ~$ \0 Q( U1 j+ N1 [
# R" v9 @2 ]4 ~
图4.3.2.1 开始仿真
% }( f# R5 |5 c, Z$ X①Register:寄存器窗口,显示了Cortex M7内核寄存器R0R15的值,还显示了内部的线程模式(处理者模式、线程模式)及特权级别(用户级、特权级),并且还显示了当前程序的运行时间(Sec),该选项卡一般用于查看程序运行时间,或者比较高级的bug查找(涉及到分析R0R14数据是否异常了)。6 t, D/ y4 \' V. T9 [, V' t, G
②Disassembly:反汇编窗口,将C语言代码和汇编对比显示(指令存放地址,指令代码,指令,具体操作),方便从汇编级别查看程序运行状态,同样也属于比较高级别的bug查找。
, U  E0 {& v  O③代码窗口,在左侧有黄绿色三角形,黄色的三角形表示将要执行的代码,绿色的三角形表示当前光标所在代码(C代码 或 当前汇编行代码对应的C代码)。一般情况下,这两个三角形是同步的,只有在点击光标查看代码的时候,才可能不同步。
6 t# z7 S; u7 [6 U/ c( B④Call Stack + Locals:调用关系&局部变量窗口,通过该窗口可以查看函数调用关系,以及函数的局部变量,在仿真调试的时候,是非常有用的。
: o* }# W* o' M: R0 I6 l) p* ~开始仿真的默认窗口,我们就给大家介绍这几个,实际上还有一些其他的窗口,比如Watch、Memory、外设寄存器等也是很常用的,可以根据实际使用选择调用合适的窗口来查看对应的数据。7 i: b  {. `* f: y+ E5 a$ [
图4.3.2.1中,还有一个很重要的工具条:Debug工具条,其内容和作用如图4.3.2.2所示:2 k+ X- u8 [0 ^7 s
$ b! s2 ^3 h  c+ h, a; A! f$ g
52e99af4551e47eb9ae4a629d19e9862.png
% K) i- C: Y8 R' f' d0 b% X3 p) i. P, ^7 Q1 v
图4.3.2.2 Debug工具条
/ \0 |$ W0 e1 D* S1 q! @5 K+ r6 n& f复位:其功能等同于硬件上按复位按钮。相当于实现了一次硬复位。按下该按钮之后,代码会重新从头开始执行。5 o5 P5 P* g; X+ ^/ r: e
执行到断点处:该按钮用来快速执行到断点处,有时候你并不需要观看每步是怎么执行的,而是想快速的执行到程序的某个地方看结果,这个按钮就可以实现这样的功能,前提是你在查看的地方设置了断点。
, S. u) D) I; m% L& p$ p停止运行:此按钮在程序一直执行的时候会变为有效,通过按该按钮,就可以使程序停止下来,进入到单步调试状态。
; m+ n! {* i+ ~) D' V8 k, A; G执行进去:该按钮用来实现执行到某个函数里面去的功能,在没有函数的情况下,是等同于执行过去按钮的。9 m% i4 B% p% L/ I) ^4 l5 t  X
执行过去:在碰到有函数的地方,通过该按钮就可以单步执行过这个函数,而不进入这个函数单步执行。( D/ a7 H$ w" W8 }
执行出去:该按钮是在进入了函数单步调试的时候,有时候可能不必再执行该函数的剩余部分了,通过该按钮就可以一步执行完该函数的余部分,并跳出函数,回到函数被调用的位置。$ @/ q9 y( e, k
执行到光标处:该按钮可以迅速的使程序运行到光标处,其实是挺像执行到断点处按钮功能,但是两者是有区别的,断点可以有多个,但是光标所在处只有一个。
' I; ^) R- T2 ?2 g反汇编窗口:通过该按钮,就可以查看汇编代码,这对分析程序很有用。
) @6 l# P9 m! A" A3 m) UCall STACK窗口:通过该按钮,显示调用关系&局部变量窗口,显示当前函数的调用关系和局部变量,方便查看,对分析程序非常有用。
  o3 R' b. H, y1 Q观察窗口:MDK5提供2个观察窗口(下拉选择),该按钮按下,会弹出一个显示变量的窗口,输入你所想要观察的变量/表达式,即可查看其值,是很常用的一个调试窗口。( E0 {% p0 [8 U' ^* p
内存查看窗口:MDK5提供4个内存查看窗口(下拉选择),该按钮按下,会弹出一个内存查看窗口,可以在里面输入你要查看的内存地址,然后观察这一片内存的变化情况。是很常用的一个调试窗口) Q, `: f0 {% ~1 |
串口打印窗口:MDK5提供4个串口打印窗口(下拉选择),该按钮按下,会弹出一个类似串口调试助手界面的窗口,用来显示从串口打印出来的内容。$ I* r2 D( k0 m/ w/ h
系统分析窗口:该图标下面有6个选项(下拉选择),我们一般用第一个,也就是逻辑分析窗口(Logic Analyzer),点击即可调出该窗口,通过SETUP按钮新建一些IO口,就可以观察这些IO口的电平变化情况,以多种形式显示出来,比较直观。4 b1 H, d* s* v) Q. b
系统查看窗口:该按钮可以提供各种外设寄存器的查看窗口(通过下拉选择),选择对应外设,即可调出该外设的相关寄存器表,并显示这些寄存器的值,方便查看设置的是否正确。
( a' ?% ]( U4 L1 ?6 BDebug工具条上的其他几个按钮用的比较少,我们这里就不介绍了。以上介绍的是比较常用的,当然也不是每次都用得着这么多,具体看你程序调试的时候有没有必要观看这些东西,来决定要不要看。; z0 b+ j% }# C+ t
我们在图4.3.2.1的基础上:关闭反汇编窗口(Disassembly)、添加观察窗口1(Watch1)。然后调节一下窗口位置,然后将全局变量:g_fac_us (在delay.c里面定义)加入Watch1窗口(方法:双击Enter expression添加/直接拖动变量t到Watch1窗口即可),如图4.3.2.3所示:  C' E1 F8 E+ h

& O8 v7 {8 e& m) r! w e7b8bfccfa6e439fbe698e40c29c6c36.png
6 H3 Z- L& f6 }# M0 h, G
* r& ]& z* N  M5 y2 ?7 W; M) r图4.3.2.3 开始仿真8 G: s9 b6 H( i$ K. `
此时可以看到Watch1窗口的g_fac_us的值提示:无法计算,我们把鼠标光标放在第32行左侧的灰色区域,然后按下鼠标左键,即可放置一个断点(红色的实心点,也可以通过鼠标右键弹出菜单来加入),这样就在delay_init函数处放置一个断点,然后点击:,执行到该断点处,然后再点击:,执行进入delay_init函数,如图4.3.2.4所示:
9 f% A0 L  n$ N: W/ J7 S- y8 c) X- m+ X
b2573d94d1124621a5066772d5f544e7.png
) ~, s/ u! F7 W, n" S
2 W+ t5 H3 S* t; ?9 L5 b图4.3.2.4 执行进入delay_init函数
$ D2 o; q7 Z! t此时,可以看到g_fac_us的值已经显示出来了,默认是0(全局变量如果没有赋初值,一般默认都是0),然后继续单击:,单步运行代码到g_fac_us = sysclk; 这一行,再把鼠标光标放在sysclk上停留一会,就可以看到MDK自动提示sysclk(delay_init的输入参数)的值为:0X01E0,即480,如图4.3.2.5所示:
5 C$ S# V, @* K! N1 \) M4 v" a9 M$ n! D
40476ca7eb834edaa3adea7282a7f846.png ; e+ _0 n: b3 P9 G7 I7 h+ Y2 m5 ]

; Q% y8 N& G2 G0 j图4.3.2.5 单步运行到g_fac_us赋值* h5 F6 ^- y& S! e
然后再单步执行过去这一行,就可以在Watch1窗口中看到g_fac_us的值变成0X01E0了,如图4.3.2.6所示:7 [* }$ @2 Y  O  ^) y% j

9 Z, C( R' o9 a  h/ Y) K2 s a226da7f346b4fb19a4cf879c50ac8e9.png
8 e" _! |1 Q) I7 h6 ]* M3 i  r
' k4 r% P! ?1 t8 t图4.3.2.6 Watch1窗口观看g_fac_us的值
! E1 ?( B# E* Y3 S2 a由此可知,某些全局变量,我们在程序还没运行到其所在文件的时候,MDK仿真时可能不会显示其值(如提示:cannot evaluate),当我们运行到其所在文件,并实际使用到的时候,此时就会显示其值出来了!
! t' r* ]' j4 m( a, P6 |然后,我们再回到main.c,在第一个LED0(0)处放置一个断点,运行到断点处,如图4.3.2.7所示:8 r1 [9 N- i* w
$ d; t! R* E  l' O: m: {
bf25966ab9ba45aab651732f07075444.png & ?( V& E( m4 [# I! ?+ _) [
, {' C+ K9 V) S0 L3 u
图4.3.2.7 运行到LED0(0)代码处
( \' I) f4 D" X8 ]5 H此时,我们点击:,执行过这一行代码,就可以看到开发板上的LED0(红灯)亮起来了,以此继续点击,依次可以看到:LED0灭LED1亮 LED1灭 LED2亮 LED2灭 LED0亮……,一直循环。这样如果全速运行,就可以看到LED0、LED1和LED2交替闪烁。
3 R. y, B8 U  c$ Z. n; |最后,我们在delay.c文件的delay_us函数,第五行处设置一个断点,然后运行到断点处,如图4.3.2.8所示:
$ s9 L, C' z" J3 I4 J
  ^$ E4 b' y5 T& C b1d104ce458d4531912078c4a6ceb9e4.png 1 O9 k; P5 M3 H- l$ \

5 n+ [. Y4 r3 A7 F* r$ h# g图4.3.2.8 查看函数调用关系及局部变量: a4 {4 m( C6 P6 m; O
此时,我们可以从Call Stack + Locals窗口看到函数的调用关系,其原则是:从下往上看,即下一个函数调用了上一个函数,因此,其关系为:main函数调用了delay_ms函数,然后delay_ms函数调用了delay_us函数。这样在一些复杂的代码里面(尤其是第三方代码),可以很容易捋出函数调用关系并查看其局部变量的值,有助于我们分析代码解决问题。& ?/ s7 N1 \  W- f: h- p$ Z
关于DAP的仿真调试,我们暂时就讲这么多。
8 i( ~$ ~% o/ `1 d6 I! x% V, v
% L+ R/ o2 a4 F1 k6 Y  [4.3.3 仿真调试注意事项. n; J1 b! P0 X7 P; b
1、由于MDK5.23以后对中文支持不是很好,具体现象是:在仿真的时候,当有断点未清除时点击结束仿真,会出现如图4.3.3.1所示的报错:
# \& g! L" g% N" O
- T9 F6 |( l0 _' {7 l b9297090ee0641528213fb9f71f72b55.png $ a5 D! V) q$ Y1 u9 u( J

" p' Q8 L% l( `4 P/ e9 P/ R8 `图4.3.3.1 仿真结束时报错!
2 w- K) i' K; j- }- p" B( m6 l8 B3 C6 m此时我们点击确定,是无法关闭MDK的,只能到电脑的任务管理器里面强制结束MDK,才可以将其关闭,比较麻烦。7 F7 c7 e( t. ^4 c& g. h
该错误就是由于MDK5.23以后的版本对中文支持不太好导致的,这里提供2个解决办法:a,仿真结束前将所有设置的断点都清除掉,可以使用File工具栏的:按钮,快速清除当前工程的所有断点,然后再结束仿真,就不会报错;b,将工程路径改浅,并改成全英文路径(比如,将源码拷贝到:E盘Source Code文件夹下。注意:例程名字一般可以不用改英文,因为只要整个路径不超过10个汉字,一般就不会报错了,如果还报错就再减少汉字数量)。通过这两个方法,可以避免仿真结束报错的问题。我们推荐大家使用第二种方法,因为这样就不用每次都全部清除所有断点,下回仿真又得重设的麻烦。4 k6 O+ n, X7 r3 ?
2、关于STM32软件仿真,老版本的教程,我们给大家介绍过如何使用MDK进行STM32软件仿真,由于其限制较多(只支持部分F1型号),而且仿真器越来越便宜,硬件仿真更符合实际调试需求,调试效果更好。所以后续我们只介绍硬件仿真,不再推荐大家使用软件仿真了!8 M# j- u1 ]0 i5 g+ `
3、仿真调试找bug是一个软件工程师必备的基本技能。MDK提供了很多工具和窗口来辅助我们找问题,只要多使用,多练习,肯定就可以把仿真调试学好。这对我们后续的独立开发项目,非常有帮助。因此极力推荐大家多练习使用仿真器查找代码bug,学会这个基本技能。
- a/ j' N) X7 j% \* Q5 _1 R* _7 D4、调试代码不要浅尝辄止,要想尽办法找问题,具体的思路:先根据代码运行的实际现象分析问题,确定最可能出问题的地方,然后在相应的位置放置断点,查看变量,查看寄存器,分析运行状态和预期结果是否一致?从而找到问题原因,解决bug。特别提醒:一定不要浅尝辄止,很多朋友只跟踪到最上一级函数,就说死机了,不会跟踪进去找问题!所以一定要一层层进入各种函数,越是底层(甚至汇编级别),越好找到问题原因。/ W3 q+ ]* A9 D8 h0 {2 j9 r

) G: c8 o+ v5 a' s" h, ?. i# T. }4.4 MDK5使用技巧
% N1 ^2 ]8 O1 @' O8 A% P* U0 K$ E( }本节,我们将向大家介绍MDK5软件的一些使用技巧,这些技巧在代码编辑和编写方面会非常有用,希望大家好好掌握,最好实际操作一下,加深印象。
: b, |$ F- S7 m5 |. i$ |4.4.1 文本美化
/ d# z0 N( a+ }# d/ k文本美化,主要是设置一些关键字、注释、数字等的颜色和字体。如果你刚装MDK,没进行字体颜色配置,你的界面效果如图4.4.1.1所示:
/ D$ _) n+ s! L/ W+ ?/ i
& t4 I* V' {- F! [7 X: V8 Z d8aff04502754601b8fb90835baa3219.png
; l" H4 Q* ~2 ^1 Q7 b1 s/ I0 d% w3 h
7 l: Y  a3 J8 ?# q2 S' d图4.4.1.1 MDK默认配色效果
9 q7 {6 Y( O* x" a上图是MDK默认的设置,可以看到其中的关键字和注释等字体的颜色不是很漂亮,而MDK提供了我们自定义字体颜色的功能。我们可以在工具条上点击 (配置对话框)弹出如图4.4.1.2所示界面:* D+ @, E' b( c
) N$ `# P) ^/ l; t: T
196f491ed1b14514bf0e52ddc9cc2a52.png
. {" O& n9 q( t: f. J9 ^3 E; z: p/ Z, X& Z8 V# j
图4.4.1.2置对话框
. j0 T. \# W1 Z2 ]①设置代码编辑器字体使用:Chinese GB2312(Simplified),以更好的支持中文。
5 f( |/ K5 m( I- {0 K- g3 j  q/ \2 Y②设置编辑器的空格可见:View White Space,所有空格使用“.”替代,TAB使用“”替代,这样可以方便我们对代码进行对齐操作。同时,我们推荐所有的对齐都用空格来替代,这样在不同软件之间查看源代码,就不会引起由于TAB键大小不一样导致代码不对齐的问题,方便使用不同软件查看和编辑代码。
+ O8 t6 B5 F5 b# H1 @0 m1 q③设置C/C++文件,TAB键的大小为4个字符,且字符使用空格替代(Insert spaces for tabs)。这样我们在使用TAB键进行代码对齐操作的时候,都会用空格替代,保证不同软件使用代码都可以对齐。
+ X' [2 f; ?# ~: V/ M% W然后,选择:Colors & Fonts选项卡,在该选项卡内,我们就可以设置自己的代码的字体和颜色了。由于我们使用的是C语言,故在Window下面选择:C/C++ Editor Files在右边就可以看到相应的元素了。如图4.4.1.3示:6 f, o3 l2 {* Y: Z' Z
6 j, g& u. p7 Y
6b1a97e2d21f498081e3f8311036a034.png
9 r" Q) {; \7 D  }  `* u4 l
* p" a+ ~+ L( R) u" q图4.4.1.3 Colors & Fonts选项卡
# Y8 P# g9 a8 ?8 S! t然后点击各个元素(Element)修改为你喜欢的颜色(注意双击,且有时候可能需要设置多次才生效,MDK的bug),当然也可以在Font栏设置你字体的类型,以及字体的大小等。5 D  {1 I3 g- k
然后,点击User Keywords选项卡,设置用户定义关键字,以便用户自定义关键字也显示对应的颜色(对应图4.4.1.3中的User Keyword/Lable颜色)。在User Keywords选项卡对话框下面输入你自己定义的关键字,如图4.4.1.4示:$ G/ n+ M9 z) h0 U6 u

: H4 r( I! L5 K9 G. Y) L; N cb75c893933f4b93892a7afbdf52c7b8.png
3 A7 ~) r% y, K) D3 F5 o: k. @) k9 F; N# e
图4.4.1.4 用户自定义关键字( [- C9 S# B6 |5 k/ w6 g: ?# P
这里我们设置了uint8_t、uint16_t和uint32_t等三个用户自定义关键字,相当于unsigned char、unsigned short和unsigned int。如果你还有其他自定义关键字,在这里添加即可。设置成之后,点击OK,就可以在主界面看到你所修改后的结果,例如我修改后的代码显示效果如图4.4.1.5示:5 z. u  m9 Q2 ^9 {2 K7 V( W# w
; M- U/ P8 A+ K! e
e219f90740de406ebe0aae16bf7814e4.png 5 g/ r2 q* m7 {
- q4 d& ?: G) |$ R6 P( i) e) }
图4.4.1.5设置完后显示效果+ q" Q6 d) M6 i( u* |
这就比开始的效果好看一些了。字体大小,则可以直接按住:ctrl+鼠标滚轮,进行放大或者缩小,或者也可以在刚刚的配置界面设置字体大小。) c! M& d! G; I5 |$ c2 O1 g; P
同时,上图中可以看到空白处有很淡的一些……显示,这就是我们勾选了View White Space选项后体现出来的效果,可以方便我们对代码进行规范对齐整理。一开始看的时候可能有点不习惯,看多了就习惯了,大家慢慢适应就好了。
5 q) K" P% _3 O5 q9 |其实在这个编辑配置对话框里,还可以对其他很多功能进行设置,比如动态语法检测等,我们将4.4.2节介绍。
: J4 l. c/ }& F, n4.4.2 语法检测&代码提示. e- e3 B* C4 w# X
MDK4.70以上的版本,新增了代码提示与动态语法检测功能,使得MDK的编辑器越来越好用了,这里我们简单说一下如何设置,同样,点击,打开配置对话框,选择Text Completion选项卡,如图4.4.2.1所示:
* f" o3 Q; @: ^' J6 u
- h( H) H4 U" t$ R8 @# Q4 p( o* c f9f2713714ad406483a9eb085f40b1ef.png
/ p  ]. J0 w  d8 L/ W0 T1 [. ?* Z% G- t, \8 X
图4.4.2.1 Text Completion选项卡设置
& G- w& r" f0 f( H& @2 _Strut / Class Members,用于开启结构体/类成员提示功能。
  Z, x1 M6 \, Y) oFunction Parameters,用于开启函数参数提示功能。
1 E5 D# s5 z( O- r; C2 OSymbols after xx characters,用于开启代码提示功能,即在输入多少个字符以后,提示匹配的内容(比如函数名字、结构体名字、变量名字等),这里默认设置3个字符以后,就开始提示。如图4.4.2.2所示:
* p$ n( d* t# O( m+ A% v0 ?
1 P: _& e+ J6 I$ @+ c( M 40deec5710dd4cac8d0bd9ac96dc86ee.png " Q& k- p6 |0 S& Z8 t; k, U) z4 b' y
, e. v& B( F5 R' A: y! W$ N
图4.4.2.2 代码提示. C/ K5 E/ G) @8 {: p/ z* ^9 W
ENTER/TAB as fill-up character,使用回车和TAB键填充字符。
5 Z8 J& U  b  V4 w0 Y0 bDynamic Syntax Checking,则用于开启动态语法检测,比如编写的代码存在语法错误的时候,会在对应行前面出现图标,如出现警告,则会出现图标,将鼠标光标放图标上面,则会提示产生的错误/警告的原因,如图4.4.2.3所示:
" D% [" y" C8 F( ? 56e9f64553fa44e19c2ad7f0a0e7b057.png ( x8 |$ ^( U' f1 b2 p$ v3 M$ u% e
+ T) g4 m& c; Z! s
图4.4.2.3 语法动态检测功能
7 `/ d% e6 A# ^$ K: s6 ~# B这几个功能,对我们编写代码很有帮助,可以加快代码编写速度,并且及时发现各种问题。不过这里要提醒大家,语法动态检测这个功能,有的时候会误报(比如sys.c里面,就有误报),大家可以不用理会,只要能编译通过(0错误,0警告),这样的语法误报,一般直接忽略即可。& m; F$ @8 e; P; y$ d8 @+ G
' h$ O0 @" h6 `  [+ x/ p! e* z+ J
4.4.3 代码编辑技巧
9 C/ d* y) j7 o, l1 ?0 L4 v这里给大家介绍几个我常用的技巧,这些小技巧能给我们的代码编辑带来很大的方便,相信对你的代码编写一定会有所帮助。% W6 a& L, H  f, X
1.TAB键的妙用- t6 a- P2 s. L
首先要介绍的就是TAB键的使用,这个键在很多编译器里面都是用来空位的,每按一下移空几个位。如果你是经常编写程序的对这个键一定再熟悉不过了。但是MDK的TAB键和一般编译器的TAB键有不同的地方,和C++的TAB键差不多。MDK的TAB键支持块操作。也就是可以让一片代码整体右移固定的几个位,也可以通过SHIFT+TAB键整体左移固定的几个位。4 X$ ~1 A  Z3 h) s
假设我们前面的串口1中断回调函数如图4.4.3.1所示:
% v9 N, R6 E7 W! g$ y0 \/ a4 f; c' o3 [4 q
63b32f12ff77429b8825dc6b38681714.png
" l8 a$ w1 c' E' b! {+ j7 m8 t
" m% @. h3 ?0 W; [$ Z图4.4.3.1 头大的代码3 m+ r/ r4 _7 R7 |: L' `/ ~
上图的代码很不规范,这还只是短短的30来行代码,如果你的代码有几千行,全部是这个样子,不头大才怪。这时我们就可以通过TAB键的妙用来快速修改为比较规范的代码格式。
9 L& ]3 c3 A2 I. s8 i# U' @( N5 I选中一块然后按TAB键,你可以看到整块代码都跟着右移了一定距离,如图4.4.3.2所示:
' s( P, K! K+ }6 a2 D7 B0 v  ~; O% N- x* M. N
649c0c4e2faa43efba924b416c5c6ab1.png ' a5 g4 {/ A: N7 v* a3 {5 ~7 E) c! H
0 q. z' e9 Y1 U* h4 ^& l
图4.4.3.2 代码整体偏移
2 z( v5 D8 T& i$ c+ l* k' ]5 d接下来我们就是要多选几次,然后多按几次TAB键就可以达到迅速使代码规范化的目的,最终效果如图4.4.3.3所示4 B; V+ O" f: i6 y. r
' F# E# M0 a" ?- {  V5 J& g8 M
78bfa43016ec4d0ab06953a081559740.png + n5 j5 O' l! ^. e) i

- i/ f' u( X& {6 c$ j图4.4.3.3 修改后的代码
& _3 a# i9 R, N( W( h1 [8 T" |图4.4.3.3中的代码相对于图4.4.3.1中的要好看多了,经过这样的整理之后,整个代码一下就变得有条理多了,看起来很舒服。
, y8 v3 V4 k/ k- \' H
- d$ ?6 H# G& ?' Q* R$ h) f" \2. 快速定位函数/变量被定义的地方  y( x* k5 ?/ ]( V2 i3 K" Q
上一节,我们介绍了TAB键的功能,接下来我们介绍一下如何快速查看一个函数或者变量所定义的地方。
3 S: k: o0 M* i# r: B/ N大家在调试代码或编写代码的时候,一定有想看看某个函数是在那个地方定义的,具体里面的内容是怎么样的,也可能想看看某个变量或数组是在哪个地方定义的等。尤其在调试代码或者看别人代码的时候,如果编译器没有快速定位的功能的时候,你只能慢慢的自己找,代码量比较少还好,如果代码量一大,那就郁闷了,有时候要花很久的时间来找这个函数到底在哪里。型号MDK提供了这样的快速定位的功能。只要你把光标放到这个函数/变量(xxx)的上面(xxx为你想要查看的函数或变量的名字),然后右键,弹出如图4.4.3.4所示的菜单栏 :
/ @2 t4 U* z6 N
( E) [  ^" h  h" U) y- a fbfd302ec1fd45ce991507c624347d64.png " M! V1 p6 F* H( `# s

( |, b' B* {4 p+ G9 W1 L图4.4.3.4 快速定位
/ U! M) |9 j. I3 y8 \5 m在图4.4.3.4中,我们找到Go to Definition Of‘sys_stm32_clock_init’ 这个地方,然后单击左键就可以快速跳到sys_stm32_clock_init函数的定义处(注意要先在Options for Target的Output选项卡里面勾选Browse Information选项,再编译,再定位,否则无法定位!)。如图4.4.3.5所示:
3 P+ x  C0 a8 k
- L5 {: b- X( N# ^- ]& I b6cd34ddb9d44aa098ef7d5f916edd77.png
3 F) H+ a6 Q; h6 T: _' C/ A
' e/ K: Z( p" }, s/ T' u图4.4.3.5 定位结果. O$ q" ]  l0 [7 s% H
对于变量,我们也可以按这样的操作快速来定位这个变量被定义的地方,大大缩短了你查找代码的时间。) ~9 G# F, w' V- a% l
很多时候,我们利用Go to Definition看完函数/变量的定义后,又想返回之前的代码继续看,此时我们可以通过IDE上的按钮(Back to previous position)快速的返回之前的位置,这个按钮非常好用!
5 {6 Y% v! G# {2 ]3 Q
2 D) S) @$ U* Q( I+ H' Q' W5 O; X6 C3. 快速注释与快速消注释% D) p1 G" _& b* h) U2 b
接下来,我们介绍一下快速注释与快速消注释的方法。在调试代码的时候,你可能会想注释某一片的代码,来看看执行的情况,MDK提供了这样的快速注释/消注释块代码的功能。也是通过右键实现的。这个操作比较简单,就是先选中你要注释的代码区,然后右键,选择AdvancedComment Selection就可以了。* H% I% e+ J8 Y$ R- z2 [
以led_init函数为例,比如我要注释掉下图中所选中区域的代码,如图4.4.3.6所示:$ [4 x8 I: [7 \$ t, t! H+ Q4 c5 `7 R+ T
( V& `. s0 N: g
4987ebd0616348b3b136ff28aee7d023.png
3 u2 B+ Z' t' c: p/ C8 E  d* w) m4 I& f* _, k) D
图4.4.3.6 选中要注释的区域
6 ~  h. R3 i: {5 f0 @我们只要在选中了之后,选择右键,再选择AdvancedComment Selection就可以把这段代码注释掉了。执行这个操作以后的结果如图4.4.3.7所示:' U( k( u3 s3 y( p2 Y! ^
+ T) p  m/ ?, ?# B' |- s; H
68f214012a1f46ed946f20da73a777b5.png 2 |& s  ]% v' X" j/ }0 }

! q' x$ }# ?' _; P7 C2 `* ~图4.4.3.7 注释完毕
! Y' S1 Q0 J/ @# |这样就快速的注释掉了一片代码,而在某些时候,我们又希望这段注释的代码能快速的取消注释,MDK也提供了这个功能。与注释类似,先选中被注释掉的地方,然后通过右键Advanced,不过这里选择的是Uncomment Selection。& v/ X/ `! g/ \) }
/ z7 M6 T' g5 z
4.4.4 其他小技巧
) u8 X6 w4 ^, M# u4 `! [% W除了前面介绍的几个比较常用的技巧,这里还介绍几个其他的小技巧,希望能让你的代码编写如虎添翼。  f0 G2 ]! `; i, c* }
第一个是快速打开头文件。在将光标放到要打开的引用头文件上,然后右键选择Open Document“XXX”,就可以快速打开这个文件了(XXX是你要打开的头文件名字)。如图4.4.4.1所示:& j0 q3 B+ h3 ~. k& t1 L! E
+ {( @1 P4 ^2 n7 r9 ]3 }
99e6962ac7754da3ab09fe42034056a5.png
% J0 b6 w$ A8 w, ~1 ~( n; c1 \6 V                                 图4.4.4.1 快速打开头文件
/ U2 J* s7 ]  F# V6 K9 ?7 X% h# c: Y. M4 }, Q0 N
第二个小技巧是查找替换功能。这个和WORD等很多文档操作的替换功能是差不多的,在MDK里面查找替换的快捷键是“CTRL+H”,只要你按下该按钮就会调出如图4.4.4.2所示界面:
4 O% I5 Y/ _; i: L. S
" Q0 M; Z* c( [; D& }& W efd51e4d6fc04492b2db048bfb506b46.png
% i5 \2 G( F- h2 K  x9 Q: h4 P
- V: y) o$ V& Q4 T' ^2 i8 c( x$ J  @图4.4.4.2 替换文本
4 [9 n% n+ q0 @这个替换的功能在有的时候是很有用的,它的用法与其他编辑工具或编译器的差不多,相信各位都不陌生了,这里就不啰嗦了。
/ J3 _6 ?4 A5 {9 j+ b1 [+ @5 I4 c第三个小技巧是跨文件查找功能,先双击你要找的函数/变量名(这里以系统时钟初始化函数:sys_stm32_clock_init为例),然后再点击IDE上面的,弹出如图4.4.4.3所示对话框:9 g8 R$ U8 T1 Y. @) O5 s4 v  a

- X. h7 u' l3 d, b, m 7892b77fa8524c45bc94ee7c13f2422e.png
2 `4 J$ _: K# n. L7 N$ P: _
9 t6 N' ~* R+ D图4.4.4.3 跨文件查找
2 d+ X$ l, {0 L点击Find All,MDK就会帮你找出所有含有sys_stm32_clock_init字段的文件并列出其所在位置,如图4.4.4.4所示:2 ?6 a' c8 d. _4 A/ w9 ]0 ~
: ~# `$ _7 O1 Y' H0 l3 S3 |7 p# l
8b533236a72c44118ca7c8c155bb7118.png " ^) @) ^! Y" t: [. f9 A

0 W4 H+ z5 D1 s& H  _8 B1 k! ?图4.4.4.4 查找结果4 m2 z% |4 O- B9 g- X1 `
该方法可以很方便的查找各种函数/变量,而且可以限定搜索范围(比如只查找.c文件和.h文件等),是非常实用的一个技巧。6 \$ E% H( Y+ r. {* [  s
————————————————
" g$ r+ X& x* D4 i& e: Y版权声明:正点原子
6 s3 k+ }3 k7 z) g0 Y3 @8 M7 v+ k# C8 Z! h9 d& V

1 {% O  n/ j. i2 A4 A
收藏 评论0 发布时间:2022-10-4 17:56

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版