资料:STM32F4XX中文参考手册—(7通用IO口/7.4GPIO寄存器)

问题描述:

我们在STM32F407关于IIC通讯实验例程中发现了一串看不懂的代码,代码所在文价夹是myiic.h ,代码如下所示:

java寄存器是干嘛的 寄存器的代码_与运算

可以看到,后边的~(3<<(9*2)),不知道什么意思。

我们就拿#define SDA_IN() { GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<9*2为例子。

如果理解了它,下边的代码#define SDA_OUT()....的代码,同理也能理解。

思考过程:

看到MODER,知道查看STM32F4XX中文参考手册,看第7章 通用IO口/7.4节 GPIO寄存器,如下图1所示:

java寄存器是干嘛的 寄存器的代码_嵌入式硬件_02

图1

GPIO 端口模式寄存器,那这个寄存器就是MODER9,他控制的是18,19位;哪个上述文件夹的这个代码可以理解为A&=~(3<<(9*2));就是3<<(9*2)取反后和原来得A值与运算再赋值给A,按照优先级的算术过程如下:

  1. 先算(9*2)
  2. 再算(3<<(9*2)) ,
  3. 接着对(3<<(9*2))取反
  4. 第3.部得出来的值再和A进行&运算
  5. 最后把第4.部算出来得值赋值给A,就是最后结果。

因此对GPIOB->MODER&=~(3<<(9*2))这个代码得理解是:

原来得GPIOB->MODER得值跟~(3<<(9*2))与运算后,再赋值给GPIOB->MODER ,就是这个意思。

软件调试:(帮助理解)

我们不知道这个GPIOB->MODER原来的值,因此要下载程序,烧入板子,才能看到。

进入到Debug调试界面看它原来的值,然后我们可以验证下,这个原来的值是烧入板子调试之后,才能出现值。这个要进入Debug,view中点击watch1小窗口,然后复制GPIOB->MODER,粘贴到watch1里面,可以看到原来的值,然后设置断点进入程序里,看他运算之后MODER的值。

如下图2所示,我们用快捷键ctrl+F搜索全局变量,就是搜索SDA_IN的全局变量,上边Find in Files,点击Find All,这样看它调试过程。

java寄存器是干嘛的 寄存器的代码_ide_03

图2

搜索全局变量之后,就能看到如下图3所示的,

java寄存器是干嘛的 寄存器的代码_嵌入式硬件_04

图3

如上图3所示,在最下边窗口蓝色标注的出现了它的相应文件夹,就是myiic.c文件夹,点击下边的就能快速进入文件夹的SDA_IN所在位置了。

这里因为对GPIOB->MODER进行了两次运算,然后我们为了方便观察,把SDA_IN替换成GPIOB->MODER&=~(3MODER|=0,并在调试之前就在这两串代码前设置断点,等会儿调试进去看下变化。如下图4所示。

java寄存器是干嘛的 寄存器的代码_ide_05

图4

java寄存器是干嘛的 寄存器的代码_嵌入式硬件_06

如上图所示,可以看到进入到第一个断点时,GPIOB->MODER的值为0x40050280,这就是执行前的值,GPIOB->MODER原来的值是0x40050280。

java寄存器是干嘛的 寄存器的代码_嵌入式硬件_07

图5

如上图5所示,又执行到下一个断点处,可以看到watch1窗口处,执行后的结果GPIOB->MODER的值为0x40010280.

我们验证下与运算后结果是否一样,如下图所示,在调试页面,直接选中它就能出现~(3<<(9*2))的值,它的值为0xFFF3FFFF。

java寄存器是干嘛的 寄存器的代码_java寄存器是干嘛的_08

同样的也可以看到与运算后的GPIOB->MODER的结果,与运算后GPIOB>MODER=0x40010280,

计算:

GPIOB->MODER&=~(3<<(9*2))

=0x40050280&(0xFFF3FFFF)=0x40010280

结果正确。

原来的GPIOB->MODER的值为0x40050280,跟~(3<<(9*2))进行与运算后变成0x40010280,可以看到5变成了1,就是0101——0001,对照中文参考手册发现是位18变成0.

java寄存器是干嘛的 寄存器的代码_与运算_09

1、然后为什么是3左移呢?

答:(1)3就是11,11左移(9*2)=18位,可以看中文参考手册数是原来11在0位和1位位置,左移数到18位,对应的是18.19位,所以此时18位,19位对应的就是11 ——(3<<(9*2)))的结果。

(2)然后取反就是18.19位变成00,00与运算任何数都是00,所以GPIOB->MODER&=~(3<<(9*2))的结果就是18,19位还是0,即把目标位清0.

2、接下来说GPIOB->MODER|=1

答:(1)1就是01,01左移(9*2)=18位,可以看中文参考手册数是原来01对应的是1位,0位置,左移数到18位,对应的是18.19位,所以此时18位,19位对应的就是01 ——(1<<(9*2))的结果

(2)然后01与任何数或运算就是那个数本身,所以本身是GPIOB->MODER值为0x40010280,从右往左数是1,0001,一个数对应4位,起始位为0,因此对应的19,18位是00,就是输入模式

//IO方向模式设置 这里第一步是将目标位设置为00,第二步才是设置(即设置新的值,让其为什么模式)
#define SDA_IN() { GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<(9*2) ;} //PB9输入模式
#define SDA_OUT() { GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=1<<(9*2);}  //PB9输出模式
//3是11,11移动到控制GPIO的位置,取反,设为00,最后与不影响其他位,所以巧妙地把那两位设置成了00,输入模式
//后面那个,1是01,最后将GPIO位设置为了01,通用输出模式