正点原子stm32mini板型号,STM32F103开发板资料连载
正点原子stm32mini板型号,STM32F103开发板资料连载}UNUSED(tmpreg);__weak void HAL_MspInit(void){__IO uint32_t tmpreg = 0x00;
1)实验平台:【正点原子】 NANO STM32F103 开发板
2)摘自《正点原子STM32 F1 开发指南(NANO 板-HAL 库版)》关注官方微信号公众号,获取更多资料:正点原子
3.3.2.2 HAL 库中__weak 修饰符讲解
在 HAL 库中,很多回调函数前面使用__weak 修饰符,这里我们有必要给大家讲解__weak修饰符的作用。weak 顾名思义是“弱”的意思,所以如果函数名称前面加上__weak 修饰符,我们一般称这个函数为“弱函数”。加上__weak 修饰符的函数,用户可以在用户文件中重新定义一个同名函数,最终编译器编译的时候,会选择用户定义的函数,如果用户没有重新定义这个函数,那么编译器就会执行__weak 声明的函数,并且编译器不会报错。这里我给大家举个例子来加深大家的理解。比如我们打开工程模板,找到并打开文件STM32f1xx_hal.c 文件,里面定义了一个函数 HAL_MsPinit,定义如下:
__weak void HAL_MspInit(void)
{
__IO uint32_t tmpreg = 0x00;
UNUSED(tmpreg);
}
大家可以看出,HAL_MspInit 函数前面有加修饰符__weak。同时,在该文件的前面有定义函数 HAL_Init,并且 HAL_Init 函数中调用了函数 HAL_MspInit。
HAL_StatusTypeDefHAL_Init(void)
{
...//此处省略部分代码
HAL_MspInit();
return HAL_OK;
}
如果我们没有在工程中其他地方重新定义 HAL_MspInit()函数,那么 HAL_Init 初始化函数执行
的时候,会默认执行 stm32f1xx_hal.c 文件中定义的 HAL_MspInit 函数,而这个函数没有任何控
制逻辑。如果用户在工程中重新定义函数 HAL_MspInit,那么调用 HAL_Init 之后,会执行用户
自己的 HAL_MspInit 函数而不会执行 stm32f1xx_hal.c 默认定义的函数。也就是说,表面上我们
看到函数 HAL_MspInit 被定义了两次,但是因为有一次定义是弱函数,使用了__weak 修饰符,
所以编译器不会报错。
__weak 在回调函数的时候经常用到。这样的好处是,系统默认定义了一个空的回调函数,保证
编译器不会报错。同时,如果用户自己要定义用户回调函数,那么只需要重新定义即可,不需
要考虑函数重复定义的问题,使用非常方便,在 HAL 库中__weak 关键字被广泛使用。
3.3.2.3 Msp 回调函数执行过程解读
大家先打开我们前面新建的工程模板,搜索 MspInit 字符串可以发现,在我们的工程模板
文件中,有 50 多个文件定义或者调用了函数名字中包含 MspInit 字符串的函数,而且函数名字
基本基本遵循 HAL_PPP_MspInit 格式(PPP 代表任意外设)。那么这些函数是怎么被程序调用,
又是什么作用呢?下面我们以串口为例进行讲解。
大家打开我们的工程模板 SYSTEM 分组下面的 usart.c 文件可以看到,内部我们定义了两
个函数 uart_init 和 HAL_UART_MspInit。我们先来大致看看这两个函数的定义(基于篇幅考虑
我们省略部分非关键代码行):
void uart_init(u32 bound)
{
//UART 初始化设置
UART1_Handler.Instance=USART1;
//USART1
UART1_Handler.Init.BaudRate=bound;
//波特率
...//此处省略部分串口 1 参数设置代码
UART1_Handler.Init.Mode=UART_MODE_TX_RX;
//收发模式
HAL_UART_Init(&UART1_Handler); //HAL_UART_Init()会使能 UART1
...//此处省略部分串口 1 参数设置代码
}
//UART 底层初始化,时钟使能,引脚配置,中断配置
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
...//此处省略部分代码
GPIO_Initure.Pin=GPIO_PIN_9;
//PA9
GPIO_Initure.Mode=GPIO_MODE_AF_PP;
//复用推挽输出
GPIO_Initure.Pull=GPIO_PULLUP;
//上拉
GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;//高速
HAL_GPIO_Init(GPIOA &GPIO_Initure); //初始化 PA9
GPIO_Initure.Pin=GPIO_PIN_10;
//PA10
GPIO_Initure.Mode=GPIO_MODE_AF_INPUT;//模式要设置为复用输入模式!
HAL_GPIO_Init(GPIOA &GPIO_Initure); //初始化 PA10
...//此处省略部分代码
}
用户函数 uart_init 主要作用是设置串口 1 相关参数,包括波特率,停止位,奇偶校验位等,并
且最终是通过调用 HAL_UART_Init 函数进行参数设置。而函数 HAL_UART_MspInit 则主要进
行串口 GPIO 引脚初始化设置。接下来我们打开 usart_init 函数内部调用的 UART 初始化函数
HAL_UART_Init 可以看到代码如下:
HAL_StatusTypeDefHAL_UART_Init(UART_HandleTypedef*huart)
{
...//此处省略部分代码
if(huart->State == HAL_UART_STATE_RESET)//如果串口没有进行过初始化
{
huart->Lock = HAL_UNLOCKED;
HAL_UART_MspInit(huart);
}
...//此处省略部分代码
Return HAL_OK;
}
在函数 HAL_UART_Init 内部,通过判断逻辑判断如果串口还没有进行初始化,那么会调
用函数 HAL_UART_MspInit 进 行 相 关 初 始 化 设 置 。 同 时 , 我 们 可 以 看 到 , 在 文 件
stm32f1xx_hal_uart.c 内部,有定义一个弱函数 HAL_UART_MspInit,内容如下:
__weak void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
UNUSED(huart);
}
这里定义的弱函数 HAL_UART_MspInit 是一个空函数,没有任何实际的控制逻辑。根据前
面的讲解可知,__weak 修饰符定义的弱函数如果用户自己重新定义了这个函数,那么会优先执
行用户定义函数。所以,实际上在函数 HAL_UART_Init 内部调用的 HAL_UART_MspInit()函数,
最终执行的是用户在 usart.c 中自定义的 HAL_UART_MspInit()函数。
那 么 整 个 串 口 初 始 化 的 过 程 为 : 用 户 函 数
usart_init->
HAL_UART_Init->HAL_UART_MspInit。学到这里的同学会问,为什么串口相关初始化不在
HAL_UART_Init 函数内部一次初始化而还要调用函数 HAL_UART_MspInit()呢?这实际就是
HAL 库的一个优点,他通过开放一个回调函数 HAL_UART_MspInit(),让用户自己去编写与串
口相关的 MCU 级别的硬件初始化,而与 MCU 无关的串口参数相关的通用配置则放在
HAL_UART_Init。
我们要初始化一个串口,首先要设置和 MCU 无关的东西,例如波特率,奇偶校验,停止
位等,这些参数设置和 MCU 没有任何关系,可以使用 STM32F1,也可以是 STM32F2/F3/F4/F7
上的串口。而一个串口设备它需要一个 MCU 的承载,例如用 STM32F4 来做承载,PA9 做为发
送,PA10 做为接收,MSP 就是要初始化 STM32F4 的 PA9,PA10,配置这两个引脚。所以 HAL
驱动方式的初始化流程就是:HAL_USART_Init()->HAL_USART_MspInit(),先初始化与 MCU
无关的串口协议,再初始化与 MCU 相关的串口引脚。在 STM32 的 HAL 驱动中
HAL_PPP_MspInit()作为回调,被 HAL_PPP_Init()函数调用。当我们需要移植程序到 STM32F1
平台的时候,我们只需要修改 HAL_PPP_MspInit 函数内容而不需要修改 HAL_PPP_Init 入口参
数内容。
在 STM32 的 HAL 库中,大部分外设都有回调函数 HAL_MspInit,通过对本小节学习,大
家对这些回调函数的作用和调用过程会非常熟悉,这里我们就不做一一列举。
3.3.2.4 程序执行流程图
经过前面的讲解,大家对工程模板以及关键文件有了比较详细的了解。接下来我们看看程
序执行流程如下图 3.3.2.4.1 所示:
图 3.3.2.4.1 程序执行流程
从该流程图可以非常清晰的理解整个程序执行流程,这里我们略微讲解一下。启动文件
startup_stm32f103xb.s 中 Rest_Handler 部分会引导先执行 SystemInit 函数,然后再进入 main 函
数。在 main 函数内部,一般情况下,我们会把 HAL 初始化函数 HAL_Init 放在最开头部分,然
后再进行时钟初始化设置。这些设置完成之后,接下来便是调用外设初始化函数 HAL_PPP_Init
进行外设参数初始化设置,同时重写回调函数 HAL_PPP_MspInit 进行外设 MCU 相关的参数设
置。最后编写我们的控制逻辑。关于程序执行流程我们就给大家介绍到这里。
3.4 程序下载与调试
上一节,我们学会了如何在 MDK 下创建 STM32F1 工程。本节,我们将向读者介绍 STM32F1
的代码下载以及调试。包括了程序下载、软件仿真和硬件调试(在线调试)。通过本章的学习,
你将了解到:1、STM32F1 软件仿真;2、STM32F1 程序下载;3、STM32F1 硬件调试;
3.4.1 STM32 软件仿真
MDK 的一个强大的功能就是提供软件仿真(注意:STM32F4 不支持软件仿真),通过软
件仿真,我们可以发现很多将要出现的问题,避免了下载到 STM32 里面来查这些错误,这样
最大的好处是能很方便的检查程序存在的问题,因为在 MDK 的仿真下面,你可以查看很多硬
件相关的寄存器,通过观察这些寄存器,你可以知道代码是不是真正有效。另外一个优点是不
必频繁的刷机,从而延长了 STM32 的 FLASH 寿命(STM32 的 FLASH 寿命≥1W 次)。当然,
软件仿真不是万能的,很多问题还是要到在线调试才能发现。废话不多说了,接下来我们开始
进行软件仿真。
上一章,我们创立了一个工程模板,本节我们将教大家如何在 MDK5 的软件环境下仿真这
个工程,以验证我们代码的正确性。首先工程模板中 main.c 中代码修如下:
#include "sys.h"
#include "delay.h"
#include "usart.h"
int main(void)
{
u8 t=0;
HAL_Init(); //初始化 HAL 库
Stm32_Clock_Init(RCC_PLL_MUL9); //设置时钟 72M
delay_init(72); //初始化延时函数
uart_init(115200); //初始化 USART
while(1)
{
printf("t:%d\n" t);
delay_ms(500);
t ;
}
}
注意:上面这段代码大家可以打开光盘的工程:“实验 0-2 Template 工程模板-调试章节使用”,从 main.c 文件中复制过来即可。
在开始软件仿真之前,先检查一下配置是不是正确,在 IDE 里面点击
,确定 Target 选
项卡内容如图 3.4.1.1 所示(主要检查芯片型号和晶振频率,其他的一般默认就可以):
图 3.4.1.1 Target 选项卡
确认了芯片以及外部晶振频率(8.0Mhz)之后,基本上就确定了 MDK5.23 软件仿真的硬
件环境了,接下来,我们再点击 Debug 选项卡,设置为如图 3.4.1.2 所示:
图 3.4.1.2 Debug 选项卡
在图 3.4.1.2 中,选择:Use Simulator,即使用软件仿真。选择:Run to main(),即跳过汇
编代码,直接跳转到 main 函数开始仿真。设置下方的:Dialog DLL 分别为:DARMSTM.DLL
和 TARMSTM.DLL,Parameter 均为:-pSTM32F103RB,用于设置支持 STM32F103RB 的软
硬件仿真(即可以通过 Peripherals 选择对应外设的对话框观察仿真结果)。最后点击 OK,完
成设置。
接下来,我们点击
(开始/停止仿真按钮),开始仿真(这里大家要注意,仿真之前,
请先编译一下工程),出现如图 3.4.1.3 所示界面:
图 3.4.1.3 开始仿真
可以发现,多出了一个工具条,这就是 Debug 工具条,这个工具条在我们仿真的时候是非
常有用的,下面简单介绍一下 Debug 工具条相关按钮的功能。Debug 工具条部分按钮的功能如
图 3.4.1.4 所示:
图 3.4.1.4 Debug 工具条
复位:其功能等同于硬件上按复位按钮。相当于实现了一次硬复位。按下该按钮之后,代
码会重新从头开始执行。
执行到断点处:该按钮用来快速执行到断点处,有时候你并不需要观看每步是怎么执行的,
而是想快速的执行到程序的某个地方看结果,这个按钮就可以实现这样的功能,前提是你在查
看的地方设置了断点。
挂起:此按钮在程序一直执行的时候会变为有效,通过按该按钮,就可以使程序停止下来,进入到单步调试状态。
执行进去:该按钮用来实现执行到某个函数里面去的功能,在没有函数的情况下,是等同
于执行过去按钮的。
执行过去:在碰到有函数的地方,通过该按钮就可以单步执行过这个函数,而不进入这个
函数单步执行。
执行出去:该按钮是在进入了函数单步调试的时候,有时候你可能不必再执行该函数的剩
余部分了,通过该按钮就直接一步执行完函数余下的部分,并跳出函数,回到函数被调用的位
置。
执行到光标处:该按钮可以迅速的使程序运行到光标处,其实是挺像执行到断点处按钮功
能,但是两者是有区别的,断点可以有多个,但是光标所在处只有一个。
汇编窗口:通过该按钮,就可以查看汇编代码,这对分析程序很有用。
观看变量/堆栈窗口:该按钮按下,会弹出一个显示变量的窗口,在里面可以查看各种你想
要看的变量值,也是很常用的一个调试窗口。
串口打印窗口:该按钮按下,会弹出一个类似串口调试助手界面的窗口,用来显示从串口
打印出来的内容。
内存查看窗口:该按钮按下,会弹出一个内存查看窗口,可以在里面输入你要查看的内存
地址,然后观察这一片内存的变化情况。是很常用的一个调试窗口
性能分析窗口:按下该按钮,会弹出一个观看各个函数执行时间和所占百分比的窗口,用
来分析函数的性能是比较有用的。
逻辑分析窗口:按下该按钮会弹出一个逻辑分析窗口,通过 SETUP 按钮新建一些 IO 口,
就可以观察这些 IO 口的电平变化情况,以多种形式显示出来,比较直观。
Debug 工具条上的其他几个按钮用的比较少,我们这里就不介绍了。以上介绍的是比较常
用的,当然也不是每次都用得着这么多,具体看你程序调试的时候有没有必要观看这些东西,
来决定要不要看。
这样,我们在上面的仿真界面里面选内存查看窗口、串口打印窗口。然后调节一下这两个
窗口的位置,如图 3.4.1.5 所示:
图 3.4.1.5 调出仿真串口打印窗口
我们把光标放到 main.c 的 25 行的空白处,然后双击鼠标左键,可以看到在 25 行的左边出
现了一个红框,即表示设置了一个断点(也可以通过鼠标右键弹出菜单来加入),再次双击则
取消)。然后我们点击
,执行到该断点处,如图 3.4.1.6 所示:
图 3.4.1.6 执行到断点处
我们现在先不忙着往下执行,点击菜单栏的 Peripherals->USARTs->USART 1。可以看到,
有很多外设可以查看,这里我们查看的是串口 1 的情况。如图 3.4.1.7 所示:
图 3.4.1.7 查看串口 1 相关寄存器
单击 USART1 后会在 IDE 之外出现一个如图 3.4.1.8(a)所示的界面:
图 3.4.1.8 串口 1 各寄存器初始化前后对比
图 3.4.8(a)是 STM32 的串口 1 的默认设置状态,从中可以看到所有与串口相关的寄存器
全部在这上面表示出来了,而且有当前串口的波特率等信息的显示。我们接着单击一下
,
执行完串口初始化函数,得到了如图 3.4.8(b)所示的串口信息。大家可以对比一下这两个图
的区别,就知道在 uart_init(115200)这个函数里面大概执行了哪些操作。
通过图 3.4.8(b),我们可以查看串口 1 的各个寄存器设置状态,从而判断我们写的代码
是否有问题,只有这里的设置正确了之后,才有可能在硬件上正确的执行。同样这样的方法也
可以适用于很多其他外设,这个读者慢慢体会吧!这一方法不论是在排错还是在编写代码的时
候,都是非常有用的。
然后我们继续单击
按钮,一步步执行,最后就会看到在 USART #1 中打印出相关的信
息,如图 3.4.1.9 所示:
图 3.4.1.9 串口 1 输出信息
图中红色方框内的数据是串口 1 打印出来的,证明我们的仿真是通过的,代码运行时会在
串口 1 不停的输出 t 的值,每 0.5s 执行一次。软件仿真的时间可以在 IDE 的最下面(右下角)
观看到,如图 3.4.1.10 所示。并且 t 自增,与我们预期的一致。再次按下
结束仿真。
图 3.4.1.10 仿真持续时间
至此,我们软件仿真就结束了,通过软件仿真,我们在 MDK5 中验证了代码的正确性,接
下来我们下载代码到硬件上来真正验证一下我们的代码是否在硬件上也是可行的。
3.4.2 ST_LINK 仿真器驱动安装
STM32F103 的程序下载有多种方法:USB、串口、JTAG、SWD 等,这几种方式,都可以
用来给 STM32F103 下载代码。NANO 板板载了 ST_LINK V2.1 版的仿真器,不用外接仿真器
即可下载仿真使用,十分的方便。
本节,我们将向大家介绍,板载的 ST_LINK 仿真器驱动的安装。
仿真器的 USB 口在 USB_JTAG 口,连接好 USB 口,首次上电,会提示安装 ST_LINK 驱
动,如图 3.4.2.1 所示
图 3.4.2.1 安装驱动
若之前电脑是没有安装过 ST_LINK 驱动,这时,会提示安装失败,如图 3.4.2.2 所示:
图 3.4.2.2 驱动安装失败
打开光盘资料找到 5,软件资料->1,软件-> ST LINK 驱动及教程->ST LINK 驱动,解压
ST-LINK 官方驱动压缩包,打开后如图 3.4.2.3 所示:
图 3.4.2.3 官方驱动
根据自己的电脑是 32 位、还是 64 位,选择对应驱动的安装。
点击驱动安装,会弹出框,我们选择“下一步”,这时会提示是否安装驱动,我们点击安装,如图 3.4.2.4 所示:
图 3.4.2.4 安装驱动
安装过程会有点久,请耐性等待。安装完成后,会弹出框提示安装成功,如图 3.4.2.5 所示:
图 3.4.2.5 安装完成
安装成功后,我们重新上电 NANO 板,这时任务栏弹出 ST_LINK 成功安装好驱动,如图
3.4.2.6-1 所示,设备管理器显示,如图 3.4.2.6-2 所示:
图 3.4.2.6-1 安装成功
图 3.4.2.6-2 设备管理器显示 STLink dongle
细心的你会发现,当我们 USB 连接 USB_JTAG 口,无论 SW1 选择开关往“左拨”或“右
拨”(SW1 开关在后面会讲解),首次上电时,电脑会识别到 U 盘,如图 3.4.2.7 所示:
图 3.4.2.7 U 盘识别
我们往 U 盘存放文件是不行的,识别出 U 盘是 ST_LINK 的固件功能,我们无需管它,直
接正常使用就可以了。
在前面我们也有介绍过,该仿真器除了有下载和仿真的功能外,还能支持虚拟串口的功能,
这里我们打开 XCOM 2.0 串口调试助手(XCOM V2.0,在光盘→6,软件资料→软件→串口调
试助手里面),串口助手会识别到仿真器的虚拟串口,如图 3.4.2.8 所示:
在设备管理器会显示已安装虚拟串口驱动,如图 3.4.2.9 所示:
图 3.4.2.9 USB 虚拟串口
在图 3.4.2.9 中可以看到,我们的 USB 虚拟串口被识别为 COM56,这里需要注意的是:不
同电脑可能不一样,你的可能是 COM4、COM5 等,但是 STLink Virtual COM Port,这个一定
是一样的。
仿真器的虚拟串口 TXD 和 RXD,是通过开发板的 P3 座子跳线帽短接 PA10 和 PA9,与STM32F103RBT6 串口通信时,P3 必须短接好,以免造成串口通信不正常,P3 座子如图 3.4.2.10
所示
图 3.4.2.10 P3 座子
SW1 选择开关是用作切换仿真器的内部或外部使用,往左拨(INS)则对 STM32F103RBT6
芯片进行使用,往右拨(EXT)则对外部使用。注意:SW1 开关必须在上电前选择好。SW1
开关如图 3.4.2.11 所示:
图 3.4.2.11 SW1 开关
当 SW1 开关往右拨(EXT),使用开发板留出的 P4 排针连接外部的 MCU 就可以使用了,
P4 排针 5P 的 SWD 接口如图 3.4.2.12 所示:
图 3.4.2.12 SWD 接口
3.4.3 STM32F1 程序下载和调试
上一节,我们讲解了开发板的 ST_LINK 驱动的安装,这节中我们将讲解,STM32 下载代
码和硬件调试。
1)STM32 下载代码
打开刚刚软件仿真的工程,点击
,打开 Options for Target 选项卡,在 Dubeg 栏选择仿真
工具为 Use:ST-Link Debugger,如图 3.4.3.1 所示:
图 3.4.3.1 Dubeg 选项卡设置
然后我们点击 Setting,在 Debug Adapter 的 Unit 选项中会看到 ST-LINK 的版本号,若电脑
同时插了 ST_LINK V2.0 和 V2.1 版本的仿真器时,下拉框会显示两个版本,这里我们需选择
ST-LINK/V2-1 选项,由于仿真器是 SWD 模式,在 ort 选项中选择“SW”,最大速度 Max 设
置为 4Mhz,如图 3.4.3.2 所示:
图 3.4.3.2 ST_LINK 模式设置
点击确定,完成此部分配置,接下来我们还需要在 Utilities 选项卡里面设置下载时的目标编程器,如图 3.4.3.3 所示:
图 3.4.3.3 FLASH 编程器选择
图 3.4.3.3 中,我们直接勾选 Use Debug Driver,选择 ST_LINK V2.1 来给目标器件的 FLASH
编程,然后点击 Settings,进入 FLASH 算法设置,设置如图 3.4.3.4 所示:
图 3.4.3.4 FLASH 算法设置
这里 MDK5 会根据我们新建工程时选择的目标器件,自动设置 flash 算法。我们使用的是
STM32F103RBT6,FLASH 容量为 128K 字节,所以 Programming Algorithm 里面默认会有 128K
型号的 STM32F10x Med-density Flash 算法。另外,如果这里没有 flash 算法,大家可以点击 Add
按钮,自行添加即可。最后,选中 Reset and Run 选项,以实现在编程后自动运行,其他默认设
置即可。设置完成之后,如图 3.4.3.4 所示。
在设置完之后,点击确定,然后再点击 OK,回到 IDE 界面,编译一下工程。然后点击:
(下载按钮),这时 IDE 会提示正在下载,左下角会显示下载进度,如图 3.4.3.5 所示:
图 3.4.3.5 程序正在下载
下载完成后,我们打开刚刚说的 XCOM 串口调试助手,选择 COM56 虚拟串口(得根据你
的实际情况选择),设置波特率为:115200,会发现从 ALIENTEK NANO STM32F103 发回来
的信息,如图 3.4.3.6 所示:
图 4.3.1.6 程序开始运行
接收到的数据和我们期望的是一样的,证明程序没有问题。至此,说明我们下载代码成功
了,并且从硬件上验证了我们代码的正确性。
2)STM32 硬件仿真
接下来我们将讲解使用 ST-LINK 通过 SWD 实现程序在线调试的方法。这里,我们只需要
点击
图标就可以开始对 STM32 进行仿真(特别注意:开发板上的 B0 要设置到 GND,否则
代码下载后不会自动运行的!),如图 4.3.1.7 所示:
图 4.3.1.7 开始仿真
因为我们之前勾选了 Run to main()选项,所以,程序直接就运行到了 main 函数的入口处,
我们在 uart_init()处设置了一个断点,点击程序将会快速执行到该处。如图 4.3.1.8 所示:
图 4.3.1.8 程序运行到断点处
接下来,我们就可以和 3.4.1 小节详解的软件仿真一样的方法开始操作了,不过这是真正的
在硬件上的运行,而不是软件仿真,其结果更可信。SWD 硬件调试就给大家介绍到这里。
3.5 MDK5 使用技巧
通过前面的学习,我们已经了解了如何在 MDK5 里面建立属于自己的工程。下面,我们将
向大家介绍 MDK5 软件的一些使用技巧,这些技巧在代码编辑和编写方面会非常有用,希望大
家好好掌握,最好实际操作一下,加深印象。
3.5.1 文本美化
文本美化,主要是设置一些关键字、注释、数字等的颜色和字体。MDK 提供了我们自定
义字体颜色的功能。我们可以在工具条上点击
(配置对话框)弹出如图 3.5.1.1 所示界面:
图 3.5.1.1 置对话框
在该对话框中,先设置 Encoding 为:Chinese GB2312(Simplified),然后设置 Tab size 为:4。
以更好的支持简体中文(否则,拷贝到其他地方的时候,中文可能是一堆的问号),同时 TAB
间隔设置为 4 个单位。然后,选择:Colors&Fonts 选项卡,在该选项卡内,我们就可以设置自
己的代码的子体和颜色了。由于我们使用的是 C 语言,故在 Window 下面选择:C/C Editor Files
在右边就可以看到相应的元素了。如图 3.5.1.2 示:
图 3.5.1.2 Colors&Fonts 选项卡
然后点击各个元素修改为你喜欢的颜色(注意双击,且有时候可能需要设置多次才生效,
MDK 的 bug),当然也可以在 Font 栏设置你字体的类型,以及字体的大小等。设置成之后,
点击 OK,就可以在主界面看到你所修改后的结果,例如我修改后的代码显示效果如图 3.5.1.3
示,代码中的数字全部修改为红色:
图 3.5.1.3 设置完后显示效果
这就比开始的效果好看一些了。字体大小,则可以直接按住:ctrl 鼠标滚轮,进行放大或
者缩小,或者也可以在刚刚的配置界面设置字体大小。
细心的读者可能会发现,上面的代码里面有一个 u8,还是黑色的,这是一个用户自定义的
关键字,为什么不显示蓝色(假定刚刚已经设置了用户自定义关键字颜色为蓝色)呢?这就又
要回到我们刚刚的配置对话框了,单这次我们要选择 User Keywords 选项卡,同样选择:C/C
Editor Files,在右边的 User Keywords 对话框下面输入你自己定义的关键字,如图 3.5.1.4 示:
图 3.5.1.4 用户自定义关键字
图 3.5.1.4 中我定义了 u8、u16、u32 等 3 个关键字,这样在以后的代码编辑里面只要出现
这三个关键字,肯定就会变成蓝色。点击 OK,再回到主界面,可以看到 u8 变成了蓝色了,如图 3.5.1.5 示:
图 3.5.1.5 设置完后显示效果
其实这个编辑配置对话框里面,还可以对其他很多功能进行设置,比如动态语法检测等,
我们将 3.5.2 节介绍。
3.5.2 语法检测&代码提示
MDK4.70 以上的版本,新增了代码提示与动态语法检测功能,使得 MDK 的编辑器越来越
好用了,这里我们简单说一下如何设置,同样,点击
,打开配置对话框,选择 Text Completion
选项卡,如图 3.5.2.1 所示:
图 3.5.2.1 Text Completion 选项卡设置
Strut/Class Members,用于开启结构体/类成员提示功能。
Function Parameters,用于开启函数参数提示功能。
Symbols after xx characters,用于开启代码提示功能,即在输入多少个字符以后,提示匹配
的内容(比如函数名字、结构体名字、变量名字等),这里默认设置 3 个字符以后,就开始提
示。如图 3.5.2.2 所示:
图 3.5.2.2 代码提示
Dynamic Syntax Checking,则用于开启动态语法检测,比如编写的代码存在语法错误的时候,会在对应行前面出现 图标,如出现警告,则会出现
图标,将鼠标光标放图标上面,则
会提示产生的错误/警告的原因,如图 3.5.2.3 所示:
图 3.5.2.3 语法动态检测功能
这几个功能,对我们编写代码很有帮助,可以加快代码编写速度,并且及时发现各种问题。
不过这里要提醒大家,语法动态检测这个功能,有的时候会误报(比如 sys.c 里面,就有很多
误报),大家可以不用理会,只要能编译通过(0 错误,0 警告),这样的语法误报,一般直
接忽略即可。
3.5.3 代码编辑技巧
这里给大家介绍几个我常用的技巧,这些小技巧能给我们的代码编辑带来很大的方便,相
信对你的代码编写一定会有所帮助。
1)TAB 键的妙用
首先要介绍的就是 TAB 键的使用,这个键在很多编译器里面都是用来空位的,每按一下移
空几个位。如果你是经常编写程序的对这个键一定再熟悉不过了。但是 MDK 的 TAB 键和一般
编译器的 TAB 键有不同的地方,和 C 的 TAB 键差不多。MDK 的 TAB 键支持块操作。也就
是可以让一片代码整体右移固定的几个位,也可以通过 SHIFT TAB 键整体左移固定的几个位。
假设我们前面的串口 1 中断响应函数如图 3. 5.3.1 所示:
图 3. 5.3.1 头大的代码
图 3. 5.3.1 中这样的代码大家肯定不会喜欢,这还只是短短的 30 来行代码,如果你的代码
有几千行,全部是这个样子,不头大才怪。看到这样的代码我们就可以通过 TAB 键的妙用来快
速修改为比较规范的代码格式。
选中一块然后按 TAB 键,你可以看到整块代码都跟着右移了一定距离,如图 3. 5.3.2 所示:
图 3. 5.3.2 代码整体偏移
接下来我们就是要多选几次,然后多按几次 TAB 键就可以达到迅速使代码规范化的目的,
最终效果如图 3. 5.3.3 所示
图 3. 5.3.3 修改后的代码
图 3. 5.3.3 中的代码相对于图 3. 5.3.1 中的要好看多了,经过这样的整理之后,整个代码一
下就变得有条理多了,看起来很舒服。
2) 快速定位函数/变量被定义的地方
上一节,我们介绍了 TAB 键的功能,接下来我们介绍一下如何快速查看一个函数或者变量
所定义的地方。
大家在调试代码或编写代码的时候,一定有想看看某个函数是在那个地方定义的,具体里
面的内容是怎么样的,也可能想看看某个变量或数组是在哪个地方定义的等。尤其在调试代码
或者看别人代码的时候,如果编译器没有快速定位的功能的时候,你只能慢慢的自己找,代码
量比较少还好,如果代码量一大,那就郁闷了,有时候要花很久的时间来找这个函数到底在哪
里。型号 MDK 提供了这样的快速定位的功能(顺便说一下 CVAVR 的 2.0 以后的版本也有这个
功能)。只要你把光标放到这个函数/变量(xxx)的上面(xxx 为你想要查看的函数或变量的
名字),然后右键,弹出如图 3.5.3.4 所示的菜单栏 :
图 3.5.3.4 快速定位
在图 3.5.3.4 中,我们找到 Go to Definition Of‘delay_init’ 这个地方,然后单击左键就可
以快速跳到 delay_init 函数的定义处(注意要先在 Options for Target 的 Output 选项卡里面勾选
Browse Information 选项,再编译,再定位,否则无法定位!)。如图 3.5.3.5 所示:
图 3.5.3.5 定位结果
对于变量,我们也可以按这样的操作快速来定位这个变量被定义的地方,大大缩短了你查
找代码的时间。细心的大家会发现上面还有一个类似的选项,就是 Go to Reference To
‘delay_init’,这个是快速跳到该函数被声明的地方,有时候也会用到,但不如前者使用得多。
很多时候,我们利用 Go to Definition/ Reference 看完函数/变量的定义/申明后,又想返回之
前的代码继续看,此时我们可以通过 IDE 上的
按钮(Back to previous position)快速的返回
之前的位置,这个按钮非常好用!
3) 快速注释与快速消注释
接下来,我们介绍一下快速注释与快速消注释的方法。在调试代码的时候,你可能会想注
释某一片的代码,来看看执行的情况,MDK 提供了这样的快速注释/消注释块代码的功能。也
是通过右键实现的。这个操作比较简单,就是先选中你要注释的代码区,然后右键,选择
Advanced->Comment Selection 就可以了。
以 delay_init 函数为例,比如我要注释掉下图中所选中区域的代码,如图 3. 5.3.6 所示:
图 3. 5.3.6 选中要注释的区域
我们只要在选中了之后,选择右键,再选择 Advanced->Comment Selection 就可以把这段代
码注释掉了。执行这个操作以后的结果如图 3.5.3.7 所示:
图 3. 5.3.7 注释完毕
这样就快速的注释掉了一片代码,而在某些时候,我们又希望这段注释的代码能快速的取
消注释,MDK 也提供了这个功能。与注释类似,先选中被注释掉的地方,然后通过右键->Advanced,不过这里选择的是 Uncomment Selection。
3.5.4 其他小技巧
除了前面介绍的几个比较常用的技巧,这里还介绍几个其他的小技巧,希望能让你的代码
编写如虎添翼。
第一个是快速打开头文件。在将光标放到要打开的引用头文件上,然后右键选择 Open
Document“XXX”,就可以快速打开这个文件了(XXX 是你要打开的头文件名字)。如图 3. 5.4.1
所示:
图 3.5.4.1 快速打开头文件
第二个小技巧是查找替换功能。这个和 WORD 等很多文档操作的替换功能是差不多的,
在 MDK 里面查找替换的快捷键是“CTRL H”,只要你按下该按钮就会调出如图 3.5.4.2 所示
界面:
图 3.5.4.2 替换文本
这个替换的功能在有的时候是很有用的,它的用法与其他编辑工具或编译器的差不多,相
信各位都不陌生了,这里就不在啰唆了。
第三个小技巧是跨文件查找功能,先双击你要找的函数/变量名(这里我们还是以系统时钟初始化函数:delay_init 为例),然后再点击 IDE 上面的
,弹出如图 3.5.4.3 所示对话框:
图 3.5.4.3 跨文件查找
点击 Find All,MDK 就会帮你找出所有含有 delay_init 字段的文件并列出其所在位置,如
图 3.5.4.4 所示:
图 3.5.4.4 查找结果
该方法可以很方便的查找各种函数/变量,而且可以限定搜索范围(比如只查找.c 文件和.h
文件等),是非常实用的一个技巧。