STM32学习笔记02-GPIO

目录

GPIO简介

GPIO基本结构

GPIO模式

浮空输入、上拉输入、下拉输入

模拟输入

开漏输出、推挽输出

复用开漏输出、复用推挽输出

GPIO应用-GPIO点灯


GPIO简介

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

GPIO基本结构

        首先所有GPIO都挂在APB2外设总线上,名称按GPIOA、GPIOB、GPIOC...命名,对于STM32F103每个GPIO外设有16个引脚编号0-15,GPIOA的0号引脚也称为PA0,GPIOA的1号引脚PA1,以此类推。

        每个GPIO模块,主要包含寄存器和驱动器,内核通过APB2总线对寄存器进行读写,完成输出电平和读取电平的功能。例如输出寄存器写1,则引脚输出高电平,写0输出低电平;输入寄存器读取为1则表示对应端口目前是高电平。STM32是32位单片机,内部寄存器是32位的,但端口只有16位,所以这个寄存器只有低16位对应有端口,高16位没有用到。驱动器用来增强信号驱动能力。

接下来看一下GPIO中每一位的具体电路结构。注意:肖特基触发器为翻译错误,实际为施密特触发器

GPIO模式

浮空输入、上拉输入、下拉输入

模拟输入

开漏输出、推挽输出

复用开漏输出、复用推挽输出

GPIO应用-GPIO点灯

学习了GPIO的基础知识后,接下来我们来操作STM32的GPIO吧!

学习单片机的第一步成为点灯大师。示例接线图:

如图只要给PA0一个低电平则LED正向通电点亮。现在我们来完成这个需求吧:

第一步使用RCC开启GPIO时钟

先来认识几个常用RCC的库函数:

/*
* 启用或禁用AHB外设时钟
* 参数1  RCC_AHBPeriph:指定AHB外设对其时钟进行门控。
* 参数2  NewState:指定外设时钟的新状态。取值为:ENABLE或DISABLE。
* 返回值:无
*/
void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState);
/*
* 开启或关闭APB2 (High Speed APB)外设时钟开关
* 参数1  RCC_APB2Periph:指定APB2外设对其时钟进行门控。
* 参数2  NewState:指定外设时钟的新状态。取值为:ENABLE或DISABLE。
* 返回值:无
*/
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);

/*
* 启用或禁用APB1 (Low Speed APB)外设时钟。
* 参数1  RCC_APB1Periph:指定APB1外设对其时钟进行门控。
* 参数2  NewState:指定外设时钟的新状态。取值为:ENABLE或DISABLE。
* 返回值:无
*/
void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);

由于GPIO都挂在APB2外设总线上,所以我们使用RCC的APB2外设时钟控制函数,又因为我们把LED接在PA0上,所以开启GPIOA的时钟。

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

第二步使用GPIO_Init()函数初始化GPIO。

同样先认识几个函数:

/*
* 将GPIOx外设寄存器初始化为其默认重置值。
* 参数  GPIOx:其中x可以为(A..G)选择GPIO外设。
* 返回值:无
*/
void GPIO_DeInit(GPIO_TypeDef* GPIOx);
/*
* 取消初始化备用函数(重新映射、事件控制)和EXTI配置,注册到它们的默认重置值。
* 参数:无
* 返回值:无
*/
void GPIO_AFIODeInit(void);
/*
* 根据GPIO_InitStruct中指定的参数初始化GPIOx外设。
* 参数1 GPIOx:其中x可以为(A..G)选择GPIO外设。
* 参数2 GPIO_InitStruct:指向GPIO_InitTypeDef结构的指针其中包含指定GPIO外设的配置信息。
* 返回值:无
*/
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
/*
* 为每个GPIO_InitStruct成员赋默认值。
* 参数 GPIO_InitStruct:指向被初始化的GPIO_InitTypeDef结构体的指针。
* 返回值:无
*/
void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct);

我们现在只需使用GPIO_Init()函数,第一个参数初始化GPIOA,第二个参数是结构体,跳转到定义有三个成员。

/** 
  * GPIO Init结构定义  
  */
typedef struct
{
  uint16_t GPIO_Pin;             /*!< 指定要配置的GPIO引脚。
该参数可以是@ref GPIO_pins_define的任意值 */

  GPIOSpeed_TypeDef GPIO_Speed;  /*!< 指定所选引脚的速度。
该参数可以是@ref GPIOSpeed_TypeDef的值*/

  GPIOMode_TypeDef GPIO_Mode;    /*!< 指定所选引脚的工作模式。
该参数可以是@ref GPIOMode_TypeDef的值 */
}GPIO_InitTypeDef;

第一个成员GPIO_Pin。可以选择GPIO_Pin_0到GPIO_Pin_15对应0到15号引脚,GPIO_Pin_All选中所有。我们使用PA0所以选择GPIO_Pin_0。

/** @defgroup GPIO_pins_define 
  * @{
  */

#define GPIO_Pin_0                 ((uint16_t)0x0001)  /*!< Pin 0 selected */
#define GPIO_Pin_1                 ((uint16_t)0x0002)  /*!< Pin 1 selected */
#define GPIO_Pin_2                 ((uint16_t)0x0004)  /*!< Pin 2 selected */
#define GPIO_Pin_3                 ((uint16_t)0x0008)  /*!< Pin 3 selected */
#define GPIO_Pin_4                 ((uint16_t)0x0010)  /*!< Pin 4 selected */
#define GPIO_Pin_5                 ((uint16_t)0x0020)  /*!< Pin 5 selected */
#define GPIO_Pin_6                 ((uint16_t)0x0040)  /*!< Pin 6 selected */
#define GPIO_Pin_7                 ((uint16_t)0x0080)  /*!< Pin 7 selected */
#define GPIO_Pin_8                 ((uint16_t)0x0100)  /*!< Pin 8 selected */
#define GPIO_Pin_9                 ((uint16_t)0x0200)  /*!< Pin 9 selected */
#define GPIO_Pin_10                ((uint16_t)0x0400)  /*!< Pin 10 selected */
#define GPIO_Pin_11                ((uint16_t)0x0800)  /*!< Pin 11 selected */
#define GPIO_Pin_12                ((uint16_t)0x1000)  /*!< Pin 12 selected */
#define GPIO_Pin_13                ((uint16_t)0x2000)  /*!< Pin 13 selected */
#define GPIO_Pin_14                ((uint16_t)0x4000)  /*!< Pin 14 selected */
#define GPIO_Pin_15                ((uint16_t)0x8000)  /*!< Pin 15 selected */
#define GPIO_Pin_All               ((uint16_t)0xFFFF)  /*!< All pins selected */

 第二个成员GPIO_Mode,选择引脚工作模式,对应讲过的八种模式。我们点灯选择推挽输出,当然你选择其他输入方式也可以,自行试验。

typedef enum
{ GPIO_Mode_AIN = 0x0, //模拟输入
  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;

第三个成员GPIO_Speed,选择50MHz就行了。

/ * *
* 输出最大频率选择
* /
typedef enum
{
GPIO_Speed_10MHz = 1,
GPIO_Speed_2MHz,
GPIO_Speed_50MHz
} GPIOSpeed_TypeDef;

综合上述,赋值如下。至此我们完成了初始化,GPIO_Init()函数执行完这个GPIOA外设的0号引脚就自动配置为推挽输出、50MHz的速度了,执行逻辑是读取结构体参数,执行一堆判断和运算,最后写入到GPIO配置寄存器,这些细节我们就不用关心了。

GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

第三步使用输出或者输入的函数控制GPIO口。

利用GPIO的库函数,掌握八个相关函数

/*
* 读取指定的输入端口引脚。
* 参数1 GPIOx:其中x可以为(A..G)选择GPIO外设。
* 参数2 GPIO_Pin:要读取的端口位。该参数可以是GPIO_Pin_x,其中x可以是(0..15)。
* 返回值:输入端口引脚值。
*/
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
/*
* 读取指定的输出数据端口位。
* 参数1 GPIOx:其中x可以为(A..G)选择GPIO外设。
* 参数2 GPIO_Pin:要读取的端口位。该参数可以是GPIO_Pin_x,其中x可以是(0..15)。
* 返回值:输出端口引脚值。
*/
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
/*
* 读取指定的GPIO输出数据端口。
* 参数 GPIOx:其中x可以为(A..G)选择GPIO外设。
* 返回值:GPIO输出数据端口值。
*/
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
/*
* 读取指定的GPIO输入数据端口。
* 参数 GPIOx:其中x可以为(A..G)选择GPIO外设。
* 返回值:GPIO输入数据端口值。
*/
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
/*
* 设置所选数据端口位。
* 参数1 GPIOx:其中x可以为(A..G)选择GPIO外设。
* 参数2 GPIO_Pin:需要写的端口位。该参数可以是GPIO_Pin_x的任意组合,其中x可以是(0..15)。
* 返回值:无
*/
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
/*
* 清除所选数据端口位。
* 参数1 GPIOx:其中x可以为(A..G)选择GPIO外设。
* 参数2 GPIO_Pin:指定要写入的端口位。该参数可以是GPIO_Pin_x的任意组合,其中x可以是(0..15)。
* 返回值:无
*/
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
/*
* 设置或清除所选数据端口位。
* 参数1 GPIOx:其中x可以为(A..G)选择GPIO外设。
* 参数2 GPIO_Pin:要写的端口位。该参数可以是GPIO_Pin_x中的一个,其中x可以是(0..15)。
* 参数3 BitVal:表示要写入所选位的值。该参数可以是BitAction枚举值之一:
*    Bit_RESET:清除端口引脚
*    Bit_SET:设置端口引脚
* 返回值:无
*/
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
/*
* 将数据写入指定的GPIO数据端口。
* 参数1 GPIOx:其中x可以为(A..G)选择GPIO外设。
* 参数2 PortVal:要写入端口输出数据寄存器的值。
* 返回值:无
*/
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);

 我们给PA0一个低电平,可以用GPIO_ResetBits:

GPIO_ResetBits(GPIOA, GPIO_Pin_0);

好了,接下来可以自行完成LED闪烁、流水灯等操作,也可以玩玩蜂鸣器,都是差不多的方法。

#include "stm32f10x.h"                  // Device header

int main(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
    GPIO_ResetBits(GPIOA, GPIO_Pin_0);
	while (1)
	{
		
	}
}

  • 9
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值