在开始按键扫描0.5s内没有按键操作的情况下,扫描按键会产生以下3种按键事件:
1.长按事件:任何发生一次的长按操作都是长按事件
2.点击事件:1次短按操作后游戏开发素材,2s内没有短按操作
3.双击事件:2次短按间隔
对于盈光单片机,首先是定时器和IO口的配置
void IO_Init(void)
{
//----------------------------
PA = 0b1111_1111;
PAC = 0b1111_1111; //1:输出 0:输入
PAPH = 0b0000_0000; //1:加上拉 0:不加上拉
PAPL = 0b0000_0000; //1:加下拉 0:不加下拉
PB = 0b1111_1110;
PBC = 0b1111_1110;
PBPH = 0b0000_0001;
PBPL = 0b0000_0000;
PADIER = 0b0000_0000; //CS脚及对应T_Key设置为模拟IO(设为0),用上位机时UART_IO设置为数字IO(设为1)
PBDIER = 0b0000_0001;
}
使用按钮进行状态控制,首先需要将定义好的引脚设置为单片机的输入。在本例中unity 按钮长按事件贴图笔刷,我使用 PB.0 引脚作为输入端口。
#define KeyOut_PIN PB.0//按键定义
小提示
定时器使用 10ms 延迟
word reload_T16;
void T16_Time(void){
$ T16M SYSCLK,/4,bit12; //T16的时钟源选择,内部的时钟分频器,中断源选择(当选择位由低到高或者由高到低时,发生中断事件);
//时钟源选择可以选择STOP, SYSCLK, PA4_F, IHRC, EOSC, ILRC, PA0_F;分频器可选择/1, /4, /16, /64
//中断源可选择BIT8, BIT9, BIT10, BIT11, BIT12, BIT13, BIT14, BIT15
reload_T16 = 4096 - 100; //每次进中断为1ms;
//计算公式为 [1/(时钟源/分频器)]*(中断源-reload_T16)=[1/(4M/4)]*(2^12-(4096-1000))=1000us=1ms
stt16 reload_T16; //设定计数器初始值reload_T16,当计数器累加超过设定中断源时产生中断;
$ INTEN T16; //中断允许寄存器,启用从T16的溢出中断;1:启用,0:停用。
$ INTRQ T16; //中断请求寄存器,此位是由硬件置位并由软件清零;1:请求,0:不请求。
//注:INTEN,INTRQ没有初始值,所以要使用中断前,一定要根据需要设定数据。即使INTEN为0,INTRQ还是会被中断发生源触发。
$ INTEGS BIT_R; //T16中断边缘选择,上升缘请求中断为BIT_R,下降缘请求中断为BIT_F;默认为上升缘请求。
// 设定INTEN、INTRQ的初始值
INTEN.T16 = 1; //开T16中断
// INTEN.T16 = 0; //关T16中断
INTRQ.T16 = 0; //清零INTRQ寄存器。
ENGINT; //打开全局中断
}
按钮函数的宏定义为
#define KeyOut_PIN PB.0//按键定义
#define key_no 0 //按键抬起
#define key_click 1//按键按下1次
#define key_double 2//双击按键
#define key_long 3//长按键
extern byte Key_detected;//按键抬起
void key_board(void);
源代码
/*按键函数以及红外触摸函数*/
#include"Keyboard.h"
word key_times=0;//按键时间初始化
byte Key_detected;//返回值,0:按键释放、1:按下按键、2:双击按键、3:长按按键
byte key_state=0;
void key_board(void)
{
switch (key_state)
{
case 0:
if(KeyOut_PIN==0)
{
key_state=1;//按键按下,开始消抖
}
break;
case 1:
if(KeyOut_PIN==0)
{
key_times++;
if(key_times>=5)
{
key_times=0;//按键仍处于按下状态,消抖完成
key_state=2;
}
}
else
{
key_times=0;
key_state=0;//按键在消抖时抬起,恢复初始状态
}
break;
case 2:
if(KeyOut_PIN==1)//按键抬起
{
key_times++; //消抖
if(key_times>=5)
{
key_times=0;
key_state=3;
}
}
else
{
key_times++;
if(key_times>=500)//判断长按
{
key_times=0;
key_detected=key_long;
key_state=4;//返回到按键抬起
}
}
break;
case 3:
key_times++;//判断双击
if(key_times<200)
{
if(KeyOut_PIN==0)
{
key_detected=key_double;
key_times=0;
key_state=4;
}
}
else
{
key_detected=key_click;
key_times=0;
key_state=4;
}
break;
case 4: //按键抬起
if(KeyOut_PIN==1)
{
key_state=0;
}
break;
}
}
此函数不会在开始和结束时将引用归零
它在循环调用结束时归零
如有必要
请在开关上执行key_detected=key_no;
因为实际中函数需要判断是单击还是双击,所以双击判断会有一个最小延时。如有需要unity 按钮长按事件,可自行修改!