stm32的按键扫描[操作寄存器+库函数]
#include <stm32f10x_lib.h>
#include “system.h”
//Key 按键端口定义
#define key0 PAin(0)// PA0
#define key1 PAin(1)// PA1
#define key2 PAin(2)// PA2
#define key3 PAin(3)// PA3
//LED 按键端口定义
#define LED0 PAout(4)// PA4
#define LED1 PAout(5)// PA5
#define LED2 PAout(6)// PA6
#define LED3 PAout(7)// PA7
void Gpio_Init(void);//初始化函数
void Key_Scan(void);
int main(void)
{
Rcc_Init(9); //系统时钟设置
Gpio_Init(); //初始化与LED连接的硬件接口
while(1)
{
Key_Scan();
}
}
void Key_Scan(void)
{
if(key0 == 0 || key1 == 0 || key2 == 0 ||key3 == 0)
//if(GPIOA -> IDR != 0x000F)
{
delay(10000); //去抖动
if(key0 == 0)
{
while(key0 == 0); //检测按键松开
LED0 = !LED0;
}
if(key1 == 0)
{
while(key1 == 0);
LED1 = !LED1;
}
if(key2 == 0)
{
while(key2 == 0);
LED2 = !LED2;
}
if(key3 == 0)
{
while(key3 == 0);
LED3 = !LED3;
}
}
}
void Gpio_Init(void)
{
RCC->APB2ENR|=1<<2; //使能PORTA时钟
GPIOA->CRL&=0X0000FFFF; // PA0~3设置为浮空输入,PA4~7设置为推挽输出
GPIOA->CRL|=0X33334444;
}
- Systick 产生一个20ms的定时,在中断中去查询各个管脚的按键是否按下。 有按键按下,进入状态1.
- 如果按下,判断是否是抖动,是则返回状态0,不是则判断是哪个管脚按键按下,实现相应功能后进入状态2.
- 在状态2中,检测按键是否松开,松开则返回状态0,否则不改变状态。代码如下: main.c
#include “stm32f10x.h”
#define KEYPORT GPIOA
#define KEY0 GPIO_Pin_3
#define KEY1 GPIO_Pin_1
#define KEY2 GPIO_Pin_2
#define KEY3 GPIO_Pin_0
typedef enum
{
KeyScanState_0 = 0x00,
KeyScanState_1 = 0x01,
KeyScanState_2 = 0x02,
}KeyScanState_Typedef;
KeyScanState_Typedef KeyScanState;
void RCC_Configuration(void);
void GPIO_Configuration(void);
void SysTick_Set(vu32 x);
int main(void)
{
RCC_Configuration();
GPIO_Configuration();
SysTick_Set(20000);
while(1);
}
void SysTick_Handler(void)
{
vu16 keyState;
keyState = GPIO_ReadInputData(KEYPORT) & 0x000f;
switch(KeyScanState)
{
case KeyScanState_0:
{
if(keyState != 0x000f)
{
KeyScanState = KeyScanState_1;
}
break;
}
case KeyScanState_1:
{
if(keyState != 0x000f)
{
if(GPIO_ReadInputDataBit(KEYPORT,KEY0) == 0)
{
GPIO_WriteBit(GPIOA,GPIO_Pin_4,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_4)));
}else if(GPIO_ReadInputDataBit(KEYPORT,KEY1) == 0)
{
GPIO_WriteBit(GPIOA,GPIO_Pin_5,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_5)));
}else if(GPIO_ReadInputDataBit(KEYPORT,KEY2) == 0)
{
GPIO_WriteBit(GPIOA,GPIO_Pin_6,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_6)));
}else if(GPIO_ReadInputDataBit(KEYPORT,KEY3) == 0)
{
GPIO_WriteBit(GPIOA,GPIO_Pin_7,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_7)));
}
KeyScanState = KeyScanState_2;
}else{
KeyScanState = KeyScanState_0;
}
break;
}
case KeyScanState_2:
{
if(keyState == 0x000f)
{
KeyScanState = KeyScanState_0;
}
break;
}
}
}
void SysTick_Set(vu32 x)
{
if(SysTick_Config(x*72)) //配置错误返回1,max 16777216
{
GPIO_SetBits(GPIOA , GPIO_Pin_7); //错误处理
}
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA , &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA , &GPIO_InitStructure);
}
void RCC_Configuration(void)
{
/ 定义枚举类型变量 HSEStartUpStatus /
ErrorStatus HSEStartUpStatus;
/* 复位系统时钟设置*/
RCC_DeInit();
/* 开启HSE*/
RCC_HSEConfig(RCC_HSE_ON);
/* 等待HSE起振并稳定*/
HSEStartUpStatus = RCC_WaitForHSEStartUp();
/* 判断HSE起是否振成功,是则进入if()内部 */
if(HSEStartUpStatus == SUCCESS)
{
/* 选择HCLK(AHB)时钟源为SYSCLK 1分频 */
RCC_HCLKConfig(RCC_SYSCLK_Div1);
/* 选择PCLK2时钟源为 HCLK(AHB) 1分频 */
RCC_PCLK2Config(RCC_HCLK_Div1);
/* 选择PCLK1时钟源为 HCLK(AHB) 2分频 */
RCC_PCLK1Config(RCC_HCLK_Div2);
/* 设置FLASH延时周期数为2 */
FLASH_SetLatency(FLASH_Latency_2);
/* 使能FLASH预取缓存 */
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
/* 选择锁相环(PLL)时钟源为HSE 1分频,倍频数为9,则PLL输出频率为 8MHz * 9 = 72MHz */
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
/* 使能PLL */
RCC_PLLCmd(ENABLE);
/* 等待PLL输出稳定 */
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
/* 选择SYSCLK时钟源为PLL */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/* 等待PLL成为SYSCLK时钟源 */
while(RCC_GetSYSCLKSource() != 0x08);
}
/* 打开APB2总线上的GPIOA时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);
}
本例中将Systick 中断处理函数从 stm32f10x_it.c中移至了main.c中 避免了需要在stm32f10x_it.c中声明外部变量等操作。