利用队列收集单双击和长按按键

利用队列收集单双击和长按按键

引言

当我们仅仅通过在while循环里面进行判断按键类型的标志位, 然后进行操作的时候, 我们的最小例程很小, 所以能够实时的检测到按键,从而触发实验现象.

image-20240820182941349

假如我们此时进入了一个事件处理函数呢 ? 并且这个这个函数的操作是不可被打断的, 如果此时我们重复按下多次按键, 标志位只能存放一个数值, 等事件处理完, 我们再处理的时候, 只能处理最后一次按下的按键类型.

image-20240820183332160

最常见的就是, 我们使用遥控器, 我们连着按下了多个下箭头, 因为电视太卡, 导致只向下一次, 会极大影响操作体验.

所以我们的需求就是, 虽然你现在可能有重要事情要做, 但是, 你可以把我的按键需求存下来, 等不忙的时候, 再来处理. 因为处理器的处理是很快的, 所以我们也不会耽搁太多的时间。

按键收集模型分析

对于按键的收集, 我们分成三种类型,单击,双击和长按, 并且我们是按顺序按下的, 按顺序处理的, 所以这很符合队列的模型, 我们把他们排成一排, 放进数组, 然后到处理的时候, 再按顺序, 逐个处理, 按键需求和用户需求保持一致即可.

image-20240820184300356

按键收集时机

对于按键收集, 假如现在我们有重要的事情去做, 不能立即去处理按键的功能, 但是我们可以中断的去收集按键类型, 因为中断是不会耽搁时间的. 只是花费CPU去记录一下数据. 所以我们在定时器函数内, 判断按键类型的时候, 把按键类型 button_mode 收集到队列里面。

image-20240820184434471

按键收集队列

我们采用数组存储, 定义一个队头,定义一个队尾,加入按键的时候,我们放在队尾, 处理按键的时候, 我们拿取队头按键处理。

初始化时候

队首,队尾都指向数组初始的时候

image-20240820193223285

加入一个按键的时候

此按键, 加入到队尾(位序0), 然后队尾后移, 因为队尾始终要承载按键, 所以后移, 为后续腾出位置

image-20240820193400748

加入两个按键的时候

把按键2,加入队尾, 位序为1处, 然后队尾后移到位序2

image-20240820193552671

所以, 在收集按键的时候, 我们定义一个数组, 队尾一直后移, 因为我们相当于一个循环队列, 所以队尾后移到最大位序的时候, 可以再次回到开头, 继续添加(这里有一个前提就是, 我们一次性处理的数据, 不能超过数组的最大位序, 保证出队和入队的正常运转即可)。

image-20240820194449335

void collect_button(void)
{
	//采集按键信息
	button_order[button_send] = button_mode;
	if(button_send >= 5) // 说明5的位置已经被填了,下个该0了(++后,所指位置为空)
	{
		button_send = 0;
	}
	else
	{
		button_send++;
	}			
}	

按键队列处理

有加入,就有取出。所以当我们取出按键的时候, 把队头按键取出, 处理此按键, 然后队头后移.

直到队头和队尾的数组位序重合, 那么我们就可以宣布,按键处理完毕了

取出按键

image-20240820193736042

按键处理完毕的时候

当队头对应的按键处理完的时候, 我们队头后移, 为下次抽取按键做准备, 但是当队头和队尾 , 重合的时候, 就代表我们没有按键需要处理了.(队尾实时指向的位置, 是为下一次加入队列的按键做准备的, 所以是空的)

image-20240820195346183

代码实现

我们一边处理着按键, 一边判断着队首和队尾是否重合, 一旦重合就代表着我们按键处理完了.

当 button_deal 队首 和 button_send 队尾 不重合时, 就一直取出按键

image-20240820200420565

每次处理完一个按键后, 队尾位序后移, 同时要记得我们是数组,所以容量总会有不够用的时候, 所以我们要回到开头, 继续添加, 逻辑上是连在一起的(只需要保证同时处理的按键总和小于数组总容量即可)

image-20240820200539697

void oled_chose(void)
{
		//下面是原子时间,不可被定时器新加命令
		button_atom = 1;
		//if(button_deal != button_send)//如果有按键指令
		
		while(button_deal != button_send )	//直到处理完指令
		{
			button_down = 1;	//代表已经有指令了
			//(短按 1, 双按 2, 长按 3)
			if(button_order[button_deal] == 1)
			{
				if(now_mode[0] == 1)
				{
					now_mode[1] ^= 1;
				}
				else
				if(now_mode[0] == 2)//歌曲选择
				{
					if(now_mode[1] == 3)
					{
						now_mode[1] = 0;
					}
					else
					{
						now_mode[1]++;
					}
				}
				else
				if(now_mode[0] == 3)//歌曲播放页面
				{
					//开关歌曲
					now_mode[2] ^= 1;
				}
			}
			else
			if(button_order[button_deal] == 2)	//(双击)
			{
				switch(now_mode[0])
				{
					case 1:break; //没想好干啥
					case 2:
						now_mode[0] = 3;//进入音乐播放界面
						now_mode[2] = 1;//播放按钮打开
						break;
					case 3:
						now_mode[0] = 2;//返回音乐菜单
						now_mode[2] = 0;//播放按钮关闭
						break;
					default:break;
				}
			}	
			else	
			if(button_order[button_deal] == 3)//长按
			{
				if(now_mode[0] == 1)
				{
					now_mode[0] = 2;//切换为音乐模式
					now_mode[1] = 0;//音乐界面默认第一个
					now_mode[2] = 0;//播放按钮也关闭
				}
				else
				{
					now_mode[0] = 1;//切换为智能模式
					now_mode[1] = 0;//界面默认第一个
					now_mode[2] = 0;//播放按钮也关闭
				}
			}
			//然后跳到下一位,接着判断是否重合
			if(button_deal >= 5) //队尾始终为空,向目标前进
			{
				button_deal = 0;
			}
			else
			{
				button_deal++;
			}

		}
		//可以接受新命令
		button_atom = 0;	
}	

注意, 我们这里队首处理完按键,并没有清除其数据, 而是位序往后走, 去覆盖了,队尾移动到此处, 相当于默认此处数据可覆盖, 所以就默认清除了. 要注意,同时我们也可以进行清除, 处理完队头后, 对数组此处赋值一个特定的数值, 方便后续我们调试.

  • 35
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值