一、Debug问题
(1)debug过程中,在watch窗口中看不到局部变量的值,显示not in scope,并且警告variable "变量" was set but never used。
原因:编译器把变量优化掉了。局部变量,如果在函数中没有赋值操作,或者赋值后没有任意操作,就会被编译器优化。例如下面的例子,idq是全局变量不会被优化;i是局部变量,被赋值,有操作,没有优化;state为什么没有使用,因为state接收了返回值之后,没有输出,也没有赋值操作了。
解决办法:
1、在定义时加上volatile
关键字,以明确告诉编译器不要优化它。
2、将KEIL工程优化等级设置为Level0(-O0),不优化任何代码。
(2)调试某个项目是发现单步执行的时候,箭头一会往前一会往后,不会按照写定逻辑运行,原因是KEIL5开启优化等级。
解决办法: Keil。改成0级优化,也就是不优化,重新编译执行即可
二、KEIL界面说明
(1)优化等级
优化等级0
Minimum optimization. Turns off most optimizations.It gives the best possible debug view and the lowest level of optimization.近乎不优化,用于调试代码。出现代码行不能设置断点可如此设置试试。
特点:最少的优化,可以最大程度上配合产生代码调试信息,可以在任何代码行打断点,特别是死代码处。
优化等级1
Restrictedoptimization. Removes unused inline functions and unused static functions.Turns off optimizations that seriously degrade the debug view. Ifused with --debug, this option gives a satisfactorydebug view with good code density.部分优化。移除未调用的内联函数和静态函数,关闭debug窗口优化,此状态也能用于调试
特点:有限的优化,去除无用的inline和无用的static函数、死代码消除等,在影响到调试信息的地方均不进行优化。在适当的代码体积和充分的调试之间平衡,代码编写阶段最常用的优化等级。
优化等级2
Highoptimization. If used with --debug, the debug viewmight be less satisfactory because the mapping of object code tosource code is not always clear.This is the default optimization level.
默认优化等级。如果处于debug状态,部分代码行将不能被调试,具体做了什么优化好像没说
特点:高度优化,调试信息不友好,有可能会修改代码和函数调用执行流程,自动对函数进行内联等。
优化等级3
Maximumoptimization. -O3 performs the same optimizationsas -O2 however the balance between space and timeoptimizations in the generated code is more heavily weighted towardsspace or time compared with -O2.等级3和等级2除了执行相同的优化,还有在空间和时间之间的平衡优化在生成的代码中比等级2更重的空间或时间。
特点:最大程度优化,产生极少量的调试信息。会进行更多代码优化,例如循环展开,更激进的函数内联等。
注意:
在debug时尽量保证优化等级在0,在出货时尽量保证等级在1,既不会出现问题,生成的代码也小。尽量不要用最高优先级,之前有碰到过调试器在最高优先级时生成的代码跑飞,不管怎么调试,总有一小块功能出问题,有尝试过去keil官网找优先级高的代码编写说明,但是没有找到,最终只能选择去优化代码结构,降低优先级来解决问题了。
(2)程序大小
- Code:即代码域,它通常是指编译器生成的机器指令,这些内容会被存储到ROM区。
- RO-data:Read Only data,即只读数据域,它指程序中用到的只读数据,这些数据被存储在ROM区,因而程序不能被修改的内容。例如C语言中const关键字定义的变量就是典型的RO-data。
- RW-data:Read Write data,即可读写数据域,它指初始化为“非0值”的可读写数据,程序刚运行时,这些数据具有非0的初始值,程序运行的时候它们又会常驻在RAM区,应用程序可以修改其内容。例如C语言中定义的全局变量,且定义时赋予“非0值”给该变量。
- ZI-data:Zero Initialie data,即0初始化数据,它指初始化为“0值”的可读写数据域,它与RW-data的区别是程序刚运行时这些数据初始值全都为0,程序运行时和RW-data的性质一样,它们也常驻在RAM区,应用程序可以更改其内容。例如C语言中使用定义的全局变量,且定义时赋予“0值”给该变量(如若定义该变量时没有赋予初始值,编译器会把它当ZI-data来对待,初始化为0);
(3)keil的floating point hardware选项
FPU单元是芯片上一个独立于CPU处理的浮点运算单元,整个单元可以被使能和关闭。
STM32F4带有32位单精度硬件FPU支持浮点指令集。相比Cortex-M3、Cortex-M0等无FPU的芯片高出数十倍甚至上百倍的运算性能。
对于使用CubeMX的用户,如果芯片带有FPU,会默认开启FPU功能。例如Cotex-M4的内核就有处理浮点数运算的能力,有FPU单元
无FPU的芯片是没有这个选项的,例如Cotex-M3的内核没有处理浮点数运算的能力,没有FPU单元
三、 KEIL如何封装文件成lib
(1)为什么要封装文件成LIB
提高编译效率
如果一份文件已经在整个工程中发挥出了我们期待的作用,现在想要将其封装成库,则可以在已经成型的工程文件中将不需要编译的文件从工程全部移出掉,只留下我们需要封装的文件,这样就可以提高我们的运行效率。
封装前编译(左图),我们可以发现hardware中的所有.c文件都被编译,但事实上,比如LED.c代码已经修改完毕,绝对不会修改,因此为了提高编译效率,我可以将LED.c封装成LED.lib。
封装前编译(右图),我们可以发现led文件没有被编译,即可提高运行效率。
(2)如何将工程中文件封装成LIB
第一步,先把自己的工程复制一份,一份用于生成LIB文件,一份用于添加LIB文件。然后勾选魔方块,把自己要封装的文件留下,其他的文件都删除
第二步:勾选魔术棒,然后将生成文件修改成特殊的名字,例如Led
第三步,编译运行,生成led.lib文件
(3)工程中如何加入LIB文件
第一步:首先将led.lib文件放入你的工程路径下,我放置的路径时hardware,然后你们放置的路劲可以任意
第二步:点击魔方块,然后删除led.c文件,加入led.lib文件
第三步:编译没有错误,执行成功,我们可以跳转LED函数,发现跳转失败
(4)注意事项
在运用自制库中的函数时,编译提示函数没有声明,包含库里面的头文件时,会显示这个头文件不存在。因此直接采用extern 声明用到的函数即可。