51单片机单按键长短处理
第十一节:同一个按键短按与长按的区别触发
第十一节:同一个按键短按与长按的区别触发开场白:上一节讲了类似电脑键盘组合按键触发的功能,这节要教会大家一个知识点:如何在上一节的基础上,略作修改,就可以实现同一个按键短按与长按的区别触发。
具体内容,请看源代码讲解。
(1)硬件平台:基于朱兆祺51单片机学习板。
用矩阵键盘中的S1和S5号键作为独立按键,记得把输出线P0.4一直输出低电平,模拟独立按键的触发地GND。
(2)实现功能:两个独立按键S1和S5,按住其中一个按键,在短时间内松手,则认为是短按,触发蜂鸣器短鸣一声。
如果一直按住这个按键不松手,那么超过规定的长时间内,则认为是长按,触发蜂鸣器长鸣一声。
(3)源代码讲解如下:#include "REG52.H"#define const_voice_short 20 //蜂鸣器短叫的持续时间#define const_voice_long 140 //蜂鸣器长叫的持续时间/* 注释一:* 调整抖动时间阀值的大小,可以更改按键的触发灵敏度。
* 去抖动的时间本质上等于累计定时中断次数的时间。
*/#define const_key_time_short1 20 //短按的按键去抖动延时的时间#define const_key_time_long1 400 //长按的按键去抖动延时的时间#define const_key_time_short2 20 //短按的按键去抖动延时的时间#define const_key_time_long2 400 //长按的按键去抖动延时的时间void initial_myself();void initial_peripheral();void delay_long(unsigned int uiDelaylong);void T0_time(); //定时中断函数void key_service(); //按键服务的应用程序void key_scan(); //按键扫描函数放在定时中断里sbit key_sr1=P0^0; //对应朱兆祺学习板的S1键sbit key_sr2=P0^1; //对应朱兆祺学习板的S5键sbit key_gnd_dr=P0^4; //模拟独立按键的地GND,因此必须一直输出低电平sbit beep_dr=P2^7; //蜂鸣器的驱动IO口unsigned char ucKeySec=0; //被触发的按键编号unsigned int uiKeyTimeCnt1=0; //按键去抖动延时计数器unsigned char ucKeyLock1=0; //按键触发后自锁的变量标志unsigned char ucShortTouchFlag1=0; //短按的触发标志unsigned int uiKeyTimeCnt2=0; //按键去抖动延时计数器unsigned char ucKeyLock2=0; //按键触发后自锁的变量标志unsigned char ucShortTouchFlag2=0; //短按的触发标志unsigned int uiVoiceCnt=0; //蜂鸣器鸣叫的持续时间计数器void main(){initial_myself();delay_long(100);initial_peripheral();while(1){key_service(); //按键服务的应用程序}}void key_scan()//按键扫描函数放在定时中断里{/* 注释二:* 长按与短按的按键扫描的详细过程:* 第一步:平时只要按键没有被按下时,按键的自锁标志,去抖动延时计数器一直被清零。
长短摁键
长短摁键2011年11月16日修改历史1.创建修改时间:2011年11月16日2.漆彦清添加流程图修改时间:2011年12月7日长短摁键1.前言经过独立摁键(一)的学习和操作,相信你已经学会了简单的摁键操作。
想不想更进一步学习和利用摁键呢?现在我们一起来看看,怎么样让摁键有长短。
2.长短摁键原理所谓长短摁键,就是单片机能通过你摁键时间的长短知道你摁的是长键还是短键。
举个例子吧~比如手机上的关机键,你可以用它来挂电话、回桌面甚至关机,那么这个普通的摁键,是如何做到这一点的呢?其实,就是通过对长短摁键的控制,来满足你不同的需求的。
长短摁键的关键,其实就在长短的界定与扫描。
长短有相对。
首先你得设定一个时间。
假设你设定个时间为1s,那么,你可以让单片机去扫描摁键。
如果发现摁键摁下时间长于或等于1s的,即判断其为长摁键;时间短于1s的则判断其为短摁键。
这样一来,就可以只用一个摁键,而去实现不同的功能了。
3.摁键抖动与消抖我们实现长短摁键的时候,仍然要对其进行消抖,这里就不再赘述了。
详情可以参见独立摁键(一)。
4.关键代码#include <reg52.h> //输入输出头文件#define uchar unsigned char //把已有的类型换名,定义成方便自#define uint unsigned int //己使用的类型名,便与记忆与使用sbit Key_S5=P3^4; //为端口P3_4改名为Key_S5sbit Led_R=P1^0; //为端口P1_0改名为Led_R,表示红灯sbit Led_G=P1^1; //为端口P1_1改名为Led_G,表示绿灯 //sbit为位定义关键字,用来定义端口中的某一位void delay_50us(uint t)//这是在晶振为11.0592HZ情况下的延时50us倍数的函数。
{ //比如t=20,可以延时20*50us=1000us=1ms。
独立按键连按和长按处理技巧
单片机按键处理技巧及编程方式2010-10-23 15:01从这一章开始,我们步入按键程序设计的殿堂。
在基于单片机为核心构成的应用系统中,用户输入是必不可少的一部分。
输入可以分很多种情况,譬如有的系统支持PS2键盘的接口,有的系统输入是基于编码器,有的系统输入是基于串口或者USB或者其它输入通道等等。
在各种输入途径中,更常见的是,基于单个按键或者由单个键盘按照一定排列构成的矩阵键盘(行列键盘)。
我们这一篇章主要讨论的对象就是基于单个按键的程序设计,以及矩阵键盘的程序编写。
◎按键检测的原理常见的独立按键的外观如下,相信大家并不陌生,各种常见的开发板学习板上随处可以看到他们的身影。
(原文件名:1.jpg)引用图片总共有四个引脚,一般情况下,处于同一边的两个引脚内部是连接在一起的,如何分辨两个引脚是否处在同一边呢?可以将按键翻转过来,处于同一边的两个引脚,有一条突起的线将他们连接一起,以标示它们俩是相连的。
如果无法观察得到,用数字万用表的二极管挡位检测一下即可。
搞清楚这点非常重要,对于我们画PCB的时候的封装很有益。
它们和我们的单片机系统的I/O口连接一般如下:(原文件名:2.jpg)引用图片对于单片机I/O内部有上拉电阻的微控制器而言,还可以省掉外部的那个上拉电阻。
简单分析一下按键检测的原理。
当按键没有按下的时候,单片机I/O通过上拉电阻R接到VCC,我们在程序中读取该I/O的电平的时候,其值为1(高电平); 当按键S按下的时候,该I/O被短接到GND,在程序中读取该I/O的电平的时候,其值为0(低电平) 。
这样,按键的按下与否,就和与该按键相连的I/O的电平的变化相对应起来。
结论:我们在程序中通过检测到该I/O口电平的变化与否,即可以知道按键是否被按下,从而做出相应的响应。
一切看起来很美好,是这样的吗?◎现实并非理想在我们通过上面的按键检测原理得出上述的结论的时候,其实忽略了一个重要的问题,那就是现实中按键按下时候的电平变化状态。
51单片机 1602液晶显示 TLC5615独立按键调频调幅
#include <reg52.h>#include <math.h>#define uint unsigned int#define uchar unsigned char#define PI 3.14sbit CS=P2^5; //定义片选信号IO口sbit SCLK=P2^4; //定义时钟信号IO口sbit DIN=P2^3; //定义数据输入IO口uint kk=1;sbit Aup=P1^4; //频率+sbit Adowm=P1^5;//频率-sbit Fup=P1^6; //幅度+sbit Fdowm=P1^7;//幅度-uint DataNum=128;//定义一个周期的点数uint AmNum=256; //定义一个周期的点数/*--------延时子程序----------*/void delay(unsigned char pp) //延迟时间等于k*8ms{while(pp--){unsigned char j;// P2=P2&0XF8;for(j = 0;j<123;j++); //j进行的内部循环,1次延迟8us,延迟1ms}}/*----------DA转换----------*/void DAConvert(uint Data){uchar i;Data<<=6;CS=0;SCLK=0;for (i=0;i<12;i++){DIN=(bit)(Data&0x8000);SCLK=1;Data<<=1;SCLK=0;}CS=1;SCLK=0;for (i=0;i<12;i++);}/*正弦波参数换算程序*/uint GetSinData(uchar x){uint SinData;SinData=((sin(2*PI*x/DataNum)+1)/2.0)*AmNum;return SinData;}/*----------主程序----------*/main(){uint i;while(1){for(i=0;i<DataNum;i++)DAConvert(GetSinData(i));//输出正弦波P1 = 0xFF; // 发全0行扫描码,列线输入if((P1&0xFF) != 0xFF) // 若有键按下{delay(1);// 延时去抖动if((P1&0xFF) != 0xFF)switch(AmNum){case 512: AmNum=256;break;case 32: AmNum=256; break;}switch(DataNum){case 256: DataNum=128;break;case 16: DataNum=128; break;}switch(P1){case 0x7f: AmNum=AmNum+32;break;//幅度+case 0xbf: AmNum=AmNum-32; break;//幅度-case 0xdf: DataNum=DataNum+16; break;//频率-case 0xef: DataNum=DataNum-16; break;//频率+}}}}。
单片机按键的解决方法
单片机按键的解决解决方案1、单片机上的按键控制一般采用两种控制方法:中断和查询。
中断必须借助中断引脚,而查询按键可用任何IO端口。
按键较少时,一个按键占用一个端口,而按键较多时,多采用矩阵形式(如:经常用4个端口作为输出,4个端口作为输入的4X4矩阵来获得16个按键);还可以用单片机的AD转换功能一个引脚接多个按键,根据电阻分压原理判断是哪个按键按下。
2、中断形式STM32可支持68个中断通道,已经固定分配给相应的外部设备,每个中断通道都具备自己的中断优先级控制字节PRI_n(8位,但是STM32中只使用4位,高4位有效),每4个通道的8位中断优先级控制字构成一个32位的优先级寄存器。
68个通道的优先级控制字至少构成17个32位的优先级寄存器.4bit的中断优先级可以分成2组,从高位看,前面定义的是抢占式优先级,后面是响应优先级。
按照这种分组,4bit一共可以分成5组第0组:所有4bit用于指定响应优先级;第1组:最高1位用于指定抢占式优先级,后面3位用于指定响应优先级;第2组:最高2位用于指定抢占式优先级,后面2位用于指定响应优先级;第3组:最高3位用于指定抢占式优先级,后面1位用于指定响应优先级;第4组:所有4位用于指定抢占式优先级。
所谓抢占式优先级和响应优先级,他们之间的关系是:具有高抢占式优先级的中断可以在具有低抢占式优先级的中断处理过程中被响应,即中断嵌套。
当两个中断源的抢占式优先级相同时,这两个中断将没有嵌套关系,当一个中断到来后,如果正在处理另一个中断,这个后到来的中断就要等到前一个中断处理完之后才能被处理。
如果这两个中断同时到达,则中断控制器根据他们的响应优先级高低来决定先处理哪一个;如果他们的抢占式优先级和响应优先级都相等,则根据他们在中断表中的排位顺序决定先处理哪一个。
每一个中断源都必须定义2个优先级。
有几点需要注意的是:1)如果指定的抢占式优先级别或响应优先级别超出了选定的优先级分组所限定的范围,将可能得到意想不到的结果;2)抢占式优先级别相同的中断源之间没有嵌套关系;3)如果某个中断源被指定为某个抢占式优先级别,又没有其它中断源处于同一个抢占式优先级别,则可以为这个中断源指定任意有效的响应优先级别。
单片机系统中的按键处理
单片机系统中的按键处理对于一个由单片机为核心构成的系统而言。
输入通道是相当重要的。
可以看到几乎每一样基于单片机的产品都有人机交互的部分。
如各种仪器设备上的各种按钮和开关,以及我们手机上的键盘,MP3上的按键等等。
最常见的输入部分,莫非就是按键了。
对于大多数初学者而言,编写一个好的按键程序是一件颇为头疼的事情。
于是乎在网上乱搜一气,程序倒是找到了不少,但是看了半天依然是不明白。
或者在某某论坛上面发帖“跪求XX按键程序,大虾帮忙……”如果你偶然间进了这个论坛,又偶然看到了这个帖子,而且恰好你对按键程序的写法也不是很清楚,那么我希望你能够静静的看完这个帖子。
如果你觉得对你很有帮助,那么我希望你能够在以后的日子中能够坚持到这个论坛来,一起交流学习,分享自己学习过程中的喜悦或者一起探讨棘手的问题,这是我写这个帖子的最大的初衷了。
OK,不能再说了,再说就变成水帖了。
那么我们开始吧。
按键的种类很多。
不过原理基本相似。
下面我们以一种轻触开关为例讲解按键程序的写法。
这种轻触开关大家不陌生吧^_^一般情况下,按键与单片机的连接如下面这幅图所示。
(图中电阻值一般去4.7k~10k之间,对于内部端口有上拉电阻的单片机则可省略此电阻)单片机对于按键的按下与否则是通过检测相应引脚上的电平来实现的。
对于上图而言,当P17引脚上面的电平为低时,则表示按键已经按下。
反之,则表明按键没有按下。
我们在程序中只要检测到了P17引脚上面的电平为低了,就可以判断按键按下。
呵呵,简单吧。
等会,您先别乐呵,话还没说完呢。
下面我们来看看,当按键按下时,P17引脚上面的波形是怎么变化的。
上图是一个理想波形图,当按键按下时,P17口的电平马上被拉低到0V了。
当然理想的东西都是不现实的。
所以我们还是看看现实的波形图吧。
看出什么区别来了没。
呵呵,只要你不是傻子我相信都能看出其中的区别。
由于按键的机械特性。
当按键闭合时,并不能马上保存良好的接触,而是来回弹跳。
单片机按键处理方式(一)——典型的按键处理方式
单⽚机按键处理⽅式(⼀)——典型的按键处理⽅式前⾔ 按键处理是学习单⽚机的必修课之⼀。
⼀次按键的过程,并⾮是⼀个理想的有⼀定宽度的电平脉冲,⽽是在按下、弹起过程中存在抖动,只有在中间阶段电平信号是稳定的。
⼀次典型的按键过程是酱紫的: 在抖动过程中,电平信号⾼低反复变化,如果你的按键检测是检测下降沿或上升沿或者是⽤外部中断检测按键,都可能在抖动时重复检测到多次按键。
这就是在未消抖的按⼀次键显⽰值加1的程序中,出现按⼀次键显⽰值+2、+3甚⾄加更多的原因。
对于按键消抖,常⽤的有硬件消抖和软件消抖。
本⽂是我个⼈对按键处理的⼀些常见⽅法的总结,由于我本⼈不太懂硬件,所以这⾥只讨论独⽴按键的软件消抖实现。
⽔平有限,如有错误请不吝指正。
硬件环境 本⽂代码均在单⽚机STC90C516RD+、晶振12.0MHz硬件环境下试验通过。
带消抖的简单的按键处理 最简单的消抖处理就是在⾸次检测到电平变化后加⼀个延时,等待抖动停⽌后再次检测电平信号。
这也是⼤多数单⽚机教程讲述的消抖⽅式。
但在实际应⽤中基本不⽤这种⽅式,原因后⾯讲,先看代码://⽅法⼀:带消抖的简单的按键处理#include <reg52.h>#define GPIO_KEY P1 //8个独⽴按键IO⼝#define GPIO_LED P0 //8个LED灯,⽤于显⽰键值unsigned char ScanKey();void DelayXms(unsigned char x);void main(){unsigned char key;GPIO_LED = 0x00; //初始化LEDwhile (1){key = ScanKey(); //读取键值// if (0xff != key) //若有键按下,则更新LED的状态GPIO_LED = ~key; //点亮LED}}unsigned char ScanKey(){unsigned char keyValue = 0xff; //赋初值,0xff表⽰没有键按下GPIO_KEY = 0xff; //给按键IO⼝置位if (0xff != GPIO_KEY) //检查按键IO⼝的电平,如有键按下则不为0xff{DelayXms(15); //延时15ms,滤掉抖动。
基于51单片机按键长按短按效果源程序
基于51单片机按键长按短按效果源程序[复制链接]* 实验名称:多位数按键加减** 晶振:12MHZ* 内容:按键加减数字,多个数码管显示,使用定时器做数码管动态扫描** 并区别长按短按效果,完全可以应用的实际生产中** ---------------------------------------------------------------*/#include<reg52.h> //包含头文件,一般情况不需要改动,//头文件包含特殊功能寄存器的定义sbit KEY_ADD=P3^3; //定义按键输入端口S17sbit KEY_DEC=P3^2; //S18#define DataPort P1 //定义数据端口程序中遇到DataPort 则用P1 替换sbit LATCH1=P2^0;//定义锁存使能端口段锁存sbit LATCH2=P2^1;// 位锁存sbit P35 = P3^5;//这是为了关闭开发板上的点阵实际应用去掉unsigned char code HEYAO_DuanMa[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};// 显示段码值0123456789unsigned char code HEYAO_WeiMa[]={0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80};//分别对应相应的数码管点亮,即位码unsigned char TempData[8]={0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF};//存储显示值的全局变量void DelayUs2x(unsigned char t);//函数声明void DelayMs(unsigned char t);void Init_Timer0(void);void Display(unsigned char FirstBit,unsigned char Num);/*------------------------------------------------主函数------------------------------------------------*/void main (void){unsigned char num=0,key_press_num;P35=0; //这是为了关闭开发板上的点阵实际应用去掉KEY_ADD=1; //按键输入端口电平置高KEY_DEC=1;Init_Timer0();while (1) //主循环{if(!KEY_ADD) //如果检测到低电平,说明按键按下DelayMs(10); //延时去抖,一般10-20msif(!KEY_ADD) //再次确认按键是否按下,没有按下则退出{while(!KEY_ADD){key_press_num++;DelayMs(10); //10x200=2000ms=2sif(key_press_num==200) //大约2s{key_press_num=0; //如果达到长按键标准//则进入长按键动作while(!KEY_ADD) //这里用于识别是否按//键还在按下,如果按//下执行相关动作,否则退出{if(num<99) //加操作num++;//即时把显示数据处理,如果去掉下面2//句处理信息,实际上看不到渐变效果,//而是看到跳变效果//用户可以自行屏蔽测试//分解显示信息,如要显示68,则68/10=6 68%10=8 TempData[0]=HEYAO_DuanMa[num/10];TempData[1]=HEYAO_DuanMa[num%10];DelayMs(50);//用于调节长按循环操作//的速度,可以自行调整此值以便达到最佳效果}}}key_press_num=0;//防止累加造成错误识别if(num<99) //加操作num++;}}if(!KEY_DEC) //如果检测到低电平,说明按键按下{DelayMs(10); //延时去抖,一般10-20msif(!KEY_DEC) //再次确认按键是否按下,没有//按下则退出{while(!KEY_DEC)key_press_num++;DelayMs(10);if(key_press_num==200) //大约2s{key_press_num=0;while(!KEY_DEC){if(num>0) //减操作num--;//分解显示信息,如要显示68,则68/10=6 68%10=8 TempData[0]=HEYAO_DuanMa[num/10];TempData[1]=HEYAO_DuanMa[num%10];DelayMs(50);//用于调节长按循环操作的速度}}}key_press_num=0;//防止累加造成错误识别if(num>0) //减操作num--;}}//分解显示信息,如要显示68,则68/10=6 68%10=8 TempData[0]=HEYAO_DuanMa[num/10];TempData[1]=HEYAO_DuanMa[num%10];// Display(0,8); //显示全部8位//主循环中添加其他需要一直工作的程序}}/*------------------------------------------------uS延时函数,含有输入参数unsigned char t,无返回值unsigned char 是定义无符号字符变量,其值的范围是0~255 这里使用晶振12M,精确延时请使用汇编,大致延时长度如下T=tx2+5 uS------------------------------------------------*/void DelayUs2x(unsigned char t){while(--t);}/*------------------------------------------------mS延时函数,含有输入参数unsigned char t,无返回值unsigned char 是定义无符号字符变量,其值的范围是0~255 这里使用晶振12M,精确延时请使用汇编------------------------------------------------*/void DelayMs(unsigned char t){while(t--){//大致延时1mSDelayUs2x(245);DelayUs2x(245);}}/*------------------------------------------------显示函数,用于动态扫描数码管输入参数FirstBit 表示需要显示的第一位,如赋值2表示从第三个数码管开始显示如输入0表示从第一个显示。
基于51单片机按键长按短按效果源程序
基于51单片机按键长按短按效果源程序[复制链接]* 实验名称:多位数按键加减** 晶振:12MHZ* 内容:按键加减数字,多个数码管显示,使用定时器做数码管动态扫描** 并区别长按短按效果,完全可以应用的实际生产中** ---------------------------------------------------------------*/#includ e<reg52.h> //包含头文件,一般情况不需要改动,//头文件包含特殊功能寄存器的定义sbit KEY_ADD=P3^3; //定义按键输入端口S17sbit KEY_DE C=P3^2; //S18#define DataPo rt P1 //定义数据端口程序中遇到D ataPo rt 则用P1 替换sbit LATCH1=P2^0;//定义锁存使能端口段锁存sbit LATCH2=P2^1;// 位锁存sbit P35 = P3^5;//这是为了关闭开发板上的点阵实际应用去掉unsign ed char code HEYAO_DuanM a[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};// 显示段码值0123456789unsign ed char code HEYAO_WeiMa[]={0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80};//分别对应相应的数码管点亮,即位码unsign ed char TempDa ta[8]={0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF};//存储显示值的全局变量void DelayU s2x(unsign ed char t);//函数声明void DelayM s(unsign ed char t);void Init_T imer0(void);void Displa y(unsign ed char FirstB it,unsign ed char Num);/*------------------------------------------------主函数------------------------------------------------*/void main (void){unsign ed char num=0,key_pr ess_n um;P35=0; //这是为了关闭开发板上的点阵实际应用去掉KEY_ADD=1; //按键输入端口电平置高KEY_DE C=1;Init_T imer0();while(1) //主循环{if(!KEY_ADD) //如果检测到低电平,说明按键按下DelayM s(10); //延时去抖,一般10-20msif(!KEY_ADD) //再次确认按键是否按下,没有按下则退出{while(!KEY_AD D){key_pr ess_n um++;DelayM s(10); //10x200=2000ms=2sif(key_pr ess_n um==200) //大约2s{key_pr ess_n um=0; //如果达到长按键标准//则进入长按键动作while(!KEY_ADD) //这里用于识别是否按//键还在按下,如果按//下执行相关动作,否则退出{if(num<99) //加操作num++;//即时把显示数据处理,如果去掉下面2//句处理信息,实际上看不到渐变效果,//而是看到跳变效果//用户可以自行屏蔽测试//分解显示信息,如要显示68,则68/10=6 68%10=8 TempDa ta[0]=HEYAO_DuanM a[num/10];TempDa ta[1]=HEYAO_DuanM a[num%10];DelayM s(50);//用于调节长按循环操作//的速度,可以自行调整此值以便达到最佳效果}}}key_pr ess_n um=0;//防止累加造成错误识别if(num<99) //加操作num++;}}if(!KEY_DEC) //如果检测到低电平,说明按键按下{DelayM s(10); //延时去抖,一般10-20msif(!KEY_DEC) //再次确认按键是否按下,没有//按下则退出{while(!KEY_DE C)key_pr ess_n um++;DelayM s(10);if(key_pr ess_n um==200) //大约2s{key_pr ess_n um=0;while(!KEY_DE C){if(num>0) //减操作num--;//分解显示信息,如要显示68,则68/10=6 68%10=8 TempDa ta[0]=HEYAO_DuanM a[num/10];TempDa ta[1]=HEYAO_DuanM a[num%10];DelayM s(50);//用于调节长按循环操作的速度}}}key_pr ess_n um=0;//防止累加造成错误识别if(num>0) //减操作num--;}}//分解显示信息,如要显示68,则68/10=6 68%10=8 TempDa ta[0]=HEYAO_DuanM a[num/10];TempDa ta[1]=HEYAO_DuanM a[num%10];// Displa y(0,8); //显示全部8位//主循环中添加其他需要一直工作的程序}}/*------------------------------------------------uS延时函数,含有输入参数unsign ed char t,无返回值unsign ed char 是定义无符号字符变量,其值的范围是0~255 这里使用晶振12M,精确延时请使用汇编,大致延时长度如下T=tx2+5 uS------------------------------------------------*/void DelayU s2x(unsign ed char t){while(--t);}/*------------------------------------------------mS延时函数,含有输入参数unsign ed char t,无返回值unsign ed char 是定义无符号字符变量,其值的范围是0~255 这里使用晶振12M,精确延时请使用汇编------------------------------------------------*/void DelayM s(unsign ed char t){while(t--){//大致延时1mSDelayU s2x(245);DelayU s2x(245);}}/*------------------------------------------------显示函数,用于动态扫描数码管输入参数FirstB it 表示需要显示的第一位,如赋值2表示从第三个数码管开始显示如输入0表示从第一个显示。
PIC单片机按键检测,单双击、长短按识别
硬件PIC16F883芯片,10个按键,4位数码管。
【芯片引脚】【数码管连接】PORTC连接数码管的8段LED,PORTA<3:0>连接数码管的4个共阴极(控制选通位)。
【按键连接】按键扫描程序在上一篇博文里面有说明,现在还是使用上面的扫面方式(代码都是一样的)。
用记录按键按下和弹起的时间判断是不是长按和双击。
TMR1设置,1:4分频、1:8预分频,计数周期为8uS。
TMR1溢出一次时间为0.524288 S keypress记录TMR1溢出的次数。
keypress大于等于2就跳出检测,认为他是长按(时间为1.048576S)。
keypress<1 且keyrelease <1 ,再次按下的keypress<1就认为是双击。
如下图:KP按键按下,KR按键弹起。
【实现代码】1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include<p16f883.inc>__CONFIG _CONFIG1, _LVP_OFF & _FCMEN_ON & _IESO_OFF & _BOR_OFF & _CPD_OFF & _CP_OFF & _MCLRE_ON & _PWRTE_ON & _WDT_OFF &_INTRC_OSC_NOCLKOUT__CONFIG _CONFIG2, _WRT_OFF & _BOR21Vudata_shrcounter res 1 ;计数个位counter0 res 1 ;计数十位counter1 res 1 ;扫描按键变量counter2 res 1 ;延时程序微调参数key_state res 1 ;按键状态keynum res 1 ;按键标号swap res 1 ;确认按键转换值29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 keypress res 1keypressbak res 1keyrelease res 1LED1 res 1LED2 res 1LED3 res 1LED4 res 1UDATAcounter3 res 1counter4 res 1sign res 1reset code 0x0000pagesel startgoto start;int_vector code 0x0004codestartbanksel ANSEL ;设置PORTA 为数字模式clrf ANSELbanksel ANSELH ;设置PORTB 为数字模式73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 clrf ANSELHbanksel TRISB ;设置PORTB 为输入模式movlw b '11111111'movwf TRISBbanksel WPUB ;设置PORTB 弱上拉movlw b '11111111'movwf WPUBbanksel OPTION_REGmovlw b '01000101' ;TMR0 64分频movwf OPTION_REGbanksel T1CONmovlw b '10010001' ;打开TMR1,设置1:8预分频,内部时钟源1:4分频movwf T1CONbanksel TRISA ;设置PORTA<3:0>为输出,接数码管的共阴极movlw b '11110000'movwf TRISAbanksel PORTAclrf PORTAbanksel TRISCmovlw b '00000000' ;设置PORTC 为输出,接8段数码管movwf TRISCclrf counter1117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159loopmovlw HIGH Table1movwf PCLATHmovf counter1,0call Table1banksel TRISBmovwf TRISBmovf counter1,0call Table1banksel PORTBmovwf PORTBmovf PORTB,0movwf key_statemovlw b '11001000'iorwf key_state,1movf counter1,0call Table1xorwf key_state,0movwf swapcomf swap,1161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 incfsz swap,1goto case1incf counter1,1movf counter1,0call Table1banksel TRISBmovwf TRISBmovf counter1,0call Table1banksel PORTBmovwf PORTBmovf PORTB,0 ;读取I/O 状态movwf key_statemovlw b '11001000'iorwf key_state,1movf counter1,0call Table1xorwf key_state,0movwf swapcomf swap,1incfsz swap,1205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 goto case2incf counter1,1movf counter1,0call Table1banksel TRISBmovwf TRISBmovf counter1,0call Table1banksel PORTBmovwf PORTBmovf PORTB,0 ;读取I/O 状态movwf key_statemovlw b '11001000'iorwf key_state,1movf counter1,0call Table1xorwf key_state,0movwf swapcomf swap,1incfsz swap,1goto case3249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291incf counter1,1movf counter1,0call Table1banksel TRISBmovwf TRISBmovf counter1,0call Table1banksel PORTBmovwf PORTBmovf PORTB,0 ;读取I/O 状态movwf key_statemovlw b '11001000'iorwf key_state,1movf counter1,0call Table1xorwf key_state,0movwf swapcomf swap,1incfsz swap,1goto case4goto continue293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335case1btfsc key_state,4goto key2movlw d '1'movwf keynumcall DealKeyPressgoto continuekey2btfsc key_state,2goto key3movlw d '2'movwf keynumcall DealKeyPressgoto continuekey3btfsc key_state,1goto key4movlw d '3'movwf keynumcall DealKeyPressgoto continue337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 key4btfsc key_state,0goto continuemovlw d '4'movwf keynumcall DealKeyPressgoto continuecase2;-------------------------------------------------;下面代码实现K10\K8\K5的按键处理btfsc key_state,2goto key8movlw d '10'movwf keynumcall DealKeyPressgoto continue;------------------------------------;处理K8381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 key8btfsc key_state,1goto key5movlw d '8'movwf keynumcall DealKeyPressgoto continue;------------------------------------;处理K5key5btfsc key_state,0goto case3movlw d '5'movwf keynumcall DealKeyPressgoto continuecase3;----------------------------------;处理K6/K9btfsc key_state,1goto key6425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 movlw d '9'movwf keynumcall DealKeyPressgoto continuekey6btfsc key_state,0goto case4movlw d '6'movwf keynumcall DealKeyPressgoto continuecase4;-----------------------------------------;处理K7btfsc key_state,0goto continuemovlw d '7'movwf keynumcall DealKeyPresscontinuecall display469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 clrf counter1goto loop;-----------------------------------;按键去抖,约8mSdelaymovlw d '4'movwf counter2LOOP2banksel TMR0clrf TMR0LOOP1banksel INTCONbtfss INTCON,T0IFgoto LOOP1bcf INTCON,T0IFdecfsz counter2,1goto LOOP2returndelay2513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 incfsz counter3,1goto delay2return;--------------------------------;按键处理程序;DealKeyPressclrf LED1clrf LED2clrf LED3clrf LED4call delaybanksel TMR1Hclrf TMR1Hbanksel TMR1Lclrf TMR1Lclrf keypresspresstimebanksel PIR1btfss PIR1,TMR1IF557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 goto nextbcf PIR1,TMR1IFincf keypressmovlw d '2'subwf keypress,0banksel STATUSbtfsc STATUS,Cgoto longpressnextmovf counter1,0call Table1banksel TRISBmovwf TRISBbanksel PORTBmovwf PORTBmovf PORTB,0 ;读取I/O 状态movwf key_statemovlw b '11001000'iorwf key_state,1movf counter1,0call Table1xorwf key_state,0601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 movwf swapcomf swap,1incfsz swap,1goto presstimecall delaybanksel TMR1Hclrf TMR1Hbanksel TMR1Lclrf TMR1Lclrf keyreleasereleasetimebanksel PIR1btfss PIR1,TMR1IFgoto next1bcf PIR1,TMR1IFincf keyreleasemovlw d '1'subwf keyrelease,0banksel STATUSbtfsc STATUS,C644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 goto clicknext1movf counter1,0call Table1banksel TRISBmovwf TRISBbanksel PORTBmovwf PORTBmovf PORTB,0 ;读取I/O 状态movwf key_statemovlw b '11001000'iorwf key_state,1movf counter1,0call Table1xorwf key_state,0movwf swapcomf swap,1incfsz swap,1goto overgoto releasetimeovercall delay688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 banksel TMR1Hclrf TMR1Hbanksel TMR1Lclrf TMR1Lclrf keypresspresstime1banksel PIR1btfss PIR1,TMR1IFgoto next2bcf PIR1,TMR1IFincf keypressmovlw d '1'subwf keypress,0banksel STATUSbtfsc STATUS,Cgoto clicknext2movf counter1,0call Table1banksel TRISBmovwf TRISBbanksel PORTB732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 movwf PORTBmovf PORTB,0 ;读取I/O 状态movwf key_statemovlw b '11001000'iorwf key_state,1movf counter1,0call Table1xorwf key_state,0movwf swapcomf swap,1incfsz swap,1goto presstime1movf keynum,0 ;双击movwf LED1movlw d '10'movwf LED2incf countergoto backlongpress ;长按movf keynum,0movwf LED2movlw d '10'776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 movwf LED1goto backclick ;单击movf keynum,0movwf LED1movwf LED2backcall CountNumreturn;----------------------------;按键计数;CountNummovlw d '9'subwf counter,0banksel STATUSbtfsc STATUS,Cgoto addincf counter820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 goto over1addincf counter0clrf countermovlw d '10'subwf counter0,0banksel STATUSbtfsc STATUS,Cgoto cleargoto over1clearclrf counter0over1movf counter,0movwf LED4movf counter0,0movwf LED3return864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 ;--------------------------------;显示数码管;displaybanksel PORTAmovlw b '11111110'movwf PORTAmovf LED1,0call Table3banksel PORTCmovwf PORTCcall delay2banksel PORTAmovlw b '11111101'movwf PORTAmovf LED2,0call Table3banksel PORTCmovwf PORTCcall delay2908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951banksel PORTAmovlw b '11111011'movwf PORTAmovf LED3,0call Table3banksel PORTCmovwf PORTCcall delay2banksel PORTAmovlw b '11110111'movwf PORTAmovf LED4,0call Table3banksel PORTCmovwf PORTCcall delay2return;----------------------;Table 真值表;952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 Table1 ;PORTB 、TRISB 扫描配置信息ADDWF PCL,fRETLW B '11111111'RETLW B '11101111'RETLW B '11111011'RETLW B '11111101'Table3 ;PORTC 设置,数码管真值表ADDWF PCL,f; RETLW B '01001001' ;三条横线RETLW B '10111111' ;0RETLW B '00000110' ;1RETLW B '01011011' ;2RETLW B '01001111' ;3RETLW B '01100110' ;4RETLW B '01101101' ;5RETLW B '01111101' ;6RETLW B '00000111' ;7RETLW B '01111111' ;8RETLW B '01101111' ;9RETLW B '00000000' ;黑屏end长按效果——3、4位数码管计数一直加,1位数码管熄灭,2位数码管显示按键编号;双击效果——3、4位数码管计数增加2,2位数码管熄灭,1位数码管显示按键编号;单击效果——1、2数码管显示按键编号,3、4位数码管计数增加1。
单片机经典长短按程序
新型的按键扫描程序不过我在网上游逛了很久,也看过不少源程序了,没有发现这种按键处理办法的踪迹,所以,我将他共享出来,和广大同僚们共勉。
我非常坚信这种按键处理办法的便捷和高效,你可以移植到任何一种嵌入式处理器上面,因为C语言强大的可移植性。
同时,这里面用到了一些分层的思想,在单片机当中也是相当有用的,也是本文的另外一个重点。
对于老鸟,我建议直接看那两个表达式,然后自己想想就会懂的了,也不需要听我后面的自吹自擂了,我可没有班门弄斧的意思,hoho~~但是对于新手,我建议将全文看完。
因为这是实际项目中总结出来的经验,学校里面学不到的东西。
以下假设你懂C语言,因为纯粹的C语言描述,所以和处理器平台无关,你可以在MCS-51,AVR,PIC,甚至是ARM平台上面测试这个程序性能。
当然,我自己也是在多个项目用过,效果非常好的。
好了,工程人员的习惯,废话就应该少说,开始吧。
以下我以AVR的MEGA8作为平台讲解,没有其它原因,因为我手头上只有AVR的板子而已没有51的。
用51也可以,只是芯片初始化部分不同,还有寄存器名字不同而已。
核心算法:unsigned char Trg;unsigned char Cont;void KeyRead( void ){unsigned char ReadData = PINB^0xff; // 1Trg = ReadData & (ReadData ^ Cont); // 2Cont = ReadData; // 3}完了。
有没有一种不可思议的感觉?当然,没有想懂之前会那样,想懂之后就会惊叹于这算法的精妙!!下面是程序解释:Trg(triger)代表的是触发,Cont(continue)代表的是连续按下。
1:读PORTB的端口数据,取反,然后送到ReadData 临时变量里面保存起来。
2:算法1,用来计算触发变量的。
一个位与操作,一个异或操作,我想学过C 语言都应该懂吧?Trg为全局变量,其它程序可以直接引用。
单片机按键 长按 短按
switch(key_num){
case 1:key_ret = 5;break;
case 2:key_ret = 6;break;
case 3:key_ret = 7;break;
case 4:key_ret = 8;break;
}
}
else{/*短按有效*/
}
ห้องสมุดไป่ตู้}
}
return key_ret;
}
if(key_flag){/*松手*/
key_flag = 0;
switch(key_num){
case 1:key_ret = 1;break;
case 2:key_ret = 2;break;
case 3:key_ret = 3;break;
case 4:key_ret = 4;break;
static bit key_flag = 0;
if((!SET)||(!KUP)||(!KDN)||(!KOK)){/*判断是否有键按下*/
if(++del_count==5){/*计数消抖*/
del_count = 0;
if(++tim_count>4){/*长按识别*/
key_flag = 0;/*短按无效*/
key_flag = 1;/*短按标志位*/
if(!SET)key_num = 1;/*一下用于识别按键*/
if(!KUP)key_num = 2;
if(!KDN)key_num = 3;
if(!KOK)key_num = 4;
51单片机-独立按键
查询方式
单片机不断的扫描键盘判断按键是否动作 特点:硬件简单,但需要单片出中断请求,单片机响应中断请求后转按键 识别程序
特点:硬件复杂,需要中断电路,但不占用CPU资源
单片机处理按键的流程
单片机处理按键动作需要以下步骤:
按键识别
单片机在识别按键时,IO口工作在输入状态:
按键弹起,IO口电平5V
Vcc
按键按下,IO口电平0V
单片机读取IO口的状态
即可知按键的状态
单片机
按键抖动
实际的按键在被按下或抬起时,由于机械 触点的弹性作用,在闭合或断开的瞬间均伴随有 一连串的抖动现象。
理想波形
实际波形
按下抖动
稳定闭合
释放抖动
完整的按键过程包括: 1. 释放状态 2. 按下抖动阶段 3. 完全按下状态 4. 释放抖动阶段 5. 释放状态
按键防抖
防抖措施:
硬件防抖
在按键输出端加RS或施密特触发器 去抖效果好、电路复杂、成本高
软件防抖
利用软件进行延时(10ms) 电路简单、成本低、但占用CPU时间
键盘的工作方式
判断按键是否按下 按键按下时的防抖 识别哪个按键按下,判断键值 判断按键是否放开 送出键值,处理按键动作
练习:单片机按键查询操作,8个按键对应8个LED灯, K1对应D1,K2对应D2,K3对应D3,……,查询按键, 按下某一个按键后对应的LED亮起,再按一次关闭。
8051按键处理程序:单击、长按、连击、组合
最近参考大神的按键处理程序,写了下面这个程序,希望大家指点一下硬件为8051,采用8255扩展接口,功能上,实现单击K1、K2、K3分别使时、分、秒递增;长按K1、K2、K3分别使时、分、秒递减;K1、K2、K3连击使第二个横杠处变为0;组合键K1、K2使第一个横杠处变为0,组合键K2、K3使第一个横杠处变为横杠;组合键K1、K3使第二个横杠处变为横杠。
下图为proteus仿真电路完整程序如下://-----------------------------------------------------------------// 8255实现接口扩展//-----------------------------------------------------------------// PA、PB为输出分别控制段码和位码,PC为输入////-----------------------------------------------------------------#include <reg51.h>#include <absacc.h>#define INT8U unsigned char#define INT16U unsigned int//8255 PA、PB、PC的端口和命令端口定义#define PA XBYTE[0x0000]#define PB XBYTE[0x0001]#define PC XBYTE[0x0002]#define COM XBYTE[0x0003]//上述定义可以这么写//#define PA *(XBYTE + 0x0000)//#define PB *(XBYTE + 0x0001)//#define PC *(XBYTE + 0x0002)//#define COM *(XBYTE + 0x0003)//根据硬件定义按键值#define KEY_V ALUE_1 0x0e#define KEY_V ALUE_2 0x0d#define KEY_V ALUE_3 0x0b#define KEY_NULL 0x0f//按键状态标志#define N_KEY 0x80#define S_KEY 0x40#define D_KEY 0x20#define L_KEY 0x10//状态机状态#define KEY_STATE_INIT 0 //初始状态#define KEY_STATE_WOBBLE 1 //电平抖动状态#define KEY_STATE_PRESS 2 //按键按下状态#define KEY_STATE_CONTINUE 3 //连击状态#define KEY_STATE_LONG 4 //长按状态#define KEY_STATE_RELEASE 5 //释放按键状态INT8U key_JL; //存储单击按键值code INT8U SEG_CODE[] ={ 0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xBF }; //共阳数码管编码,最后一位为横杠//初始显示的数字12-39-59INT8U Disp_Buf[] = {1,2,10,3,9,10,5,9};//-----------------------------------------------------------------// 8255端口按键处理//-----------------------------------------------------------------//按键底层处理,这里只识别单击和长按static INT8U Key_driver(){static INT8U key_time=0,key_state=KEY_STATE_INIT;INT8U key_temp,key_return=N_KEY;key_temp=PC&0x0f;switch(key_state){case KEY_STA TE_INIT:if(key_temp!=KEY_NULL) key_state=KEY_STATE_PRESS;break;// caseKEY_STA TE_WOBBLE://按键消抖处理,由于是仿真,为了加快按键灵敏度,减短延时时间// key_state=KEY_STA TE_PRESS;break;case KEY_STA TE_PRESS: //按键下,此处不返回值if(key_temp!=KEY_NULL) {key_state=KEY_STA TE_LONG; key_JL=key_temp;}else key_state=KEY_STA TE_INIT;break;case KEY_STA TE_LONG:if(key_temp==KEY_NULL) //单击确认{key_return=S_KEY|key_JL;key_state=KEY_STATE_INIT;}else if(++key_time>=100) //长按等待1s{key_return=L_KEY|key_temp; //返回长按值key_time=0;// key_state=KEY_STATE_RELEASE;key_state=KEY_STATE_INIT;}break;// case KEY_STA TE_RELEASE ://此处如果加上这段程序,长按不会不断递减// if(key_temp==KEY_NULL) key_state=KEY_STA TE_INIT;// break;}return key_return;}//按键处理中层按键判定单击、双击static INT8U Key_Read(){static INT8U key_time_1=0,key_m=KEY_STA TE_INIT;INT8U key_return=N_KEY,key_temp;key_temp=Key_driver();switch(key_m){case KEY_STA TE_INIT:if(key_temp&S_KEY){key_time_1=0;key_m=KEY_STA TE_CONTINUE;}elsekey_return=key_temp;break;case KEY_STA TE_CONTINUE:if(key_temp&S_KEY){key_return=key_temp|D_KEY;key_m=KEY_STATE_INIT;}else{if(++key_time_1>=30){key_return=key_JL|S_KEY;key_time_1=0;key_m=KEY_STA TE_INIT;}}break;}return key_return;}//按键处理顶层static void Key_Process(){INT8U key_temp;INT8U shi,fen,miao;key_temp=Key_Read();switch(key_temp){case 0x4e:shi=Disp_Buf[0]*10+Disp_Buf[1];shi++;if(shi==24) shi=0;Disp_Buf[0]=shi/10;Disp_Buf[1]=shi%10;break;case 0x1e:shi=Disp_Buf[0]*10+Disp_Buf[1];shi--;if(shi==255) shi=23;Disp_Buf[0]=shi/10;Disp_Buf[1]=shi%10;break;case 0x6e:Disp_Buf[5]=0x00; break;case 0x4d:fen=Disp_Buf[3]*10+Disp_Buf[4];fen++;if(fen==60) fen=0;Disp_Buf[3]=fen/10;Disp_Buf[4]=fen%10;break;case 0x1d:fen=Disp_Buf[3]*10+Disp_Buf[4];fen--;if(fen==255) fen=59;Disp_Buf[3]=fen/10;Disp_Buf[4]=fen%10;break;case 0x6d:Disp_Buf[5]=0x00; break;case 0x4b:miao=Disp_Buf[6]*10+Disp_Buf[7];miao++;if(miao==60) miao=0;Disp_Buf[6]=miao/10;Disp_Buf[7]=miao%10;break;case 0x1b:miao=Disp_Buf[6]*10+Disp_Buf[7];miao--;if(miao==255) miao=59;Disp_Buf[6]=miao/10;Disp_Buf[7]=miao%10;break;case 0x6b:Disp_Buf[5]=0x00; break;case 0x1c:Disp_Buf[2]=0x00;break;case 0x1a:Disp_Buf[5]=10; break;case 0x19:Disp_Buf[2]=10; break;default: break;}}INT8U time_scan=0;//-----------------------------------------------------------------// Ö÷³ÌÐò//-----------------------------------------------------------------void main(){INT8U i; //初始化定时中断TMOD=0x01; //定时器T0中断EA=1;ET0=1;TH0=(-1000)/256;TL0=(-1000)%256;TR0=1;COM=0x89; //初始化8255接口while(1){for(i=0;i<8;i++) //数码管显示{PA=0xff;PB=(1<<i);PA=SEG_CODE[Disp_Buf[i]];}if(time_scan==10) //每隔10ms进行一次扫描按键{Key_Process();time_scan=0;}}}//1ms定时中断void T0_time() interrupt 1{TH0=(65536-1000)/256;TL0=(65536-1000)%256;time_scan++;}。
单片机按键长短按得识别原理
单⽚机按键长短按得识别原理stm32f103按键长短按得识别原理需要⼀个定时器,⽤来计算按键按下的时间,可以⼀秒钟检测100次, 设置初始化为10ms的中断,⽐如使⽤定时4作为按键时间计算的定时器⽐如我们需要4种模式,轻触,短按,长按,超级长按#define clickTypeTouch 1 //轻触#define clickTypeShort 2 //短按#define clickTypeLong 3 //长按#define clickTypeVeryLong 4 //⾮常长的长按#define timeCntClickTouch 500 //ms内为短按#define timeCntClickShort 1000 //ms内为短按#define timeCntClickLong 2000//ms内,且⼤于短按时间为长按#define timeCntClickVeryLong 5000//ms的按键时间为⾮常长,⽤于进⼊⾼级模式//这⾥时钟选择为APB1的2倍,⽽APB1为36M//arr:⾃动重装值。
//psc:时钟预分频数//这⾥使⽤的是定时器7void TIM4_Init(u16 arr,u16 psc){TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //时钟使能TIM_TimeBaseStructure.TIM_Period = arr; //设置在下⼀个更新事件装⼊活动的⾃动重装载寄存器周期的值TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置⽤来作为TIMx时钟频率除数的预分频值 10Khz的计数频率TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位TIM_ITConfig( //使能或者失能指定的TIM中断TIM4,TIM_IT_Update ,ENABLE //使能);NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; //TIM中断NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器TIM_Cmd(TIM4, ENABLE); //使能TIMx外设}定时器的初始化然后设置⼀个变量⽤来累计按键按下的时间,没按键按下的时候, ⼀直循环累计时间,从0到溢出,有按键按下的时候,⽴即清空,重新开始累计⾸先初始化按键端⼝void keyIOInit(void){GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PAGPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11; //LED0-->PA.8 端⼝配置GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //推挽输出GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA}u16 timeKeyPressed; //按键按下的时间 10ms 步进设置两个常量,⽤来区别按键的状态,是按下还是释放#define keyStatusPressed 0#define keyStatusReleased 1定时器的中断,累计时间void TIM4_IRQHandler(void) //中断{if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) //检查指定的TIM中断发⽣与否:TIM 中断源 {TIM_ClearITPendingBit(TIM4, TIM_IT_Update ); //清除TIMx的中断待处理位:TIM 中断源timeKeyPressed+=10; //10ms的中断}}这个键,我叫做设置键,什么时候开始给设置键开始计算按下时间呢?设置键被按下⽽且按键状态还是释放需要⼏个常量标志和⼏个变量u8 statusCntingKeyTime; //是否开始计算按键时间#define statusCnting 1#define statusNotCnting 0//设置键按下,且之前没开始计时的时候,开始计算按下时间if(keySet==keyStatusPressed && statusCntingKeyTime==statusNotCnting ){timeKeyPressed=0; //设置键按下后,重新开始计时statusCntingKeyTime=statusCnting;//开始计算按下时间}当按键松开后,统计⼀下,按下的时间为多长//松⼿后统计按下时间if(keySet==keyStatusReleased && statusCntingKeyTime==statusCnting){statusCntingKeyTime=statusNotCnting;//停⽌计时//轻触if(timeKeyPressed<=timeCntClickTouch ){}//短按else if(timeKeyPressed>=timeCntClickShort &&timeKeyPressed<timeCntClickLong ){}//长按else if(timeKeyPressed>=timeCntClickLong &&timeKeyPressed<timeCntClickVeryLong){}//超级长按else if(timeKeyPressed>=timeCntClickVeryLong){}}。
6.2.2 独立式按键的程序设计_快速学通51单片机C语言程序设计_[共2页]
第6章 键盘接口设计129║图6.1 按键抖动波形图6.2 防抖动电路6.2 独立式按键的应用设计本节主要讲述独立式按键的特点、工作原理及接口的设计。
6.2.1 独立式按键的工作原理及特点独立式按键的特点是结构简单,体积小、造价低。
它将数字的输入功能和选择确认功能都集于一键之上,因此独具特色。
在工作原理上,独立式按键采用“分时复用”的处理方法,即按触键时间的长短来划分操作的性质,通常使用短按来输入数据,用长按来确定操作的性质。
在数据输入时,它以计数的方式来进行加1计数,根据进制的不同,滚动计数的限制也不同。
当长按时,表示以短按的计数值作为输入值。
由于输入的数据不只一位,因此长按操作也起着更换数据位的作用。
一旦完成了各位数据的设置,长按就成为了结束输入的确认键。
将按键的一端与单片机的I/O口相连,另一端接地即可构成独立式按键。
6.2.2 独立式按键的程序设计使用P1.0与按键S构成一个独立式按键,按其工作原理,设计一个参数控制程序,通过该按键接口与显示电路等配合可实现一个计数控制装置。
下面是一个4位十进数的设置程序,其参数存储在40H~43H单元中。
#include<reg51.h>#include<intrins.h>#include<absacc.h>#define uchar unsigned charsbitS1=P1^0; //按键入口int n;uchar n1,n2,n3,n4,i;ucharsetf=1; //数据位标识void delay20ms(void);void set_n(void);。