STM32单片机快速入门——GPIO篇
STM32单片机快速入门——GPIO篇
STM32单片机的GPIO(通用输入输出)端口是其重要的外设之一,广泛应用于各种嵌入式系统中。本文将从GPIO的基本概念、工作模式、常用库函数以及具体的编程实战等方面,帮助读者快速入门STM32的GPIO编程。
1.简介
STM32是一系列基于ARM Cortex-M内核的32位微控制器。该系列微控制器广泛应用于计算机、通讯、工业自动化、消费电子、汽车电子、医疗仪器及家庭电器等领域。该系列控制器具有高性能、低功耗、智能化等特点。其中,GPIO就是STM32控制器中的一种重要的通用输入输出口。
作为快速入门,重点应先学会使用,之后再深究其中原理,否则容易磨灭学习的热情,故不在这里对GPIO的具体结构以及相关寄存器做太多详细的介绍,如果读者想要深入研究,可参考此篇文章:
区别于51单片机的IO口,STM32的GPIO功能更加强大和灵活,能满足多样化和复杂的嵌入式系统需求,尤其在需要多种外设或模拟功能时具有显著优势。
我们以经典的STM32F103C8T6芯片进行讲解。
2.GPIO模式
STM32的GPIO总共有八种输入输出模式,个人感觉可分为三大类:
- 输入模式
- 输出模式
- 模拟模式
(1)输入模式
GPIO引脚配置为输入模式时,主要用于读取外部设备的信号的高电平或低电平(逻辑1或逻辑0)。这类模式进一步细分为以下几种:
- 浮空输入(Input Floating):引脚悬空时无内部上拉或下拉电阻,依赖外部电路提供信号,默认悬空状态。
- 上拉输入(Input Pull-Up):引脚内部连接上拉电阻,默认状态为高电平。
- 下拉输入(Input Pull-Down):引脚内部连接下拉电阻,默认状态为低电平。
(2)输出模式
GPIO引脚配置为输出模式时,用于控制外部设备或输出信号。这类模式进一步细分为以下几种:
- 推挽输出(Output Push-Pull):GPIO既可以输出高电平,也可以输出低电平。
- 开漏输出(Output Open-Drain):GPIO只能输出低电平,输出高电平时需要外部上拉电阻。
(3)模拟模式
- 模拟输入:引脚用于接收连续变化的模拟信号,信号直接输入到ADC模块,用于模数转换。例如:传感器信号采集(如温度、光线强度等)。
- 模拟输出:引脚用于数模转换,将数字信号转换为模拟信号输出。例如:音频信号生成、波形输出等。
3.GPIO常用库函数介绍
(1)GPIO初始化函数
GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)。
(2)读取GPIO状态函数
GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) :读取指定引脚的输入状态(高电平或低电平)。
GPIO_ReadInputData(GPIO_TypeDef* GPIOx) : 读取整个GPIO端口的输入数据寄存器内容。
GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) :用于读取指定引脚的输出状态。
GPIO_ReadOutputData(GPIO_TypeDef* GPIOx) :读取整个GPIO端口的输出数据寄存器内容。
(3)写入GPIO函数
GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) :指定引脚输出高电平。
GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) :指定引脚输出低电平。
GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal) :指定引脚输出指定电平。
GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal) :指定整个GPIO端口输出指定电平。
4.GPIO标准库配置步骤
(1)开启时钟
在文件stm32f10x_rcc.h中,可以找到三个有关于开关总线时钟的函数。对于STM32系列单片机而言,GPIO的时钟大多位于APB2总线,对APB2函数右键,跳转到函数定义,可以看到有哪些外设挂载到了APB2总线上。
函数的第一个参数是需要开启时钟的外设,第二个参数,填入ENABLE表示使能打开,填入DISABLE表示失能关闭。
(2)GPIO结构体参数配置
右键跳转到GPIO初始化结构体定义
第一个结构体参数:GPIO_Pin,即要初始化的引脚,若有多个需要进行同类型的初始化,可进行或操作,例如:GPIO_Pin_1 | GPIO_Pin_2。
第二个结构体参数:GPIO_Speed,即GPIO最快翻转速率,如无特殊要求,一般选用GPIO_Speed_50MHz。
选中GPIO_Speed后的GPIOSpeed_TypeDef,Ctrl+F进行查找,可以看到该参数可以取的值(以下操作同理)
第三个结构体参数:GPIO_Mode。
配置成模拟量输入:
a.GPIO_Mode_AIN。
配置成输入模式:
a.GPIO_Mode_IPU :配置成上拉输入。
b.GPIO_Mode_IPD :配置成下拉输入。
c.GPIO_Mode_IN_FLOATING :配置成浮空输入。
配置成输出模式:
a.GPIO_Mode_Out_OD :配置成开漏输出。
b.GPIO_Mode_AF_OD: 配置成复用开漏输出。
c.GPIO_Mode_Out_PP :配置成推挽输出。
d.GPIO_Mode_AF_PP :配置成复用推挽输出。
其中,带有复用的输出有别于正常的输出:除了兼容相应正常输出模式的功能以外,还与其他的外设和功能有联动。
(3)GPIO初始化
调用GPIO初始化函数:GPIO_Init;
5.编程实战
(1)点亮一个LED
这里我们以点亮STM32F103C8T6自带的LED进行演示,该LED位于GPIOC的Pin13上,写入低电平点亮。
/* 头文件 */
#include "stm32f10x.h" // 包含STM32F10x的设备头文件,定义了寄存器和外设相关的宏和函数
/* Main */
int main(void)
{
/* 开启 GPIOC 的时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //开启GPIOC的时钟,GPIOC外设挂载在APB2总线上
/* GPIOC结构体参数配置 */
GPIO_InitTypeDef GPIO_InitStructure; //定义一个结构体变量,用于配置 GPIO 参数
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置为推挽输出模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; //选择 GPIOC 的第13引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //配置输出速度为50MHz
/* GPIO结构体初始化 */
GPIO_Init(GPIOC, &GPIO_InitStructure); //调用 GPIO 初始化函数,根据配置初始化 PC13 引脚
/* 设置 GPIOC 第13引脚输出高电平 */
GPIO_ResetBits(GPIOC, GPIO_Pin_13); //将 PC13 引脚设置为低电平
while (1)
{
}
}
6.总结
(1)GPIO模式
1.输入模式:
浮空输入(GPIO_Mode_IN_FLOATING)
上拉输入(GPIO_Mode_IPU)
下拉输入(GPIO_Mode_IPD)
2.输出模式:
推挽输出(GPIO_Mode_Out_PP)
开漏输出(GPIO_Mode_Out_OD)
3.复用功能:
推挽复用(GPIO_Mode_AF_PP)
开漏复用(GPIO_Mode_AF_OD)
4.模拟输入/输出(GPIO_Mode_AIN)
(2)GPIO常用库函数
设置高电平:GPIO_SetBits(GPIOx, GPIO_Pin_x)
设置低电平:GPIO_ResetBits(GPIOx, GPIO_Pin_x)
切换电平:GPIO_WriteBit(GPIOx, GPIO_Pin_x, Bit_SET/Bit_RESET)
读取状态:GPIO_ReadInputDataBit / GPIO_ReadOutputDataBit
(3)GPIO标准库配置步骤
1.开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx, ENABLE);
2.创建初始化结构体
GPIO_InitTypeDef GPIO_InitStructure;
3.配置结构体参数
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 输出速度
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_x; // 选择引脚
4.调用 GPIO_Init 函数
GPIO_Init(GPIOx, &GPIO_InitStructure);
5.引脚操作
GPIO_SetBits(GPIOx, GPIO_Pin_x); // 设置高电平
GPIO_ResetBits(GPIOx, GPIO_Pin_x); // 设置低电平
uint8_t pinState = GPIO_ReadInputDataBit(GPIOx, GPIO_Pin_x); // 读取引脚状态
//... ...