本文为参考野火stm32教程中的GPIO_Init()函数的个人初步解析。
假定:需使用的引脚为GPIOA的A3口:
控制的引脚是GPIO_Pin_3,
引脚的模式是 GPIO_Mode_Out_PP(通用推挽输出),
引脚的速率是GPIO_Speed_10MHz,
用到的寄存器是CRL(低八位)
将上述的引脚、模式、速率换算成32位的16进制,分别是:
- 控制的引脚是GPIO_Pin_3
换算成32位的16进制是:0x0000 0004 - 引脚的模式是 GPIO_Mode_Out_PP(通用推挽输出)
换算成32位的16进制是:0x0000 0010 - 引脚的速率是GPIO_Speed_10MHz
换算成32位的16进制是:0x0000 0001
然后调用库函数GPIO_Init(),初始化GPIOA
GPIO_Init(GPIOA, &GPIO_InitStruct);
- GPIO_Init()函数的解析开始如下:
currentmode = ((uint32)GPIO_InitStruct->GPIO_Mode) & ((uint32)0x0F);//GPIO_Mode的低四位暂存在currentmode
- 可以得出currentmode=0x0000 0010 & 0x0000 000F =0x0000 0000
if ((((uint32)GPIO_InitStruct->GPIO_Mode) & ((uint32)0x10)) != 0x00)//bit4=1为OUT,=0为IN;判断是输入还是输出模式
- 本例:0x0000 0010 & 0x0000 00010 !=0x 0000 0000
此处结果为1则执行下面语句
{
currentmode |= (uint32)GPIO_InitStruct->GPIO_Speed; //若为输出模式则写入输出速度,
可以得出currentmode=currentmode | 0x0000 0001=0x0000 0000 | 0x0000 0001
=0x0000 0001
}
if (((uint32)GPIO_InitStruct->GPIO_Pin & ((uint32)0x00FF)) != 0x00) //判定端口是否为低八位,并配置端口。
-
本例:0x0000 0004 & 0x 0000 00FF != 0x0000 0000,此处结果为1则执行下面语句
{
tmpreg = GPIOx->CRL; -
备份原CRL寄存器的值 则是:tmpreg=0x4444 4444
for (pinpos = 0x00; pinpos < 0x08; pinpos++)
{
pos = ((uint32)0x01) << pinpos; // pos的值为1左移pinpos位
-
本例:pos =0x0000 0001 << 0x03= 0x0000 1000
currentpin = (GPIO_InitStruct->GPIO_Pin) & pos; // 令pos与输入参数GPIO_PIN作位与运算,为下面的判断作准备。
-
可得currentpin = 0x0000 1000 & 0x00001000
=0x0000 1000if (currentpin == pos)
-
由上面得出的pos = 0x0000 1000
currentpin = 0x0000 1000
两者相等,则执行下面代码语句{
pos = pinpos << 2; -
可得pos = 0x0000 0003 << 2
=0x 0000 000C把控制这个引脚的4个寄存器位清零,其它寄存器位不变
①pinmask = ((uint32_t)0x0F) << pos; -
可得pinmask=0x0000 000F << 0x0000 000C=0x0000 F000
相当于把1111左移12个位,0x1111 0000 0000 0000=0xF000,即A3口。
②tmpreg &= ~pinmask; -
可得 tmpreg = tmpreg & ~pinmask
= 0x4444 4444 & 0xFFFF 0FFF
= 0x4444 0444
tmpreg |= (currentmode << pos);
-
首先,要知道currentmode << pos = 0x0000 0001 << 0x 0000 0003
= 0x 0000 1000
可得 tmpreg = tmpreg | 0x0000 1000
= 0x4444 0444 | 0x0000 1000
= 0x4444 1444if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD) 判断是否为下拉输入模式 { GPIOx->BRR = (((uint32_t)0x01) << pinpos); } else { /* Set the corresponding ODR bit */ if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU) 判断是否为上拉输入模式 { GPIOx->BSRR = (((uint32_t)0x01) << pinpos); } } 结果,两种输入模式都不是,而是通用推挽输出,所以不执行
}
}
GPIOx->CRL = tmpreg;
- 把前面处理后的暂存值写入到CRL寄存器之中 也就是GPIOx->CRL = 0x4444 1444
}
最终,向GPIOB组的CRL寄存器写入一个值:GPIOx->CRL = 0x4444 4443。转换为二进制是:(0100 0100 0100 0100 0001 0100 0100 0100)B
因此,Pin3的控制值为(0001)B即CNF:00,MODE:01。其他低八位的IO口的值默认为0x44。从头至尾的例举结果判断此程序编写的效果OK。