野火stm32F103霸道开发板中为了让初学者了解库函数的建立过程,和GPIO端口寄存器的设置。特意写了一章,其中关于端口某个引脚的初始化函数,逻辑很复杂,对初学者不是很友好,现将原有代码和优化后的代码分享给大家
1.野火原教程代码
1 **/**
2 *****函数功能:初始化引脚模式
3 *****参数说明: **GPIOx**,该参数为 **GPIO_TypeDef **类型的指针,指向 **GPIO **端口的地址
4 *** GPIO_InitTypeDef:GPIO_InitTypeDef **结构体指针,指向初始化变量
5 ***/**
6 **void **GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
7 **{**
8 **uint32_t **currentmode =0x00,currentpin = 0x00,pinpos = 0x00,pos = 0x00;
9 **uint32_t **tmpreg = 0x00, pinmask = 0x00;
10
11 **/*---------------- GPIO **模式配置 **-------------------*/**
12 **// **把输入参数 **GPIO_Mode **的低四位暂存在 **currentmode**
13 **currentmode = ((**uint32_t**)GPIO_InitStruct->GPIO_Mode) &**
14 **((**uint32_t**)0x0F);**
15
16 **// bit4 **是 **1 **表示输出, **bit4 **是 **0 **则是输入
17 **// **判断 **bit4 **是 **1 **还是 **0**,即首选判断是输入还是输出模式
18 **if **((((**uint32_t**)GPIO_InitStruct->GPIO_Mode) &
19 **((**uint32_t**)0x10)) != 0x00)**
20 **{**
21 **// **输出模式则要设置输出速度
22 **currentmode |= (**uint32_t**)GPIO_InitStruct->GPIO_Speed;**
23 **}**
24 **/*-----GPIO CRL **寄存器配置 **CRL **寄存器控制着低 **8 **位 **IO- ----*/**
25 **// **配置端口低 **8 **位,即 **Pin0~Pin7**
26 **if **(((**uint32_t**)GPIO_InitStruct->GPIO_Pin &
27 **((**uint32_t**)0x00FF)) != 0x00)**
28 **{**
29 **// **先备份 **CRL **寄存器的值
30 **tmpreg = GPIOx->CRL;**
31
32 **// **循环,从 **Pin0 **开始配对,找出具体的 **Pin**
33 **for **(pinpos = 0x00; pinpos < 0x08; pinpos++)
34 **{**
35 **// pos **的值为 **1 **左移 **pinpos **位
36 **pos = ((**uint32_t**)0x01) << pinpos;**
37
38 **// **令 **pos **与输入参数 **GPIO_PIN **作位与运算
39 **currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;**
40
41 **//**若 **currentpin=pos,**则找到使用的引脚
42 **if **(currentpin == pos)
43 **{**
44 **//pinpos **的值左移两位**(**乘以 **4),**因为寄存器中 **4 **个位配置一个引脚
45 **pos = pinpos << 2;**
46 **//**把控制这个引脚的 **4 **个寄存器位清零,其它寄存器位不变
47 **pinmask = ((**uint32_t**)0x0F) << pos;**
48 **tmpreg &= ~pinmask;**
49
50 **// **向寄存器写入将要配置的引脚的模式
51 **tmpreg |= (currentmode << pos);**
52
53 **// **判断是否为下拉输入模式
54 **if **(GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
55 **{**
56 **// **下拉输入模式**,**引脚默认置 **0,**对 **BRR **寄存器写 **1 **对引脚置 **0**
57 **GPIOx->BRR = (((**uint32_t**)0x01) << pinpos);**
58 **}**
59 **else**
60 **{**
61 **// **判断是否为上拉输入模式
62 **if **(GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
63 **{**
64 **// **上拉输入模式**,**引脚默认值为 **1,**对 **BSRR **寄存器写 **1 **对引脚置 **1**
65 **GPIOx->BSRR = (((**uint32_t**)0x01) << pinpos);**
66 **}**
67 **}**
68 **}**
69 **}**
70 **// **把前面处理后的暂存值写入到 **CRL **寄存器之中
71 **GPIOx->CRL = tmpreg;**
72 **}**
73 **/*--------GPIO CRH **寄存器配置 **CRH **寄存器控制着高 **8 **位 **IO- -----*/**
74 **// **配置端口高 **8 **位,即 **Pin8~Pin15**
75 **if **(GPIO_InitStruct->GPIO_Pin > 0x00FF)
76 **{**
77 **// // **先备份 **CRH **寄存器的值
78 **tmpreg = GPIOx->CRH;**
79
80 **// **循环,从 **Pin8 **开始配对,找出具体的 **Pin**
81 **for **(pinpos = 0x00; pinpos < 0x08; pinpos++)
82 **{**
83 **pos = (((**uint32_t**)0x01) << (pinpos + 0x08));**
84
85 **// pos **与输入参数 **GPIO_PIN **作位与运算
86 **currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos);**
87
88 **//**若 **currentpin=pos,**则找到使用的引脚
89 **if **(currentpin == pos)
90 **{**
91 **//pinpos **的值左移两位**(**乘以 **4),**因为寄存器中 **4 **个位配置一个引脚
92 **pos = pinpos << 2;**
93
94 **//**把控制这个引脚的 **4 **个寄存器位清零,其它寄存器位不变
95 **pinmask = ((**uint32_t**)0x0F) << pos;**
96 **tmpreg &= ~pinmask;**
97
98 **// **向寄存器写入将要配置的引脚的模式
99 **tmpreg |= (currentmode << pos);**
100
101 **// **判断是否为下拉输入模式
102 **if **(GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
103 **{**
104 **// **下拉输入模式**,**引脚默认置 **0,**对 **BRR **寄存器写 **1 **可对引脚置 **0**
105 **GPIOx->BRR = (((**uint32_t**)0x01) << (pinpos + 0x08));**
106 **}**
107 **// **判断是否为上拉输入模式
108 **if **(GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
109 **{**
110 **// **上拉输入模式**,**引脚默认值为 **1,**对 **BSRR **寄存器写 **1 **可对引脚置 **1**
111 **GPIOx->BSRR = (((**uint32_t**)0x01) << (pinpos + 0x08));**
112 **}**
113 **}**
114 **}**
GPIO模式枚举类型定义
**1 **/**
2 *** GPIO **输出速率枚举定义
3 ***/**
4 typedef **enum**
5 **{**
6 **GPIO_Speed_10MHz = 1, **// 10MHZ (01)b
7 **GPIO_Speed_2MHz, **// 2MHZ (10)b
8 **GPIO_Speed_50MHz **// 50MHZ (11)b
9 **} GPIOSpeed_TypeDef;**
10
11 **/****
12 *** GPIO **工作模式枚举定义
13 ***/**
14 typedef **enum**
15 **{**
16 **GPIO_Mode_AIN = 0x0, **// **模拟输入 **(0000 0000)b
17 **GPIO_Mode_IN_FLOATING = 0x04, **// **浮空输入 **(0000 0100)b
18 **GPIO_Mode_IPD = 0x28, **// **下拉输入 **(0010 1000)b
19 **GPIO_Mode_IPU = 0x48, **// **上拉输入 **(0100 1000)b
20
21 **GPIO_Mode_Out_OD = 0x14, **// **开漏输出 **(0001 0100)b
22 **GPIO_Mode_Out_PP = 0x10, **// **推挽输出 **(0001 0000)b
23 **GPIO_Mode_AF_OD = 0x1C, **// **复用开漏输出 **(0001 1100)b
24 **GPIO_Mode_AF_PP = 0x18 **// **复用推挽输出 **(0001 1000)b
25 **} GPIOMode_TypeDef;**
2.优化后代码
端口模式结构体定义
typedef enum
{
GPIO_Input = 0x00,
GPIO_Speed_10MHz = 0x01,
GPIO_Speed_2MHz = 0x02,
GPIO_Speed_50MHz =0x03,
} GPIOSpeed_TypeDef;
typedef enum
{
GPIO_Mode_AIN = 0x00,
GPIO_Mode_IN_FLOATING = 0x04,
GPIO_Mode_IPD = 0x08,
GPIO_Mode_IPU = 0x08,
GPIO_Mode_Out_PP = 0x00,
GPIO_Mode_Out_OD = 0x04,
GPIO_Mode_AF_PP = 0x08,
GPIO_Mode_AF_OD = 0x0C,
} GPIOMode_TypeDef;
typedef struct
{
uint_16 GPIO_Pin;
GPIOSpeed_TypeDef GPIO_Speed;
GPIOMode_TypeDef GPIO_Mode;
} GPIO_InitTypeDef;
初始化函数定义
void GPIO_init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef GPIO_InitStruct, RCC_TypeDef *RCCx)
{
int num_port = (((unsigned int)GPIOx)%((unsigned int) 0x2000)/((unsigned int) 0x400));
int pin_num = log(GPIO_InitStruct.GPIO_Pin)/log(2);
RCCx->APB2ENR |= (1 << num_port);
if (pin_num < 8)
{
GPIOx->CRL &= ~(0xF << (4 * (pin_num)));
GPIOx->CRL |= ((GPIO_InitStruct.GPIO_Mode | GPIO_InitStruct.GPIO_Speed) << (4 * (pin_num)));
}
else
{
GPIOx->CRH &= ~(0xF << 4 * (pin_num - 8));
GPIOx->CRH |= ((GPIO_InitStruct.GPIO_Mode | GPIO_InitStruct.GPIO_Speed) << 4 * (pin_num-8));
}
}
直接根据端口和管脚移位,省去了复杂的判断逻辑