欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

STM32 GPIO之二——按键例程 学习总结

程序员文章站 2022-06-09 08:43:39
...

一. GPIO的8种工作模式

1.4种输入模式:

(1)上拉输入模式(GPIO_Mode_IPU):在默认状态下(GPIO引脚无输入),读取得的GPIO引脚数据为1,高电平。

(2)下拉输入模式(GPIO_Mode_IPD):在默认状态下(GPIO引脚无输入),读取得的GPIO引脚数据为0,低电平。

(3)浮空输入模式(GPIO_Mode_IN_FLOATING):一般把这种模式用于标准的通信协议如I²C、USART的接收端。

(4)模拟输入模式(GPIO_Mode_AIN):使用ADC外设时,必须设置为模拟输入模式。

2.4种输出模式:

(1)推挽输出模式(GPIO_Mode_OUT_PP):一般应用在输出电平为0到3.3伏的场合。

(2)开漏输出模式(GPIO_Mode_OUT_OD):一般应用在电平不匹配的场合。

(3)复用推挽输出模式:如GPIO的引脚用作串口的输出。

(4)复用开漏输出模式:如在IC、SMBUS这些需要线与功能的复用场合。

二、开发板原理图如下:

STM32 GPIO之二——按键例程 学习总结

三、测试代码:

实现功能:LED1亮,按下按键时LED1灭,再按下按键时LED1亮,如此循环。

STM32 GPIO之二——按键例程 学习总结


/*led.c*/
#include "led.h"

/*配置LED用到的I/O口*/

void LED_GPIO_Config(void)
{
	/*定义一个GPIO_InitTypeDef类型的结构体*/
   GPIO_InitTypeDef GPIO_InitStructure;
	
	/*开启GPIOC的外设时钟*/
	 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);
	
	/*选择要控制的GPIO引脚*/
	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_6 | GPIO_Pin_5;
	
	/*设置引脚模式为通用推挽输出*/
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	
	/*设置引脚速率为50MHz*/
	 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	/*调用库函数,初始化GPIOB、GPIOD*/
	 GPIO_Init(GPIOB,&GPIO_InitStructure);
	 GPIO_Init(GPIOD,&GPIO_InitStructure);
	
	/*关闭所有LED灯*/
	 GPIO_SetBits(GPIOB,GPIO_Pin_5);//3、6、5引脚输出高电平,关闭三盏LED灯
	 GPIO_SetBits(GPIOD,GPIO_Pin_3|GPIO_Pin_6);
	                                                       
}

/*led.h*/
#ifndef __LED_H
#define __LED_H

#include "stm32f10x.h"

#define ON  0
#define OFF 1

#define LED1(a) if(a) \
                 GPIO_SetBits(GPIOD,GPIO_Pin_3);\
				 else   \
				 GPIO_ResetBits(GPIOD,GPIO_Pin_3)
				 
#define LED2(a) if(a) \
                 GPIO_SetBits(GPIOD,GPIO_Pin_6);\
				 else   \
				 GPIO_ResetBits(GPIOD,GPIO_Pin_6)	
				 
#define LED3(a) if(a) \
                 GPIO_SetBits(GPIOB,GPIO_Pin_5);\
				 else   \
				 GPIO_ResetBits(GPIOB,GPIO_Pin_5)
	
void LED_GPIO_Config(void);

#endif /*__LED_H*/
				 

/*key.c*/
#include "key.h"

void Delay(u16 time)
{    
   u16 i=0;  
   while(time--)
   {
      i=10;  //自己定义
      while(i--) ;    
   }
}
/*
*函数名:Key_GPIO_Config
*描述  :配置按键用到的I/O口
*输入  :无
*输出  :无
*/
void Key_GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
	
	  /*开启按键端口(PE5)的时钟*/
	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
	
	  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
	//GPIO_InitStructure.GPIO_Speed = GPIO_Speed_MHZ;
	  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	
	  GPIO_Init(GPIOC,&GPIO_InitStructure);
}

/*
*函数名:Key_Scan(GPIO_TypeDef* GPIOx,u16 GPIO_Pin)
*描述  :检测是否有按键按下
*输入  :GPIOx:x 可以是A,B,C,D或者E
*        GPIO_Pin:待读取的端口位
*输出  :KEY_OFF(没按下按键)、KEY_ON(按下按键)
*/
u8 Key_Scan(GPIO_TypeDef* GPIOx,u16 GPIO_Pin)
{
  /*检测是否有键按下*/
	if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON )
	{
     /*延时消抖*/
		 Delay(10000);
		    if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON )
				{
             /*等待按键释放*/
					while(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON);
					          return KEY_ON;
        }
		else
			      return KEY_OFF;
  }
 else
	      return KEY_OFF;
}
/*key.h*/

#ifndef __KEY_H
#define __KEY_H

#include "stm32f10x.h"

#define KEY_ON  0
#define KEY_OFF 1

void Key_GPIO_Config(void);
u8 Key_Scan(GPIO_TypeDef* GPIOx,u16 GPIO_Pin);
void Delay(u16 time);
#endif /*__LED_H*/

/*main.c*/
#include "stm32f10x.h"
#include "led.h"
#include "key.h" 
int main (void)
{
	 LED_GPIO_Config();
	 LED1( ON );
	
	 Key_GPIO_Config();
	
   while(1)
	{
      if( Key_Scan(GPIOC,GPIO_Pin_5) == KEY_ON )
			{
				/*LED反转*/
        GPIO_WriteBit(GPIOB, GPIO_Pin_5,(BitAction)((1-GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_5))));
				
      }
  }
} 

四、范例

/*stm32v5_led.c*/

#include "stm32v5_led.h"

static led_gpio_t   leds_gpio[MAX_LED] =
{
		{LED1, GPIOB, GPIO_Pin_5}, /* LED1 用的GPB5 */
		{LED2, GPIOD, GPIO_Pin_6}, /* LED2 用的GPD6 */
		{LED3, GPIOD, GPIO_Pin_3}, /* LED3 用的GPD3 */		
};


void init_led_gpio(void)
{
	int                i;
	GPIO_InitTypeDef   GPIO_InitStructure;

	/* 使能PB和PD组 GPIO的时钟 */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOD , ENABLE);	
	
	/*设置 PB5(LED1), PD6(LED2), PD3(LED3)为 GPIO 输出推免模式,口线翻转速度为50MHz */
	for(i=0; i<MAX_LED; i++)
	{
		/*设置 PB5(LED1)为 GPIO 输出推免模式,口线翻转速度为50MHz */
		GPIO_InitStructure.GPIO_Pin = leds_gpio[i].pin;				     
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(leds_gpio[i].group, &GPIO_InitStructure);						
  }
}

void turn_led(int which, int cmd)
{
   if(which<0 || which> MAX_LED )
		 return;
	 
	 if(OFF == cmd)
		 GPIO_ResetBits(leds_gpio[which].group, leds_gpio[which].pin);
	 else
		 GPIO_SetBits(leds_gpio[which].group, leds_gpio[which].pin);
}


/*stm32v5_led.h*/
#ifndef __STM32V5_LED_H
#define __STM32V5_LED_H

#include"stm32f10x.h"

#define ON           1
#define OFF          0

enum 
{
  LED1 = 0,
	LED2,
	LED3,
	MAX_LED,
};

typedef struct led_gpio_s
{
	int                 num;    /* LED编号 */
	GPIO_TypeDef        *group; /* LED使用的GPIO在哪一组: GPIOB or GPIOD */	
  uint16_t            pin;    /* LED使用的GPIO组中的那一个pin: GPIO_Pin_x */
} led_gpio_t;

extern void init_led_gpio(void);
extern void turn_led(int which, int cmd);

#endif

/*stm32v5_key.c*/
#include "stm32f10x.h"
#include "stm32f10x_exti.h"
#include "stm32f10x_rcc.h"
#include "misc.h"
#include "stm32v5_led.h"
#include "stm32v5_key.h"

#define DEFINE_PIN_EXTI(group, pin, IRQn, SubPriority) \
void init_P##group##pin##_as_EXTI(void) \
{ \
	GPIO_InitTypeDef GPIO_InitStructure; \
	EXTI_InitTypeDef EXTI_InitStructure; \
	NVIC_InitTypeDef NVIC_InitStructure; \
	\
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO##group|RCC_APB2Periph_AFIO, ENABLE); \
	\
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_##pin;	\
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; \
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; \
  GPIO_Init(GPIO##group, &GPIO_InitStructure); \
	\
	GPIO_EXTILineConfig(GPIO_PortSourceGPIO##group, GPIO_PinSource##pin); \
  EXTI_InitStructure.EXTI_Line = EXTI_Line##pin; \
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; \
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; \
  EXTI_InitStructure.EXTI_LineCmd = ENABLE; \
  EXTI_Init(&EXTI_InitStructure);	\
	\
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); \
  NVIC_InitStructure.NVIC_IRQChannel = IRQn;	\
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; \
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; \
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;	\
  NVIC_Init(&NVIC_InitStructure); \
} 

/* Key1(PC5) configured as EXTI5, SubPriority as 1 */
DEFINE_PIN_EXTI(C, 5, EXTI9_5_IRQn, 1)

/* Key2(PC2) configured as EXTI2, SubPriority as 2 */
DEFINE_PIN_EXTI(C, 2, EXTI2_IRQn, 2)

/* Key3(PC3) configured as EXTI3, SubPriority as 3 */
DEFINE_PIN_EXTI(C, 3, EXTI3_IRQn, 3)

/* PC5 Key1 interrupt handler */
void EXTI9_5_IRQHandler(void)
{
	static uint8_t        led1_status = OFF;
	
	if(EXTI_GetITStatus(EXTI_Line5) != RESET)
	{
		led1_status ^= 1;	
		turn_led(LED1, led1_status);
//		EXTI_ClearITPendingBit(EXTI_Line5);
  }
}

/* PC2 Key2 interrupt handler */
void EXTI2_IRQHandler(void)
{
	static uint8_t        led2_status = OFF;
	
	if(EXTI_GetITStatus(EXTI_Line2) != RESET)
	{
		led2_status ^= 1;		
		turn_led(LED2, led2_status);
		EXTI_ClearITPendingBit(EXTI_Line2);
  }
}

/* PC3 Key3 interrupt handler */
void EXTI3_IRQHandler(void)
{
	static uint8_t        led3_status = OFF;
	
	if(EXTI_GetITStatus(EXTI_Line3) != RESET)
	{
		led3_status ^= 1;
		turn_led(LED3, led3_status);
		EXTI_ClearITPendingBit(EXTI_Line3);
  }
}

void init_keys_interrupt(void)
{
	init_PC5_as_EXTI();
	init_PC2_as_EXTI();
	init_PC3_as_EXTI();
}

/*stm32v5_key.h*/
#ifndef __STM32V5_KEY_H
#define __STM32V5_KEY_H

extern void init_keys_interrupt(void);

#endif

/*main.c*/
#include "stm32f10x.h"
#include "stm32v5_led.h"
#include "stm32v5_key.h"

int main(void)
{
	init_led_gpio();
	init_keys_interrupt();

  while(1)
  {
			;
  }
}