GPIO介绍

本文主要是在学习STM32开发过程中记录一些学习过程,日后可以经常查看。

1 GPIO概述

GPIO是STM32最基本的外设之一。

GPIO是通用输入输出端口(General-purpose input/output)的英文简写。

STM32单片机的GPIO被分为很多组,每组有16个引脚,不同型号的MCU的GPIO个数是不同的,比如STM32F103C8T6只有PA、PB以及个别PC引脚而STM32F103ZET6拥有PA~PG的全部112个引脚。

所有的GPIO都有基本的输入输出功能,同时GPIO还可以作为其它的外设功能引脚。

作为STM32最基本的外设,GPIO最基本的输出功能是由STM32控制 引脚输出高低电平,比如可以把GPIO接LED灯来控制其亮灭。

GPIO最基本的输入功能是检测外部电平变化,比如把GPIO引脚连接到按键电路,通过电平的高低变化来识别按键是否被按下。

2 GPIO工作模式

STM32的GPIO共有8种工作模式,分别是:

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

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

注意:

推挽输出可以输出强高低电平(高电平为3.3V),一般用来连接数字器件。在STM32的应用中,除了必须用开漏模式的场合,我们都习惯使用推挽输出模式。

开漏输出只可输出强低电平,高电平需要靠外部电阻拉高。输出端相当于三极管的集电极;要得到高电平状态需要上拉电阻才行。适合于做电流型的驱动,其吸收电流的能力相对强(一般20ma以内)。开漏输出一般应用在I2C、SMBUS通讯等需要“线与”功能的总线电路中。除此之外,还用在电平不匹配的场合,如需要输出5伏的高电平,就可以在外部接一个上拉电阻,上拉电源为5伏,并且把GPIO设置为开漏模式,当输出高阻态时,由上拉电阻和电源向外输出5伏电平。

3 GPIO复用和重映射

为了最大限度的利用端口资源,STM32的大部分端口都具有复用功能。

所谓复用,就是一些端口不仅仅可以做为通用IO口,还可以复用为一些外设引脚,比如PA9,PA10可以复用为STM32的串口1引脚。

为了方便布线  ,STM32配有端口重映射功能,所谓重映射就是可以把某些功能引脚映射到其他引脚。比如串口1默认引脚是PA9,PA10可以通过配置重映射映射到PB6,PB7。

4 GPIO寄存器

STM32的每组GPIO都包含7个寄存器,分别是:

        -  GPIOx_CRL:端口配置低寄存器

        - GPIOx_CRH:端口配置高寄存器

        - GPIOx_IDR:端口输入寄存器

        - GPIOx_ODR:端口输出寄存器

        - GPIOx_BSRR:端口位设置/清除寄存器

        - GPIOx_BRR :端口位清除寄存器

        - GPIOx_LCKR:端口配置锁存寄存器

每个I/O端口位可以自由编程,然而I/O端口寄存器必须按32位字被访问(不允许半字或字节访问) 
 

5 GPIO库函数编程

1> 初始化函数

//stm32l4xx_hal_gpio.h
/**
  * @brief   GPIO Init structure definition
  */
typedef struct
{
  uint32_t Pin;        /*!< Specifies the GPIO pins to be configured.
                           This parameter can be any value of @ref GPIO_pins */

  uint32_t Mode;       /*!< Specifies the operating mode for the selected pins.
                           This parameter can be a value of @ref GPIO_mode */

  uint32_t Pull;       /*!< Specifies the Pull-up or Pull-Down activation for the selected pins.
                           This parameter can be a value of @ref GPIO_pull */

  uint32_t Speed;      /*!< Specifies the speed for the selected pins.
                           This parameter can be a value of @ref GPIO_speed */

  uint32_t Alternate;  /*!< Peripheral to be connected to the selected pins
                            This parameter can be a value of @ref GPIOEx_Alternate_function_selection */
}GPIO_InitTypeDef;


/* Initialization and de-initialization functions *****************************/
void              HAL_GPIO_Init(GPIO_TypeDef  *GPIOx, GPIO_InitTypeDef *GPIO_Init);
void              HAL_GPIO_DeInit(GPIO_TypeDef  *GPIOx, uint32_t GPIO_Pin);

2> IO操作函数

//stm32l4xx_hal_gpio.h
/* IO operation functions ********/
GPIO_PinState     HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void              HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
void              HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void              HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin);
void              HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);

3> 例程

3.1> GPIO输出

#include "sys.h"
#include "delay.h"
#include "usart.h"

//RGB接口定义
#define LED_R(n)			(n?HAL_GPIO_WritePin(GPIOE,GPIO_PIN_7,GPIO_PIN_SET):HAL_GPIO_WritePin(GPIOE,GPIO_PIN_7,GPIO_PIN_RESET))
#define LED_R_TogglePin		HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_7)	//LED_R电平翻转

#define LED_G(n)			(n?HAL_GPIO_WritePin(GPIOE,GPIO_PIN_8,GPIO_PIN_SET):HAL_GPIO_WritePin(GPIOE,GPIO_PIN_8,GPIO_PIN_RESET))
#define LED_G_TogglePin     HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_8)	//LED_G电平翻转

#define LED_B(n)			(n?HAL_GPIO_WritePin(GPIOE,GPIO_PIN_9,GPIO_PIN_SET):HAL_GPIO_WritePin(GPIOE,GPIO_PIN_9,GPIO_PIN_RESET))
#define LED_B_TogglePin     HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_9)	//LED_B电平翻转


void led_init( void )
{
	/*
	LED-B	PE9
	LED-G	PE8
	LED-R	PE7	
	*/
    GPIO_InitTypeDef GPIO_InitStruct;
    __HAL_RCC_GPIOE_CLK_ENABLE(); //开启 GPIOE 时钟

    GPIO_InitStruct.Pin = GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_PULLUP;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
}

int main( void )
{
    HAL_Init();
  /* Configure the System clock to have a frequency of 80 MHz */
    SystemClock_Config();

    led_init(0);
    
    while(1)
    {
        LED_R(1);
        delay_ms(1000);
        LED_R(0);
        delay_ms(1000);
    }


    return 0;
}

3.2> GPIO输入

#include "sys.h"
#include "delay.h"
#include "usart.h"


#define KEY0        HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_10)
#define KEY1        HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_9)
#define KEY2        HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_8)
#define WK_UP       HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13)

#define KEY0_PRES 		1
#define KEY1_PRES		2
#define KEY2_PRES		3
#define WKUP_PRES   	4

void KEY_Init( void )
{
	/*
		KEY0 	- PD10 //低电平有效
		KEY1 	- PD9  //低电平有效
		KEY2 	- PD8  //低电平有效
		WK_UP 	- PC13  //高电平有效
	*/
	
	GPIO_InitTypeDef GPIO_InitStruct;
	
	__HAL_RCC_GPIOD_CLK_ENABLE();  //使能GPIOD 时钟
	__HAL_RCC_GPIOC_CLK_ENABLE();  //使能GPIOC 时钟
	
	GPIO_InitStruct.Pin = GPIO_PIN_8| GPIO_PIN_9 | GPIO_PIN_10;
	GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
	GPIO_InitStruct.Pull = GPIO_PULLDOWN;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
	
	GPIO_InitStruct.Pin = GPIO_PIN_13;
	GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
	GPIO_InitStruct.Pull = GPIO_PULLUP;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);	
}


/**
 * @brief	按键处理函数
 *
 * @remark	注意此函数有响应优先级,KEY0>KEY1>KEY2>WK_UP!!
 *
 * @param   mode	0:不支持连续按,1:支持连续按
 *
 * @return  u8		返回按键值	
*					0:没有任何按键按下,1:KEY0按下,2:KEY1按下,3:KEY2按下,4:WK_UP按下
 */
u8 KEY_Scan(u8 mode)
{
	static u8 key_up = 1;   //按键松开标志

    if(mode == 1)
		key_up = 1; //支持连按
	
	if(key_up && (KEY0 == 0 || KEY1 == 0 || KEY2 == 0 || WK_UP == 1))
    {
        delay_ms(10);
        key_up = 0;

        if(KEY0 == 0)       
			return KEY0_PRES;
        else if(KEY1 == 0)  
			return KEY1_PRES;
        else if(KEY2 == 0)  
			return KEY2_PRES;
        else if(WK_UP == 1) 
			return WKUP_PRES;
    }
    else if(KEY0 == 1 && KEY1 == 1 && KEY2 == 1 && WK_UP == 0)
		key_up = 1;

    return 0;   //无按键按下	
}

int main( void )
{
    HAL_Init();
  /* Configure the System clock to have a frequency of 80 MHz */
    SystemClock_Config();

    KEY_Init();
    
    u8 key = 0;
    while(1)
    {
        key = KEY_Scan(0);
	    switch( key )
	    {
		    case KEY0_PRES:
			    {
				    printf( "key0 press\n" );
			    }
			    break;
		    case KEY1_PRES:
			    {
				    printf( "key1 press\n" );
			    }
			    break;
		    case KEY2_PRES:
			    {
				    printf( "key2 press\n" );
			    }
			    break;
		    case WKUP_PRES:
			    {
				    printf( "wkup press\n" );
			    }
			    break;
		    default:
			    break;
	    }    
    }


    return 0;
}

3.3> GPIO外部中断

#include "sys.h"
#include "delay.h"
#include "usart.h"
/*
	KEY0 	- PD10
	KEY1 	- PD9
	KEY2 	- PD8
	WK_UP 	- PC13
*/
#define KEY0        HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_10)
#define KEY1        HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_9)
#define KEY2        HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_8)
#define WK_UP       HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13)

#define KEY0_PRES 		1
#define KEY1_PRES		2
#define KEY2_PRES		3
#define WKUP_PRES   	4


/**
 * @brief	外部中断初始化函数
 *
 * @param   void
 *
 * @return  void
 */
 void EXTI_Init( void )
 {
	 /*
		KEY0 	- PD10
		KEY1 	- PD9
		KEY2 	- PD8
		WK_UP 	- PC13
	*/
	 
	 GPIO_InitTypeDef GPIO_Initure; 
	
	 __HAL_RCC_GPIOC_CLK_ENABLE(); //使能GPIO_C时钟
	 __HAL_RCC_GPIOD_CLK_ENABLE(); //使能GPIO_D时钟
	 
	 GPIO_Initure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10;
	 GPIO_Initure.Mode = GPIO_MODE_IT_FALLING; //下降沿触发GPIO_MODE_IT_FALLING
	 GPIO_Initure.Pull = GPIO_PULLUP;
	 HAL_GPIO_Init( GPIOD, &GPIO_Initure );
	 
	 
	 GPIO_Initure.Pin = GPIO_PIN_13;
	 GPIO_Initure.Mode = GPIO_MODE_IT_RISING; //下降沿触发GPIO_MODE_IT_FALLING
	 GPIO_Initure.Pull = GPIO_PULLDOWN;
	 HAL_GPIO_Init( GPIOC, &GPIO_Initure );
	 
	 //中断线8,9
	 HAL_NVIC_SetPriority( EXTI9_5_IRQn, 2, 0 ); //抢占优先级为2,子优先级为0
	 HAL_NVIC_EnableIRQ( EXTI9_5_IRQn );		 //使能中断线
	 
	 HAL_NVIC_SetPriority( EXTI15_10_IRQn, 2, 1 );//抢占优先级为2,子优先级为1
	 HAL_NVIC_EnableIRQ( EXTI15_10_IRQn );		 //使能中断线
	 
 }
 
 
 /**
 * @brief	EXTI9_5中断服务函数, 产生中断的时候进入该函数
 *
 * @param   void
 *
 * @return  void
 */
 
 void EXTI9_5_IRQHandler(void)
 {
	HAL_GPIO_EXTI_IRQHandler( GPIO_PIN_8 ); //调用中断处理公用函数
	HAL_GPIO_EXTI_IRQHandler( GPIO_PIN_9 ); 
 }
 
 
 /**
 * @brief	EXTI15_10中断服务函数, 产生中断的时候进入该函数
 *
 * @param   void
 *
 * @return  void
 */
void EXTI15_10_IRQHandler(void)
{
	HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_10);//调用中断处理公用函数
	
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);//调用中断处理公用函数
}
 
 


/**
 * @brief	中断服务程序中需要做的事情,在HAL库中所有的外部中断服务函数都会调用此函数
 *          注:该函数时__WEEK函数
 * @param   GPIO_Pin	中断引脚号
 *
 * @return  void
 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	delay_ms(50);      //消抖
	switch(GPIO_Pin)
	{
		case  GPIO_PIN_13:		
            if( WK_UP == 1)
                printf("WK_KEY\n");
			break;

		case  GPIO_PIN_8:		
			if( KEY2 == 0)
				printf("KEY_2\n");
			break;

		case  GPIO_PIN_9:		
			if( KEY1 == 0)
			    printf("KEY_1\n");
			break;

		case  GPIO_PIN_10:		
			if( KEY0 == 0)
				printf("KEY_0\n");
			break;
		default:
			break;
	}
}


 
 
 int main( void )
{
    HAL_Init();
  /* Configure the System clock to have a frequency of 80 MHz */
    SystemClock_Config();
    EXTI_Init();

    while (1)
    {
        printf("OK\r\n");           //打印OK提示程序运行
        delay_ms(1000);             //每隔1s打印一次
    }
}
 
 
 
 
 
 
 
 
 
 

参考文档:

STM32-GPIO介绍_stm32上拉输入和下拉输入-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值