一、Keil5 背景主题安装
keil5背景主题在网上有很多,直接从网上下载,安装方法如下:
- 找到安装Keil路径(X:\Keil_v5\UV4);
- 在UV4目录下的global.prop文件;
- 将网上下载的.prop文件覆盖原有文件,建议覆盖前备份原文件。
当然也可以细点配制出自己想要的风格(我比较懒),详细的配色方法可以参照这位博主:Keil软件配置
二、Configuration配置
在工具栏中找到小扳手图标或者在菜单栏中打开 Edit-Configuration
,大多数功能都在这改。
2.1 缩进和编码设置
如下图设置将编码格式设置为国标,Tab固定缩进为4格
- ASCII编码:一个英文字母(不分大小写)占一个字节的空间,一个中文汉字占两个字节的空间。一个二进制数字序列,在计算机中作为一个数字单元,一般为8位二进制数,换算为十进制。最小值0,最大值255。
- UTF-8编码:一个英文字符等于一个字节,一个中文(含繁体)等于三个字节。
- Unicode编码:一个英文等于两个字节,一个中文(含繁体)等于两个字节。
符号:英文标点占一个字节,中文标点占两个字节。举例:英文句号“.”占1个字节的大小,中文句号“。”占2个字节的大小。 - GBK编码:方式是中文占两个字节,英文占1个字节。
从上面可知,假如是做嵌入式前端界面时,不要采用我们编程通用的 UTF-8格式,因为它的中文储存字节相对更大。前端界面要储存较多的汉字字库等,因此界面不会采用UTF-8编码格式。
2.2 代码自动补全
进入Text Completion
,勾选如下图并填入你需要在输入第几个字符后开启补全提示。
2.3 快捷键的设置
查询某句代码时候,往往会使用ctrl+F
跳到Find
选项进行查询,如下图所示
Look in:
有两个选项:
1)Current Document
只查询当前文档
2)Current Project
查询整个工程Find
选项,查询到的时候,是要一直点击next查看下一个的;而Find in Files
则是可以在下面列出一个所有能查询到的列表,实际上更常用的是这个(每次都要动下鼠标改成Find in Files
)。
因此,在Configuration找到Shortcut Keys选项
1)将Edit:Find
快捷键去掉,将Edit:Find in Files
快捷键补上ctrl+F
;
2)顺便加一下注释的快捷键 Edit:Advanced :Comment Selection
和Edit:Advanced :Uncomment Selection
为ctrl+shift+ c|v
(个人喜好);
3)顺便将Edit:Advanceed:Go toDefinition of current Word
设置为ctrl+d
,这样后面进入具体参数位置就ctrl+d
或F12
都可以用。
2.4 快速浏览 .c文件的函数位置
先在view
选项把基本没用的books
和Templates
功能给隐藏掉。如下图所示
然后进入在Configuration
找到Scan funtion names in project files
给关掉
关掉它有什么好处呢?我们可以在Project
旁边的{}Functions
只会显示你在右边的框打开的.c文件,然后 你就可以.c文件打开查看函数,假如没有关掉它的话,它会把项目所有的 .c和.h文件都放出来,到时候别说找函数了,你可能连 .c文件都找不到。
三、Options for Target配置
这里讲下Options for Target配置里面需要注意的内容
3.1 Target选项
Target界面主要分为两块
3.1.1 FPU浮点处理器
基于Cortex-m4(例如:STM32F407)最大的特色就是加入了一个FPU浮点处理器,能支持DSP运算。更高版本的甚至能够支持double类型处理(例如:STMH7)。
如果只是写裸机程序的话,就无需在意;
假如是写实时操作系统(例如UCOSIII)需要注意的是:UCOS III官方的移植版本竟然不支持FPU浮点运算;如果在MDK的设置选项中,使能FPU
, 运行的时候会出现奇怪的错误,有时候直接跑飞(例如:程序如果进行打印浮点型数据就会进入硬件错误;甚至有时候程序量大的时候,一编译,你根本不知道bug在哪?而且还会报错)。逐步调试会发现:只要运行打印浮点数就会程序跳转到硬件fault;
1)可能是字节对齐问题,修改字节对齐即可解决问题;
2)或者你移植的RTOS本来就不支持,需要修改底层配置函数;
解决方法:ucosii中调用Printf打印浮点型数据就进入硬件错误,STM32F4
个人建议:移植UcosIII的时候,程序运行暂时先不启用FPU,等到程序跑得稳定、需要优化的时候,再启用FPU,明确不是原有程序版本带有的bug。
3.1.2 IROM
如果不涉及bootloader在线升级的情况下,采用一般的例程的配置IROM
即可;倘若涉及到,可详细看这篇博文:STM32开发
3.2 Output
Browse Information
选项是可以查看函数具体内容和位置;但是这里有点经验,就是当你编译类似stm32H7系列那种大容量RAM的芯片的时候,往往它自带的库也是很大,里面有很多函数要编译;当你编译工程的时候,那速度你会怀疑人生,这个时候你可以关闭这个选项,可以大大减少你需要的编译时间,但是缺点是不能跳转函数,可以用ctrl+F
替代找到你要的函数位置。
Create HEX File
选项,是生成hex文件
烧录程序方式分为两种:
1) .bin
文件进行烧录
2) .hex
文件进行烧录
我们常用的串口、J-link(SW模式,直接在项目工程)烧录程序进芯片,均是采用hex文件;.bin
文件只会在脱机烧录和在线升级的时候才会用到。
更多相关.bin
文件和.hex
文件知识,可详细看这篇博文的bootloader章节:STM32开发
3.3 User
这里是运行keil脚本的地方,是要在编译前调用执行脚本,还是编译后调用执行脚本。如 *3.2 Output *所示,Output选项
中只有生成.hex
文件,没有生成.bin
文件的选项;一般情况下,就有人在 编译后选项 里调用keil自带的脚本fromelf.exe
,用于生成.bin
文件。
由于每个人的电脑的Keil安装路径不同,因此别人安装的脚本位置也就不同;有时候你编译别人的代码,会出现非代码的Error:显示你找不到对应路径的fromelf.exe
;这个就是找(错)不到脚本位置而报错,这个时候可以将上图红色地方选项,勾选给取消掉就可以用了,当需要对应的bin文件再进行更改具体路径即可。
3.4 C/C++
3.4.1 芯片库选择
Stm32芯片型号移植的时候,最重要的就是这个位置;在这里举例一下F10x系列
至于要使用哪个宏,则需要根据具体的芯片来进行选择。如果是STM32F105xx和STM32F107xx,是Connectivity Line Devices,则宏定义选择的是STM32F10X_CL;如果是别的型号,则根据FLASH的容量来进行选择。可能文字写的有点不太清楚,还是以表格来说明:
宏定义更换的时候,也好同时把启动文件给换掉,例如:startup_stm32f10x_hd.s修改为startup_stm32f10x_md.s
Ps:其实到这里基本移植完了,不过有时候会出现程序跑的非常慢,有些工程在汇编底层启动文件调用Systeminit()
;再跳转到main()
,有些则无配置时钟树,这个时候在系统初始化时调用 SystemInit();
,后面就正常了
3.4.2 优化等级
在上图所示,中间有一个Optimization
选项,是对程序优化的等级;一般我们调试的时候,采用最低的Level 0
,因为如果我们进行仿真调试,优化等级太高,程序无法跳转运行到设置的断点;当程序调试稳定后,再根据需求提高其代码优化等级即可。
四、技巧用法
这里讲一些自己在用的实用小技巧
4.1 仿真精确测量代码运行时间
为什么需要精确测量代码运行时间?其实往往之所以需要其精确的运行时间,主要分为两种情况:
- 上电初始化,某些芯片模块本身的器件性质,导致MCU不能上电立马 初始化(通信进行软件配置)该芯片;根据初始化函数放的位置,MCU初始化的指令执行够快,上电快速与其芯片立马通讯后,导致会出现不可预知且随机的bug;并且这种bug是隐性的,如果你其他的功能所需的初始化时间够长,这个bug就会(偶然)消失掉。因此需要测出时间,并在该芯片初始化通讯前增加延时(死循环)
- 需要知道整个程序循环一遍需要多长时间。往往串口通讯、开关扫描、AD采样等的数据处理往往是通过
轮询
的方式实现的。例如,AD采样频率是 960次/秒 ,如果你的程序的循环次数 达不到至少(冗余) 1000次/秒 ,那么就算是使用 ADC采样(外部)中断 及时获取到数据,但是由于程序循环速度太慢,AD采样数据无法及时进行处理换算,实际上 AD采样频率 < 程序循环次数 < 960次/秒 。因此 程序循环所需时间大小,也决定了轮询处理响应速度的慢快。
Ps:获取数据的方式有两种:轮询 和 中断 。一般情况下,最好是使用中断方式,能够及时获取到数据;采用轮询方式来获取数据,当没有数据来临时,也会进入轮询。当你的程序量比较少的时候,你的程序循环速度会很快,这样的话,轮询将会占用较多的CPU(内存)资源,而中断如果不触发,则不会进入,单位时间内程序循环将会相对来讲会优化一些。
实际上有很多种方法可以实现测量运行时间
4.1.1 采用Keil仿真的 Trace 功能
首先要先配置好仿真的时钟:在Debug
,然后设置成J-link
(或者ST-link,大同小异),进入setting
,再选择Trace
选项
SW模式:先勾选Enable,调成对应时钟(例:72MHz),再使能Autodetect max SWO Clk
JTAG模式(不常用):设置时钟,然后不勾选Enable(JTAG不支持Trace,会报错,容易出现SW
切换JTAG
时忘记关掉Trace
)
仿真的时候找下有个时间窗口
上面两个是复位“t1
”和“t2
”的,下面3个是选择在状态栏上显示哪个时间。
“t0
”表示程序开始运行到现在的时间,是不能复位的。另外两个可以随便复位,就可以用来测具体某一个函数或某一行程序的运行时间。
具体操作为:在要测试的代码前加一个断点,当程序运行到目标行时会停下,然后复位“t1”或“t2”,并在下一行代码前加断点,然后继续运行程序,程序会停在下一行代码前,这个时候“t1”的值就是目标行程序的运行时间。
Ps:Keil仿真 全速运行时 观察窗口变量没刷新;解决方法:在仿真时点击工具栏里的view
选择下面的periodict window update
,勾选完后数据开始动态更新。
Ps:Cortex-M0不支持Trace功能,因为是ARM V6结构,比较旧,所以无论你用J-link,还是ST-Link,都不能用到Trace。Keil会提示TRACE HW not present
4.1.2 采用定时器计时
配置好一个定时器,具体计算配置操作可以看STM32开发
思路:获取 进入程序段的当前时间,退出程序段后再获取当前时间,两个时间之差就是其运行时间(* 定时器计时基数)。
4.2 程序跑飞跳转
有时候你会在工程看到这段汇编的函数.
1 | __asm void wait() |
HardFault_Handler
栈溢出检查机制,适用于所有CM3芯片,造成主栈(MSP)溢出的原因有很多,如过多的定义局部变量,递归调用,中断嵌套等都有可能会导致主栈溢出,stm32不具备MPU,没有对内存进行保护的硬件机制,而软件检测栈溢出又有其局限性。
STM32出现HardFault_Handler
故障的原因主要有两个方面:
- 内存溢出或者访问越界。这个需要自己写程序的时候规范代码,遇到了需要慢慢排查。
- 堆栈溢出。增加堆栈的大小。大多数是因为中断嵌套寄存器均是32位,且STM32是小端模式(参考Cortex-M3权威)
1)出现问题时排查的方法:DEBUG,下断点单步看程序停在哪
2)另一种方法:默认的HardFault_Handler
处理方法为:内部是一个 汇编 或者 C语言 形式的死循环;
将它改成如上面代码的 BX LR
直接返回的形式。然后在这条语句打个断点,一旦在断点中停下来,说明出错了,然后再返回,就可以找到程序跑飞出错的位置的语句在哪。
4.3 自动生成版本号(编译时间和编译日期)
经常都需要手动添加版本号或者生成时间会很繁琐。这个时候,C语言中的两个宏__DATE__
和__TIME__
可以帮到我们。
__DATE__用于获取系统日期,而__TIME__用于获取系统时间,我们可以根据该两个宏获取到的信息将其保存于程序变量中,在程序运行过程中直接调用。
我们在程序中可以按以下所示使用:
1 | const unsigned char cRevisionDate[12] = __DATE__; |
运行结果如下所示:
1 | Rev Info: Sep 8 2018 17 51 26 |
更复杂的使用方法可以看这篇:Keil版本号生成
4.4 仿真动态显示
点击仿真后,如果Watch
窗口数据不能动态显示,可在仿真状态下点击tool
栏的view
,观察periodict window update
是否勾选,确保勾选即可。此时数据动态更新。
Ps:退出仿真状态下,工具栏的view
没有periodict window update
选项。
4.5 如何上传github
首先新建一个批处理,用于清除掉keil工程的编译文件:
1 | ::删除Keil编译产生的一些垃圾文件 |
具体的批处理操作解读,可以看另外一篇文章Window的简易bat处理
4.6 搭配推荐
推荐一些自己在用的实用搭配
4.6.1 Astyle
Astyle是keil的一个插件,关于Astyle看另外一篇博客:Keil格式化工具_Astyle
4.6.2 Snipatse
Snipatse是一个超级方便的截图软件
4.6.3 Compare
Compare是一个比较代码的软件,特别好用。你可以比较现在版本和之前版本的区别;或者是你的版本和别人的版本,能很快找到差别