GPIO(General Purpose Input-Output)引脚用作一般的数字输入输出引脚。其内部有双向保护二极管,有可配置是否使用的上拉和下拉电阻。
一个GPIO口的16个引脚的功能可以单独设置,每个引脚的输入输出数据可以单独读取或输出。
一共有四种模式,如下(只需要懂输入浮空、上拉、下拉,推挽输出就够用了,想要进一步了解可以查看GPIO输入输出模式原理)。
(1)输入浮空(Input floating),并且不使用上拉或下拉。
(2)输入上拉(Input pull-up),使用内部上拉电阻,引脚外部无输入时读取的引脚输入电平为高电平。
(3)输入下拉(Input pull-down),使用内部下拉电阻,引脚外部无输入时读取的引脚输入电平为低电平。
举例: 以下是一个按键输入电路图。
通过电路图可以知道,想要使得按键有用(即当按键按下时相应的引脚电平高低发生变化),PA0脚必须保持低电平(0V),PE4、PE3、PE2必须保持高电平(3.3V)。四个按键都没有按下时,四个引脚的电平发生变化。由此确定GPIO输入的上拉和下拉。
即:PA0:下拉输入,未按下时,PA0输入为0,按下后PA0输入为1
PE2、PE3、PE4:上拉输入,未按下时,输入为1,按下后输入为0
(1)具有上拉或下拉的开漏输出(Output open-drain)。如果没有上拉或下拉,开漏输出1时引脚是高阻态,输出0时引脚是低电平,这种模式可用于共用总线的信号。
(2)具有上拉或下拉的推挽输出(Output push-pull)。如果没有上拉或下拉,推挽输出1时引脚为高电平,输出0时引脚为低电平。若需要增强引脚输出驱动能力,就可以使用上拉。
举例: 以下是一个LED输出电路图。
通过电路可知,想要让LED亮起,PF9和PF10必须保持低电平,反之,保持高电平,由此确定确定PF9和PF10为推挽输出。
与推挽输出相对的就是开漏输出,对于开漏输出和推挽输出的区别最普遍的说法就是开漏输出无法真正输出高电平,即高电平时没有驱动能力,需要借助外部上拉电阻完成对外驱动。**很少用到,知道基本的概念就行了,**想要进一步了解请查看其它博客。
模拟(Analog 功能),作为GPIO模拟引脚,用于ADC输入或DAC输出引脚。
(1)具有上拉或下拉的复用功能推挽(Alternate function push-pull)
(2)具有上拉或下拉的复用功能开漏(Alternate function open-drain)
接下来的编程在接口调试的基础上进行的,如果没有接口调试这一步程序将无法烧录,链接:接口调试。
设计目标:LED灯以一定频率闪烁,按一次按键后灯的闪烁频率发生变化。
该例以一款自带外设的stm32F405系列的单片机为例,如果使用无外设的单片机(如STM32F103C8T6小系统板),请按照需求自行连接外设。
已知电路图如下:
由此可知LED灯的引脚为PB13,按键的引脚为PB14。
这里的输入为按键,且当按键未按下时,PB14为高电平,按键按下后,PB14为低电平,即为上拉输入。
LED灯PB13引脚为推挽输出。
接下来的操作将在上一个博客的基础上进行操作。
将PB13和PB14引脚的模式分别选为GPIO_Output和GPIO_Input,点击右键分别命名为“LED1”和“KeyUser”
接下来,点击左面System Core选项卡中的GPIO,分别配置PB13和PB14引脚。具体如下图:
完成以上配置后,点击生成代码(GENERATE CODE),并打开IDE工程文件。`
接下来,在打开的IDE文件中进行编程。
在主函数(main.c)中的while循环中加入以下代码:`
if(HAL_GPIO_ReadPin(KeyUser_GPIO_Port, KeyUser_Pin)== GPIO_PIN_RESET) //如果读取到的KeyUser引脚的电平状态为低电平(即按键按下)
{
HAL_Delay(50); //防止按键抖动,延时50ms
if(HAL_GPIO_ReadPin(KeyUser_GPIO_Port, KeyUser_Pin)==GPIO_PIN_RESET)//再次判断按键是否按下,如果按下
{
HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin, GPIO_PIN_SET); //LED灯的引脚输出高电平(即灯灭)
HAL_Delay(300);
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET); //LED灯的引脚输出低电平(既灯亮)
HAL_Delay(300); //交替进行进而闪烁
}
}
else //按键没有按下时
{
HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin, GPIO_PIN_SET); //同理
HAL_Delay(1000);
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
HAL_Delay(1000);
}
(代码都有注释,不做过多说明)
运行烧录后,现象为:灯以1秒的频率进行闪烁,按下按键后灯以0.3秒的频率进行闪烁,松手后又以1秒的频率闪烁。
为了确保按键按下后松开,灯依旧保持不同频率的闪烁,加入按键检测和一个变量对代码进行优化。
在gpio.c文件中加入按键扫描的代码:
uint8_t Key_Scan(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin)
{
if(HAL_GPIO_ReadPin(KeyUser_GPIO_Port, KeyUser_Pin) == KEY_OFF)
{
while (HAL_GPIO_ReadPin(KeyUser_GPIO_Port, KeyUser_Pin) == KEY_OFF)//消除按键抖动
return KEY_OFF;
}
else
return KEY_ON;
}
在gpio.h文件中加入宏定义和函数声明相关代码:
#define KEY_ON 1
#define KEY_OFF 0
uint8_t Key_Scan(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin);
在main.h文件中的while循环中加入以下代码:
if(Key_Scan(KeyUser_GPIO_Port, KeyUser_Pin)==KEY_OFF)
{ A = A + 1;
HAL_Delay(100);
}
if(A % 2 == 1)
{
HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);//电平跳转
HAL_Delay(1000);
}
else
{
HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
HAL_Delay(300);
}
注意这里请在while循环外面单独定义A为一个整数(如:int A=1;)。
运行烧录后,现象为:灯以1秒的频率进行闪烁,按下按键松手后灯以0.3秒的频率进行闪烁,再次按下按键松手后又以1秒的频率闪烁。
(注意:以上两种控制不一样,一种是按下后不松手产生频率变化,一种是按下后松手产生频率变化)
以下是该示例的代码链接:GPIO输入输出的应用(按键控制灯的闪烁)配套学习代码
以上是关于GPIO输入输出的相关介绍和应用实践。GPIO是stm32最基础的内容,初学者只需要了解推挽输出,上拉输入和下拉输入,理解每一句代码就达到GPIO学习的效果了。同样,把LED灯换成其它外设(如蜂鸣器)也是一样的过程。
对于初学者要熟悉使用CubeMX和CubeIDE这两个软件。知道代码在IDE中编写的位置(必须放置在Begin和end之间),如果位置错误,再次生成代码时原有代码将被移除(在本例中,while循环中的语句位置有意错误,你发现了吗?自行调整)。
/* USER CODE END WHILE */
//while循环中代码位置
/* USER CODE BEGIN 3 */
至此,GPIO输入输出的内容已经讲完。大家一起学习一起进步,希望大家点赞和关注,下期将带来OLED显示屏的内容。
[STM32Cube HAL库教程](一)调试接口的设置及仿真器(ST-Link、J-Link)连接调试