中断法键盘扫描c程序
- 格式:docx
- 大小:19.44 KB
- 文档页数:7
实验二按键中断实验一、实验目的了解中断的含义二、实验内容板子加电后,按动板子上K1-K3按键,可控制对应的LED1-LED3的亮灭,该实验学习了外部中断(EXTI)程序的编制及控制流程。
三、实验仪器、设备计算机、开发板、keil软件四、硬件设计在开发板上V6、V7、V8分别与MCU的PB5、PD6、PD3相连,如下图所示键盘部分如下图所示:例程所用到的列扫描线:PC5,PC2,PC3。
例程所用到的行扫描线(EXTI中断线):PE2。
五、实验要求和步骤开发板上有3个蓝色状态指示灯V6(LED1),V7(LED2),V8(LED3),通过对应的按键K1-K3,控制LED的亮灭,将PE2引脚配置为外部中断,当其上出现下降沿时产生一个中断,根据扫描PC5,PC2,PC3来判别是哪个按键按下。
首先我们了解一下什么是外部中断/事件控制器(EXTI)。
外部中断/事件控制器由19个产生事件/中断要求的边沿检测器组成。
每个输入线可以独立地配置输入类型(脉冲或挂起)和对应的触发事件(上升沿或下降沿或者双边沿都触发)。
每个输入线都可以被独立的屏蔽。
挂起寄存器保持着状态线的中断要求。
EXTI控制器的主要特性如下:每个中断/事件都有独立的触发和屏蔽每个中断线都有专用的状态位支持多达19 个中断/事件请求检测脉冲宽度低于APB2 时种宽度的外部信号如要产生中断,中断线必须事先配置好并被激活。
这是根据需要的边沿检测通过设置2个触发寄存器,和在中断屏蔽寄存器的相应位写“1”到来允许中断请求。
当需要的边沿在外部中断线上发生时,将产生一个中断请求,对应的挂起位也随之被置1。
通过写“1”到挂起寄存器,可以清除该中断请求。
为产生事件触发,事件连接线必须事先配置好并被激活。
这是根据需要的边沿检测通过设置2个触发寄存器,和在事件屏蔽寄存器的相应位写“1”到来允许事件请求。
当需要的边沿在事件连线上发生时,将产生一个事件请求脉冲,对应的挂起位不被置1。
单片机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语言进行实现。
在电子设备中,按键通常是一种开关,用于接通或断开电路。
按下按键时,电路闭合,产生一个信号,通过按键检测可以获取到这个信号,并进行相应的处理。
按键检测的原理算法如下:1. 初始化:首先需要对按键进行初始化设置,包括设置按键引脚的输入/输出状态和电平状态。
2. 检测按键状态:通过读取按键引脚的电平状态来检测按键的状态。
一般来说,按键引脚的电平为高电平(1)表示按键未按下,低电平(0)表示按键按下。
3. 延时:为了避免检测到按键的抖动(按键在按下和松开的瞬间会产生多次信号),可以在检测到按键状态改变后进行一个短暂的延时,一般为几毫秒。
4. 再次检测:在延时后,再次读取按键引脚的电平状态。
如果检测到的状态与之前不同,说明按键的状态发生了改变。
5. 处理按键事件:根据按键的状态改变来进行相应的处理,比如执行一段代码、发送一个信号等。
6. 循环检测:以上步骤需要放在一个循环中进行,以实现对按键状态的持续监测和响应。
下面是一个简单的按键检测的C语言示例代码:```c#include <stdio.h>#include <wiringPi.h>#define BUTTON_PIN 17int main(){if (wiringPiSetup() == -1) // 初始化wiringPi库{printf("wiringPi setup failed!\n");return -1;}pinMode(BUTTON_PIN, INPUT); // 设置按键引脚为输入模式int previousState = HIGH; // 初始状态为未按下while (1){int currentState = digitalRead(BUTTON_PIN); // 读取按键引脚的电平状态if (currentState != previousState) // 检测到按键状态改变{delay(50); // 延时50毫秒,避免按键抖动currentState = digitalRead(BUTTON_PIN); // 再次读取按键引脚的电平状态if (currentState != previousState) // 再次检测到按键状态改变{if (currentState == LOW) // 按键按下{printf("Button pressed!\n");// 其他处理代码...}else // 按键松开{printf("Button released!\n");// 其他处理代码...}}}previousState = currentState; // 更新前一个状态}return 0;}```以上代码使用了wiringPi库来进行GPIO的控制和读取,需要在编译时加上-lwiringPi选项。
C语言中断#includevoid init(void)//声明中断初始化{ EA=1;//中断总开关EX0=1;//开中断0开关。
中断1为,EX1=1;IT1=1;//采用边沿触发,下降沿有效。
IT1=0为低电平触发中断。
}main(){ init();调用中断初始化函数=====主程序;}void in_0(void)interrupt 0//中断服务函数{ ====要服务的程序}系统级C语言程序设计(中断原理简介)系统级C语言程序设计(中断原理简介)摘要:本文主要介绍C语言中中断服务程序的编写、安装和使用。
由于硬中断服务程序的编写涉及到硬件端口读写操作,使得用户直接和硬件打交道,在程序设计过程中要用到的数据(如硬件端口地址等)比较多,这就使程序员和计算机的硬件设备间缺少一种“缓冲”的作用,况且,用汇编语言来直接对硬件编程要方便得多。
本文仅对软中断程序的编写作个介绍。
关键词:软中断、中断向量、中断向量表、TSR内存驻留、DOS重入、中断请求、段地址、偏移量、寄存器、BIOS、DOS、setvect ( )、getvect ( )、keep ( )、disable ( )、enable ( )、geninterrupt ( )、int86 ( )、interrupt 对于一般的C语言爱好者而言,就如何在C 中使用中断例程这一问题应该已经非常熟悉,例如,我们可以通过int86 ( )函数调用13H号中断直接对磁盘物理扇区进行操作,也可以通过INT86 ( )函数调用33H号中断在屏幕上显示鼠标光标等。
其实,13H号也好,33H号也好,它们只不过就是一些函数,这些函数的参数通过CPU的寄存器传递。
中断号也只不过是间接地指向函数体的起始内存单元,说它是间接的,也就是说,函数的起始段地址和偏移量是由中断号通过一种方法算得的(具体如何操作,下面会作解释)。
如此一来,程序员不必要用太多的时间去写操作硬件的程序了,只要在自己的程序中设置好参数,再调用BIOS或DOS提供的中断服务程序就可以了,大大减小了程序开发难度,缩短了程序开发周期。
c语言中断处理程序C语言中断处理程序一、引言中断是计算机系统中常见的一种机制,用于处理来自外部设备的异步事件。
中断处理程序是一段特殊的代码,用于响应和处理这些中断事件。
在C语言中,中断处理程序通常被称为中断服务函数(Interrupt Service Routine,简称ISR),本文将探讨C语言中断处理程序的基本原理和编写方法。
二、中断的基本原理中断是一种由硬件设备触发的事件,可以打断CPU正在执行的程序,转而执行与中断相关的处理程序。
中断可以分为外部中断和内部中断两类。
外部中断是来自外部设备的中断请求,如按键、定时器溢出等;内部中断是由CPU内部产生的中断,如除零错误、非法指令等。
当发生中断时,CPU会保存当前的执行现场(包括程序计数器、寄存器等),然后跳转到中断向量表中存储的中断处理程序的入口地址。
中断向量表是一个存储中断处理程序入口地址的表格,每个中断类型对应一个入口地址。
根据中断向量表中的地址,CPU会开始执行中断处理程序。
三、编写中断处理程序的基本步骤编写中断处理程序的基本步骤如下:1. 定义中断处理函数的原型:在C语言中,中断处理函数的原型通常采用特殊的修饰符进行定义,以告知编译器该函数是一个中断处理函数。
例如,使用"void interrupt ISRName(void)"的形式定义中断处理函数。
2. 设置中断向量表:在程序中设置中断向量表,将中断类型与中断处理函数的入口地址进行关联。
具体的设置方法因各种开发环境而异,可参考相关开发工具的文档。
3. 编写中断处理函数:根据中断类型的不同,编写相应的中断处理函数。
中断处理函数应该尽可能地简洁和高效,避免使用过多的计算和延时操作,以免影响系统的实时性。
4. 中断处理程序的优先级:在某些情况下,系统可能会有多个中断同时发生,这时需要确定各个中断的优先级。
具体的设置方法也因开发环境而异,可参考相关开发工具的文档。
四、中断处理程序的注意事项在编写中断处理程序时,需要注意以下几个方面:1. 中断处理程序的执行时间应尽量短,以避免影响系统的实时性。
极其简单好用的按键扫描程序(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为全局变量,其它程序可以直接引用。
键盘扫描原理及应⽤键盘本资源为⽹上搜集⽽来,如果该程序涉及或侵害到您的版权请⽴即写信通知我键盘扫描键盘是由按键构成,是单⽚机系统⾥最常⽤的输⼊设备。
我们可以通过键盘输⼊数据或命令来实现简单的⼈-机通信。
1.按键及键抖动按键是⼀种常开型按钮开关。
平时,按键的两个触点处于断开状态,按下按键时两个触点才闭合(短路)。
如图1-1所⽰,平常状态下,当按键K未被按下时,按键断开,PA0输⼊⼝的电平为⾼电平;当按键K被按下时,按键闭合,PA0输⼊⼝的电平为低电平。
图1-1 按键电路图1-2 按键抖动⼀般的按键所⽤开关都是机械弹性开关,由于机械触点的弹性作⽤,按键开关在闭合时不会马上稳定地连接,在断开进也不会马上完全的断开,在闭合和断开的瞬间均有⼀连串的抖动。
按键按下的电压信号波形图如图1-2所⽰,从图中可以看出按键按下和松开的时候都存在着抖动。
抖动时间的长短因按键的机械特性不同⽽有所不同,⼀般为5ms~10ms。
如果不处理键抖动,则有可能引起⼀次按键被误读成多次,所以为了确保能够正确地读到按键,必须去除键抖动,确保在按键的稳定闭合和稳定断开的时候来判断按键状态,判断后再做处理。
按键在去抖动,可⽤硬件或软件两种⽅法消除。
由于使⽤硬件⽅法消除键抖动,⼀般会给系统的成本带来提⾼,所以通常情况下都是使⽤软件⽅法去除键抖动。
常⽤的去除键抖动的软件⽅法有很多种,但是都离不开基本的原则:就是要么避开抖动的时候检测按键或是在抖动的时候检测到的按键不做处理。
这⾥说明⼀下常⽤的两种⽅法:第⼀种⽅法是检测到按键闭合电平后先执⾏⼀个延时程序,做⼀个12ms~24ms的延时,让前抖动消失后再⼀次检测按键的状态,如果仍是闭合状态的电平,则认为真的有按键按下;若不是闭合状态电平,则认为没有键按下。
若是要判断按键松开的话,也是要在检测到按键释放电平之后再给出12ms~24ms的延时,等后抖动消失后再⼀次检测按键的状态,如果仍为断开状态电平,则确认按键松开。
南通大学实验报告院系:计算机科学与技术姓名:课程名称:接口技术成绩:学号:1213022013指导教师:李跃华同组实验者:实验日期:2014-5-7实验名称:键盘中断实验一.实验目的1.熟练运用CodeWarrior 嵌入式开发系统环境、C 语言、调试方式。
2.复习串行通信接口(SCI)的内容。
3.加强键盘中断基本原理及编程原理的理解。
4.理解“行扫描”法的原理并能进行键值识别和键值编码二.实验内容键盘的c 语言编程:1)初始化,先按IO 口方式初始化,即定义列线为输入且上拉,行线为输出,然后依输入口的键盘功能初始化相应的寄存器。
2)定义键值表3)扫描一次,读取键值4)获得键盘定义值行扫描法是使键盘的某一行输出为低电平,其余行为高电平,然后读取列值,如果列值中有某位为低电平,则表明该行和列交点处的键被按下;若为全高则再扫描下一行,直至扫描完全部的行线为止。
这样就可以确定是哪一行哪一列交点的键被按下。
2. 软件设计三程序流程图四编程1.内核定时器中断void tpm0_isr(void){static uint_32 TPMCounter = 0; //计时器uint_8 value; //键盘变量static uint_8 LEDindex=0; //位选口声明uint_8 LEDDataBuffer[4]; //LED显示缓冲区uint_8 i;//LED缓冲区赋值LEDDataBuffer[0]='0';LEDDataBuffer[1]='2';LEDDataBuffer[2]='3';LEDDataBuffer[3]='5';//LCD显示缓冲区,其中.表示按下的数字uint_8 kbv[32]="The keyboard you just input is .";if((TPM_SC_REG(TPM0_BASE_PTR) & TPM_SC_TOF_MASK) == TPM_SC_TOF_MASK) {TPMCounter++;}BSET(TPM_SC_TOF_SHIFT,TPM_SC_REG(TPM0_BASE_P TR)); //中断置标志位写1清0//处理LED部分LEDindex++;//位选位+1if (LEDindex>=4) LEDindex=0; //大于4位选口置0i=LEDchangeCode(LEDDataBuffer[LEDindex]-'0');//转码LEDshow1(LEDindex,i);//显示LEDif(TPMCounter>100){TPMCounter = 0;//键盘得到扫描值value = KBScanN(2);//扫描键值,存于value中if(KBDef(value) != 0xff) //发送键值{//修改.成为按键值kbv[31] = KBDef(value);//通过LCD显示出来LCDShow(kbv);uart_send_string(UART_2,kbv);//键盘发送信息}}}2.程序的入口int main(void){//1.声明主函数使用的局部变量uint_8 * g_DispalyInit;//2.关总中断enter_critical();//3.初始化底层模块uart_init (UART_1,BUSCLK, 9600); //串口1初始化, 总线时钟24000Khz,波特率9600LEDInit();//LED初始化LCDInit();//LCD初始化KBInit(); //键盘初始化tpm_init(TPM0,TPM_CLKSRC_PLL,1000);//初始化TPM模块,1ms中断一次//4.缓冲区赋值g_DispalyInit = (uint_8 *)"Wait Receiving..Soochow 2013.01.";//5.开中断tpm_enable_int(0);init_critical();//6.lcd显示初始字符LCDShow(g_DispalyInit);//================================= ================================== ========for(;;){}//============================================return 0;}四.实验小结在这次实验中主要让我们熟悉掌握gpio口通信的知识,在熟悉代码的前提下在主函数里初始化波特率何在中断函数里添加一个接收函数就可以。
LPC2138实验程序(尾部附有电路图)①实现键盘1中断(1~9数字),数码管1显示按键数字,同时用7个LED显示数码管1的相应位,即每个LED对应数码管相应位(a~g)。
②实现按键1中断,7个LED实现流水灯;实现按键2中断,7个LED实现跑马灯。
③实现按键3中断,7个LED闪烁10次,延时采用定时器#include <LPC213X.H>#define uchar unsigned charint k=0; //定时器中断计数器uchar a=0; //LED闪烁函数标志void delay(int x) //普通延时函数{int i;for(;x>0;x--)for(i=10000;i>0;i--);}void ms(unsigned int x) //定时器中断延时函数{T0TCR = 0X01;while(k!=x);T0TCR = 0X00;T0TC = 0;T0PC = 0;k=0;}void LED_1() //流水灯函数{unsigned char i;for(i=0;i<7;i++){IO1SET = 1<<(i+16);delay(20);IO1CLR = 1<<(i+16);}}void LED_2() //跑马灯函数{unsigned char i;for(i=0;i<15;i++){if(i<7){IO1SET = 1<<(i+16);delay(20);IO1CLR = 1<<(i+16);}else{IO1SET = 1<<(29-i);delay(20);IO1CLR = 1<<(29-i);}}}void LED_3() //LED闪烁函数{unsigned char i;for(i=0;i<10;i++){IO1SET = 0x7F<<16;delay(20);IO1CLR = 0X7F<<16;delay(20);}}void display(uchar x) /*数码管显示函数x为显示的数字*/ {unsigned char table[10]={0x00, 0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};IO0SET = (table[x]<<25);IO1SET = (table[x]<<16);delay(20);IO0CLR = (table[x]<<25);IO1CLR = (table[x]<<16);}void key_w() //键盘按行低电平扫描函数{IO0SET = 0X7<<20;IO0CLR = 1<<20;delay(2);IO0SET = 1<<20;IO0CLR =1<<21;delay(2);IO0SET =1<<21;IO0CLR =1<<22;delay(2);IO0SET =1<<22;}unsigned char key_r() /*键盘按列读取扫描数值返回值为键盘对应数字*/ {int a=0,b;switch(IO0PIN&(7<<16)){case 0x00060000:b=1;break;case 0x00050000:b=2;break;case 0x00030000:b=3;break;default:break;}switch(IO0PIN&(7<<20)){case 0x00600000:a=1;break;case 0x00500000:a=2;break;case 0x00300000:a=3;break;default :break;}if(a!=0)a=(a-1)*3+b;else a=0;return(a);}void EINT0()__irq //外部中断0服务函数,对应矩阵键盘{unsigned char num;num=key_r();display(num);EXTINT = 0x0f;VICVectAddr=0;}void EINT1()__irq //外部中断1服务函数,对应流水灯{LED_1();VICVectAddr=0;}void EINT2()__irq //外部中断2服务函数,对应跑马灯{LED_2();EXTINT = 0x0f;VICVectAddr=0;}void EINT3()__irq //外部中断3服务函数,对应LED闪烁标志a=1 {a=1;EXTINT = 0x0f;VICVectAddr=0;}void time0()__irq //定时器服务函数,对应k++{k++;T0IR = 1;VICVectAddr = 0;}void init () //初始化函数,引脚功能设置{PINSEL0 = 0X000CC0CC;PINSEL1 = 0X0;IO0DIR = 0XFE700000;IO1DIR = 0X00FF0000;}void EXTinit (uchar x,uchar y) /*外部中断初始化设置x为中断触发方式,y为中端极性,x,y为两位HEX*/{EXTMODE = x;EXTPOLAR = y;}void TIMEinit() //定时器初始化(未给使能){T0TC = 0;T0PR = 0;T0PC = 0;T0MCR= 0x03;T0MR0= 1105920;}void VIC() //中断标志,优先级,指向函数设置{VICIntSelect&= (~(0xF<<14));VICIntSelect&= (~(0x1<<4));VICVectCntl1 = 0x20|14;VICVectAddr1 = (unsigned int)EINT0;VICVectCntl2 = 0x20|15;VICVectAddr2 = (unsigned int)EINT1;VICVectCntl3 = 0x20|16;VICVectAddr3 = (unsigned int)EINT2;VICVectCntl4 = 0x20|17;VICVectAddr4 = (unsigned int)EINT3;VICVectCntl0 = 0x20|4;VICVectAddr0 = (unsigned int)time0;EXTINT = 0x0f;VICIntEnable|= 0xF<<14;VICIntEnable|= 0x1<<4;}int main(void) //主函数{init();EXTinit(0x00,0x00);VIC();TIMEinit();while(1){key_w();if(a==1){LED_3();a=0;}}}。
中断法键盘扫描c程序
/*
程序效果:按下按键,蜂鸣器响,数码管有相应的键值显示,按下E键继电器关,按下C键继电器开。
这与上一程序的功能相同,比上一程序简洁
但理解相对困难些。
运行平台:51hei单片机学习板
*/
#include; //头文件
#include;
#define uchar unsigned char //宏定义
#define uint unsigned int
sbit jdq=P3^5; //位声明,驱动继电器管脚
sbit fmq=P3^4; //位声明,驱动蜂鸣器管脚
code uchar table[]={0x3f,0x06,0x5b,//数码管显示的数值
0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,
0x77,0x7c,0x39,0x5e,0x79,0x71};
code uchar key_tab[17]={
//此数组为键盘编码
0xed,0x7e,0x7d,0x7b,
// 0,1,2,3,
0xbe,0xbd,0xbb,0xde, // 4,5,6,7,
0xdd,0xdb,0x77,0xb7,
// 8,9,a, b,
0xee,0xeb,0xd7,0xe7,0xff}; // c,d,e,f,
uchar l_key=0x00; //定义变量,存放键值
uchar l_keyold=0xff; //作为按键放开否的凭证
void readkey();
//扫描键盘,获取键值
void display(uchar *lp,uchar lc); //显示子函数void delay(); //延时子函数
void main() //主函数
{
EA=1; //打开总中断
EX0=1; //打开外部中断
P0=0xf0; //键值高4位为高电平,低4位为低电平
while(1)
{
display(&l_key,1); //调用显示子函数
if(l_key==14) //是否按下E键,是则关闭继电器 jdq=1;
if(l_key==12) //是否按下C键,是则打开继电器jdq=0;
}
}
void key_scan() interrupt 0//外部中断0,0的优先级最高
{
EX0=0; //在读键盘时,关闭外部中断,防止干扰带来的多次中断
TMOD&=0xf1; //设置定时器为工作方式1
TH0=0x2e; //设置初值,为12毫秒,十进制值为11776 TL0=0x00;
ET0=1; //开启定时器中断0
TR0=1; //启动定时器计数
}
void time0() interrupt 1
//定时器0的中断函数
{
TR0=0;
//关闭定时器0
readkey(); //定时12ms后产生中断,调用此函数,读取键值
}
void readkey()
//扫描键盘子函数
{
uchar i,j,key; //定义局部变量
j=0xfe;
//设定初值
key=0xff;
for(i=0;i<4;i++) // 逐列扫描键盘
{
P0=j;
if((P0&0xf0)!=0xf0) //有按键按下,高4位不可能全为1
{
key=P0; //读取P0口的值,推出循环,否则循环下次
break;
}
j=_crol_(j,1); //此函数的功能是:左移循环
}
if(key==0xff)
//如果读取不到P0口的值,如干扰,则返回{
l_keyold=0xff;
P0=0xf0;
// 恢复P0口的值,等待按键按下
fmq=1;
EX0=1;
//在返回前,打开外部中断
return;
}
fmq=0;
//有按键按下,打开蜂鸣器
if(l_keyold==key) // 检查按键放开否,如果相等表明没有放开
{
TH0=0x2e; //设置初值
TL0=0x00;
TR0=1; //继续启动定时器,检查按键放开否
return;
}
TH0=0x2e;
TL0=0;
TR0=1; //启动定时器
l_keyold=key; //获取键值,作为放开否的凭证
for(i=0;i<17;i++)
//查表获得相应的16进制值存放到l_key中{
if(key==key_tab[i])
{
l_key=i;
break;
}
}
//程序运行到此,就表明有键值存放到l_key中,主程序
//就可以检测键盘值并作相应的处理
}
void display(uchar *lp,uchar lc) //显示子函数{
uchar i;
//定义局部变量
P1=0xf8; //点亮第一个数码管
P2=0;
//P2口为输出值
for(i=0;i<lc;i++) //循环显示
{
P2=table[lp[i]]; //查表获得相应的要显示的数字的数码段
delay(); //延时
P2=0; //清零,准备显示下一个数值
}
}
void delay() //延时子函数
{
_nop_();_nop_();_nop_();_nop_();_nop_();
}。