什么是库函数?
通过函数和宏封装配置寄存器
外设结构体
我们可以定义一种外设结构体,结构体的地址等于外设的基地址,结构体的成员等于寄存器,成员的排列顺序跟寄存器的顺序一样。
Volatile类型
volatile表示易变的变量,防止编译器优化,要求程序运行是不要从缓存中取值,而是去数据最原始的位置重新取值。
GPIO 初始化结构体
*定义GPIO_InitTypeDef 结构体类型
typedef struct
{
uint16_t GPIO_Pin; /*!< 选择要配置的GPIO引脚 */
uint16_t GPIO_Speed; /*!< 选择GPIO引脚的速率 */
uint16_t GPIO_Mode; /*!< 选择GPIO引脚的工作模式 */
} GPIO_InitTypeDef;
枚举类型
* /GPIO输出速率枚举定义
*/
typedef enum
{
GPIO_Speed_10MHz = 1, // 10MHz (01)b , 定义枚举的初始值从1 开始
GPIO_Speed_2MHz, // 2MHz (10)b
GPIO_Speed_50MHz // 50MHz (11)b
} GPIOSpeed_TypeDef;
枚举是int 类型, 就是给枚举元素标号, 默认是从0开始, 但是也可以设置初始值,比如上例中定义从1开始。 后续的两个枚举成员没有定义具体值,因此会使用默认的连续标号, 即2 和3 .
*GPIO 工作模式定义
*/typedef enum
{
GPIO_Mode_AIN = 0x0, // 模拟输入 (0000 0000)b
GPIO_Mode_IN_FLOATING = 0x04, // 浮空输入 (0000 0100)b
GPIO_Mode_IPD = 0x28, // 下拉输入 (0010 1000)b
GPIO_Mode_IPU = 0x48, // 上拉输入 (0100 1000)b
GPIO_Mode_Out_OD = 0x14, // 开漏输出 (0001 0100)b
GPIO_Mode_Out_PP = 0x10, // 推挽输出 (0001 0000)b
GPIO_Mode_AF_OD = 0x1C, // 复用开漏输出 (0001 1100)b
GPIO_Mode_AF_PP = 0x18 // 复用推挽输出 (0001 1000)b
} GPIOMode_TypeDef;
枚举是int 类型, 就是给枚举元素标号,除了按照初始值顺序编号外, 还可以指定具体的枚举值。如上例。
GPIO 初始化结构体赋值
GPIO_InitTypeDef GPIO_InitStructure;
/* GPIO端口初始化 */
/*选择要控制的GPIO引脚*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
/*设置引脚模式为输出模式*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/*设置引脚的输出类型为推挽输出*/
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO 初始化函数
代码清单8-13 GPIO初始化函数
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的低4位暂存在currentmode
13 currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) &((uint32_t)0x0F);
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 & ((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 }
115 //把前面处理后的暂存值写入CRH寄存器中
116 GPIOx->CRH = tmpreg;
117 }
118 }
GPIO 操作的具体流程
创建GPIO初始化结构体()--》初始话时钟是能寄存器,初始GPIO初始化结构体-》使用bitset 等函数操作GPIO
第8章学习总结
书本中对MODEy寄存器,对输出模式的定义有错误。只有MODE有=00的时候是输入模式。