⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 keycontrol.c

📁 51键盘控制
💻 C
📖 第 1 页 / 共 2 页
字号:
#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint  unsigned int

#define shut_dis() P1 |= 0xF8;                                           //关闭显示
#define RCtrl 0x10                                                       //定义上档键,对应位为1的是上档键
#define RConti 0xFE                                                      //定义连击键,对应位为1的是连击键

#define N 2                                                              //去抖时年龄下限
#define MaxRate 50                                                       //重复前的延迟值600ms
#define MinRate 20                                                       //重复速度240ms
#define leddark 83                                                       //闪烁时灭时间1s
#define ledshow 83                                                       //闪烁时亮时间1s
#define decimal 0x7F                                                     //小数点的段码

/*定时器1的时间常数和方式控制字 2ms*/
#define V_TH0 0xF8
#define V_TL0 0xCC
#define V_TMOD 0x01

sbit sda = P1^0;                                                         //移位寄存器数据线
sbit clk = P1^1;                                                         //移位寄存器时钟线
sbit key_sl = P1^2;                                                     //键盘回送线

/*定义键盘扫描程序返回数据类型*/
typedef struct{
  uchar shiftcnt;                                                        //上档键的个数
  uchar funcnt;                                                          //功能键个数
  uchar shiftval;                                                        //最后扫描的上档键的值
  uchar funval;                                                          //最后扫描到的功能键的值
}keyret;

/*0,1,2,3,4,5,6,7,8,9,*//*A,B,C,D,E*//*F,P,全亮,全灭*/
uchar code led_stroke[19]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E,0x8C,0x00,0xFF};  
/*定义位选码*/
uchar code led_cs[5]={0x7F,0xBF,0xDF,0xEF,0xF7}; 
uchar data led_buf[5]={0xFF,0x81,0x82,0x83,0x84};  
uchar *pb = &led_buf[1];                                                 //定义指向数码管显示缓冲区的指针

/*定义一组全局变量*/
uchar task,state;                      //task:按键状态,0:去抖,1:重复的延缓,2:重复;state:显示位置变量
bit keydone,keyprocess;                 //keydone:按键任务完成标志,为1时已完成;keyprocess:按键有效标志,为1时对按键执行
uchar keypre[2]={0x00,0x00};           //存放上次功能键和上次上档键的键值;keypre0存放功能键
uchar blink,ledtime;                   //blink:闪烁控制寄存器,某位为1时闪烁;ledtime:累计闪烁时已点亮或已熄灭的时间
                                       /**************************************
									    *D7 D6 D5 D4  D3   D2   D1   D0
										*X  X  X  X  LED1 LED2 LED3 LED4
									    **************************************/
bit ledtask;                            //ledtime:累计闪烁时已点亮或已熄灭的时间
bit keymark;                            //keymark:指示当前工作状态,为1时处于设定状态,为0时正常显示工作
bit enflash;                            //enflash:闪烁使能标志,1闪烁

/***********************************************************************************
*函数原型:void send_shift(uchar d)
*功能:由移位寄存器送出段码或扫描键d,clk下降沿有效,高位在前
************************************************************************************/
void send_shift(uchar d)
{
  uchar i;
  for(i=0x80;i>=0x01;i=i>>1)
  {
    if((d&i)==0)
	   sda = 0;
	else
	   sda = 1;
	clk = 0;
	clk = 1;
  }
}
/***********************************************************************************
*函数原型:void lflash()
*功能:闪烁处理,ledtask指示当前的显示状态;亮或灭,ledtask为0时亮
*参数:闪烁时,亮和灭的时间分别由ledshow和leddark决定
*说明:只有在enflash为1且blink的低4位不全为0时,该函数才会被执行
************************************************************************************/
void lflash()
{
  if(enflash&&(blink&0x0F))
  {
    if(ledtime-- == 0)
	{
	  if(!ledtask)
	    ledtime = leddark;
	  else
	    ledtime = ledshow;                          //显示状态翻转
	}
  }
  else
  {
    ledtask = 0;
  }
}
/***********************************************************************************
*函数原型:void display(uchar pos)
*功能:将pos对应的显示缓冲区的内容显示在第pos位数码管上
************************************************************************************/
void display(uchar pos)
{
  bit sflag;
  shut_dis();                                     //关显示
  sflag = (blink>>(4-pos))&0x01;                  //取出Pos对应数码管的闪烁控制位
  if(pos==0) 
  {                                               //指示灯显示时直接将显示内容送显示端口
    send_shift(led_buf[0]);
  }
  else if(!sflag||(sflag&!ledtask))               //不闪烁或处于闪烁时的亮阶段
  {
    if((led_buf[pos]&0x80) == 0)                  //不显示小数点,查表得到段码送显示端口
	  send_shift(led_stroke[led_buf[pos]]);
	else
	  send_shift(led_stroke[led_buf[pos]&0x7F]&decimal);         //显示小数点,把查表得到的段码与小数点的段码与的结果送显示端口
  }
  else
	send_shift(0xFF);                           //Pos位数码不显示 
  P1 &= led_cs[pos];                             //送出位选码
}
/***********************************************************************************
*函数原型:void scankey(keyret *kpd)
*功能:键盘扫描,返回上档键个数、上档键键值、功能键个数、功能键键值
************************************************************************************/     
void scankey(keyret *kpd)
{
  uchar i,scan;
  scan = 0xFE;
  shut_dis();                                     //显示关
  for(i=1;i<=8;i++)
  {
    send_shift(scan);                             //送出键扫描
	if(!key_sl)                                   //有键闭合
	{
	  if(~scan&RCtrl)                             //该键是上档键
	  {
	    kpd ->shiftcnt++;                         //上档键个数加1
		kpd ->shiftval=i;                         //将键值存入上档键键值缓冲
	  }
	}
	else
	{
	  kpd ->funcnt++;                             //功能键个数加1
	  kpd ->funval=i;                             //将键值存入功能键键值缓冲
	}
	scan = _crol_(scan,1);                        //未扫完,修改键扫描码指向下一行
  }
}   
/***********************************************************************************
*函数原型:void key()
*功能:键值处理
*说明:根据键盘扫描程序返回的键盘数据进行去抖动;
*      连击键处理,串键处理按键有效时keyprocess为1
************************************************************************************/          
void key()
{
  uchar krpt = RConti;
  static uchar keycnt;
  static bit   keyesc;
  keyret keytemp={0x00,0x00,0x00,0x00};
  if(keydone)
  {
    scankey(&keytemp);                           //扫描键盘
	if(!keytemp.funcnt || keytemp.shiftcnt>1)       //无功能键按下或者上档键个数多于1个
	{
	  enflash = 1;                               //允许闪烁
	  
	  keypre[1]=0x00;keypre[0]=0x00;             //上次功能键和上档键缓冲清零
	  keyesc=0x00;task=0x00;keycnt=0x00;         //年龄计数器、键释放标志、按键状态清零
	}
	else if(!keyesc)                             //键已释放
	{
	  if(keytemp.funcnt>1)                       //有多于一个功能键按下、复位按键释放标志
	     keyesc=1;
	  else if(keytemp.funval!=keypre[0]||keytemp.shiftval!=keypre[1]&&keypre[1])
	  //本次功能键键值和上次不同或本次上档键键值和上次不同且上次有上档键
	  {
	    keypre[0]=keytemp.funval;                 //用本次键值更新上次键值
		keypre[0]=keytemp.shiftval;
		keycnt=0x00;                              //年龄计数器复位
	  }
	  else if(!keypre[1] && keytemp.shiftval)     //2次功能键相同,上次无上档键本次有
	    keyesc=1;                                 //置位keyesc,屏蔽先按下功能键,再按上档键这种键组合
	  else
	  {
	    keycnt++;                                 //2次功能键和上档键都相同
		switch(task)
		{
		 case 0:                                  //去抖阶段
		   if(keycnt == N)                        //年龄等于下限N
		   {
		     enflash = 1;
			 keyprocess = 1;                      //进行键值处理
			 if((keytemp.shiftcnt==1)||!(krpt>>(keytemp.funval-1)&0x01))         //是一对复合键或该键不允许连击
			   keyesc = 1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -