嵌入式设计与开发项目-独立按键扫描程序设计

一、实现的功能

  • ①单击按键PB1控制LED1 -> LED8移动一位点亮,长按按键PB1会控制LED1 -> LED8移动两位点亮,如果超出LED8,重新从LED1重新开始移位点亮;
  • ②单击按键PB2控制LED8 -> LED1移动一位点亮,长按按键PB2会控制LED8 -> LED1移动两位点亮,如果超出LED1,重新从LED8重新开始移位点亮;
  • ③长按PB3,蜂鸣器一直打开,释放PB3,蜂鸣器关闭。

二、根据功能实现代码

1、主文件main.c

#include"key.h"
#include"led.h"			//包含LED与key头文件

unsigned char ucLed =1;			//亮灯标志位
unsigned char ucKey_Long;		//按键长按标志位
unsigned long ulTick_ms,ulKey_Time;		//记录时间标志位

void KEY_Proc(void);			//声明按键实现功能函数
int main(void)
{
	SysTick_Config(72000);
	KEY_Init();
	LED_Init();
	BUZ_Init();			//初始化key、led、buz外设
	
	while(1)
	{
		KEY_Proc();
		LED_Disp(ucLed);
	}
}

void KEY_Proc(void)
{
	unsigned char ucKey_Val;		//定义一个局部变量保存按键值
	ucKey_Val = KEY_Scan();
	if(ucKey_Val !=ucKey_Long)
	{
		ucKey_Long = ucKey_Val;		//把当前保存的按键值保存到ucKey_Long中
		ulKey_Time = ulTick_ms;		//把当前运行的时间值保存到ulKey_Time 中
	}
	else
	  ucKey_Val = 0;				//如果ucKey_Val 和ucKey_Long相等,则把ucKey_Val 置0,重新扫描按键值
	  
	  if(ucKey_Val == 1) //B1短按
	  {
		ucLed <<=1;
		if(ucLed ==0)
		ucLed = 1;
	  }
	  if(ucKey_Val == 2) //B2短按
	  {
		ucLed >>=1;
		if(ucLed ==0)
		ucLed =0x80;		//重新从LED8开始移位
	  }
	  if(ucKey_Long == 1) //B1长按
	  {
		if(ulTick_ms - ulKey_Time >800)
		{
			ulKey_Time = ulTick_ms;
			ucLed <<= 2;
			if(ucLed ==0)
			ucLed=1;
		}
	  }
	  if(ucKey_Long == 2) //B2长按
	  {
		if(ulTick_ms - ulKey_Time >800)
		{
			ulKey_Time = ulTick_ms;
			ucLed >>= 2;
			if(ucLed ==0)
			ucLed=0x80;
		}
	  }
	  if(ucKey_Long ==3)	//B3长按
			GPIO_ResetBits(GPIOB,GPIO_Pin_4);
	  else
			GPIO_SetBits(GPIOB,GPIO_Pin_4);
		
	
}
//SysTick中断处理
void SysTick_Handler(void)
{
	ulTick_ms++;		//进行定时计数
}

主函数分析:❤️ ❤️ ❤️

  1. 需要添加一个长按和长按时间全局标志位的定义,方便判断按键是否长按
  2. 在主函数main后面定义的KEY_Proc()函数,需要在main之前进行声明,否则无法使用;
  3. 第27行的if(ucKey_Val !=ucKey_Long)判断当前按下的值是否与上一次保存的按键值相等。如果相等则把按键值置0,根据ucKey_Long来判断是否属于长按;否则ucKey_Long保存ucKey_Val的值以及保存时间,执行当前ucKey_Long扫描到的按键;
  4. 800ms作为按键长按的判断;

2、独立按键头文件“key.h”

#include "stm32f10x.h"

void KEY_Init(void);
unsigned char KEY_Scan(void);
void Delay_KEY(unsigned int ms);

3、独立按键源文件“key.c”文件

#include"key.h"

//KEY接口初始化
void KEY_Init(void)
{
	//初始化结构体
	GPIO_InitTypeDef GPIO_InitStruct;
	
	//使能GPIOA、GPIOB时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	//配置PA0和PA8引脚参数,并设置为浮空输入(复位状态,可不配置)
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_8;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	//配置PB1和PB2引脚参数,并设置为浮空输入(复位状态,可不配置)
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOB,&GPIO_InitStruct);
	
}

//KEY扫描
unsigned char KEY_Scan(void)
{
	unsigned char ucKey_Val = 0;
	//判断B1、B2按键是否按下
	if(~GPIO_ReadInputData(GPIOA) & 0X101)		//GPIO有16个位,每个位代表一个引脚
	{
		//延时10ms消抖
		Delay_KEY(10);
		if(!GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0))
		ucKey_Val = 1;
		if(!GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_8))
		ucKey_Val = 2;
	}
	
	//判断B1、B2是否按下
	else if(~GPIO_ReadInputData(GPIOB) & 6)		//6=0x0006代表一个PB1和PB2引脚
	{
		//延时10ms消抖
		Delay_KEY(10);
		if(!GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1))
		ucKey_Val = 3;
		if(!GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_2))
		ucKey_Val = 4;
	}
	return ucKey_Val;
}

//延时函数
void Delay_KEY(int ms)
{
	unsigned int i,j;
	for(i=0;i<ms;i++)
		for(j=0;j<7992;j++);	//SYSCLK = 72MHz,延时毫秒
}

简要分析:❤️ ❤️

  1. PA0、PA8、PB1、PB2连接着四个按键,复位状态为浮空输入模式,可省略配置GPIO参数的步骤,需要使能端口对应的时钟;
  2. ~GPIO_ReadInputData(GPIOA) & 0x101判断PA0与PA8是否接收到按键输入的的低电平,通过取反再和0x101进行与运算,即可判断按键是否按下(0x101=0000 0001 0000 0001);
  3. Delay_KEY()延时函数是根据单片机的晶振进行粗略延时的;
  4. 按键按下时需要延时一段时间进行消抖,否则按键不能灵活使用;

三、实现功能过程的注意与学习点

1、注意点

  1. 在按键长按时,都会先执行一次短按的程序,然后再进行长按操作(可优化);
  2. 每个GPIO有16个位,每个位代表一个引脚的电平状态;

2、学习的知识点

  1. 通过GPIO寄存器的数值取反再和对于的位进行与运算判断按键是否按下。
  2. 定义长按标志位ucKey_Long保存上一次按键的值,再与当前值进行判断,然后再根据800ms的间隔判断是否属于长按。
  3. 根据单片机系统SYSCLK的晶振的频率进行粗略的延时。
    ❤️ ❤️ ❤️ ❤️ ❤️ ❤️
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序小鹿

博主不差钱,点个赞就行哈哈

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值