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这些需要线与功能的复用场合。
二、开发板原理图如下:
三、测试代码:
实现功能:LED1亮,按下按键时LED1灭,再按下按键时LED1亮,如此循环。
/*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)
{
;
}
}
上一篇: Linux串口编程