1.认识GPIO
GPIO:通用输入输出口。与51中的IO口功能大致一样。
32中GPIO引脚的电平为0~3.3V,部分特殊的引脚(在外设清单中标有FT的IO口)可以忍受5V电压。通过IO口输出的电压只有3.3V,但是输入IO口的电压,标有FT的可以忍受5V。GPIO在32上挂载在APB2总线上。
2.GPIO的输入输出模式
上侧部分为输入模式,下侧为输出模式。这里的输入输出是针对GPIO而言,对GPIO输入数据,以及从GPIO输出数据。
从I/O引脚开始看,两个二极管确保IO口的电压在0~3.3V以内,当电压小于0V(相对VSS)下方二极管导通,方框内的其他电路被短路,起到保护作用。同理,当电压大于3.3V时,上方二极管导通,同样起到保护作用。
然后看输入模式,电压进入输入电路,先是两个上拉下拉电阻,这个可用通过代码来控制上拉还是下拉以应用于不同场景。然后通过一个施密特触发器产生数字信号0/1,再把该数据存入寄存器中,就可以通过代码来读出这位数据。模拟输入和复用功能输入是连接在32上其他的外设,这个以后学到再说。
再看输出部分,输出数据的来源可以有其他外设和代码写入。其中代码写入是通过修改寄存器数据,对输入数据寄存器只能整体修改,而通过位设置/清楚寄存器可以实现对输入数据寄存器中的某一位单独进行修改,位设置寄存器给1的位,对应输入数据寄存器中的那一位就会被改为1,位设置寄存器给0的位,对应输入数据寄存器的那一位不会被改变。同样的位清除寄存器给1,对应位改为0,位清除寄存器给0,对应位不变;此外,来自其他外设的输入可以直接通过IO口输出。
输出模式一共有三种,推挽,开漏,关闭。其中推挽输出就是P-MOS和N-MOS都正常工作,高电平P-MOS导通,低电平N-MOS导通,这样,无论高低电平,IO口都能有输出,也就是我们说的高低电平都有驱动能力。开漏输出模式就是只有N-MOS工作而P-MOS不工作。这样,低电平时N-MOS导通,有驱动能力,高电平时N-MOS断开,P-MOS因为没有工作也认为是断开,这样输出部分就和IO口没有导线连接,认为其处于高阻状态(相当于断路)。注意此时IO口的连接是悬空的,一般用上拉电阻来避免引脚不稳定。
3.Keil5代码
要使用GPIO,首先要打开对应的时钟,其次完成初始化,最后进行读写操作。
3.1使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
打开GPIOA系列引脚的时钟。对应的函数名混个眼熟即可,在代码编写时可以通过ctrl+空格快捷键打开提示框来快速编写。
3.2初始化
GPIO_Init(GPIOA,&GPIO_InitStruct);
这是GPIO初始化函数,其参数为GPIOx(对应之前打开时钟的那个GPIOx),以及一个结构体,这个结构体在库函数中也已经给出了,GPIO_InitTypeDef 就是这个结构体的数据类型,只需要定义一个GPIO_InitTypeDef类型的变量即可。
在定义一个GPIO_InitTypeDef类型的变量后,对其中三个变量进行赋值。
第一个变量,GPIO_Mode,是设定GPIO的工作模式,上述理论部分也提到过,输入的上拉下拉悬空模式,输出的推挽开漏关闭模式。这些工作模式就是通过GPIO_Mode这个变量进行调控的。在库函数中比较常用的定义:
GPIO_Mode_IPD = 0x28, //下拉输入
GPIO_Mode_IPU = 0x48, //上拉输入
GPIO_Mode_Out_OD = 0x14, //开漏输出
GPIO_Mode_Out_PP = 0x10, //推挽输出
第二个变量,GPIO_Pin,是确定给GPIOx系列引脚中哪一个引脚初始化,一个GPIOx系列下有0~15一共16个引脚,GPIO_Pin选择其中一个进行初始化。用于赋值的变量值形式为GPIO_Pin_x。x为0~15。但是注意其中A15,B3,B4为JTAG的调时端口,如果要使用需要进行额外的配置,这个以后学习到再说。
第三个变量,GPIO_Speed,GPIO通信的速度,这个一般要求不是特别高的情况下就选50MHZ就行。
三个变量赋完值,就可以用GPIO_Init(GPIOA,&GPIO_InitStruct);来完成初始化了。
3.3读写
常用的读写函数:
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
对GPIOx系列的某个引脚的输入值读
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
对GPIOx整个系列的引脚的输入值读
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
对GPIOx系列的某个引脚的输出值进行读
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
对GPIOx整个系列的引脚的输出值读
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
给对应的GPIOx的某个引脚写1。
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
给对应的GPIOx的某个引脚写0。
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
对GPIOx的某个引脚写0(Bit_RESET)或写1(Bit_SET)
BitAction BitVal 是枚举变量,其取值只有上述两种。
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
对GPIOx系列整体赋值,赋值为uint16_t PortVal,16进制数。这个数会被直接存在ODR寄存器中。