key.c
#include "key.h"
void KEY_GPIO_Config(KEY_Type KEYType){
GPIO_InitTypeDef GPIO_InitStruct;
if (KEYType == KEY1) {
RCC_APB2PeriphClockCmd(KEY1_CLK, ENABLE);
GPIO_InitStruct.GPIO_Pin = KEY1_PIN;
} else if (KEYType == KEY2) {
RCC_APB2PeriphClockCmd(KEY2_CLK, ENABLE);
GPIO_InitStruct.GPIO_Pin = KEY2_PIN;
}
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
if (KEYType == KEY1) {
GPIO_Init(KEY1_PORT, &GPIO_InitStruct);
} else if (KEYType == KEY2) {
GPIO_Init(KEY2_PORT, &GPIO_InitStruct);
}
}
uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin){
/*检测是否有按键按下 */
if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON )
{
/*等待按键释放 */
while(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON);
return KEY_ON;
}
else{
return KEY_OFF;
}
}
key.h
#ifndef __KEY_H
#define __KEY_H
#include "stm32f10x.h"
#define KEY_ON 1
#define KEY_OFF 0
#define KEY1_CLK RCC_APB2Periph_GPIOA
#define KEY1_PIN GPIO_Pin_0
#define KEY1_PORT GPIOA
#define KEY2_CLK RCC_APB2Periph_GPIOC
#define KEY2_PIN GPIO_Pin_13
#define KEY2_PORT GPIOC
typedef enum{
KEY1,
KEY2,
}KEY_Type;
void KEY_GPIO_Config(KEY_Type KEYType);
uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);
#endif
main.c
#include "stm32f10x.h"
#include "led.h"
#include "key.h"
#include "delay.h"
int main(void) {
//来到这里的时候,系统时钟已经被配置成72M
RGB_GPIO_Config(RGB_R); // 初始化红色 LED
RGB_GPIO_Config(RGB_G); // 初始化绿色 LED
RGB_GPIO_Config(RGB_B); // 初始化蓝色 LED
KEY_GPIO_Config(KEY1); //初始化KEY1
KEY_GPIO_Config(KEY2); //初始化KEY2
// RGB_ON(RGB, RED);
// RGB_OFF(RGB,RED);
// RGB_ON(RGB,BLUE);
// RGB_OFF(RGB,BLUE);
//
// RGB_ON(RGB,GREEN);
// RGB_OFF(RGB,GREEN);
while(1){
if((Key_Scan(KEY1_PORT,KEY1_PIN) == KEY_ON)){
RGB_ON(RGB, RED);
}
if(Key_Scan(KEY2_PORT,KEY2_PIN) == KEY_ON){
RGB_OFF(RGB,RED);
}
}
}
下面开始逐步讲解多个按键初始化要点
void KEY_GPIO_Config(KEY_Type KEYType){
GPIO_InitTypeDef GPIO_InitStruct;
if (KEYType == KEY1) {
RCC_APB2PeriphClockCmd(KEY1_CLK, ENABLE);
GPIO_InitStruct.GPIO_Pin = KEY1_PIN;
} else if (KEYType == KEY2) {
RCC_APB2PeriphClockCmd(KEY2_CLK, ENABLE);
GPIO_InitStruct.GPIO_Pin = KEY2_PIN;
}
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
if (KEYType == KEY1) {
GPIO_Init(KEY1_PORT, &GPIO_InitStruct);
} else if (KEYType == KEY2) {
GPIO_Init(KEY2_PORT, &GPIO_InitStruct);
}
}
以下是代码中的主要要点解释:
-
void KEY_GPIO_Config(KEY_Type KEYType)
:这是函数的声明和定义。它接受一个参数KEYType
,用来指示要配置的按键类型是KEY1
还是KEY2
。可以在KEY_Type枚举中继续添加key3,key4,key5,key6......typedef enum{ KEY1, KEY2, //.....可以继续枚举例如key3,key4,key5等等等等 }KEY_Type;
-
GPIO_InitTypeDef GPIO_InitStruct;
创建了一个名为GPIO_InitStruct
的结构体变量,用于存储 GPIO 初始化的配置信息。 -
RCC_APB2PeriphClockCmd(KEY1_CLK, ENABLE);
根据KEYType
的值,选择性地使能KEY1
或KEY2
对应的外设时钟。这样做是为了在初始化按键之前,确保相应的外设时钟已经被启用。 -
GPIO_InitStruct.GPIO_Pin = KEY1_PIN;
和GPIO_InitStruct.GPIO_Pin = KEY2_PIN;
根据KEYType
的值,选择性地设置GPIO_InitStruct
的GPIO_Pin
成员,即选择初始化KEY1
或KEY2
的引脚。 -
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
将GPIO_InitStruct
的GPIO_Mode
成员设置为GPIO_Mode_IN_FLOATING
,表示配置的引脚为悬空输入模式。 -
GPIO_Init(KEY1_PORT, &GPIO_InitStruct);
和GPIO_Init(KEY2_PORT, &GPIO_InitStruct);
根据KEYType
的值,选择性地将初始化配置应用到KEY1_PORT
或KEY2_PORT
引脚上。这里使用GPIO_Init
函数进行引脚初始化。
总的来说,这段代码的目的是根据传入的按键类型,在不同的引脚上进行初始化配置,确保相应的外设时钟已经被启用,并设置引脚为悬空输入模式,在这个框架上可以继续很方便快捷的扩展按键的初始化程序。
uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin){
/*检测是否有按键按下 */
if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON )
{
/*等待按键释放 */
while(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON);
return KEY_ON;
}
else{
return KEY_OFF;
}
}
-
uint8_t Key_Scan(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
这是函数的定义,它接受两个参数:一个指向GPIO_TypeDef
类型的指针GPIOx
,和一个表示GPIO引脚的GPIO_Pin
。函数返回一个uint8_t
类型的值,可能是KEY_ON
或者KEY_OFF
。 -
if (GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == KEY_ON) {
这是一个条件语句,检查给定的GPIO引脚是否处于被按下的状态 (KEY_ON
)。GPIO_ReadInputDataBit
是一个函数,用于读取指定GPIO引脚的输入状态。 -
表示如果上面的条件为真,则执行接下来的代码块。
-
while (GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == KEY_ON);
这是一个循环语句,它会一直循环执行,直到按键被释放。它通过不断地读取指定的GPIO引脚的输入状态来判断按键是否还处于按下状态。分号表示一个空的循环体,即没有实际的代码块执行。 -
return KEY_ON;
一旦按键被释放,循环将结束,函数将返回KEY_ON
,表示按键曾经被按下过。 -
else
如果条件判断的结果为假,即按键没有被按下,那么将执行这里的代码块。 -
return KEY_OFF;
这里直接返回KEY_OFF
,表示按键没有被按下。
总的来说,这段代码的作用是检测给定的GPIO引脚上的按键状态。如果按键被按下,它会等待按键释放,并返回 KEY_ON
,表示按键曾经被按下过。如果按键没有被按下,它会直接返回 KEY_OFF
。这种方式的按键扫描常见于嵌入式系统中,用于检测外部事件,比如按钮的按下和释放。
main.c
while(1){
if((Key_Scan(KEY1_PORT,KEY1_PIN) == KEY_ON)){
RGB_ON(RGB, RED);
}
if(Key_Scan(KEY2_PORT,KEY2_PIN) == KEY_ON){
RGB_OFF(RGB,RED);
}
}
我们在main.c中调用Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)等待按键被按下,得到返回值。将返回值和KEY_ON比较,KEY1被按下则让RGB灯的红色亮起,KEY2按键被按下则让RGB灯的红色熄灭,这是一个按键轮询检测的基本框架和原理,可以通过这个框架继续添加许多代码实现各种功能。