精华内容
下载资源
问答
  • 单片机按键扫描函数

    千次阅读 2020-01-16 14:02:27
    按键扫描(支持连续按) 检测按键IO口的高低电平 u8 KEY_Scan(void) { if(KEY按下) { delay_ms(10);//延时10-20ms 消蚪 if(KEY确实按下) { return KEY_Value; } return 无效值; } } 按键扫描(不...

    按键扫描(支持连续按)

    检测按键IO口的高低电平

    u8 KEY_Scan(void)
    {
    	if(KEY按下)
    	{
    		delay_ms(10);//延时10-20ms 消蚪
    		if(KEY确实按下)
    		{
    			return KEY_Value;
    		}
    		return 无效值;
    	}
    }
    

    按键扫描(不支持连续按)

    检测高低电平的变化(上升沿,下降沿)

    u8 LEY_Scan(void)
    {
    	static u8 key_up = 1;
    	if(key_up&&KEY按下)
    	{
    		delay_ms(10);//延时消抖
    		key_up=0;//标记这次key已经按下
    		if(KEY确实按下)
    		{
    			return KEY_Value; 
    		}
    		else if(KEY 没有按下)key_up=1;
    		return 没有按下; 
    	}
    }
    

    按键扫描(二合一)

    传入参数mode 如果mode=1则支持连续按

    u8 KEY_Scan(u8 mode)
    {
    	static u8 key_up=1;
    	if(mode ==1 )key_up=1;//支持连续按
    	if(key_up&&KEY按下)
    	{
    		delay_ms(10);//延时消抖
    		key_up=0;//标记这次key已经按下
    		if(KEY确实按下)
    		{
    			return KEY_Value; 
    		}
    		else if(KEY没有按下)key_up=1;
    		return 没有按下;
    	}
    }
    
    展开全文
  • /****************************************键盘_不采用定时器_不延时特点:按键在松手后有效,灵敏度高,消耗资源少,运行效率高独立键盘为:K01=P2^4;K02=P2^5;K03=P2^6;K04=P2^7;矩阵键盘为:行(上到下)_P2.3_P...
  • #include "REG52.H" ... * 调整抖动时间阀值的大小,可以更改按键的触发灵敏度。 * 去抖动的时间本质上等于累计定时中断次数的时间。 */ #define const_key_time_short120//短按的按键去抖动延时的时间 #d...
    1. #include "REG52.H"  
    2.   
    3. #define const_voice_short  20   //蜂鸣器短叫的持续时间  
    4. #define const_voice_long   140   //蜂鸣器长叫的持续时间  
    5.   
    6. /* 注释一:
    7. * 调整抖动时间阀值的大小,可以更改按键的触发灵敏度。
    8. * 去抖动的时间本质上等于累计定时中断次数的时间。
    9. */  
    10. #define const_key_time_short1  20    //短按的按键去抖动延时的时间  
    11. #define const_key_time_long1   400     //长按的按键去抖动延时的时间  
    12.   
    13. #define const_key_time_short2  20    //短按的按键去抖动延时的时间  
    14. #define const_key_time_long2   400     //长按的按键去抖动延时的时间  
    15.   
    16. void initial_myself();      
    17. void initial_peripheral();  
    18. void delay_long(unsigned int uiDelaylong);  
    19. void T0_time();  //定时中断函数  
    20. void key_service(); //按键服务的应用程序  
    21. void key_scan(); //按键扫描函数 放在定时中断里  
    22.   
    23. sbit key_sr1=P3^2; //对应朱兆祺学习板的S1键  
    24. sbit key_sr2=P3^3; //对应朱兆祺学习板的S5键  
    25. sbit key_gnd_dr=P0^4; //模拟独立按键的地GND,因此必须一直输出低电平  
    26.   
    27. sbit beep_dr=P2^7; //蜂鸣器的驱动IO口  
    28.   
    29. unsigned char ucKeySec=0;   //被触发的按键编号  
    30.   
    31. unsigned int  uiKeyTimeCnt1=0; //按键去抖动延时计数器  
    32. unsigned char ucKeyLock1=0; //按键触发后自锁的变量标志  
    33. unsigned char ucShortTouchFlag1=0; //短按的触发标志  
    34.   
    35. unsigned int  uiKeyTimeCnt2=0; //按键去抖动延时计数器  
    36. unsigned char ucKeyLock2=0; //按键触发后自锁的变量标志  
    37. unsigned char ucShortTouchFlag2=0; //短按的触发标志  
    38.   
    39. unsigned int  uiVoiceCnt=0;  //蜂鸣器鸣叫的持续时间计数器  
    40.   
    41. void main()  
    42.   {  
    43.    initial_myself();    
    44.    delay_long(100);    
    45.    initial_peripheral();  
    46.    while(1)    
    47.    {  
    48.        key_service(); //按键服务的应用程序  
    49.    }  
    50.   
    51. }  
    52.   
    53. void key_scan()//按键扫描函数 放在定时中断里  
    54. {    
    55. /* 注释二:
    56. * 长按与短按的按键扫描的详细过程:
    57. * 第一步:平时只要按键没有被按下时,按键的自锁标志,去抖动延时计数器一直被清零。
    58. * 第二步:一旦两个按键都被按下,去抖动延时计数器开始在定时中断函数里累加,在还没累加到
    59. *         阀值const_key_time_short1或者const_key_time_long1时,如果在这期间由于受外界干扰或者按键抖动,而使
    60. *         IO口突然瞬间触发成高电平,这个时候马上把延时计数器uiKeyTimeCnt1
    61. *         清零了,这个过程非常巧妙,非常有效地去除瞬间的杂波干扰。这是我实战中摸索出来的。
    62. *         以后凡是用到开关感应器的时候,都可以用类似这样的方法去干扰。
    63. * 第三步:如果按键按下的时间超过了短按阀值const_key_time_short1,则马上把短按标志ucShortTouchFlag1=1;
    64. *         如果还没有松手,一旦发现按下的时间超过长按阀值const_key_time_long1时,
    65. *         先把短按标志ucShortTouchFlag1清零,然后触发长按。在这段程序里,把自锁标志ucKeyLock1置位,
    66. *         是为了防止按住按键不松手后一直触发。
    67. * 第四步:等按键松开后,自锁标志ucKeyLock12及时清零,为下一次自锁做准备。如果发现ucShortTouchFlag1等于1,
    68. *         说明短按有效,这时触发一次短按。
    69. * 第五步:以上整个过程,就是识别按键IO口下降沿触发的过程。
    70. */  
    71.   if(key_sr1==1)//IO是高电平,说明两个按键没有全部被按下,这时要及时清零一些标志位  
    72.   {  
    73.       ucKeyLock1=0; //按键自锁标志清零  
    74.       uiKeyTimeCnt1=0;//按键去抖动延时计数器清零,此行非常巧妙,是我实战中摸索出来的。      
    75.             if(ucShortTouchFlag1==1)  //短按触发标志  
    76.           {  
    77.              ucShortTouchFlag1=0;  
    78.                  ucKeySec=1;    //触发一号键的短按  
    79.           }  
    80.   }  
    81.   else if(ucKeyLock1==0)//有按键按下,且是第一次被按下  
    82.   {  
    83.      uiKeyTimeCnt1++; //累加定时中断次数  
    84.      if(uiKeyTimeCnt1>const_key_time_short1)  
    85.      {  
    86.             ucShortTouchFlag1=1;   //激活按键短按的有效标志    
    87.      }  
    88.   
    89.      if(uiKeyTimeCnt1>const_key_time_long1)  
    90.      {  
    91.             ucShortTouchFlag1=0;  //清除按键短按的有效标志  
    92.   
    93.         uiKeyTimeCnt1=0;  
    94.         ucKeyLock1=1;  //自锁按键置位,避免一直触发  
    95.   
    96.         ucKeySec=2;    //触发1号键的长按  
    97.                 
    98.      }  
    99.   
    100.   }  
    101.   
    102.   if(key_sr2==1)//IO是高电平,说明两个按键没有全部被按下,这时要及时清零一些标志位  
    103.   {  
    104.       ucKeyLock2=0; //按键自锁标志清零  
    105.       uiKeyTimeCnt2=0;//按键去抖动延时计数器清零,此行非常巧妙,是我实战中摸索出来的。      
    106.             if(ucShortTouchFlag2==1)  //短按触发标志  
    107.           {  
    108.              ucShortTouchFlag2=0;  
    109.                  ucKeySec=3;    //触发2号键的短按  
    110.           }  
    111.   }  
    112.   else if(ucKeyLock2==0)//有按键按下,且是第一次被按下  
    113.   {  
    114.      uiKeyTimeCnt2++; //累加定时中断次数  
    115.      if(uiKeyTimeCnt2>const_key_time_short2)  
    116.      {  
    117.             ucShortTouchFlag2=1;   //激活按键短按的有效标志    
    118.      }  
    119.   
    120.      if(uiKeyTimeCnt2>const_key_time_long2)  
    121.      {  
    122.             ucShortTouchFlag2=0;  //清除按键短按的有效标志  
    123.   
    124.         uiKeyTimeCnt2=0;  
    125.         ucKeyLock2=1;  //自锁按键置位,避免一直触发  
    126.   
    127.         ucKeySec=4;    //触发2号键的长按  
    128.                 
    129.      }  
    130.   
    131.   }  
    132.   
    133.   
    134. }  
    135.   
    136.   
    137. void key_service() //第三区 按键服务的应用程序  
    138. {  
    139.   switch(ucKeySec) //按键服务状态切换  
    140.   {  
    141.     case 1:// 1号键的短按  对应朱兆祺学习板的S1键  
    142.   
    143.           uiVoiceCnt=const_voice_short; //按键声音的短触发,滴一声就停。  
    144.           ucKeySec=0;  //响应按键服务处理程序后,按键编号清零,避免一致触发  
    145.           break;          
    146.     case 2:// 1号键的长按  对应朱兆祺学习板的S1键  
    147.   
    148.           uiVoiceCnt=const_voice_long; //按键声音的长触发,滴一声就停。  
    149.           ucKeySec=0;  //响应按键服务处理程序后,按键编号清零,避免一致触发  
    150.           break;        
    151.     case 3:// 2号键的短按  对应朱兆祺学习板的S5键  
    152.   
    153.           uiVoiceCnt=const_voice_short; //按键声音的短触发,滴一声就停。  
    154.           ucKeySec=0;  //响应按键服务处理程序后,按键编号清零,避免一致触发  
    155.           break;          
    156.     case 4:// 2号键的长按  对应朱兆祺学习板的S5键  
    157.   
    158.           uiVoiceCnt=const_voice_long; //按键声音的长触发,滴一声就停。  
    159.           ucKeySec=0;  //响应按键服务处理程序后,按键编号清零,避免一致触发  
    160.           break;    
    161.   }                  
    162. }  
    163.   
    164.   
    165.   
    166. void T0_time() interrupt 1  
    167. {  
    168.   TF0=0;  //清除中断标志  
    169.   TR0=0; //关中断  
    170.   
    171.   key_scan(); //按键扫描函数  
    172.   
    173.   if(uiVoiceCnt!=0)  
    174.   {  
    175.      uiVoiceCnt--; //每次进入定时中断都自减1,直到等于零为止。才停止鸣叫  
    176.          beep_dr=0;  //蜂鸣器是PNP三极管控制,低电平就开始鸣叫。  
    177.   }  
    178.   else  
    179.   {  
    180.      ; //此处多加一个空指令,想维持跟if括号语句的数量对称,都是两条指令。不加也可以。  
    181.            beep_dr=1;  //蜂鸣器是PNP三极管控制,高电平就停止鸣叫。  
    182.   }  
    183.   
    184.   
    185.   TH0=0xf8;   //重装初始值(65535-2000)=63535=0xf82f  
    186.   TL0=0x2f;  
    187.   TR0=1;  //开中断  
    188. }  
    189.   
    190.   
    191. void delay_long(unsigned int uiDelayLong)  
    192. {  
    193.    unsigned int i;  
    194.    unsigned int j;  
    195.    for(i=0;i<uiDelayLong;i++)  
    196.    {  
    197.       for(j=0;j<500;j++)  //内嵌循环的空指令数量  
    198.           {  
    199.              ; //一个分号相当于执行一条空语句  
    200.           }  
    201.    }  
    202. }  
    203.   
    204.   
    205. void initial_myself()  //第一区 初始化单片机  
    206. {  
    207. /* 注释三:
    208. * 矩阵键盘也可以做独立按键,前提是把某一根公共输出线输出低电平,
    209. * 模拟独立按键的触发地,本程序中,把key_gnd_dr输出低电平。
    210. * 朱兆祺51学习板的S1和S5两个按键就是本程序中用到的两个独立按键。
    211. */  
    212.   key_gnd_dr=0; //模拟独立按键的地GND,因此必须一直输出低电平  
    213.   
    214.   
    215.   beep_dr=1; //用PNP三极管控制蜂鸣器,输出高电平时不叫。  
    216.   
    217.   
    218.   TMOD=0x01;  //设置定时器0为工作方式1  
    219.   
    220.   
    221.   TH0=0xf8;   //重装初始值(65535-2000)=63535=0xf82f  
    222.   TL0=0x2f;  
    223.   
    224. }  
    225. void initial_peripheral() //第二区 初始化外围  
    226. {  
    227.   EA=1;     //开总中断  
    228.   ET0=1;    //允许定时中断  
    229.   TR0=1;    //启动定时中断  
    230.   
    展开全文
  • 单片机——按键扫描

    万次阅读 多人点赞 2017-07-30 11:16:51
    按键扫描,我当时入门的时候是看的郭天祥的51单片机入门的,视频里面讲的是循环扫描io引脚,一旦有电平变化就利用软件延时消抖,模拟延时就是让单片机空转,什么也不做,等待个几十毫秒之后再检测一次如果...

    按键扫描,我想应该是比较简单的单片机应用了,但是有时候看起来简单的东西反而不好写。

    本文拿大部分人觉得简单的按键扫描聊聊我工作至今对于软件结构的理解。嗯,对的,是结构,不是架构,暂时不敢提架构这个词。

    按键扫描,我当时入门的时候是看的郭天祥的51单片机入门的,视频里面讲的是循环扫描io引脚,一旦有电平变化就利用软件延时消抖,模拟延时就是让单片机空转,什么也不做,等待个几十毫秒之后再检测一次如果电平没有变化就认为按键按下。这种方法也能实现按键检测,好处是简单,缺点是占用太多的软件资源,CPU空转这一点我觉得挺不好的。

    下面说说我个人对于一个按键检测的代码理解。

    按键检测需要做什么事情呢?一个是按键按下的这个物理事件的检测,一个是按下时候的消抖。能想到这两个已经可以写一段代码来实现功能了。

     

    #define DEBOUNCE 10//延时消抖时间
    uint8 key_scan( uint8 keycur )
    {
    	static uint8 KeyLast = KEY_NULL; 	
    	static uint8 KeyCountdowm = 0; 	
    	uint8 keyret = KEY_NULL;   	    
    
    	if(  keycur != KEY_NULL )	//如果检测到按键按下,开始进行延时消抖			
    	{
    		if( KeyLast == keycur  || KEY_NULL == KeyLast)				
    		{
    			KeyCountdowm++;				
    		}
    	}
    	else
    	{
    		if( KeyCountdowm >= DEBOUNCE)//按键抬起
    		{
    			keyret = KeyLast;
    		}
    		else
    		{
    		        keyret = KEY_NULL;
    		}
    
    		KeyCountdowm = 0;
    	}
    	
    	KeyLast = keycur;//按键备份值更新
    
    	return keyret;
    }

    上面是一个简单的按键扫描函数,函数需要放置在一个10ms的定时函数里面,注意是定时函数不是定时中断函数,需要传递按键信息,这个信息可以是从通信函数获取的,也可以是直接读取IO端口获得,返回一个消抖过后的键值,键值不做逻辑判断。

     

    然后我们来聊聊这个消抖函数,这个消抖函数只实现了一个功能,按下消抖,那如果使用环境或者硬件设计缺陷,导致抬起的时候也有抖动呢?所以需要添加抬起消抖。

    下面对函数进行优化一下

     

    #define DEBOUNCE 10//延时消抖时间
    uint8 key_scan( uint8 keycur )
    {
    	static uint8 KeyLast = 0; 	
    	static uint8 KeyCountdowm = 0; 	
    	static uint8 KeyCountup = 0; 	
    	unsigned uint8 keyret = 0;   	  
    
    	keyret = KEY_NULL;
    	if(  keycur != KEY_NULL )				
    	{
    		if( KeyLast == keycur || KEY_NULL == KeyLast)			
    		{
    			KeyCountdowm++;			
    			KeyCountup = 0;
    		}
    	}
    	else
    	{
    		KeyCountup++;	
    
    		if( KeyCountup > 1 ) 
    		{
    			KeyCountup = 0;	
    
    			if( KeyCountdowm >= DEBOUNCE )
    			{
    				keyret = KeyLast;
    				KeyCountdowm = 0;
    			}
    		}
    	}
    	
    	KeyLast = keycur;	
    	return keyret;
    }

    添加了20ms的抬起消抖,这段代码添加了两个消抖检测,一个是在抬起的时候有20ms的消抖,一个是在按键按下过程的一个过程消抖。

    上面的代码实现的是抬起有效,那么如果需要做到按下有效呢?

    #define DEBOUNCE 10//延时消抖时间
    uint8 key_scan( uint8 keycur )
    {
    	static uint8 KeyLast = 0; 	
    	static uint8 KeyCountdowm = 0; 	
    	static uint8 KeyCountup = 0; 	
    	unsigned uint8 keyret = 0;   	  
    
    	keyret = KEY_NULL;
    	if(  keycur != KEY_NULL )				
    	{
    		if( KeyLast == keycur || KEY_NULL == KeyLast)			
    		{
    			KeyCountdowm++;			
    			KeyCountup = 0;
    			
    			if( KeyCountdowm >= DEBOUNCE )
    			{
    				keyret = KeyLast;
    			}
    		}
    	}
    	else
    	{
    		KeyCountup++;	
    
    		if( KeyCountup > 1 ) 
    		{
    			KeyCountup = 0;	
    			KeyCountdowm = 0;
    		}
    	}
    	
    	KeyLast = keycur;	
    	return keyret;
    }

    挪动按键的延时检测判断语句,在按下超过延时消抖时间的时候,返回按键按下值。

     

    然后一个简单按键检测函数就实现了,下面再给这个函数添加长按键判断和连续按键。

    #define DEBOUNCE 10//延时消抖时间
    #define LONGPRESS 100//长按键判断函数
    uint16 key_scan( uint8 keycur )
    {
    	static uint8 KeyLast = 0; 	
    	static uint8 KeyCountdowm = 0; 	
    	static uint8 KeyCountup = 0; 	
    	unsigned uint16 keyret = 0;   	  
    
    	keyret = KEY_NULL;
    	if(  keycur != KEY_NULL )				
    	{
    		if( KeyLast == keycur || KEY_NULL == KeyLast)			
    		{
    			KeyCountdowm++;			
    			KeyCountup = 0;
    			
    			if( KeyCountdowm >= DEBOUNCE && KeyCountdowm < LONGPRESS)//短按键判断
    			{
    				keyret = KeyLast;
    			}
    			else if( KeyCountdowm == LONGPRESS )//长按键判断				
    			{
    				keyret = KeyLast;	
    				keyret |= 0x0100;		
    			}
    			else if(KeyCountdowm > LONGPRESS+DEBOUNCE)//连续按键判断
    			{
    				KeyCountdowm -= DEBOUNCE;
    				keyret = KeyLast;	
    				keyret |= 0x0200;	
    			}
    		}
    	}
    	else
    	{
    		KeyCountup++;	
    
    		if( KeyCountup > 1 ) 
    		{
    			KeyCountup = 0;	
    			KeyCountdowm = 0;
    		}
    	}
    	
    	KeyLast = keycur;	
    	return keyret;
    }

     

    当有多个设备的时候,可以将静态局部变量修改为结构体指针的形式,如下

    type struct key
    {
    	uint8 Last;
    	uint8 CountDowm;
    	uint8 CountUp;
    }KEY_TYPE;
    
    #define DEBOUNCE 10//延时消抖时间
    #define LONGPRESS 100//长按键判断函数
    
    uint16 key_scan( KEY_TYPE *Key ,uint8 keycur)
    {	
    	unsigned uint16 keyret = 0;   	  
    
    	keyret = KEY_NULL;
    	if(  keycur != KEY_NULL )				
    	{
    		if( Key->Last == keycur || KEY_NULL == Key->Last)			
    		{
    			Key->CountDowm++;			
    			Key->CountUp = 0;
    			
    			if( Key->CountDowm >= DEBOUNCE && Key->CountDowm < LONGPRESS)//短按键判断
    			{
    				keyret = KeyLast;
    			}
    			else if( Key->CountDowm == LONGPRESS )//长按键判断				
    			{
    				keyret = Key->KeyLast;	
    				keyret |= 0x0100;		
    			}
    			else if(KeyCKey->CountDowmountdowm > LONGPRESS+DEBOUNCE)//连续按键判断
    			{
    				Key->CountDowm -= DEBOUNCE;
    				keyret = Key->KeyLast;	
    				keyret |= 0x0200;	
    			}
    		}
    	}
    	else
    	{
    		Key->CountUp++;	
    
    		if( Key->CountUp > 1 ) 
    		{
    			Key->CountUp = 0;	
    			Key->CountDowm = 0;
    		}
    	}
    	
    	Key->KeyLast = keycur;	
    	return keyret;
    }

     

    最后说说这个功能的实现,按键检测分为三个部分,一个是按键获取函数,一个是消抖,一个是按键筛选函数,先把代码贴上来。

    type struct key
    {
    	uint8 Last;
    	uint8 CountDowm;
    	uint8 CountUp;
    }KEY_TYPE;
    
    #define DEBOUNCE 10//延时消抖时间
    #define LONGPRESS 100//长按键判断函数
    /*
    * description: 按键消抖函数
    * intput:按键结构体,键值
    * output:键值
    * 
    */
    uint16 key_scan( KEY_TYPE *Key ,uint8 keycur)
    {
    	unsigned uint16 keyret = 0;   	  
    
    	keyret = KEY_NULL;
    	if(  keycur != KEY_NULL )				
    	{
    		if( Key->Last == keycur || KEY_NULL == Key->Last)			
    		{
    			Key->CountDowm++;			
    			Key->CountUp = 0;
    			
    			if( Key->CountDowm >= DEBOUNCE && Key->CountDowm < LONGPRESS)//短按键判断
    			{
    				keyret = KeyLast;
    			}
    			else if( Key->CountDowm == LONGPRESS )//长按键判断				
    			{
    				keyret = Key->KeyLast;	
    				keyret |= 0x0100;		
    			}
    			else if(KeyCKey->CountDowmountdowm > LONGPRESS+DEBOUNCE)//连续按键判断
    			{
    				Key->CountDowm -= DEBOUNCE;
    				keyret = Key->KeyLast;	
    				keyret |= 0x0200;	
    			}
    		}
    	}
    	else
    	{
    		Key->CountUp++;	
    
    		if( Key->CountUp > 1 ) 
    		{
    			Key->CountUp = 0;	
    			Key->CountDowm = 0;
    		}
    	}
    	
    	Key->KeyLast = keycur;	
    	return keyret;
    }
    
    /*
    * description: 获取按键的函数
    * intput:none
    * output:键值
    * 
    */
    uint8 GetKeyValue(void)
    {
    	uint8 ret=NULL;
    	/*
    	这个部分的代码需要自己实现,这里可以从通信函数如iic,spi获得键值,也可以从gpio端口获得键值
    	*/
    	return ret;
    }
    
    
    #define KEY_NULL 0
    #define KEY_UP 1
    #define KEY_DOWN 2
    #define KEY_ON 3
    #define KEY_UP_L 4
    #define KEY_DOEN_L 5
    #define KEY_ON_L 6
    /*
    * description: 筛选按键的函数,只筛选需要的键值
    * intput:键值
    * output:键值
    * 
    */
    uint8 GetKeyValue(uint8 key)
    {
    	uint8 ret=KEYNULL;
    	switch(key)
    	{
    		0x01:
    		{
    			ret = KEY_UP;
    		}
    			break;
    		0x0101:
    		{
    			ret = KEY_UP_L;
    		}
    			break;
    		default:
    			break;
    	}
    	
    	return ret;
    }
    
    

     

    函数的三个部分的按键获取函数部分需要自己去编写,不同的键值来源不同,我试过从IIC中读取键值,也试过从GPIO中读取键值。

    然后是消抖函数,消抖函数需要如果有多个按键来源的话需要定义多个结构体,如果只有一个键值来源可以替换成静态局部变量版的函数。

    分成三个部分的好处是,函数间各干各事情,互不影响,更容易读,我在接手别人的代码时候,如果涉及到按键部分出现问题的话,一般先问上一个维护的人做没做过程消抖,如果回答说有做,好的,接着问怎么做的,一般把对方的过程消抖搞懂了,基本就懂了按键这部分的代码。如果对方说没有做或者很茫然的看着我,好吧,我会直接把对方的这部分代码删掉,重写。

     

    写于2017年7月30日 一个没有空调的夏天

    深圳

    展开全文
  • } /** * @brief 扫描按键函数 * @param 无 * @retval 独立按键扫描的详细过程: * 第一步:平时没有按键被触发时,按键的自锁标志和去抖动延时计数器一直被清零。 * 第二步:一旦有按键被按下,去抖动延时计数器...

    一、使用proteus绘制简单的电路图,用于后续仿真

    二、编写程序

    /********************************************************************************************************************
    ----	@Project:	Independent-KEY
    ----	@File:	main.c
    ----	@Edit:	ZHQ
    ----	@Version:	V1.0
    ----	@CreationTime:	20200506
    ----	@ModifiedTime:	20200506
    ----	@Description:	有两个独立按键,每按一个独立按键,蜂鸣器发出“滴”的一声后就停。
    ----	当主函数正在处理一气呵成的耗时任务时(前提是没有关闭定时器中断),这个时候如果有按键按下来,就有可能没有及时被响应到而遗漏了。
    ----	在定时中断函数里处理独立按键的扫描程序,可以有效地避免这个问题。
    ----	单片机:AT89C52
    ********************************************************************************************************************/
    #include "reg52.h"
    
    /*——————宏定义——————*/
    #define FOSC 11059200L
    #define T1MS (65536-FOSC/12/1000)   /*1ms timer calculation method in 12Tmode*/
    
    #define const_voice_short  80   /*蜂鸣器短叫的持续时间*/
    
    #define const_key_time1   60  /*按键去抖动延时的时间*/
    #define const_key_time2   60  /*按键去抖动延时的时间*/
    
    /*——————变量函数定义及声明——————*/
    /*定义按键S1*/
    sbit Key_S1 = P0^0;
    /*定义按键S2*/
    sbit Key_S2 = P0^1;
    /*定义蜂鸣器*/
    sbit BUZZER = P2^7;
    
    unsigned char ucKeySec = 0;   /*被触发的按键编号*/
    
    unsigned int  uiKeyTimeCnt1 = 0; /*按键去抖动延时计数器*/
    unsigned char ucKeyLock1 = 0; /*按键触发后自锁的变量标志*/
    
    unsigned int  uiKeyTimeCnt2 = 0; /*按键去抖动延时计数器*/
    unsigned char ucKeyLock2 = 0; /*按键触发后自锁的变量标志*/
    
    unsigned int  uiVoiceCnt = 0;  /*蜂鸣器鸣叫的持续时间计数器*/
    
    
    /**
    * @brief  定时器0初始化函数
    * @param  无
    * @retval 初始化T0
    **/
    void Init_T0(void)
    {
    	TMOD = 0x01;                    /*set timer0 as mode1 (16-bit)*/
    	TL0 = T1MS;                     /*initial timer0 low byte*/
    	TH0 = T1MS >> 8;                /*initial timer0 high byte*/
    }
    /**
    * @brief  外围初始化函数
    * @param  无
    * @retval 初始化外围
    **/
    void Init_Peripheral(void)
    {
    	ET0 = 1;/*允许定时中断*/
    	TR0 = 1;/*启动定时中断*/
    	EA = 1;/*开总中断*/
    
    }
    
    /**
    * @brief  初始化函数
    * @param  无
    * @retval 初始化单片机
    **/
    void	Init(void)
    {
    	Init_T0();
    	BUZZER = 1;
    }
    /**
    * @brief  扫描按键函数
    * @param  无
    * @retval 独立按键扫描的详细过程:
    * 第一步:平时没有按键被触发时,按键的自锁标志和去抖动延时计数器一直被清零。
    * 第二步:一旦有按键被按下,去抖动延时计数器开始累加,在还没累加到
    *         阀值const_key_time1时,如果在这期间由于受外界干扰或者按键抖动,而使
    *         IO口突然瞬间触发成高电平,这个时候马上又把延时计数器uiKeyTimeCnt1
    *         清零了,这个过程非常巧妙,非常有效地去除瞬间的杂波干扰。
    *         以后凡是用到开关感应器的时候,都可以用类似这样的方法去干扰。
    * 第三步:如果按键按下的时间超过了阀值const_key_time1,则触发按键,把编号ucKeySec赋值。
    *         同时,马上把自锁标志ucKeyLock1置位,防止按住按键不松手后一直触发。
    * 第四步:等按键松开后,自锁标志ucKeyLock1及时清零,为下一次自锁做准备。
    * 第五步:以上整个过程,就是识别按键IO口下降沿触发的过程。
    **/
    void Key_Scan(void)
    {
    	/*扫描S1*/
    	if(Key_S1 == 1)	/*如果没有键按下(高电平),将一些标志位及时清零*/
    	{
    		ucKeyLock1 = 0;/*自锁标志位清0*/
    		uiKeyTimeCnt1 = 0;/*按键去抖动延时计数器清零*/
    	}
    	else if(ucKeyLock1 == 0)	/*如果有按键按下,且是第一次按下*/
    	{
    		uiKeyTimeCnt1 ++;
    		if(uiKeyTimeCnt1 > const_key_time1)
    		{
    			uiKeyTimeCnt1 = 0;
    			ucKeyLock1 = 1;/*自锁标志位置位,避免一直触发*/
    			ucKeySec = 1; /*触发S1*/
    		}
    	}
    	/*扫描S2*/
    	if(Key_S2 == 1)	/*如果没有键按下(高电平),将一些标志位及时清零*/
    	{
    		ucKeyLock2 = 0;/*自锁标志位清0*/
    		uiKeyTimeCnt2 = 0;/*按键去抖动延时计数器清零*/
    	}
    	else if(ucKeyLock2 == 0)	/*如果有按键按下,且是第一次按下*/
    	{
    		uiKeyTimeCnt2 ++;
    		if(uiKeyTimeCnt2 > const_key_time2)
    		{
    			uiKeyTimeCnt2 = 0;
    			ucKeyLock2 = 1;/*自锁标志位置位,避免一直触发*/
    			ucKeySec = 2; /*触发S2*/
    		}
    	}	
    	
    }
    /**
    * @brief  按键服务函数
    * @param  无
    * @retval 根据扫描得到的值,进行数据处理
    **/
    void key_Service(void)
    {
    	switch(ucKeySec)
    	{
    		case 1: /*S1按下*/
    				uiVoiceCnt = const_voice_short;  /*蜂鸣器短叫*/			
    				ucKeySec = 0; /*响应按键服务处理程序后,按键编号清零,避免一致触发*/
    		break;
    		case 2:/*S2按下*/
    				uiVoiceCnt = const_voice_short;  /*蜂鸣器短叫*/		
    				ucKeySec = 0; 
    		break;			
    	}
    }
    /**
    * @brief  定时器0中断函数
    * @param  无
    * @retval 无
    **/
    void ISR_T0(void)	interrupt 1
    {
    	TF0 = 0;  /*清除中断标志*/
      TR0 = 0; /*关中断*/
    	/*扫描按键*/
    	Key_Scan();
    	if(0 != uiVoiceCnt)
    	{
    		uiVoiceCnt --;
    		BUZZER = 0;
    	}
    	else
    	{
    		BUZZER = 1;
    	}
    	
    	TL0 = T1MS;                     /*initial timer0 low byte*/
    	TH0 = T1MS >> 8;                /*initial timer0 high byte*/
      TR0 = 1; /*开中断*/	
    }
    /**
    * @brief  延时函数
    * @param  无
    * @retval 无
    **/
    void Delay_Long(unsigned int uiDelayLong)
    {
       unsigned int i;
       unsigned int j;
       for(i=0;i<uiDelayLong;i++)
       {
          for(j=0;j<500;j++)  /*内嵌循环的空指令数量*/
              {
                 ; /*一个分号相当于执行一条空语句*/
              }
       }
    }
    /*——————主函数——————*/
    /**
    * @brief  主函数
    * @param  无
    * @retval 实现LED灯闪烁
    **/
    void main()
    {
    	/*单片机初始化*/
    	Init();
    	/*延时,延时时间一般是0.3秒到2秒之间,等待外围芯片和模块上电稳定*/
    	Delay_Long(100);
    	/*单片机外围初始化*/	
    	Init_Peripheral();
    	while(1)
    	{
    
    		/*按键服务函数*/
    		key_Service();
    	}
    }
    
    

    三、仿真实现

    展开全文
  • 51单片机矩阵键盘扫描程序 #include<reg52.h> #define uint unsigned int #define uchar unsigned char sbit dula=P2^6; sbit wela=P2^7; sbit key1=P3^4; uchar code table[]={//数码表 0x3f,0x06,0x5b,0x4f,...
  • 51单片机矩阵按键扫描

    千次阅读 2018-10-03 10:43:55
    目标:获取矩阵键盘的按键值(按下按键,在单个数码管上显示出键值) 连线: P1与矩阵键盘连接,P0 与单个数码管连接 代码如下: #include &lt;reg51.h&gt; unsigned char code table[] = {0x80,0x40,0x...
  • 正在学习郭天祥《51单片机C语言教程(第2版)》第4章,键盘检测原理。矩阵键盘检测部分的代码又长又啰嗦,所以修改了下。 权当个记录。 问题描述: 在实验板TX-1C上实现如下描述,实验板上电时,数码管不显示,顺序...
  • 一,按键控制数码管 ...//功能:任意独立按键控制(带扫描式的) //优点:中间有20ms延时函数消抖;可以扩展任意个按键;可移植 // 含扫描按键所有操作; //作者: 梦 //提醒: 记得点赞哦!!!!! //转载要著...
  • 51单片机4x4矩阵键盘扫描+数码管显示 材料:AT89C52、2位数码管、74HC595、 Proteus仿真 实例代码 #include<reg52.h> #include "intrins.h" sbit ST=P2^0;//定义74HC595移位寄存器 sbit SH=P2^2; sbit DS=...
  • 一个51单片机键盘扫描程序,算法简单有效  发一个51单片机键盘扫描程序,算法简单有效   再给大家分享一个不错按键程序(来自ourdev) /****************************************  键盘_不采用...
  • 写在前面 单片机的定时器和中断可以说是贯穿了各个模块的始终,这一个概念可以说是最最最...当人不去触碰按键的时候,按键会有可能因为各种原因产生抖动,从到使得串口读取到的电压会在0/1之间来回跳动,这也就使得程
  • 51单片机4x4矩阵键盘扫描+数码管显示(二)(修bug篇) 修正上一篇文章显示效果《51单片机4x4矩阵键盘扫描+数码管显示》闪烁,消隐处理,优化。 材料:AT89C52、2位数码管、74HC595、 Proteus仿真 在调试效果的...
  • C51单片机无延迟函数按键识别

    千次阅读 2018-10-13 19:28:58
    C51单片机无延迟函数按键识别 #include&lt;reg52.h&gt; sbit Key=P3^4; ungsigned char key_now,key_pre,key_flag; void scan(void) { key_now=Key; key_flag=(key_now^key_old)^kay_flag; key_old=key...
  • 51单片机4x4矩阵键盘扫描+数码管显示(二) 演示效果 材料:AT89C52、2位数码管、74HC595、 Proteus仿真 《先列后行扫描法》 方法二:先列后行扫描法 实例代码 #include<reg52.h> #include "intrins.h" sbit...
  • 按键的一端接地,另一端与单片机的某个I/O口相连,开始时先给该I/O口赋一个高电平,然后让单片机不断地检测该I/O口是否变成了低电平,当按键闭合时,相当于该I/O口通过按键与地相连,变成低电平,程序一旦检测到I/...
  • 适合初学者的按键使用状态机的网络资源,再主函数里调用按键扫描函数,取得按键值,用按键值判断现在的状态
  • 51单片机扫描键盘程序   //-----------------------函数声明,变量定义-------------------------------------------------------- #include sbit LED_1 =P1^4; sbit LED_2 =P1^5; sbit LED_3 =P1^6; sbit ...
  • 里面运用了不少知识,其中比较重要的有外部中断,数码管动态显示,按键扫描(还有现在看起来极其啰嗦与智障的程序构思。 )要是想了解这些内容的可以康康这篇。 外部中断 这个非常重要,51单片机好像并不能完成多...
  • 51单片机按键消抖方式总结

    千次阅读 2021-07-07 17:34:24
    } } } } 按键效果如下: 51单片机按键抖动 2、延时消除抖动 存在如下缺点: delay()延时函数会占用大量时间; 需要while循环不断的扫描按键,对单片机运算资源的浪费。 #include #include sbit KeyValue=P3...
  • 单片机项目中,按键操作通常是产品与用户交互必不可少功能,按键又有短按、长按、重复、组合键等操作,本文介绍了一种按键扫描的实现方法,能够实现短按、长按、重复以为组合键的功能。 短按:即按下按键马上松开...
  • (1 思路分析(2 添加头文件(3 延时程序(4 键盘扫描程序(5 配置按键功能(6 补坑(7 深度补坑(8 程序入口四、让程序跑起来1、生成.hex文件2、单片机添加程序文件五、 总结 一、环境 我用的是Keil5做编译工具,用...
  • 51单片机函数库制作

    2020-11-19 20:41:11
    单片机函数库 1.延时 void delay(uint x) { uint i,j; for(i=0;i<x;i++) for(j=0;j<110;j++); } 2.数码管显示 void dispw(uchar w,uchar s)//w为位数,s为显示的数字 {P2=_cror_(0x7f,w); P0=smg[s]; ...
  • 51单片机键盘、矩阵键盘松手检测

    千次阅读 2019-09-27 23:08:39
    当按下按键不松手,是进行一次响应操作,还是重复进行响应操作呢?下面就基于51单片机的独立按键和矩阵键盘对连按功能进行配置。
  • 一、使用proteus绘制简单的电路图,用于后续仿真 二、编写程序 /******************************************************************... } } 三、仿真实现 51单片机实现在主函数while循环中驱动数码管的动态扫描程序
  • 51单片机实现按键键盘的功能

    千次阅读 多人点赞 2020-02-21 17:32:18
    实现按键键盘的功能 写在前面 按钮开关 轻触开关是一种电子开关,使用时,轻轻按开关按钮就可使开关接通,当松开手时,开关断开。我们使用的开关如下图:   LED连接P0.0口,独立按键连接p1.0口,当按键按下时...
  • 这篇博文主要记录51单片机键盘篇(非编码键盘与编码键盘、非编码键盘扫描方式、独立键盘、矩阵键盘键盘消抖等)包含原理图、代码等(一)基础补充1.键盘的任务2.键盘的识别3.如何消除按键的抖动4.非编码键盘与...
  • (蓝桥杯)51单片机按键处理

    千次阅读 2018-04-30 20:34:47
    按键程序用固定延时的时候,会显的很呆板,并且还很长很长,这样显的程序也臃肿,所以我在网上查了很多按键程序,见到了各种各样的形式,最后只有一种在定时器里扫描按键的这个最合我心意,但代码都杂乱,下面是我...
  • 1、优化了《51单片机——独立按键、矩阵按键多种方案1.0》的代码。 2、添加了矩阵按键逐行扫描法KEY16_1、KEY16_2 #ifndef __KEY_H__ #define __KEY_H__ #include "delay.h" //按键占用P3口 extern unsigned ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,006
精华内容 802
关键字:

51单片机按键扫描函数