按键.docx
- 文档编号:3199827
- 上传时间:2023-05-05
- 格式:DOCX
- 页数:18
- 大小:20.58KB
按键.docx
《按键.docx》由会员分享,可在线阅读,更多相关《按键.docx(18页珍藏版)》请在冰点文库上搜索。
按键
AVR单片机定时器按键扫描程序
*******************************************************************************
*程序共定义了6个键的功能:
K1、K2、K3、K4以及K5、K8组成的一对复合键,其中K2,K3为连击键,K5为上档键。
在正常工作模式下按K1则切换至状态,在设定模式下按K1键循环选择4个数码管中的某个,被选中的数码管闪烁,此时单按K2键显示数值加1;常按K2显示数值以一定速度递增,同时数码管停止闪烁,当K2松开,数码管恢复闪烁,显示数值停留在K2松开前的值上。
K3完成的功能和K2类似。
其完成减操作。
这2个键只有在设定状态才有效,可以有效防止误操作。
K4为确认键,按下该键回到正常显示状态,所有指示灯熄灭,数码管显示刚刚设定的数值。
K5+K8这对复合键执行复位操作,任何情况下同时按下K5和K8或先按下K5再按下K8,所有数码管的显示全为0,指示灯全灭,进入正常显示状态。
同时程序还对如下几个异常操作进行了处理:
* 2个或多个功能键同时按下
* 一个功能键按下未释放,又按另一个功能键,然后再松开其中一个功能键
* 先按下功能键再按下上档键
* 多个上档键和一个功能键同时按下,此时不做处理。
等到松开其他上档键,只剩下一个上
* 档键和一个功能键时才执行这对复合键;或松开所有上档键,处理单一功能键。
*******************************************************************************/
#include
#include
#define uchar unsigned char
#define uint unsigned int
#define RCtrl 0x20 //定义上挡键 第5键
#define RConti 0xfe //定义连击键 第6键
#define N 2 //去抖年龄下限
#define MaxRate 50 //重复前的延迟值 600ms
#define MinRate 20 //重复速度 240ms
#define leddark 83 //闪烁时灭时间1s
#define ledshow 83 //闪烁时亮时间1s
#define decimal 0x80 //小数点的段数
#define KEY_DDR DDRC
#define KEY_PORTO PORTC
#define KEY_PORTI PINC
#define OUT 0x3f
#define IN 0xc0
#define KeyValue 0x3f
#define LEDD_DDR DDRB
#define LEDD_PORTO PORTB
#define LEDS_DDR DDRD
#define LEDS_PORTO PORTD
#define LEDS_MASK 0xfc
#define LEDS_NUM 0x06
#define TRUE 1
#define FALSE 0
/*定义键盘扫描程序返回数据类型*/
typedef struct
{
uchar shiftcnt; //上档键的个数值
uchar funcnt; //功能键的个数值
uchar shiftval; //最后扫描到的上档键的值
uchar funval; //最后扫描到的功能键的值
} keyret;
/*定义显示字符段码*/
uchar const led_stroke[19] =
{
//0,1,2,3,4,5,6,7,8,9
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,
//a,b,C,d,e,F,P,
0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71, 0x73,
//all on all off
0xff, 0x00
};
/*定义位选码*/
uchar const led_cs[LEDS_NUM] =
{
0xfb, //11111011
0xf7, //11110111
0xef, //11101111
0xdf, //11011111
0xbf, //10111111
0x7f //01111111
};
uchar led_buf[LEDS_NUM] =
{
0x73, 0x81, 0x82, 0x83, 0x84,0x85
};
uchar *pb = &led_buf[1]; //定义指向数码管数据缓冲区的指针
/*定义全局变量*/
uchar task, state; //task:
按键状态,0:
去抖 1,重复的延迟 2,重复
//state:
显示位置变量
uchar keydone, keyprocess; //keydone:
按键任务完成标志,为1表示已完成
//keyprocess:
按键有效标志,为1时表示对按键执行
uchar keypre[2] =
{
0x00, 0x00
}; //存放上次功能键和上档键的键值
//keypre0存放功能键
uchar blink, ledtime; //blink:
闪烁控制寄存器,某位为1时闪烁
//d7d6d5d4d3d2d1d0
//xxxx1111
//ledtime:
累计闪烁时已点亮和已熄灭的时间
uchar ledtask; //ledtask:
当前的闪烁状态,0代表亮
uchar keymark; //keymark:
只是当前工作状态,为1时处于设定状态,为0时正常工作
uchar enflash; //enflash:
闪烁使能标志,1闪烁
#define shut_dis() LEDS_PORTO|=LEDS_MASK; //shut display
/*******************************************************************************
*函数原型:
uchar _crol_(uchar data,uchar shiftbit);
*功能:
字节左移shiftbit
*参数:
*说明:
*******************************************************************************/
uchar _crol_(uchar data,uchar shiftbit)
{
data &=0xff;
if(shiftbit>8)return 0;
return ((~data)< } /******************************************************************************* *函数原型: uchar _cror_(uchar data,uchar shiftbit); *功能: 字节右移shiftbit *参数: *说明: *******************************************************************************/ uchar _cror_(uchar data,uchar shiftbit) { data &=0xff; if(shiftbit>8)return 0; return ((~data)>>shiftbit); } /******************************************************************************* *函数原型: void send_shift(uchar d); *功能: 将显示数据由B口送出 *******************************************************************************/ void send_shift(uchar data) { LEDD_PORTO = data; } /******************************************************************************* *函数原型: void lflash(); *功能: 闪烁处理。 ledtask指示当前的显示状态: 亮或灭,ledtask为0时亮 *参数: *说明: *******************************************************************************/ void lflash() { if (enflash && (blink &0x3f)) { if (ledtime-- == 0) { if (! ledtask) ledtime = leddark; else ledtime = ledshow; ledtask = ~ledtask; //显示状态翻转 } } else ledtask = 0; } /******************************************************************************* *函数原型: void display(uchar pos); *功能: 将pos对应的显示缓冲区的内容显示在第pos位数码管上 *参数: *说明: *******************************************************************************/ void display(uchar pos) { uchar sflag; shut_dis(); //关显示 sflag = (blink >> (6-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] &0x7f] |decimal); //显示小数点,把查表得到段码与小数点的段码与的结果送显示端口 else send_shift(led_stroke[led_buf[pos] &0x7f]); else send_shift(0xff); //pos位数码管不显示 LEDS_PORTO &= led_cs[pos]; //送出位选码 } /******************************************************************************* *函数原型: void scankey(keyret *kpd); *功能: 键盘扫描,返回上档键个数,上档键值,功能键个数,功能键值 *参数: *说明: *******************************************************************************/ void scankey(keyret *kpd) { uchar i,j; shut_dis(); //关显示 KEY_DDR = OUT; //定义数据端口为输出 KEY_PORTO |= KeyValue; //输出数据(输出检测码) KEY_DDR = IN; //定义数据端口为输入 i = (KEY_PORTI &KeyValue); //取出键盘位 if (i ! = KeyValue) //检测是否有键按下 { i |= ~KeyValue; //组成完整的字节 if (~i &RCtrl) //该键是上档键 { kpd->shiftcnt++; //上档键个数加1 ? ? //这里不对 for(j=0;j<6;j++) { if((0x01< { kpd->shiftval = j+1; //上档键值存入上档键值缓冲 ? ? } } } else { for(j=0;j<6;j++) { if((0x01< { kpd->funcnt++; //功能键个数加1 ? ? kpd->funval =j+1; //上档键值存入上档键值缓冲 ? ? } } } } KEY_DDR = OUT; //数据端口还原为输出 } /******************************************************************************* *函数原型: void key(); *功能: 键盘扫描,返回上档键个数,上档键值,功能键个数,功能键值 *参数: *说明: *******************************************************************************/ void key() { uchar krpt = RConti; static uchar keycnt; static uchar keyesc; keyret keytemp = { 0x00, 0x00, 0x00, 0x00 }; if (keydone) //上次按键任务已完成 { scankey(&keytemp); //扫描键盘 if (! keytemp.funcnt || keytemp.shiftcnt > 1) //功能键计数器为0或上档键个数多于1 { enflash = 1; //允许闪烁 // USART0_TransmitString("shiftcnt! "); keypre[0] = 0x00; //清零上次功能键和上档键缓冲 keypre[1] = 0x00; //清零 keyesc = 0x00; //键释放标志 清零 task = 0x00; //按键状态 标志为去抖阶段 keycnt = 0x00; //年龄计数器 清零 } else if (! keyesc) //键已释放 按下上挡键后按键释放标志请零 { // USART0_TransmitString("keyesc! "); if (keytemp.funcnt > 1) //有多于一个的功能键按下 keyesc = 1; //置位按键释放标志 //本次功能键值和上次不同或本次上档键值和上次不同且上次有上档键 else if (keytemp.funval ! = keypre[0] || keytemp.shiftval ! = keypre[1] &&keypre[1]) { keypre[0] = keytemp.funval; //用本次键值更新上次键值 keypre[1] = keytemp.shiftval; keycnt = 0x00; //年龄计数器复位 } else if (! keypre[1] && keytemp.shiftval) //2次功能键相同,上次无上档键本次有 keyesc = 1;//置位keyesc,屏蔽先按下功能键,再按下上档键这种按键组合 else { keycnt++; //2次功能键和上档键都相同 switch (task) { case 0: if (keycnt == N) { enflash = 1; keyprocess = 1; //键值处理 if ((keytemp.shiftcnt == 1) || ! (krpt >> (keytemp.funval - 1) &0x01)) keyesc = 1;//是一对复合键或该键不允许连击 else { task++; //按键状态转入重复的延缓阶段 keycnt = 0; //按键年龄清0 } } break; case 1: //重复的延缓阶段 if (keycnt == MaxRate)//按键年龄等于重复的延缓阶段 { enflash = 0; //不允许闪烁 keyprocess = 1; //进行键值处理 keycnt = 0; //按键年龄清0 task++; //按键转入重复状态 } break; case 2: //重复阶段 if (keycnt == MinRate)//重复时间到 { enflash = 0; //不允许闪烁 keyprocess = 1; //进行键值处理 keycnt = 0; //按键年龄清0 } break; } } } } } /******************************************************************************* *函数原型: void key1_handler(); *功能: 按键1处理 *参数: *说明: 正常工作模式下,按下按键1即进入设定状态,此时第一个数码管闪烁,同时对应led1 * 的指示灯亮。 设定模式下,按下按键1,在led1和led4之间循环切换选择被选中的数码 * 管闪烁,相应的指示灯亮 *******************************************************************************/ void key1_handler() { if (! keymark) //进入设定状态 { led_buf[0] = 0xfe; //点亮第一个led pb = &led_buf[1]; //pb指向第一个数码管 //blink = 0x80; //第一个数码
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 按键