按键的C51源程序

发布者:InspiredDreamer最新更新时间:2016-03-25 来源: eefocus关键字:按键  C51源程序 手机看文章 扫描二维码
随时随地手机看文章
8条口线24按键的C51源程序
 

//键盘扫描处理,无按键返回0,有按键返回键值,键值对应于keycode[]下标值。8条(以P2为例)口线24按键
//键盘码也可定义为局部数组变量
unsigned char code keycode[]=
{0x00,0xee,0xde,0xbe,0xed,0xdd,0xbd,0xeb,0xdb,0xbb,0xd7,0xe7,0xb7,0x7b,0x7d,0x7e,0x77,

0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0x7f,0xbf};

unsigned char keyread(void)
{ unsigned char i,j,x,k1,k2;
P2=0xff;
if(P2!=0xff)
{k1=P2;
delay();
P2=0xff;
if(P2!=0xff)
{for(P2=0xff;P2!=0xff;P2=0xff)
x=k1;}
}
else{x=0;
}
//以上判断接地按键
//以下判断交叉按键(反转法)
if(x==0)
{P2=0x0f;
if(P2!=0x0f)
{delay();
P2=0x0f;
if(P2!=0x0f)
{k1=P2;
P2=0xf0;
if(P2!=0xf0)
{k2=P2;
for(P2=0xf0;P2!=0xf0;P2=0xf0)
x=k1^k2;}
}
}
else{x=0;} }
if(x==0){i=0;}
else{i=j=0xff;
do{i++;j++;
if(keycode[i]==x){j=24;}
else if(j==24){i=0;}else{;} }

while(j!=24);}

return(i);
}

void delay()//延时
{ unsigned char b;
for (b=0;b<=0xff;b++)
{
for (b=0;b<=0xff;b++)
{;}
}
}

 


 96个key的零延时采集
 Juliet发表评论于2006-5-10 11:35:00

96个key的零延时采集
 
 
HotPower 发表于 2003-11-5 18:04 侃单片机 ←返回版面   

;-------96键演示程序-------------------------
;这是1个回复题中的应用示例,已通过软仿真“验证”
;这只是键扫描技术的1个“缩影”,方法实在太多.
;有“难看之处”,敬请高手们批评指教.
;HotPower将虚心接受,坚决改正.重新做人.
;发表目的: 在21IC中壮大游击队.
;----------------------------------------------------
;由于2051资源问题,本程序只取多任务键盘的压放键2个事件
;废除长压键(压键1段时间后才激活)事件
;废除长放键(放键1段时间后才激活)事件
;废除双击键事件
;废除任意组合键事件
;----------常数定义------------------------------
TIME208US  EQU -208;20mS/96=208uS
TIME50MS   EQU -5000;50000uS
;KEYCOUNT   EQU   1;键盘键个数(软仿真时用)
;------------------------------------------------
KEYCOUNT   EQU   96;键盘键个数(实际应用)


;----------RAM地址定义----------------------------
;--------96键键状态标志位数组Bits[12*8位]--------
KEYBUFF1   DATA  08H;08H~13H(12个字节96位)对应96键
;--------96键键跳变标志位数组Bits[12*8位]--------
KEYBUFF2   DATA  14H;14H~1FH(12个字节96位)对应96键
;------------------------------------------------
KEYNUM     DATA  30H;
HotPower_55H      DATA   6EH
HotPower_AAH      DATA   6FH
;---------------------------------------
SP_MIN       DATA HotPower_AAH
;-------主程序开始----------------------
    ORG   0000H
START:
    LJMP  MAINSTART;主程序开始
    ORG   0003H
;-------掉电保护中断INT0服务程序--------
INT0_INTADDR:
    RETI
    ORG   000BH
;-------定时器T0中断服务程序------------
;工作在8位自动装载方式,每208uS中断一次
T0_INTADDR:
    LJMP  T0INTPROC;定时器T0中断服务程序
    RETI
    ORG   0013H
;-------外部中断INT1服务程序------------
INT1_INTADDR:
    RETI
    ORG   001BH
;-------定时器T1中断服务程序------------
T1_INTADDR:
    LJMP  T1INTPROC;定时器T1中断服务程序
    RETI
   ORG   0023H
;-------串行中断服务程序----------------
;SINT_INTADDR:
   RETI
;-------------------------------------------
   ORG   002BH
;-------定时器T2中断服务程序------------
   LJMP  T2INTPROC;执行中断服务程序
   RETI
;-------执行键盘命令----------------------
;本程序利用散转回收技术(指针函数)
;它的最大优点是散转处的子程序可被它用(函数)
;它比JMP @A+DPTR指令要“游击”很多,灵活和隐蔽了许多
;它在对付“反汇编”方面,比JMP @A+DPTR更“坏”
;HotPower打死也不用JMP @A+DPTR
KEYPROC:
;入口:  DPTR散转地址表
      ACC 散转号
    CJNE  A,#KEYCOUNT,$+3
    JNC   KEYPROC_EXIT;非法键(96~255)防止程序飞,不散转
    RL    A;*2;地址需要2字节(像ARM的大端模式)
    ADD   A,DPL
    MOV   DPL,A
    CLR   A
    ADDC  A,DPH
    MOV   DPH,A
    MOV   A,#01H;低8位
    MOVC  A,@A+DPTR;取低8位地址
        PUSH  ACC;压入事件处理低8位地址
        CLR   A;高8位
    MOVC  A,@A+DPTR;取高8位地址
        PUSH  ACC;压入事件处理高8位地址
KEYPROC_EXIT:
    RET;执行键盘命令(散转JMP @A+DPTR)
;-------压键事件处理地址表--------------------
KEYJMPPROCTAB:
    DW    KEYPROC0;0键压键
    DW    KEYPROC1
    DW    KEYPROC2
;............................
    DW    KEYPROC95;95键压键
;-------放键事件处理地址表--------------------
KEYJMPPROCTABX:
    DW    KEYPROC0X;0键放键
    DW    KEYPROC1X
    DW    KEYPROC2X
;............................
    DW    KEYPROC95X;95键放键
MAINSTART:
;-------P0口初始化------------------
    MOV   P0,#11111111B
;-------P1口初始化------------------
    MOV   P1,#11111111B
;-------P2口初始化------------------
    MOV   P2,#11111111B
;-------P3口初始化------------------
    MOV   P3,#11111111B
;--------------------------------
    MOV   IE,#00000000B;EA=0,ES=ET2=ET1=EX1=ET0=EX0=0
    MOV   SP,#SP_MIN;
          MOV   PSW,#00000000B;RS1RS0=00,R0~R7=00H~07H
    MOV   A,#LOW(MAINNEXT)
    PUSH  ACC
    MOV   A,#HIGH(MAINNEXT)
    PUSH  ACC
    RETI
MAINPROC:
    LCALL MAININIT;系统初始化
        MOV   IE,#10001010B;开中断
;-------主循环-------------------------------
MAINLOOP:
    ORL   PCON,#10001101B;待机
    SJMP  MAINLOOP;死循环
MAINNEXT:
    MOV   A,#LOW(MAINPROC)
    PUSH  ACC
    MOV   A,#HIGH(MAINPROC)
    PUSH  ACC
    RETI
;-------主程序初始化------------------------
MAININIT:
;-------接口初始化--------------------------
;-------内存初始化-------------------------
    MOV   A,HotPower_55H
    XRL   A,HotPower_AAH
    CPL   A
    JZ    MAININITNEXT;内存未破坏
    MOV   HotPower_55H,#055H
    MOV   HotPower_AAH,#0AAH
    LCALL SYSTEMINIT;系统初始化
MAININITNEXT:
;-------运行初始化---------------
    LCALL SYSTEMSETUP;系统设置
    RET
SYSTEMINIT:
    LCALL KEYBUFFINIT
    RET
SYSTEMSETUP:
;-------系统主频12MHz---------------------------------
   MOV   IP,#00100001B;中断优先级EX0>ET2>ET0>EX1>ES
     MOV   TMOD,#00010010B;T1=MODE1(16位定时器),T0=MODE2(8位定时器)
    MOV   TCON,#01010101B;启动定时器TR1EQUTR0EQU1,IT1EQUIT0EQU1
;------------------------------------------------------
    MOV   TL0,#TIME208US;设置定时器0时间常数
    MOV   TH0,#TIME208US;设置定时器0时间常数
;------------------------------------------------------
   MOV   TL1,#LOW(TIMEXMS);设置定时器1时间常数
   MOV   TH1,#HIGH(TIMEXMS)
;-------
KEYBUFFINIT:
    MOV   KEYNUM,#00H
    MOV   R0,#KEYBUFF1
KEYBUFFINITLOOP:
    MOV   @R0,#00H
    INC   R0
    CJNE  R0,#KEYBUFF2+12,KEYBUFFINITLOOP
    RET
;---------------------------------------------
INKEY:
;T0每中断1次,将进行1次键"扫描"
    LCALL TESTKEY;键盘测试(不扫但描)
;-------键盘软仿真测试点-----------------
;在此   A=0 无键压下,A<>0有键压下
;若调试n个键,需将KEYCOUNT设置为n.(KEYCOUNT=1~96)
;----------------------------------------
    JNZ   INKEY1;有键压下
INKEY0:
;-------无键压下------------------------
    LCALL GETKEYBIT;取键状态
    JZ    INKEY01;键状态未发生变化
        LCALL CLRKEYBIT;设置放键标志
    LCALL SETKEYBITK;设置跳变标志(防止放键抖动)
    RET
INKEY01:
    LCALL GETKEYBITK;取键跳变标志
    JZ    INKEY02;键未发生跳变(防止2次事件处理)
    LCALL CLRKEYBITX;设置重入标志
        MOV   A,KEYNUM;取键号
        MOV   DPTR,#KEYJMPPROCTABX;键盘放键事件处理表
    LCALL KEYPROC;执行键盘放键事件处理
INKEY02:
    RET
INKEY1:
;-------有键压下------------------------
    LCALL GETKEYBIT;取键状态
    JNZ   INKEY11;键状态未发生变化(防止2次事件处理)
        LCALL SETKEYBIT;设置压键标志
    LCALL SETKEYBITK;设置跳变标志(防止压键抖动)
    RET
INKEY11:
    LCALL GETKEYBITK;取键跳变标志
    JZ    INKEY12;键未发生跳变
    LCALL CLRKEYBITX;设置重入标志
        MOV   A,KEYNUM;取键号
        MOV   DPTR,#KEYJMPPROCTAB;键盘压键事件处理表
    LCALL KEYPROC;执行键盘压键事件处理
INKEY12:
    RET
GETKEYBITK:
    MOV   A,R0
    ADD   A,#12
    MOV   R0,A
    SJMP  GETKEYBITX
GETKEYBIT:
    LCALL GETKEYBITADDR
    LCALL GETKEYBITVAL
GETKEYBITX:
    MOV   A,@R0
        ANL   A,B
    RET
SETKEYBITK:
    MOV   A,R0
    ADD   A,#12
    MOV   R0,A
    SJMP  SETKEYBITX
SETKEYBIT:
    LCALL GETKEYBITADDR
    LCALL GETKEYBITVAL
SETKEYBITX:
    MOV   A,@R0
        ORL   A,B
    MOV   @R0,A
    RET
CLRKEYBITK:
    MOV   A,R0
    ADD   A,#12
    MOV   R0,A
    SJMP  CLRKEYBITX
CLRKEYBIT:
    LCALL GETKEYBITADDR
    LCALL GETKEYBITVAL
CLRKEYBITX:
    MOV   A,@R0
    XRL   B,#0FFH;取反B
        ANL   A,B
    XRL   B,#0FFH;还原B
    MOV   @R0,A
    RET
;-----------------------------------
;CPLKEYBITK:
   MOV   A,R0
   ADD   A,#12
   MOV   R0,A
   SJMP  CPLKEYBITX
;CPLKEYBIT:
   LCALL GETKEYBITADDR
   LCALL GETKEYBITVAL
;CPLKEYBITX:
   MOV   A,@R0
       XRL   A,B
   MOV   @R0,A
   RET
;---------------------------------------------
GETKEYBITVAL:
    MOV   A,KEYNUM
    ANL   A,#07H
    ADD   A,#GETKEYBITTAB-GETKEYBITTABOFF
    MOVC  A,@A+PC
GETKEYBITTABOFF:
    MOV   B,A
    RET
GETKEYBITTAB:
    DB    00000001B
    DB    00000010B
    DB    00000100B
    DB    00001000B
    DB    00010000B
    DB    00100000B
    DB    01000000B
    DB    10000000B
    RET
;----------------------------------------------
GETKEYBITADDR:
    MOV   A,KEYNUM
    ANL   A,#01111000B
    RR    A
    RR    A
    RR    A
    ADD   A,#KEYBUFF1
    MOV   R0,A
    RET
;-------键测试子程序--------------------------
TESTKEY:
;键号KEYNUM=000 0000B~101 1111B(0~95)
;入口  
;出口   ACC==0 无键压下(键号KEYNUM)
      ACC<>0 有键压下(键号KEYNUM)
    MOV   A,KEYNUM;取键号
    ANL   A,#0FH;取行号(键号低4位)
    ANL   P3,#0F0H;清行信号
    ORL   P3,A;发送行扫描信号DCBA;P3.3~P3.0
    MOV   A,KEYNUM;取键号
    ANL   A,#01110000B;取列号(键号高3位)
    SWAP  A;变换到低3位
    ADD   A,#TESTKEYTAB-TESTKEYTABOFF;得到表地址
        MOVC  A,@A+PC;取列表值
TESTKEYTABOFF:
    JZ    TESTKEYEXIT;6,7非法列,认为无键压下
    PUSH  B;保护现场
    MOV   B,A;暂存
    ANL   A,P1;接收列值P1.7~P1.2,有键压下为0
    XRL   A,B;有键压下非0
    POP   B;恢复现场
TESTKEYEXIT:
    RET
TESTKEYTAB:
    DB    00000100B;0列
    DB    00001000B;1列
    DB    00010000B;2列
    DB    00100000B;3列
    DB    01000000B;4列
    DB    10000000B;5列
    DB    00000000B;6列非法
    DB    00000000B;7列非法
;-------定时器T0中断服务程序--------------------
;每个键20mS扫描1次,并自动进行压键或放键消抖处理
;这是1个大规模(96键)的键盘游击战的非典战例
;特点:
;1.不需键扫描.(T0中断的次序即为键扫描号)
;2.不需键消抖.(在T0中断96次后自动消抖)
;3.压键放键事件分离(散转回收技术)
;4.用户事件"并行处理"(mS级分时)
T0INTPROC:
    PUSH  PSW
    PUSH  ACC
    PUSH  B
    PUSH  DPL
    PUSH  DPH
T0INTPROC_START:
    LCALL INKEY;键扫描并执行压放键事件处理
    INC   KEYNUM;准备下一键号(T0中断计数)
    MOV   A,KEYNUM
    CJNE  A,#KEYCOUNT,T0INTPROC_EXIT
    MOV   KEYNUM,#00H;开始下1轮键扫描
T0INTPROC_EXIT:
    POP   DPH
    POP   DPL
    POP   B
    POP   ACC
    POP   PSW
    RETI
;-------定时器T1中断服务程序------------
T1INTPROC:
    RETI
;-------0键压键事件处理---------------------
KEYPROC0:
;在此添加用户压键事件
    RET
;-------1键压键事件处理---------------------
KEYPROC1:
;在此添加用户压键事件
    RET
;-------2键压键事件处理---------------------
KEYPROC2:
;在此添加用户压键事件
    RET
;-------95键压键事件处理---------------------
KEYPROC95:
;在此添加用户压键事件
    RET
;-------0键放键事件处理---------------------
KEYPROC0X:
;在此添加用户放键事件
    RET
;-------1键放键事件处理---------------------
KEYPROC1X:
;在此添加用户放键事件
    RET
;-------2键放键事件处理---------------------
KEYPROC2X:
;在此添加用户放键事件
    RET
;-------95键放键事件处理---------------------
KEYPROC95X:
;在此添加用户放键事件
    RET
;-------全部程序结束--------------------------------------
    END

 


 按键扫描驱动程序
 Juliet发表评论于2006-5-10 11:35:00

按键扫描驱动程序
 
 
//按键扫描驱动程序

unsigned char key,key_h,kpush;
unsigned int key_l;

//按键连接到p1.0、p1.1、p1.2

void int_t0(void) interrupt 1 {
 unsigned char dd,i;
 TL0=TL0+30;TH0=0xfb; //800
 
 if ((P1&0x7)==0x7) {
  if ((key_l>30)&&(key_l<800)&&(key_h>30)) {  //释放按键,如果之前按键时间少于1秒,读入键值
   key=kpush;
  }
  if ((++key_h)>200) key_h=200;
  key_l=0;
  if (key>=0x80) key=0;       //如果之前的按键为长按1秒,清除键值
 } else {
  kpush=P1&0x7;
  key_l++;
  if ((key_l>800)&&(key_h>30)) {     //如果按键超过1秒,键值加0x80标志长按键
   key=kpush|0x80;
   key_h=0;
   key_l=0;
  }
 }
}
void main(void) {
 TMOD=0x1;TR0=1;ET0=1;EA=1;
 while (1) {
  while (!key) {}
  switch (key) {
  case 1:break;
  case 2:break;
  }
 }
}


关键字:按键  C51源程序 引用地址:按键的C51源程序

上一篇:51单片机IO口模拟串口通讯C源程
下一篇:At89c51单片机键盘扫描和显示程序

推荐阅读最新更新时间:2024-03-16 14:48

STC15F104W单片机四路按键循环开关程序
用一个按键控制四个继电器循环导通,程序由51单片机的程序改到STC15F104W上,第一次按键,第一个继电器吸合,第二次按键,第二个继电器吸合,第一个继电器释放,以此类推。最初的想法就是实现电风扇,三档开关,程序里面可以修改端口。 #include reg52.h sbit key = P3^4; //定义按键 void delayms(void); //延时 void led_refresh(unsigned char i); //led显示 unsigned char keyscan(void); //按键 void init(void); /
[单片机]
89c51 c语言软件防抖动按键
仿真结果如下: #include reg51.h sbit SI=P1^4; sbit LED0=P3^0; void delay() { unsigned char i,j; for(i=0;i 100;i++) for(j=0;j 100;j++) ; } void main() { LED0=0; while(1) { if(SI==0) { delay(); //延时一段时间 if(SI==0) //再次确认是否有按键按下 LED0=1; //当有按键
[单片机]
AVR单片机学习按键与数码管的程序设计
简介:按键与数码管的程序设计 AVR IO口的输入模式与上拉电阻 选择结构语句与按键的查询方式程序设计 数码管基本原理 扫描方式显示多位数码管 一、输入状态IO寄存器设置 1、DDRx 某一位置0,相应位的IO口被设置为输入 2、PORTx某一位置1,使能对应IO口相应位的上拉电阻 3、PINx的对应位是输入的数据,0或1 选择结构语句 一、关系运算符和关系表达式 小于 小于等于 = 大于 大于或等于== 不等于!= 二、逻辑运算符和逻辑表达式 逻辑与&&逻辑或||逻辑非! 三、if 语句结构 if(表达式1)语句1 else if(表达式2)语句2 else 语句3 四
[单片机]
AVR单片机学习<font color='red'>按键</font>与数码管的程序设计
关于STM32F103型号的矩阵按键的程序书写
最近参加电子大赛要写一个矩阵按键,刚开始写了好长时间换了好几个矩阵按键都不好使,但是 我感觉我的程序和原理都没有错,调试了好久也没有发现问题在哪?我按照我自己的思路把程序重写了一遍bug消失了,程序很好的运行。程序贴出来,纪念一下。 #include keypad.h #include stm32f10x.h #include delay.h /*************************************************************************/ /****************************************************************
[单片机]
一键多功能(按键控制LED亮度)
本例子利用主要实现功能,一个按键,控制LED台灯的亮度。上电默认关机,第一次按下,LED全亮,第二次按下,LED亮58%,第三次按下,LED亮47%,第四次按下,LED亮9%。 本例中主要利用模拟PWM进行LED亮度控制。由于考虑成本,所以使用价格低廉,功能单一的单片机(没有中断功能)。所以一切靠模拟。选用 PIC16F505,其实可以用12F508或者12F509,反正8脚的单片机都可以用。RC4接按键,RC2接LED(可以通过扩流去驱动更大概率的 LED负载)。 程序如下: } 利用timer1(uint y)这个函数实际上很好的解决了,利用按键控制PWM调光,RGB渐变等多种状态的转跳。 #include
[单片机]
四个按键控制的四个流水灯的速度
#define uchar unsigned char //定义一下方便使用 #define uint unsigned int #define ulong unsigned long #include //包括一个52标准内核的头文件 sbit K1= P3^1; sbit K2= P3^2; sbit K3= P3^3; sbit K4= P3^4; bit ldelay=0; //长定时溢出标记,预置是0 uchar speed=90; //设置一个变量保存默认的跑马灯的移动速度 char code dx516 _at_ 0x003b;//这是为了仿真设置的 //4个按键4级变速的跑马灯试
[单片机]
学51单片机-按键的中断检测
接着昨天,继续说按键的事。昨天说的是扫描检测,今个说一下中断检测。先插播一个小故事~~ 当年我和凯凯学单片机的时候,我用扫描检测的方法做的项目,他用中断检测的方法做的项目。当我俩坐一起交流按键检测的方式时,他火了,直接跳起来跟我吼:你不用中断怎么检测? 当时我就意识到他可能陷入了只能用中断的误区,然后就乐呵呵的说:用扫描啊~ 他继续吼,我继续乐,我俩就这样陷入了死循环。终于都累了,然后把程序和原理给他看,了解~ 在STC89C52单片机上,具有外部中断功能的引脚有两个:P3.2 –INT0 和 P3.3-INT1。上电默认的情况下,他们是普通IO引脚;当配置好相关寄存器之后,他们就变成
[单片机]
学51单片机-<font color='red'>按键</font>的中断检测
节能设计的双线4×4按键键盘接口
  可以用带有 ADC 的微控制器设计一个双线加接地组成的键盘接口。例如,可以用一个电阻分压器判定一个按下的键(参考文献 1)。微控制器的整合 ADC, 其输入电阻一般在数百千欧量级,为了有足够的精度,键盘分压器应该具有相对较低电阻值,一般为数十千欧量级。但是,在电池供电系统中,电阻分压器会消耗数百毫安电流,这迫使设计者选择经典的数字矩阵开关和多条 I/O 线作替代。此外,便携设备设计通常也限制了元件的数量。   为满足这两个要求,图 1 中的电路采用了一个矩阵键盘和一个分为两行、两列的电阻网络。对于 4 X 4 按键的键盘,7 只电阻器就足以为所有按键编码,电路只在一个键保持闭合时消耗能量。而当没有按下任何按键时,待机电流
[嵌入式]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved