“神奇”的volatile关键字

有感而发写下自己对volatile关键字的一点浅显理解,有理解不当的地方希望大家多指正。
近日写了个姿态解算的小project,先介绍下工具。
开发环境: keil MDK V5
MCU: stm32f407VG
主要传感器: MPU6050,hmc5883
写完以后,第一次烧录进去跑一遍,果然是失败的。。,只解算出了yaw轴数据,而pith,roll轴都输出了0!没关系,是时候祭出强大的仿真调试工具JLINK了,设断点,单步执行,“错误”定位到了这里:

注意q0 q1以及q0q1的值,MCU竟然“算错”数了!
为什么呢?我想到了MDK编译器具有优化机制,难道是代码被它“神优化”了?然后我给他加上了volatile关键字,果然
看起来运算是正确的。编译,烧录,跑起来,竟然还是没有解算出pitch,roll轴角度!没办法,接着单步调试吧,然后我就发现了一个致命(脑残)的错误,我忘开定时器了,所以。。。
,果断打开定时器,这次烧录后成功解算出三轴角度数据。这样就结束了吗,木有,咱得有探索精神,MCU为什么会“算错”数呢,这个问题很有趣呀。先看下百科对volatile的介绍

有点儿没读懂,原谅我理解力有点儿差,那么怎么才能看出加volatile关键字前后的不同之处呢?向底层找答案吧
汇编!
其实,在我看来,所有的问题不外乎有两种解决方法,第一,向问题底层去看,去寻找问题的本质;第二,把问题抽象出来,从上层去看。科学不就是朝着这两个方向发展的吗,小到研究质子夸克,大到研究银河系黑洞。生活中的问题也是这样,。。算了,不扯淡了,看机器反汇编代码吧。

这是不加volatile关键字的反汇编代码

这是加了volatile关键字后的反汇编代码,对比下,5句汇编指令只有最后一句不一样,加volatile关键字的最后一句汇编代码是VSTR s0,[sp,#0x24].什么意思呢,

看到这句汇编是把s0寄存器的值送到0x24地址的内存区域了(这就是变量q0q0在内存中的地址),而不加volatile关键字的汇编代码则是把s0寄存器的值copy到s29寄存器了(便于下次快速开始运算)。顿时豁然开朗,原来我们在仿真调试环境下观测变量的值实际上是在看对应地址的内存中存放的值!所以这个volatile关键字是不需要加的,确切的说是最好不加的,因为这样能提高运算速度,所起看起来MCU算错了,实则不然。打个比方,就如一个人要做一道题,计算y=x*c的值,其中x=a*b。第一个人先计算出a*b的值,然后在纸上写下x等于这个数,再用这个数乘c计算出y;另一个人呢,也是先计算出a*b的值,不过他不写纸上,他记在脑袋里,然后用这个数乘以C计算y。哪个人算得快就一目了然了吧。

明白了这个问题后,我果断去掉volatile关键字,此时虽然在仿真调试过程中依然观测到MCU“算错”数,但是最终解算出来的三个姿态角是正确的。
因为忘开定时器而学到了volatile的神奇作用也算是“因愚得知了”吧,嘿嘿。
–crisb

你可能感兴趣的:(stm32,数据,传感器,linux)