源函代码分步拆解
/*---------------------------- GPIO Mode Configuration -----------------------*/
1 currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F);
2 if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)
3 {
4 /* Check the parameters */
5 assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed));
6 /* Output mode */
7 currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;
}
1行:保留二进制后四位, GPIO_Mode可以取的值有:
typedef enum
{ GPIO_Mode_AIN = 0x0, //0000 0000
GPIO_Mode_IN_FLOATING = 0x04, //0000 0100
GPIO_Mode_IPD = 0x28, //0010 1000
GPIO_Mode_IPU = 0x48, //0100 1000
GPIO_Mode_Out_OD = 0x14, //0001 0100
GPIO_Mode_Out_PP = 0x10, //0001 0000
GPIO_Mode_AF_OD = 0x1C, //0001 1100
GPIO_Mode_AF_PP = 0x18 //0001 1000
}GPIOMode_TypeDef;
转换为八位二进制之后可以发现二进制后四位才是我们要写进寄存器的值(注意:四种输出模式还没有加上速度,所以最后两位为00)。所以GPIO_Mode & 0x0F 将前四位置0,后四位保留。
2~7行:为输出模式添加速度,因为只有四种输出模式的前四位为 0001 ,所以使用GPIO_Mode & 0x10 来判断是否为输出模式。
/*---------------------------- GPIO CRL Configuration ------------------------*/
/* Configure the eight low port pins */
1 if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)
2 {
3 tmpreg = GPIOx->CRL;
4 for (pinpos = 0x00; pinpos < 0x08; pinpos++)
5 {
6 pos = ((uint32_t)0x01) << pinpos;
7 /* Get the port pins position */
8 currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;
9 if (currentpin == pos)
10 {
11 pos = pinpos << 2;
12 /* Clear the corresponding low control register bits */
13 pinmask = ((uint32_t)0x0F) << pos;
14 tmpreg &= ~pinmask;
15 /* Write the mode configuration in the corresponding bits */
16 tmpreg |= (currentmode << pos);
17 /* Reset the corresponding ODR bit */
18 if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
19 {
20 GPIOx->BRR = (((uint32_t)0x01) << pinpos);
21 }
22 else
23 {
24 /* Set the corresponding ODR bit */
25 if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
26 {
27 GPIOx->BSRR = (((uint32_t)0x01) << pinpos);
28 }
29 }
30 }
31 }
32 GPIOx->CRL = tmpreg;
}
这一部分代码配置 GPIO_Pin_0 ~ GPIO_Pin_7
1行: 判断引脚值是否合理
4~9行:判断为几号引脚,因为引脚的宏定义如下图,通过循环对GPIO_Pin的后八位每位都进行一次 & 1 操作,如果该位为1则 & 1 后值为 1 ,如GPIO_Pin_1 = 0000 0010,第二次循环时pinpos = 1,所以pos = 0000 0010,GPIO_Pin & pos = 0000 0010,即 currentpin = 0000 0010 , currentpin == pos 即GPIO_Pin右边第二位为1,所以为GPIO_Pin_1。
#define GPIO_Pin_0 ((uint16_t)0x0001) //0000 0000 0000 0001
#define GPIO_Pin_1 ((uin00t16_t)0x0002) //0000 0000 0000 0010
#define GPIO_Pin_2 ((uint16_t)0x0004) //0000 0000 0000 0100
#define GPIO_Pin_3 ((uint16_t)0x0008) //0000 0000 0000 1000
#define GPIO_Pin_4 ((uint16_t)0x0010) //0000 0000 0001 0000
#define GPIO_Pin_5 ((uint16_t)0x0020) //0000 0000 0010 0000
#define GPIO_Pin_6 ((uint16_t)0x0040) //0000 0000 0100 0000
#define GPIO_Pin_7 ((uint16_t)0x0080) //0000 0000 1000 0000
#define GPIO_Pin_8 ((uint16_t)0x0100) //0000 0001 0000 0000
#define GPIO_Pin_9 ((uint16_t)0x0200) //0000 0010 0000 0000
#define GPIO_Pin_10 ((uint16_t)0x0400) //0000 0100 0000 0000
#define GPIO_Pin_11 ((uint16_t)0x0800) //0000 1000 0000 0000
#define GPIO_Pin_12 ((uint16_t)0x1000) //0001 0000 0000 0000
#define GPIO_Pin_13 ((uint16_t)0x2000) //0010 0000 0000 0000
#define GPIO_Pin_14 ((uint16_t)0x4000) //0100 0000 0000 0000
#define GPIO_Pin_15 ((uint16_t)0x8000) //1000 0000 0000 0000
#define GPIO_Pin_All ((uint16_t)0xFFFF) //1111 1111 1111 1111
11行:因为CRL寄存器4位为一组,所以 pos = pinpos << 2 = pinpos * 4
13~14行:将相应的 4 位设置为 0
(uint32_t) 0x0F = 0000 … 0000 0000 1111
pinmask = 0x0F << pos = 0000 …0000 1111 0000 … 0000
~ pinmask = 1111 …1111 0000 1111 … 1111
tmpreg &= ~ pinmask = xxxx … xxxx 0000 xxxx … xxxx
16行:将相应的4位设置为配置的模式
18~27行:根据官方参考手册可知,如下表 20 ,如果模式设置为上拉输入时要将BSRR寄存器相应的位置1,设置为下拉输入时要将BRR寄存器相应的位置1。
32行:将配置好的tmpreg写入CRL寄存器。
/*---------------------------- GPIO CRH Configuration ------------------------*/
/* Configure the eight high port pins */
if (GPIO_InitStruct->GPIO_Pin > 0x00FF)
{
tmpreg = GPIOx->CRH;
for (pinpos = 0x00; pinpos < 0x08; pinpos++)
{
pos = (((uint32_t)0x01) << (pinpos + 0x08));
/* Get the port pins position */
currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos);
if (currentpin == pos)
{
pos = pinpos << 2;
/* Clear the corresponding high control register bits */
pinmask = ((uint32_t)0x0F) << pos;
tmpreg &= ~pinmask;
/* Write the mode configuration in the corresponding bits */
tmpreg |= (currentmode << pos);
/* Reset the corresponding ODR bit */
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
{
GPIOx->BRR = (((uint32_t)0x01) << (pinpos + 0x08));
}
/* Set the corresponding ODR bit */
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
{
GPIOx->BSRR = (((uint32_t)0x01) << (pinpos + 0x08));
}
}
}
GPIOx->CRH = tmpreg;
}
这一部分配置GPIO_Pin_8 ~ GPIO_Pin_15 ,配置过程和上面的基本一样