题:用任意一单片机设计一个4X4的键盘并编出程序得到键值,要求有去抖,去抖时单片机可以做其它事情,按一下键盘蜂鸣器叫一下,蜂鸣器叫过程中也要单片机可以做其它事情。(提示:用定时器产生基本节拍)
题目是我做后记下来的,当时在做得时候写的很乱,被老师评为编程不怎么样。回来后想想其实很简单就一个中断函数搞定:
void time1_sv() interrupt 5 using 2{
EA=0;
TF2=0; //清中断标志位
if((spcnt--)==0){spcnt=0;SPEAK=0x00;}
if(scankey()){count++;
if(count>8){getkeyval();count=0;spcnt=30;SPEAK=0xff;}
}
else {count=0;}
EA=1;
}
思路是:连续n次进入中断时都检测到有按键,那就去取按键值,并使蜂鸣器叫,蜂鸣器叫多长时间由spcnt的值决定。
试验源程序:
#include "mydef.h"
//定义外围器件地址
#define SPEAK XBYTE[0xC000]
#define KEYIN XBYTE[0xE000]
#define KEYOUT XBYTE[0xF000]
#define PORTA XBYTE[0xa000]
#define PORTB XBYTE[0xb000]
#define LEDD XBYTE[0x9000]
//3000个机器周期中断一次
#define TIME_H (65535-3000)/256
#define TIME_L (65535-3000)%256
//LED显示译码
uchar code table[]={0x0C0,0x0F9,0x0A4,0x0B0,0x99,0x92,0x82,0x0F8,0x80,0x90,0x88,0x83,0x0C6,0x0A1,0x86,0x8E,0x7F,0x89};
//全局变量
uchar key_value,count,spcnt;
//判断有无按键
uchar scankey()
{ KEYOUT=0x00;
if(((~KEYIN)&0x0f)!=0) return(1); //有键按下
else return(0);
}
//得到键值
void getkeyval(void)
{
KEYOUT=0x0e;
switch(KEYIN&0x0f)
{ case 14:key_value=0;break;
case 13:key_value=1;break;
case 11:key_value=2;break;
case 7:key_value=3;break;
default:break;
}
KEYOUT=0x0d;
switch(KEYIN&0x0f)
{ case 14:key_value=4;break;
case 13:key_value=5;break;
case 11:key_value=6;break;
case 7:key_value=7;break;
default:break;
}
KEYOUT=0x0b;
switch(KEYIN&0x0f)
{ case 14:key_value=8;break;
case 13:key_value=9;break;
case 11:key_value=10;break;
case 7:key_value=11;break;
default:break;
}
KEYOUT=0x07;
switch(KEYIN&0x0f)
{ case 14:key_value=12;break;
case 13:key_value=13;break;
case 11:key_value=14;break;
case 7:key_value=15;break;
default:break;
}
}
//定时T2中断 89c52,w78e58之类的单片机都有定时器2
void time1_sv() interrupt 5 using 2{
EA=0;
TF2=0; //清中断标志位
if((spcnt--)==0){spcnt=0;SPEAK=0x00;}
if(scankey()){count++;
if(count>8){getkeyval();count=0;spcnt=30;SPEAK=0xff;}
}
else {count=0;}
EA=1;
}
//粗劣延时mS级
void msec(uint x)
{
unsigned int j;
while((x--)!=0)
{
for(j=0;j<=123;j++)
{;}
}
}
//数码管显示
void dir(uchar leddat)
{
ORTA=0x00;
ORTB=0xff;
LEDD=table[leddat];
msec(2);
ORTA=0xff;
LEDD=table[leddat];
ORTB=0x00;
msec(2);
ORTB=0xFF;
}
//主函数
main()
{
C_T2=0; //T2工作在定时器
CP_RL2=0; //自动装栽
RCAP2H=TH2=TIME_H;
RCAP2L=TL2=TIME_L;
EA=1;
ET2=1;
TR2=1;
while(1)
{ dir(key_value);
}
}
欢迎光临 应届生求职招聘论坛 (https://bbs.yingjiesheng.com/) | Powered by Discuz! X3.2 |