GPIO_Pin:
//只要引脚号不为0则宏定义的值为1,注:#define
GPIO_Pin_0 ((uint16_t)0x0001) 引脚号从1开始
#define IS_GPIO_PIN(PIN) ((((PIN) &
(uint16_t)0x00) == 0x00) && ((PIN) != (uint16_t)0x00))
//宏定义GPIO所有可能的值,如果不在这个范围内会通过assert_param报警
#define IS_GPIO_ALL_PERIPH(PERIPH) (((PERIPH)
== GPIOA) || \
((PERIPH) ==
GPIOB) || \
((PERIPH) ==
GPIOC) || \
((PERIPH) ==
GPIOD) || \
((PERIPH) ==
GPIOE) || \
((PERIPH)
== GPIOF) || \
((PERIPH) ==
GPIOG))
//宏定义引脚对应值
#define GPIO_Pin_0 ((uint16_t)0x0001) //至于这里为什么是以移位设置而不是递增的方式设置跟库函数有关,下面程序有介绍
#define GPIO_Pin_1 ((uint16_t)0x0002)
#define GPIO_Pin_2 ((uint16_t)0x0004)
#define GPIO_Pin_3 ((uint16_t)0x0008)
#define GPIO_Pin_4 ((uint16_t)0x0010)
…………
GPIO_Speed:是个枚举GPIOSpeed_TypeDef类型
typedef enum
{
GPIO_Speed_10MHz = 1,
GPIO_Speed_2MHz = 2,
GPIO_Speed_50MHz = 3
}GPIOSpeed_TypeDef;
GPIO_Speed 只能是在这个枚举范围内选值
GPIO_Mode:同样是个枚举GPIOMode_TypeDef类型
typedef enum
{ GPIO_Mode_AIN = 0x0, //模拟输入模式
GPIO_Mode_IN_FLOATING = 0x04, //浮空输入模式(复位后的状态)
GPIO_Mode_IPD = 0x28, //下拉输入模式
GPIO_Mode_IPU = 0x48, //上拉输入模式
GPIO_Mode_Out_OD = 0x14, //通用开漏输出模式,至于这里为什么第五位都为1,下面程序中介绍
GPIO_Mode_Out_PP = 0x10, //通用推挽输出模式
GPIO_Mode_AF_OD = 0x1C, //复用功能开漏输出模式
GPIO_Mode_AF_PP = 0x18 //复用功能推挽输出模式
}GPIOMode_TypeDef;
GPIO_Mode 只能是在这个枚举范围内选值
对应模式设置如下寄存器
接来下解析一下void GPIO_Init(GPIO_TypeDef* GPIOx,
GPIO_InitTypeDef* GPIO_InitStruct)这个函数
void GPIO_Init(GPIO_TypeDef* GPIOx,
GPIO_InitTypeDef* GPIO_InitStruct)
{ //形参为两个结构体指针类型,上面已经介绍了,一个用于指定GPIO,一个用于初始状态包括速度,模式设置
uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos =
0x00;
uint32_t tmpreg = 0x00, pinmask = 0x00;
//currentmode:模式设置(对应CRH和CRL的32个bit)
//currentpin:保存引脚号
//pinpos:引脚扫描变量,分为扫描GPIO的0~7和8~15引脚
//pos:循环扫描8次,与上面的currentpin比较,相同即对相应的引脚进行设置
//tmpreg:保存上次设置的值不变,跟这次引脚号的设置不冲突,进行&和|运算以后赋给寄存器CRL
//pinmask:对应指定IO口的CNF和MODE位
/*
Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); //检测参数准确性,不在范围内会报错,上面有对assert_param的介绍
assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode)); //检测参数准确性
assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin)); //检测参数准确性
/*---------------------------- GPIO Mode
Configuration -----------------------*/
currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) &
((uint32_t)0x0F); //记录输入输出和模式
if
((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)
{ //如果为输出模式则记录下设置的速度,这就是为什么上面定义的时候第五位都是1的原因,用于分开输入和输出标志
/* Check the parameters */
assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed)); //检测参数准确性
/* Output mode */
currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed; //保存设置的速度
}
/*---------------------------- GPIO CRL
Configuration ------------------------*/
/*
Configure the eight low port pins */
if
(((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)
{//如果是GPIO的0~7端口,则设置CRL寄存器,0X00FF代表后面8位为1,这就是为什么上面#define那么定义引脚号的原因,而不用递增
tmpreg = GPIOx->CRL; //保存上次的设置
for (pinpos = 0x00; pinpos < 0x08; pinpos++)//循环8次,依次对应GPIO口0到7
{
pos = ((uint32_t)0x01) << pinpos; //对应8个IO,依次遍历
/* Get the port pins position */
currentpin = (GPIO_InitStruct->GPIO_Pin) & pos; //获取引脚位置
if (currentpin == pos) //找到了对应的引脚,执行下面的设置
{
pos = pinpos << 2; //向左移两位为x2,即对应到指定IO的4个bit(CNF和MODE)的寄存器
/* Clear the corresponding low control register bits */
pinmask = ((uint32_t)0x0F) << pos; //对应到所指定IO口的CNF和MODE,
tmpreg &= ~pinmask;
//先清空对应的CNF和MODE
/* Write the mode configuration in the corresponding bits */
tmpreg |= (currentmode << pos); //然后配置对应IO的寄存器模式
/* Reset the corresponding ODR bit */
if (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); //设置对应端口为1,即实现对应上拉的效果
}
}
}
}
GPIOx->CRL = tmpreg;//将设置好的值赋给CRL寄存器
}
//下面代码几乎和上面没差,用于设置CRH
/*---------------------------- 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;
}
}