按键处理程序 C语言 单片机

合集下载

自己写的按键单片机程序

自己写的按键单片机程序

自己写的按键单片机程序用4个按键来控制数码管显示的内容#include#define duan P0//段选#define wei P2//位选unsigned char code wei1[8] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//位选控制查表的方法控制unsigned char code duan1[17] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0 x71};//0、1、2、3、4、5、6、7、8、9、A、b、C、d、E、F的显示码unsigned char ge,shi,bai,a,b;sbit key1=P1;sbit key2=P1 ;sbit key3=P1 ;sbit key4=P1 ;void keys();//按键函数void s(unsigned char xms);//延时函数void DigDisplay(); //动态显示函数void init(); //初始化函数void main(void){init(); while(1){DigDisplay();keys();} }void DigDisplay(){unsigned char i;unsigned int j;bai=a/100;shi=a%100/10;ge=a%10;i=0;wei = wei1[i];//发送位选duan = duan1[bai]; //发送段码j = 10;//扫描间隔时间设定while(j--);duan = 0x00; //消隐i++;wei = wei1[i];//发送位选duan = duan1[shi]; //发送段码j = 10;//扫描间隔时间设定while(j--);duan = 0x00; //消隐i++;wei = wei1[i];//发送位选duan = duan1[ge]; //发送段码j = 10;//扫描间隔时间设定while(j--);duan = 0x00; //消隐}void init() {key1=1;key2=1;key3=1;key4=1;TMOD=0X01;TH0=(65536-45872)/256;TL0=(65536-45872)%256;EA=1;ET0=1;}void s(unsigned char xms){unsigned char x,y;for(x=xms;x>0;x--)for(y=110;y>0;y--);}void times() interrupt 1{TH0=(65536-45872)/256;TL0=(65536-45872)%256;b++;if(b==20){b=0;a++;if(a==256){a=0;}}}voidkeys(){if(key1==0){s(10);if(key1==0){a++;TR0=0;if(a==256)a=0;while(!key1)Dig Display();}}if(key2==0){s(10);if(key2==0){TR0=0;if(a==0)a=256;a--。

从单片机初学者迈向单片机工程师----按键处理

从单片机初学者迈向单片机工程师----按键处理

从单片机初学者迈向单片机工程师----按键处理2009-11-24 11:25前些日子把自己以前下载的一些按键的资料好好看了下。

发现万变不离其中。

无非就是把以前延时消抖动改变为对按键进行计数,或者是状态的变化的判断。

这样的好处不言而喻,释放了MCU,能够有更多时间去处理其它任务。

而单片机初学者最容易犯的错误就是在这里。

按键按下?----> YES ----> 延时20MS ----> 按键按下?----> YES ----> 返回键值| N O | NO| |退出退出这是一个比较经典的处理模式,为什么这样说呢,因为大部分的单片机教材上面都是这样写的。

以至于很多初学者以为按键处理就是这个模式。

不得不说,现在的单片机教材优秀的太少,大部分都是抄来抄去。

最终受害的还是我们学习者。

可能要很久以后才会发现,原来自己走了这么长的时间的弯路。

下面贴一个很久以前在网上收集到的按键处理的资料。

理解了其中的精髓就会一通百通。

状态机是一个有向图形,由一组节点和一组相应的转移函数组成。

状态机通过响应一系列事件而“运行”。

每个事件都在属于“当前”节点的转移函数的控制范围内,其中函数的范围是节点的一个子集。

函数返回“下一个”(也许是同一个)节点。

这些节点中至少有一个必须是终态。

当到达终态,状态机停止。

这一段抽象的数学定义,或许会晕倒一片人,但是我们能不能换一个说法来更好的理解状态机呢,学习方法中,我最推崇“类比", 因为天地一大宇宙,人身一小宇宙,天地间一切可类比。

就像电流与水流,电学与力学一样。

在此表弟我不才,也想对状态机类比一下。

其实在我看来,有限状态机就是一个人的悲喜剧,生命不息,状态不止。

在父母面前,他是一个好的儿子,他所做的事就是孝敬父母,在妻子面前他是一个好丈夫,呵护着自己的老婆,支撑着这个家,在儿女面前,他是一个好爸爸淳淳教导着自己的子女,在老板面前,他是一个好职员,他所做的是为公司的明天而打拼. 如此环环不息,直至生命的终结,没有人是不死的,状态机也一样(在此不考虑无限状态机). 此类比中的"好儿子“,"好丈夫","好爸爸" 就是一个人的不同的自我,在扮演着不同的角色,演绎着不同的故事,可以称之为“状态”,而“孝敬父母”“呵护老婆”“教导子女”则是在不同状态下的行为。

单片机按键程序(汇编)

单片机按键程序(汇编)

;P0.0为键盘,P2.0为LED指示,按下LED亮,再按0.5秒,LED灭;00h为识别LED状态的标志位,当00H为1时LED亮,当00H为0时,LED灭。

初始化00H为0LED_OFF BIT P2.0K0 BIT P0.0LED_STATE EQU 00HORG 0000HSJMP MAINORG 0030HMAIN: CLR LED_STA TE ;清标志位START:JNB K0,LOOPSJMP START ;判断K0状态,若KO不为0,则继续检测K0状态,若k0为0,则跳到loopLOOP:CLR LED_OFFSETB LED_STATE ;点亮LED以及置标志位,CHECK1:LCALL DELAYJNB K0,CHECK1 ;若开关未弹起,则一直循环,直至开关弹起。

CHECK_LED_ON:LCALL DELAYJB K0,CHECK_LED_ON ;检查开关是否被按下,若未被按下则一直循环,若被按下,则判断标志位MOV C,LED_STATEJC CHECK_LED_OFF ;若标志位为1,则跳转到CHECK_LED_OFFCLR LED_OFFSETB LED_STATE ;若标志位为0,则点亮LED,同时置标志位为1CHECK2:LCALL DELAYJNB K0,CHECK2 ;检查开关是否被弹起,一直循环JMP CHECK_LED_ON ;开关弹起后,跳到CHECK_LED_ON,检查开关是否被按下CHECK_LED_OFF:JB K0,CHECK_LED_ONLCALL DELAYJB K0,CHECK_LED_ONLCALL DELAYJB K0,CHECK_LED_ONLCALL DELAYJB K0,CHECK_LED_ONLCALL DELAYJB K0,CHECK_LED_ONLCALL DELAYJB K0,CHECK_LED_ONLCALL DELAYJB K0,CHECK_LED_ON ;检查开关是否被按下0.5s,若中途弹起则跳转到CHECK_LED_ON。

单片机按键程序设计

单片机按键程序设计

单片机按键程序设计单片机按键的基本原理其实并不复杂。

通常,按键就是一个简单的开关,当按键按下时,电路接通,对应的引脚电平发生变化;当按键松开时,电路断开,引脚电平恢复到初始状态。

在程序设计中,我们需要不断检测引脚的电平变化,从而判断按键是否被按下。

在实际的按键程序设计中,有多种方式可以实现按键检测。

其中一种常见的方法是查询法。

这种方法是通过不断地读取按键对应的引脚状态来判断按键是否被按下。

以下是一个简单的查询法示例代码:```cinclude <reg51h> //包含 51 单片机的头文件sbit key = P1^0; //定义按键连接的引脚void main(){while(1) //无限循环{if(key == 0) //如果按键按下,引脚为低电平{//执行按键按下的操作//比如点亮一个 LED 灯P2 = 0xfe;while(key == 0);//等待按键松开}}}```上述代码中,我们首先定义了按键连接的引脚`key`,然后在主函数的无限循环中不断检测按键引脚的状态。

当检测到按键按下时,执行相应的操作,并通过`while(key == 0)`等待按键松开。

除了查询法,还有中断法可以用于按键检测。

中断法的优点是能够及时响应按键动作,不会因为程序的其他操作而导致按键响应延迟。

```cinclude <reg51h> //包含 51 单片机的头文件sbit key = P1^0; //定义按键连接的引脚void int0_init()//中断初始化函数{IT0 = 1; //下降沿触发中断EX0 = 1; //使能外部中断 0EA = 1; //开总中断}void int0() interrupt 0 //外部中断 0 服务函数{//执行按键按下的操作//比如点亮一个 LED 灯P2 = 0xfe;}void main(){int0_init();//初始化中断while(1);//无限循环,保持程序运行}```在上述代码中,我们首先在`int0_init` 函数中对中断进行了初始化设置,然后在`int0` 函数中编写了按键按下时的处理代码。

我的51单片机之 按键 的 C语言与汇编的编程

我的51单片机之 按键 的 C语言与汇编的编程
void main() {
P1=0xFF; P3=0xFF; while(1) {
if(KINT0==0) {
LD1=0; } if(KINT1==0) {
LD2=0; } if(KT0==0) {
LD3=0; } if(KT1==0) {
LD4=0; } if(KA2==0) {
LD5=0;
} if(KA1==0) {
KINT0 EQU P3.2; KINT1 EQU P3.3; KT0 EQU P3.4; KT1 EQU P3.5; KA2 EQU P3.6; KA1 EQU P3.7; LD1 EQU P1.0; LD2 EQU P1.1; LD3 EQU P1.2; LD4 EQU P1.3; LD5 EQU P1.4; LD6 EQU P1.5;
LD6=0; } } }
四、独立按键汇编程序: ;**************************************************************** ;每个独立铵键用一只指示灯指示;按复位键可熄灭,made by luqichao ;**************************************************************** ORG 0000H AJMP MAIN ORG 0030H
//字形码:0--f 及小数点
unsigned char code AscLed[10]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};
//
{ 0 , 1, 2 , 3 , 4 , 5, 6, 7, 8, 9 }
void main() {
start: LED2=0; //亮数码管 P3=0xFF; KH1=0; if(KL1==0){LEDCODE=AscLed[1];goto start;};//k1 if(KL2==0){LEDCODE=AscLed[2];goto start;};//k2 if(KL3==0){LEDCODE=AscLed[5];goto start;};//k5 KH2=0; if(KL1==0){LEDCODE=AscLed[3];goto start;};//k3 if(KL2==0){LEDCODE=AscLed[4];goto start;};//k4 if(KL3==0){LEDCODE=AscLed[6];goto start;};//k6 KH3=0; if(KL1==0){LEDCODE=AscLed[7];goto start;};//k7 if(KL2==0){LEDCODE=AscLed[8];goto start;};//k8 if(KL3==0){LEDCODE=AscLed[9];goto start;};//k9

按键处理程序C语言单片机

按键处理程序C语言单片机

按键处理程序C语言单片机分享一种按键处理程序(用C)//头文件定义:Ustruct KEY{Uchar Val;#define Key_Model_C 0 //按键1值#define Key_AddVal_C 1 //按键2值Uint ScanOnTime;Uchar LongKeyState;Uchar LongKeyRestState;Uchar SetInRn;Uchar Model; //按键状态(模式)#define Off_C 0 //之前未按下#define On_C 1 //现按下#define Delay_C 2 //按键处理后标志}Key;//----------------定义两个IO输入口为按键入口--------------------//#define KeyMo_Bin (GPIOB->IDR.Bit.B5)#define KeyAdd_Bin (GPIOB->IDR.Bit.B6)/*===================================== ==========================*/GPIO_Init(GPIO_Pin_5|GPIO_Pin_6,GPIO_Mode_In_PU_No_IT); //初始化为上拉输入无中断/*===================================== ==========================*///主程序大循环中每1毫秒扫描1次void KeyScan(void){if(Key.LongKeyRestState == 1) //长按键标志(复位处理长按键){if((KeyMo_Bin == 1) && (KeyAdd_Bin == 1)) //当两按键均抬起{if(++Key.ScanOnTime >= 130) //延时后复位{Key.LongKeyRestState=0;Key.Model=Delay_C;}}elseKey.ScanOnTime=0;return;}if(Key.Model == Off_C) //如果当前按键状态为未按下“Off_C”{if((KeyMo_Bin == 0) || (KeyAdd_Bin == 0))//按键1或按键2已按下(低有效){if(++Key.ScanOnTime >= 10) //当按下后自加1,加够10次即1ms*10=10ms去抖动{Key.ScanOnTime=0;if(KeyMo_Bin == 0) //如果按键1为0即按下{Key.Val=Key_Model_C; //付当键1值(看头文件定义)Key.Model=On_C; //置按键已按下标志}else if(KeyAdd_Bin == 0) //如果按键2为0即按下{Key.Val=Key_AddVal_C; //付当键2值(看头文件定义)Key.Model=On_C; //置按键已按下标志}BellOn(200); //蜂鸣器响}}elseKey.ScanOnTime=0; //清去抖延时计数值}else if(Key.Model == Delay_C) //如果当前按键状态为已按下且已处理“Delay_C”{if((KeyMo_Bin == 1) && (KeyAdd_Bin == 1))//如果两按键均抬起{if(++Key.ScanOnTime >= 100) //延时100ms后复位按键状态为“Off_C”{Key.SetInRn=0;Key.ScanOnTime=0;Key.Model=Off_C;}}else //如果按键没有被抬起,对应上面if{if(++Key.ScanOnTime >= 1000) //延时1000ms后再复位按键状态为“Off_C”(为长按处理){Key.ScanOnTime=0;Key.Model=Off_C;}}}}//===================================== ========================================= ========void LoadCheckKeyRest(void){Key.LongKeyRestState=1;Key.ScanOnTime=0;}//===================================== ========================================= ========//处理相应按键(可250ms才调用一次)长按if(Key.Model == On_C) //按键状态为已按下{if(Key.Val == Key_Model_C) //是键1按下(看头文件定义){if(++Key.SetInRn >= 3) //连计3次数3秒后为长按键(对应上面,如果按下未抬起的话会延时1000ms){Key.SetInRn=0;LoadCheckKeyRest(); //调清长按处理BellOn(600); //蜂鸣器响//-----------长按需处理的内容-----下-----------//WorkStateBit.Bit.SettingMo=1;SetOverTime=0;SetMoRn=0;SetBak[0]=Rtc_InitDate.RTC_Year;SetBak[1]=Rtc_InitDate.RTC_Month;SetBak[2]=Rtc_InitDate.RTC_Date;SetBak[3]=Rtc_InitDate.RTC_WeekDay;SetBak[4]=Rtc_InitTime.RTC_Hours;SetBak[5]=Rtc_InitTime.RTC_Minutes;//-----------长按需处理的内容------上----------//Key.Model=Delay_C; //置按键模式为:已处理按键(看头文件定义)return;}}elseKey.SetInRn=0;Key.Model=Delay_C;}。

单片机c语言程序设计---矩阵式键盘实验报告

单片机c语言程序设计---矩阵式键盘实验报告

单片机c语言程序设计---矩阵式键盘实验报告课程名称:单片机c语言设计实验类型:设计型实验实验项目名称:矩阵式键盘实验一、实验目的和要求1.掌握矩阵式键盘结构2.掌握矩阵式键盘工作原理3.掌握矩阵式键盘的两种常用编程方法,即扫描法和反转法二、实验内容和原理实验1.矩阵式键盘实验功能:用数码管显示4*4矩阵式键盘的按键值,当K1按下后,数码管显示数字0,当K2按下后,显示为1,以此类推,当按下K16,显示F。

(1)硬件设计电路原理图如下仿真所需元器件(2)proteus仿真通过Keil编译后,利用protues软件进行仿真。

在protues ISIS 编译环境中绘制仿真电路图,将编译好的“xxx.hex”文件加入AT89C51。

启动仿真,观察仿真结果。

操作方完成矩阵式键盘实验。

具体包括绘制仿真电路图、编写c源程序(反转法和扫描法)、进行仿真并观察仿真结果,需要保存原理图截图,保存c源程序,总结观察的仿真结果。

完成思考题。

三、实验方法与实验步骤1.按照硬件设计在protues上按照所给硬件设计绘制电路图。

2.在keil上进行编译后生成“xxx.hex”文件。

3.编译好的“xxx.hex”文件加入AT89C51。

启动仿真,观察仿真结果。

四、实验结果与分析void Scan_line()//扫描行{Delay(10);//消抖switch ( P1 ){case 0x0e: i=1;break;case 0x0d: i=2;break;case 0x0b: i=3;break;case 0x07: i=4;break;default: i=0;//未按下break;}}void Scan_list()//扫描列{Delay(10);//消抖switch ( P1 ){case 0x70: j=1;break;case 0xb0: j=2;break;case 0xd0: j=3;break;case 0xe0: j=4;break;default: j=0;//未按下break;}}void Show_Key(){if( i != 0 && j != 0 ) P0=table[ ( i - 1 ) * 4 + j - 1 ];else P0=0xff;}五、讨论和心得。

极其简单好用的按键扫描程序C语言

极其简单好用的按键扫描程序C语言

极其简单好用的按键扫描程序(C语言)不过我在网上游逛了很久,也看过不少源程序了,没有发现这种按键处理办法的踪迹,所以,我将他共享出来,和广大同僚们共勉。

我非常坚信这种按键处理办法的便捷和高效,你可以移植到任何一种嵌入式处理器上面,因为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为全局变量,其它程序可以直接引用。

单片机按键LEDC语言程序

单片机按键LEDC语言程序
}
void main()
{
P2=0xff;
while(1)
{
uchar key;
key=keyscan();
switch(key)
{
case 0:P2=LED_VAL[0];break;
case 1:P2=LED_VAL[1];break;
case 2:P2=LED_VAL[2];break;
case 3:P2=LED_VAL[3];break;
uchar keyscan(void)
{
uchar i,j,k,h2,key_s=0;
P3=0xf0;
if(P3!=0xf0)
{
delay_ms(10);
if(P3!=0xf0)
{
j=0xfe;
for(i=0;i<4;i++)
{
P3=j;
k=(P3&0xf0);
switch(k)
{
case 0xe0: h2=0*4+i;key_s++;break;
P2=led_point[i];
Delay_ms(5);
P1=0XFF;
P2=0XFF;
}
}
//////////// /////////////////////////
void Delay_ms(uint delay)
{
uchar j;
while(delay--)
{
for(j=125;j>0;j--)
case 4:P2=LED_VAL[4];break;
case 5:P2=LED_VAL[5];break;
case 6:P2=LED_VAL[6];break;

单片机经典长短按程序

单片机经典长短按程序

新型的按键扫描程序不过我在网上游逛了很久,也看过不少源程序了,没有发现这种按键处理办法的踪迹,所以,我将他共享出来,和广大同僚们共勉。

我非常坚信这种按键处理办法的便捷和高效,你可以移植到任何一种嵌入式处理器上面,因为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为全局变量,其它程序可以直接引用。

按键程序

按键程序
我用C51做的键盘程序,望大家批砖
作者:hexiaoxiao栏目:单片机
我用C51做的键盘程序,望大家批砖
该程序没有被仿真过,可能有一些错误.不过编译是;intrins.h>
#include<reg51.h>
#define uCHAR unsigned CHAR
if(state!=0x0F) //&Oacute;&ETH;&frac14;ü°&acute;&Iuml;&Acirc;
{
SWITCH(state)
{
case 0x0E:
key=(0x4-i)*0x4+0x1;
break;
case 0x0D:
key=(0x4-i)*0x4+0x2;
break;
case 0x0B:
{
delayms();
if((P0&0x0f)!=0x0f) //确认有键按下
{
for(i=0;i<4;i++) //扫描4行
{
P0=m; //从P0.4=0(第一行)开始扫描
if(KEY_A==0) //列1有效
{
h=h+1; //算出列1键盘值
flag0=1;
while(KEY_A==0) //等待按键松开
11楼:>>参与讨论
作者:fushaobing于2005-4-15 17:32:00发布:
--------------------------------------------------------------------------------
TO xwj:
你的意思是不是这样:把键盘扫描放在定时中断子程序中(定时周期约10ms),可以用两次中断的时间间隔来去抖动,可以引入“键龄”的概念来实现连击的处理(在中断中使键龄减1)。例如,如果设“键龄=25”,则每25*10=250ms操作一次按键。

单片机按键处理技巧及C语言编程方式

单片机按键处理技巧及C语言编程方式

单片机按键处理技巧及编程方式在基于单片机为核心构成的应用系统中,用户输入是必不可少的一部分。

输入可以分很多种情况,譬如有的系统支持PS2键盘的接口,有的系统输入是基于编码器,有的系统输入是基于串口或者USB或者其它输入通道等等。

在各种输入途径中,更常见的是,基于单个按键或者由单个键盘按照一定排列构成的矩阵键盘(行列键盘)。

我们这一篇章主要讨论的对象就是基于单个按键的程序设计,以及矩阵键盘的程序编写。

按键检测的原理: 它们和我们的单片机系统的I/O口连接一般如下:对于单片机I/O内部有上拉电阻的微控制器而言,还可以省掉外部的那个上拉电阻。

简单分析一下按键检测的原理。

当按键没有按下的时候,单片机I/O通过上拉电阻R接到VCC,我们在程序中读取该I/O的电平的时候,其值为1(高电平); 当按键S按下的时候,该I/O被短接到GND,在程序中读取该I/O的电平的时候,其值为0(低电平) 。

这样,按键的按下与否,就和与该按键相连的I/O的电平的变化相对应起来。

结论:我们在程序中通过检测到该I/O 口电平的变化与否,即可以知道按键是否被按下,从而做出相应的响应。

一切看起来很美好,是这样的吗?在我们通过上面的按键检测原理得出上述的结论的时候,那就是现实中按键按下时候的电平变化状态。

我们的结论是基于理想的情况得出来的,而实际中,由于按键的弹片接触的时候,并不是一接触就紧紧的闭合,它还存在一定的抖动,尽管这个时间非常的短暂,但是对于我们执行时间以us为计算单位的微控制器来说,它太漫长了。

因而,实际的波形图应该如下面这幅示意图一样。

这样便存在这样一个问题。

假设我们的系统有这样功能需求:在检测到按键按下的时候,将某个I/O的状态取反。

由于这种抖动的存在,使得我们的微控制器误以为是多次按键的按下,从而将某个I/O的状态不断取反,这并不是我们想要的效果,假如该I/O控制着系统中某个重要的执行的部件,那结果更不是我们所期待的。

单片机按键

单片机按键

在数字电路中,常利用触发器消除键盘抖动,但在单
片机系统中,按键可以直接接在单片机的I/O口上,常利用
键盘程序来消除键盘的抖动现象。
6.3 利用外部中断实现键盘输入
一、电路原理 在图6-3中,单片机的P0.0口接一只LED,键盘接在
P3.2端口,按键不按时,由于P3.2接有上拉电阻R3,所
以P3.2此时为高电平+5V,如果按键按下,P3.2电源地短
这里没有设置INT0是下降沿触发中断或是低电平触发
中断,原因是按键按下,不管产生不产生键抖现象,总能
使INT0引脚产生1个下降沿和低电平。如果设置只有下降 沿才触发INT0中断,需要利用设置计时器控制寄存器 TCON的IT0 = 1位,按键按下是否产生中断,可以利用程 序检测TCON的IE0位。利用外部中断触发作为按键输入很 好的解决了键盘抖动问题。
C1 30P C2 30P R1 1K
R2~9 200
AC a g d b c dot
a b c f d e f e g dot
9
RESET
SEVEN_SEG
C3 10 μ
29 30 31
PSEN ALE EA
VCC
1 2 3 4 5 6 7 8
P1.0 P1.1 P1.2 P1.3 P1.4 P1.5 P1.6 P1.7
如果需要多个键盘,把INT0口与I/O口之间用键盘连
接,I/O输出低电平扫面信号即可。在数码管动态显示电路
中,为了节省硬件资源,可以在INT0口和P2口之间接入 键盘,实现8只按键输入。
三、利用延时程序防止键盘抖动,实现键盘输入
按键按下产生的抖动现象持续的时间不会很久,因此
在按键按下后,可延时一段时间跳过抖动,再对按键的状 态检测,从而利用延时的方法也可以实现键盘输入。本案 例完通过两个键盘设计,实现对数码管显示数据的调整。

单片机键盘输入编程(C语言)

单片机键盘输入编程(C语言)

学习过单片机技术的人都知道,单片机的按键输入一般可分为简单的独立式按键输入及行列式键盘输入两种。

图1为简单的独立式键盘输入示意图,独立式键盘输入适合于按键输入不多的情况(<5个按键),具有占用口线较少、软件编写简单容易等特点。

图2为行列式键盘输入示意图,列线接P1.0~P1.3,行线接P1.4~P1.7。

行列式键盘输入适合于按键输入多的情况,如有16个按键输入,用简单按键输入用要占用2个输入口(共16位),而使用行列式键盘输入只需占用一个输入口(8位)。

但行列式键盘输入软件编写较复杂,对初学者而言有一定的难度。

以上略谈了一下按键输入的情况。

在很多状态下,按键输入的值要同时要在LED数码管上显示出来。

如一个按键设计为输入递增(加法)键,可以设计成每点按一下,数值递增加1,同时在LED数码管上显示出来;也可设计成持续按下时,数值以一定时间间隔(如0.3秒)累加。

但是当欲输入值较大时(如三位LED数码管作输入显示时的输入值最大为999),则可能按下键的时间太长(最长达300秒),看来这种方式只适用于一位或至多两位数值(最大99)的输入。

当然你也可多设几个键,每个键只负责一位数值的输入,但这样会占用较多的口线,浪费宝贵的硬件资源。

大家可能见到过,一些进口的温度控制器(如日本RKC INSTRUMENT INC. 生产的REX_C700温控器)的面板设计为:温度测量值用4位LED数码管显示,输入设定值显示也用4位LED数码管,输入按键只有4个,一个为“模式设定键”,一个为“左移键”,另两个为“加法键”、“减法键”。

欲输入设定值(温控值)时,按一下“模式设定键”,程序进入设定状态,此时输入设定值显示的4位LED数码管中,个位显示最亮(稳定显示),而十、百、千位显示较暗(有闪烁感),说明可对个位进行输入。

按下“加法键”或“减法键”,即可输入个位数的值;点按一下“左移键”,变为十位显示最亮,而个、百、千位显示较暗,说明可对十位进行输入。

单片机按键程序的编写

单片机按键程序的编写
就会认为已经按下,或者松开很多次了。 而事实上,我们的手一直按在按键上, 并没有重复按动很多次。要想能够正确 的判断按键是否按下就要避开这段抖动 的时间。根据一般按键的机械特点,以 及按键的新旧程度等而言,这段抖动的 时间一般在 5MS~20MS 之间。 看到这里你明白了该如何做了吧。
看看下面的这个流程图,你应该不 陌生吧。
if( KeyTime )
//定时扫描时间到
{
KeyValue = u8_ReadKey_f() ;
}
具体的工作就交给您去完成啦。
看看效果:
按键单击
连发时候的截图
至此,关于单个按键的学习就告一 段落了,您是否已经明白了。如果 您还不明白,那么把这个程序好好 的看看,并画下流程图,分析分析。 估计您就会恍然大悟。关键是思路 要转换过来。
//临时保存读到的键值
KeyTemp = P1 & 0x0f ;
//读键值
if( KeyTemp == 0x0f )
{
KeyCount = 0 ;
KeyOverTime = KEY_OVER_TIME ;
return NOKEY ;
//无键按下返回 NOKEY
}
else
{
if( KeyTemp == LastKey ) //是否第一次按下
再说就变成水帖了。那么我们开始吧。 按键的种类很多。不过原理基本相似。下面我们以一种轻触开关为例讲 解按键程序的写法。 这种轻触开关大家不陌生吧^_^
一般情况下,按键与单片机的连接如下面这幅图所示。
(图中电阻值一般去 4.7k~10k 之间,对于内部端口有上拉电阻的单片机则可省略此电阻) 单片机对于按键的按下与否则是通过检测相应引脚上的电平来实现的。对于上图而言,当 P17 引脚上面的电平为低时,则表示按键已经按下。反之,则表明按键没有按下。我们在程 序中只要检测到了 P17 引脚上面的电平为低了,就可以判断按键按下。呵呵,简单吧。等会, 您先别乐呵,话还没说完呢。下面我们来看看,当按键按下时,P17 引脚上面的波形是怎么 变化的。
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Uchar SetInRn;
Uchar Model; //按键状态(模式)
#defineOff_C0 //之前未按下
#defineOn_C1 //现按下
#defineDelay_C 2 //按键处理后标志
}Key;
//----------------定义两个IO输入口为按键入口--------------------//
SetBak[0]=Rtc_InitDate.RTC_Year;
SetBak[1]=Rtc_InitDate.RTC_Month;
SetBak[2]=Rtc_InitDate.RTC_Date;
SetBak[3]=Rtc_InitDate.RTC_WeekDay;
SetBak[4]=Rtc_InitTime.RTC_Hours;
}
SetBak[5]=Rtc_InitTime.RTC_Minutes;
//-----------长按需处理的内容------上----------//
Key.Model=Delay_C; //置按键模式为:已处理按键(看头文件定义)
return;
}
}
else
Key.SetInRn=0;
Key.Model=Delay_C;
//处理相应按键(可250ms才调用一次)长按
if(Key.Model == On_C) //按键状态为已按下
{
if(Key.Val == Key_Model_C) //是键1按下(看头文件定义)
{
if(++Key.SetInRn >= 3) //连计3次数3秒后为长按键(对应上面,如果按下未抬起的话会延时1000ms)
{
Key.ScanOnTime=0;
if(KeyMo_Bin == 0) //如果按键1为0即按下
{
Key.Val=Key_Model_C; //付当键1值(看头文件定义)
Key.Model=On_C; //置按键已按下标志
}
else if(KeyAdd_Bin == 0) //如果按键2为0即按下
分享一种按键处理程序(用C)
//头文件定义:
Ustruct KEY
{
Uchar Val;
#defineKey_Model_C0 //按键1值
#defineKey_AddVal_C 1 //按键2值
Uint ScanOnTime;
Uchar LongKeyState;
Uchar LongKeyRestState;
/*===============================================================*/
//主程序大循环中每1毫秒扫描1次
void KeyScan(void)
{
if(Key.LongKeyRestState == 1) //长按键标志(复位处理长按键)
{
void LoadCheckKeyRest(void)
{
Key.LongKeyRestState=1;
Key.ScanOnTime=0;
}
//======================================================================================
return;
}
if(Key.Model == Off_C) //如果当前按键状态为未按下“Off_C”
{
if((KeyMo_Bin == 0) || (KeyAdd_Bin == 0))//按键1或按键2已按下(低有效)
{
if(++Key.ScanOnTime >= 10) //当按下后自加1,加够10次即1ms*10=10ms去抖动
#define KeyMo_Bin(GPIOB->IDR.Bit.B5)
#define KeyAdd_Bin(GPIOB->IDR.Bit.B6)
/*===============================================================*/
GPIO_Init(GPIO_Pin_5|GPIO_Pin_6,GPIO_Mode_In_PU_No_IT); //初始化为上拉输入无中断
{
Key.SetInRn=0;
LoadCheckKeyRest(); //调清长按处理
BellOn(600); //蜂鸣器响
//-----------长按需处理的内容-----下-----------//
WorkStateBit.Bit.SettingMo=1;
SetOverTime=0;
SetMoRn=0;
if((KeyMo_Bin == 1) && (KeyAdd_Bin == 1)) //当两按键均抬起
{
if(++Key.ScanOnTime >= 130) //延时后复位
{
Key.LongKeyRestState=0;
Key.Model=Delay_C;
}
}
else
Key.ScanOnTime=0;
{
if((KeyMo_Bin == 1) && (KeyAdd_Bin == 1))//如果两按键均抬起
{
if(++Key.ScanOnTime >= 100) //延时100ms后复位按键状态为“Off_C”
{
Key.SetInRn=0;
Key.ScanOnTime=0;
Key.Model=Off_C;
}Байду номын сангаас
}
else //如果按键没有被抬起,对应上面if
{
if(++Key.ScanOnTime >= 1000) //延时1000ms后再复位按键状态为“Off_C”(为长按处理)
{
Key.ScanOnTime=0;
Key.Model=Off_C;
}
}
}
}
//======================================================================================
{
Key.Val=Key_AddVal_C; //付当键2值(看头文件定义)
Key.Model=On_C; //置按键已按下标志
}
BellOn(200); //蜂鸣器响
}
}
else
Key.ScanOnTime=0; //清去抖延时计数值
}
else if(Key.Model == Delay_C) //如果当前按键状态为已按下且已处理“Delay_C”
相关文档
最新文档