STM32F4 学习(GPIO)

一、GPIO介绍

GPIO(General Purpose Input Output)通用输入输出口 可配置为8种输入输出模式。输出模式下可控制端口输出高低电平,用以驱动LED、控制蜂鸣器、模拟通信协议输出时序等 输入模式下可读取端口的高低电平或电压,用于读取按键输入、外接模块电平信号输入、ADC电压采集、模拟通信协议接收数据等。

😯STM32 芯片 GPIO 接口内部原理如下:

通过 GPIO 硬件结构图,就可以从整体上深入的了解 GPIO 外设以及它的各种应用模式。从图的最右端看,最右端代表的是 STM32 芯片引出的 GPIO 引脚,其余部件都位于芯片内部。

♈1.2.1 保护二极管

引脚上的两个保护二级管用于防止引脚外部过高或过低的电压输入,当引脚电压高于 Vdd 时,上方的二极管导通,当引脚电压低于 Vss 时,下方的二极管导通,防止不正常电压引入芯片导致芯片烧毁。

尽管有这样的保护,并不意味着 STM32 的引脚能直接外接大功率驱动器件,如直接驱动电机,强制驱动要么电机不转,要么导致芯片烧坏,必须要加大功率及隔离电路驱动。

♈1.2.2 P-MOS、N-MOS 管

GPIO引脚线路经过两个保护二极管后,向上流向“输入模式”结构,向下流向“输出模式”结构。先看输出模式部分,线路经过一个由 P-MOS 和 N-MOS 管组成的单元电路。这个结构使 GPIO 具有了“推挽输出”和“开漏输出”两种模式。

二、GPIO的工作模式

typedef enum
 {
 	GPIO_Mode_AIN = 0x00,          // 模拟输入
 	GPIO_Mode_IN_FLOATING = 0x04,  // 浮空输入
 	GPIO_Mode_IPD = 0x28,          // 下拉输入
 	GPIO_Mode_IPU = 0x48,          // 上拉输入
 	GPIO_Mode_Out_OD = 0x14,       // 开漏输出
 	GPIO_Mode_Out_PP = 0x10,       // 推挽输出
 	GPIO_Mode_AF_OD = 0x1C,        // 复用开漏输出
 	GPIO_Mode_AF_PP = 0x18         // 复用推挽输出
 } GPIOMode_TypeDef;

😫4种输入模式:

      1)浮空输入(GPIO_Mode_IN_FLOATING)

浮空输入的电平不确定,电平高低由外部的输入决定,有着降低功耗的功能。

     2)上拉输入(GPIO_Mode_IPU)

上拉输入的电平默认为高电平,可以使电流增大,抗干扰能力增强。

    3)下拉输入(GPIO_Mode_IPD)

下拉输入的电平默认为低电平,可以起到钳位电平的作用。

    4)模拟输入(GPIO_Mode_AIN)

模拟输入用于AD转换,与以上三种不同的是,模拟输入的信号是以电平形式输入的,且上下拉对其无影响。

 😴4种输出模式:

   1)推挽输出(GPIO_Mode_Out_PP)

推挽输出时双MOS管以推挽形式工作,受ODR控制,且可以控制I/O口输出强高低电平。

   2)复用推挽输出(GPIO_Mode_AF_PP)

复用推挽输出时,此时I/O口受内部外设控制,比如定时器的PWM、I2C的SCL,SDA等。

   3)开漏输出(GPIO_Mode_Out_OD)

开漏输出时只有N-MOS管工作,只可控制I/O口输出强低电平。

   4)开漏复用输出(GPIO_Mode_AF_OD)

开漏复用输出时,此时I/O口受内部外设控制,如TX1,MOSI,MISO,SCK,SS等。

4种最大输出速度:-2MHZ    -25MHz    -50MHz     -100MHz


😠😠在固件库中,GPIO 总共有 8 种细分的工作模式,稍加整理可以大致归类为以下三类: 

♈1.3.1 输入模式 (模拟/浮空/上拉/下拉)

  • 在输入模式时,施密特触发器打开,输出被禁止,可通过输入数据寄存器 GPIOx_IDR 读取 I/O 状态。其中输入模式,可设置为上拉、下拉、浮空和模拟输入四种。
  • 上拉和下拉输入很好理解,默认的电平由上拉或者下拉决定。浮空输入的电平是不确定的,完全由外部的输入决定,一般接按键的时候用的是这个模式。模拟输入则用于 ADC 采集。

♈1.3.2 输出模式 (推挽/开漏)

  • 在输出模式中,推挽模式时双 MOS 管以轮流方式工作,输出数据寄存器 GPIOx_ODR 可控制 I/O输出高低电平。
  • 开漏模式时,只有 N-MOS 管工作,输出数据寄存器可控制 I/O 输出高阻态或低电平。输出速度可配置,有 2MHz、10MHz、50MHz 的选项。此处的输出速度即 I/O 支持的高低电平状态最高切换频率,支持的频率越高,功耗越大,如果功耗要求不严格,把速度设置成最大即可。
  • 在输出模式时施密特触发器是打开的,即输入可用,通过输入数据寄存器 GPIOx_IDR 可读取 I/O的实际状态。

♈1.3.3 复用功能 (推挽/开漏)

  • 复用功能模式中,输出使能,输出速度可配置,可工作在开漏及推挽模式,但是输出信号源于其它外设,输出数据寄存器 GPIOx_ODR 无效;输入可用,通过输入数据寄存器可获取 I/O 实际状态,但一般直接用外设的寄存器来获取该数据信号。
  • 通过对 GPIO 寄存器写入不同的参数,就可以改变 GPIO 的工作模式,要了解具体寄存器时一定要查阅 《STM32F10X-中文参考手册》 中对应外设的寄存器说明。
  • 在 GPIO 外设中,控制端口高低控制寄存器 CRH 和 CRL 可以配置每个 GPIO 的工作模式和工作的速度,每 4 个位控制一个 IO,CRH 控制端口的高八位,CRL 控制端口的低 8 位,具体的看 CRH 和 CRL 的寄存器描述。

三、GPIO的配置(库函数) 

        👊配置流程

STM32F4的GPIO_InitTypeDef结构体

GPIO配置流程

void XXX_Init_Config(void)

{

    GPIO_InitTypeDef GPIO_InitStructure; //对应的结构体变量定义

    RCC_APH1PerphClockCmd(端口,enable);//具体函数需要根据端口挂载在哪个总线上

    配置GPIO_InitTypeDef结构体的五个参数;

    GPIO_Init(端口,结构体)

}

输入配置的例子:

这里以配置LED灯为案例,因为LED灯分布在不同的引脚,所以我们要配置多个参数

void LED_Init(void)//初始化LED
{
	GPIO_InitTypeDef GPIO_InitStructure;//定义初始化的结构体变量
	//使能GPIOC和GPIOB时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOB,ENABLE);
	//模式选择
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //通用输出模式
	//输出类型
	GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出
	//速度选择
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //50HZ
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP; //上拉
	//引脚选择
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4 | GPIO_Pin_5; //两个LED对应的端口
	//初始化GPIOC
	GPIO_Init(GPIOC,&GPIO_InitStructure);
	GPIO_SetBits(GPIOC,GPIO_Pin_4 | GPIO_Pin_5);//默认高电平熄灭
	//初始化GPIOB
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;//引脚选择
	GPIO_Init(GPIOB,&GPIO_InitStructure);
	GPIO_SetBits(GPIOB,GPIO_Pin_0);//默认高电平熄灭		
}

输入配置:

这里就以配置按键来做案例

//初始化按键函数
void Key_Init(void)
{
	//定义结构体变量
	GPIO_InitTypeDef GPIO_Key_Structure;
	//使能GPIO时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOB |RCC_AHB1Periph_GPIOA,
								ENABLE);
	//模式选择
	GPIO_Key_Structure.GPIO_Mode=GPIO_Mode_IN; //输入方式
	GPIO_Key_Structure.GPIO_Speed=GPIO_Speed_50MHz; //速度
	GPIO_Key_Structure.GPIO_PuPd=GPIO_PuPd_UP;//上拉输入
	//初始化GPIOC
	GPIO_Key_Structure.GPIO_Pin=GPIO_Pin_13; //配置引脚
	GPIO_Init(GPIOC ,&GPIO_Key_Structure);
	//初始化GPIOB
	GPIO_Key_Structure.GPIO_Pin=GPIO_Pin_1; //配置引脚
	GPIO_Init(GPIOB ,&GPIO_Key_Structure);
	//初始化GPIOA
	GPIO_Key_Structure.GPIO_PuPd = GPIO_PuPd_DOWN ;//下拉
	GPIO_Key_Structure.GPIO_Pin=GPIO_Pin_0;
	GPIO_Init(GPIOA ,&GPIO_Key_Structure);
	
}

这里还需要配置一个按键扫描函数;

        我个人做了一个按键消抖,很好用,可以应用在很多地方

/**
  *功能: 通过按键按下来获取电平状态
  *   
  * 参数1:模式选择 
  * mode:0,不支持连续按; 1,支持连续按;
  *          
  * 返回值:按键按下返回对应的数值 1,2,3
***/
u8 KEY_scan(u8 mode)
{
	static u8 Key_up=1;
	if(mode==1) Key_up=1;
	if(Key_up &&(KEY2==0||KEY3==0||KEY1==1))
	{
		delay_ms(20); //消抖
		Key_up=0;
		if(KEY1==1){while(KEY1==1){}delay_ms(20); return 1;}//通过循环卡住按键的状态进行消抖
		else if(KEY2==0){while(KEY2==0){}delay_ms(20); return 2;}
		else if(KEY3==0) {while(KEY3==0){}delay_ms(20); return 3;}
	}else if(KEY2==0 && KEY3==0 && KEY1==1) Key_up=1; 
	
	return 0;		
}

主函数必须进行初始化的调用

四、几个重要的输入输出函数

        😁1个初始化函数:

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);

        😁2个读取输入电平函数:

uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); //读取当前GPIO口的电平状态

uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx); //读取当前GPIO口组的所有IO口电平状态

        😁2个读取输出电平函数:

uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); //读取当前设置GPIO口输出电平为何状态

uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx); //读取当前GPIO口组所有IO口输出状态

        😁4个设置输出电平函数:

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); //设置单个GPIO口输出高电平

void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); //设置单个GPIO口输出低电平

void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal); //不常用

void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal); //不常用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值