STM32学习之GPIO工作模式


前言


本篇介绍GPIO八种工作模式的原理(简单易懂,适合初学者初学时建立简单印象框架),并通过点亮小灯来学习常用的控制GPIO的库函数。

一、GPIO是什么?

GPIO(General Purpose Input/Output,通用输入/输出) 是用于与外部设备进行数字信号交互的基本外设模块,下表是stm32f10 3c8t6的其他外设。
在这里插入图片描述

二、8个工作模式

1.总括

这是GPIO的基本结构,对于八种工作模式是通过一个寄存器,控制该结构的变化来实现不同的功能。
在这里插入图片描述

2. 四种输入

在这里插入图片描述
部分③是用于过滤信号的,有时接收到的型号是非数字信号,会出现部分信号似零非零,似一非一,很容易出现误判,该触发器设置了上界和下界,就能将非数字信号转换成为数字信号。简单来说这个触发器就是将模拟信号转换为数字信号的
当配置为输入模式时,输出相当于断开的,即输出模块中的P-MOS和N-MOS均是无效的

浮空输入

浮空输入就是将上图中部分②和部分①两个开关全都断开,当两个开关全都断开时,输入就会处于一种浮空的状态,输入电平极易受外界干扰而发生改变。

上拉输入

上拉输入就是将上图中部分①闭合,部分②断开,VDD接入输入部分,默认的输入信号就是高电平,即在该模式下,当接口没有信号接入时,默认输入高电平信号

下拉输入

下拉输入就是将上图中部分①断开,部分②闭合,VSS接入输入部分,默认的输入信号就是低电平,即在该模式下,当接口没有信号接入时,默认输入低电平信号

模拟输入

模拟输入时接收模拟信号,跳过触发器,即信号不经过触发器直接传入接收信号处
在这里插入图片描述

3.四种输出

推免模式和开漏模式

在这里插入图片描述

推免输出(强推输出)

推免输出时,结构中的P-MOS和N-MOS都有效,输出高电平时,P-MOS导通,接口接VDD,呈现高电平,而输出低电平时,N-MOS导通,接口介VSS,呈现低电平。因此在推免输出模式下,STM32对高低电平具有绝对的控制权,高低电平都由STM32说了算。这种模式是真正的输出了高低电平,因此高低电均有驱动能力,即有输出电流的能力,简单来说假如接口接了小灯,无论是高电平还是低电平,均有足够的电流来保证小灯的正常工作

开漏输出

开漏输出时,P-MOS是无效的,只有N-MOS有效,从而输出低电平时,N-MOS导通,直接接地,吸入电流,强驱动;当输出高电平时,因为P-MOS的无效,N-MOS的断开,此时接口处的高低电平是不确定的,接口处与结构内部是完全断开的状况(称为高阻态),电平有外部决定,因此在接口处添加一个上拉电阻,保证在接口输出不确定的情况下,得到高电平。

复用推免和复用开漏

在这里插入图片描述

复用开漏输出

除数据来源与开漏输出不一致,其他均与开漏模式相同

复用推免输出

除数据来源与推免输出不一致,其他均与推免模式相同

4.小小总结

八种工作模式,四种输入包含 浮空(默认输入不确定可高可低),上拉(默认输入时高电平),下拉(默认输入时低电平),模拟(不经过触发器直接接ADC),四种输出包含推免(高低电平均有强驱动能力),开漏(低电平具有强驱动能力,高电平需外接上拉电阻),复用开漏和复用推免(数据源与片上外设)。在输入模式下,输出均不可用,但在输出模式下,输入是可以用的,即在输出模式下,也可同时进行输入,除了在模拟输入模式状况外,上拉输入,下拉输入,浮空输入总是可以工作 。

三、输出练习(点亮小灯)

使用PA0口,点亮小灯有(1)、(3)两种电路连接方式,(1)方式PA0口输出低电平点亮小灯,可使用开漏和推免两种方式进行控制,而方式(3)需通过PA0输出高电平点亮小灯,只能使用推免方式控制
在这里插入图片描述

1.配置RCC

已知STM32有诸多外设,RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);该函数是用于开启或禁用APB2总线上的外设时钟。此处需使用PA0,属于GPIOA,因此传入参数为RCC_APB2Periph_GPIOA
ENABLE,即打开GPIOA的时钟。通过此表选择要传入的参数。
在这里插入图片描述

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

2.配置GPIO

已知GPIO有8种工作模式,根据点亮小灯的需求,选择输出模式,因此开漏和推免都可选。配置方式是通过创建结构体对象,配置其中的属性,从而达到配置GPIO寄存器的目的。

创建结构体

	GPIO_InitTypeDef GPIO_InitStructure;//创建GPIO配置对象
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//设置工作模式为推免模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//设置端口
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//设置速度一般为50MHZ
	GPIO_Init(GPIOA, &GPIO_InitStructure);//将设置好的结构体对象传入函数,对GPIO配置寄存器进行配置

3.设置输出信号

库函数设置输出信号有三种方式

GPIO_ResetBits&GPIO_SetBits

GPIO_ResetBits(GPIOA, GPIO_Pin_0);//对PA0设置低电平
GPIO_SetBits(GPIOA, GPIO_Pin_0);//对PA0设置高电平

GPIO_WriteBit

	GPIO_WriteBit(GIOA, GPIO_Pin_0, Bit_RESET);//对PA0设置低电平
	GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);//对PA0设置高电平

GPIO_Write

	uint16_t  PortValLow = 0xfffe;
	GPIO_Write(GPIOA, PortValLow);//对PA0设置低电平
	uint16_t  PortValHigh = 0x0001;
	GPIO_Write(GPIOA, PortValHigh);//对PA0设置高电平

自此编译上传便可点亮小灯

4.延时闪烁

通过延时函数,添加Delay.h和Delay.c文件(源与B站江协科技学习包),调用延时函数,完成小灯的闪烁
在这里插入图片描述

	while(1){
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);//选择三种方式之一设置低电平
		Delay_ms(100);//延时100毫秒
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);//选择三种方式之一设置高电平
		Delay_ms(100);
	}

四、输入练习(认识四种传感器)

在这里插入图片描述
四中传感器的原理非常相似,大致仅是更换了N1电阻,光敏传感器N1是光敏电阻,热敏传感器N1是热敏电阻等。
在这里插入图片描述
以光敏电阻为例,光线越强,电阻越小。AO处电压越大,因此在AO处输出线性的模拟信号,IN+处于AO电压一致。下图图(2)也会输出一个电压,该电压可以理解为设置好的一个标准电压通过IN-输出,两个电压通过图(1)的电压比较器,IN+的电压如果小于IN-处的电压,图(1)中DO口就会输出低电平,反之输出高电平,从而将模拟信号转换为数字信号接入图(4)中进行输出
在这里插入图片描述
这就是四个传感器的大致原理,每个传感器有四个接口:模拟信号、数字信号、GND、VCC

5、连接方式

图(1)、(2)、(3)、(4)是按钮的接线方式,图(1)(2)都是按钮按下是输入低电平,但图(1)未接上拉电阻,浮空模式时,默认输入是不确定的,图(2)有接上拉电阻,从而在浮空模式下,默认输入是高电平;

而图(3)(4)是按钮按下是输入高电平,区别与图(1)(2)的区别一致,在浮空模式下,其默认输入不一样;

图(5)是将传感器的数字信号端接入PA0口
在这里插入图片描述

6、输入接收函数

uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);

第一个函数是读取输入寄存器的某一个端口的值。第二个函数是读取整个输入寄存器的值

额外介绍两个函数

uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);

这两个函数是用来读取输出寄存器的值,用来查看输出寄存器输出了哪个值。第一个函数是看输出寄存器的某一位,而第二个函数是用来看整个输出寄存器的值。

7、按钮控制小灯

使用PB1和PB11两个端口作为输入端口,连接两个按钮
使用PA1和PA2两个端口作为输出端口,连接两个LED小灯

输入端口初始化

void KEY_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}

检测按钮按下

uint8_t KEY1_GetNum(void)
{
	uint8_t KeyNum = 0;//定义一个变量作为返回值,记录按钮状态
	
	if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)//检测按钮1按下
	{
		Delay_ms(20);//消除按钮按下的抖动
		while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0);//循环检测按钮松手
		Delay_ms(20);//消除松手的抖动
		KeyNum = 1;
	}
	if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0)
	{
		Delay_ms(20);
		while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0);
		Delay_ms(20);
		KeyNum = 2;
	}
	return KeyNum;
}

输出端口初始化

void LED_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIOInitStructure;
	GPIOInitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIOInitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_1;
	GPIOInitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOA, &GPIOInitStructure);
	GPIO_SetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2);//初始化小灯熄灭
}

按键控制小灯

当小灯熄灭时,按键按下是点亮小灯,当小灯点亮时,按键按下是熄灭小灯,实现此功能需知晓按键按下时,小灯的状态,即该接口输出了什么。刚好需要用到上文介绍的 GPIO_ReadOutputDataBit函数

void LED_Turn(uint8_t Led)//通过传入的参数判断是哪个按键按下
{
	//Led  
	if(Led == 1)
	{//按键1按下,控制小灯1
		if(GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1) == 0)//获取小灯当前状态
	  {
		  GPIO_SetBits(GPIOA, GPIO_Pin_1);//熄灭小灯
	  }
	  else{
		  GPIO_ResetBits(GPIOA, GPIO_Pin_1);//点亮小灯
		}
	}
	else{//按键2按下控制小灯2
		if(GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_2) == 0)//获取小灯当前状态
		{
		  GPIO_SetBits(GPIOA, GPIO_Pin_2);//熄灭小灯
	  }
	  else{
		  GPIO_ResetBits(GPIOA, GPIO_Pin_2);//点亮小灯
		}
	}
}

主函数调用

uint8_t KeyNum = 0;
//按钮控制小灯
int main(void)
{
	LED_Init();//初始化LED小灯
	KEY_Init();//初始化按键模块
	while(1)
	{
		KeyNum = KEY1_GetNum();//获取按键状态
		if(KeyNum == 1)
		{//按键1按下
			LED_Turn(1);
		}                                                                                                
		
		if(KeyNum == 2)
		{//按键2按下
			LED_Turn(2);
		}
	}
}

8、光敏电阻控制蜂鸣器

光敏电阻初始化

void LightSensor_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}

蜂鸣器初始化

void Buzzer_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIOInitStructure;
	GPIOInitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIOInitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIOInitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOB, &GPIOInitStructure);
	GPIO_SetBits(GPIOB, GPIO_Pin_1);
}

光敏电阻输入信号

uint8_t LightSensor_GetNum(void)
{
	return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);
}

蜂鸣器输出信号

void Buzzer_ON(void)
{
	GPIO_ResetBits(GPIOB, GPIO_Pin_1);
}

void Buzzer_OFF(void)
{
	GPIO_SetBits(GPIOB, GPIO_Pin_1);
}

void Buzzer_Turn(void)
{
	if(GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_1) == 0)
	{
		GPIO_SetBits(GPIOB, GPIO_Pin_1);
	}
	else
	{
		GPIO_ResetBits(GPIOB, GPIO_Pin_1);
	}
}

主函数控制

int main(void)
{
	Buzzer_Init();
	LightSensor_Init();
	uint8_t KeyNum = 1;
	while(1)
	{
		KeyNum = LightSensor_GetNum();
		if(KeyNum == 1)
		{
			Buzzer_ON();
		}
		else{
		  Buzzer_OFF();
		}
	}
}

总结

本文介绍了GPIO的八种工作模式电路结构的简单介绍,以及控制GPIO接口输入输出代码编写步骤和函数理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值