关闭

stm32的按键扫描[操作寄存器+库函数]

485人阅读 评论(0) 收藏 举报
分类:
本例将实现stm32的按键扫描功能。
 
操作寄存器
 
stm32的I/O口作为输入使用时,是通过读取GPIOx -> IDR 寄存器的内容来读取I/O口状态的。
 
IDR寄存器各位描述如下:
gpio_idr.png
 
由于systick不能像库函数那样方便的产生中断,通过查询systick状态位后,再查询各管脚状态反而更为不方便,所以和库函数方法不一样,直接查询了管脚状态来检测按键。
 
代码中调用 PAout(x) 、 PAin(x)等函数 在sys.h文件中,参见:(sys.h 代码参照 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; 
	  
}

 
 
库函数操作
 
学过EDA都应该知道一个概念叫状态机,触发某一条件后进入另一状态,再触发一个条件就进入下一状态,不满足条件就进入初态,或者不改变状态。实现按键扫描的思路,大致如此。
  1. Systick 产生一个20ms的定时,在中断中去查询各个管脚的按键是否按下。 有按键按下,进入状态1.
  2. 如果按下,判断是否是抖动,是则返回状态0,不是则判断是哪个管脚按键按下,实现相应功能后进入状态2.
  3. 在状态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中声明外部变量等操作。

0
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

STM32 下的库函数和寄存器操作比较

以 led闪烁中的flashLed函数例子:库函数操作简单,但是效率不如寄存器操作的高; 寄存器操作很复杂,因为要熟悉上百个寄存器,但是程序效率很高/**下面是通过直接操作库函数的方式实现IO控制**...
  • mao0514
  • mao0514
  • 2015-08-15 11:10
  • 4219

STM32---初学者用库函数好还是直接对寄存器操作比较好

首先,两个都是C语言。 从51过渡过来的话,就先说寄存器操作。每个MCU都有自己的寄存器,51是功能比较简单的一种,相应的寄存器也比较少,我们常用的就那么几个,像P0 P1 SMOD TMOD之类的,...
  • u010349006
  • u010349006
  • 2014-12-03 11:18
  • 2520

STM32F1学习-按键实验(寄存器版本)

支持连续按与不支持连续按的区别: 支持连续按:按下不松开则认为是连续有效。程序实现:就是检测相应的端口,只要是是按下的状态,就执行相应的操作。 不支持连续按:按下不松开则认为是一次有效的。程序实现...
  • u013355826
  • u013355826
  • 2016-07-18 13:51
  • 1084

stm32 i2c通信 [操作寄存器+库函数]

I2C总线是由NXP(原PHILIPS)公司设计,有十分简洁的物理层定义,其特性如下: 只要求两条总线线路:一条串行数据线SDA,一条串行时钟线SCL; 每个连接到总线的器件都可以通过...
  • minyuanxiani
  • minyuanxiani
  • 2014-03-18 16:06
  • 1382

stm32 BKP寄存器操作[操作寄存器+库函数]

BKP是“BACKUP”的缩写,stm32f103RCTE的内部配备了10个16位宽度的BKP寄存器。在主电源切断或系统产生复位时间时,BKP寄存器仍然可以在备用电源的支持下保持其内容。  BKP在...
  • niepangu
  • niepangu
  • 2015-07-16 08:36
  • 1077

STM32——GPIO之从库函数到寄存器的前因后果

例子为单片机的“Hello World”级的流水灯实验——虽然只有一个,其中并不是将完整的代码给出,只是给出关键部分来说明“如何调用ST公司的的库来完成对硬件的控制,以及对库文件代码进行跟踪和分析至寄...
  • mao0514
  • mao0514
  • 2015-08-15 16:52
  • 1629

stm32 i2c通信 [操作寄存器+库函数]

I2C总线是由NXP(原PHILIPS)公司设计,有十分简洁的物理层定义,其特性如下: 只要求两条总线线路:一条串行数据线SDA,一条串行时钟线SCL; 每个连接到总线的器件都可以通过唯一的地址...
  • qutiezhu
  • qutiezhu
  • 2016-08-30 21:29
  • 2134

STM32按键扫描/按键中断/外部中断

接触STM32有一段时间了,也算是简单入了门,但由于一些原因,今天才来写本应该是入门级的按键相关程序,分为扫描模式和中断模式 MCU:STM32F334C8 1.扫描模式 下面的代码完成的功能是:按键...
  • Wind4study
  • Wind4study
  • 2015-05-19 17:08
  • 4148

stm32 独立看门狗[操作寄存器+库函数]

以单片机为核心的微型计算机系统中,单片机经常会受到来自外界电磁场的干扰。 造成程序跑飞,只是程序的正常运行状态被打断而进入死循环,从而使单片机控制的系统无法正常工作。看门狗就是一种专门用于检测单片机...
  • minyuanxiani
  • minyuanxiani
  • 2014-03-18 16:10
  • 1034

STM32串口寄存器库函数配置方法

1、参考资料       《STM32F1开发指南-库函数版本》- 5.3 usart串口文件夹介绍             ...
  • lbd321
  • lbd321
  • 2017-05-04 18:02
  • 739
    最新评论
    个人资料
    • 访问:66026次
    • 积分:155
    • 等级:
    • 排名:千里之外
    • 原创:6篇
    • 转载:111篇
    • 译文:1篇
    • 评论:3条