单片机矩阵按键定时器消抖程序源码
下面是矩阵键盘的电路图,矩阵键盘是接在p2口的.
下面是单片机部分的图,数码管显示等完整的原理图可以从http://www.51hei.com/f/ks51.pdf 这里下载
下面是程序源码:
/********矩阵按键定时器消抖**************/
/**
*时间:2014年3月18日20:27:23
*作者:寒竹子
*工程写法:用定时器为按键消抖不占用cpu的时间
**/
#include
typedef unsigned int uint;
typedef unsigned char uchar;
//138
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
//KeyIn
sbit KeyIn1 = P2^4;
sbit KeyIn2 = P2^5;
sbit KeyIn3 = P2^6;
sbit KeyIn4 = P2^7;
//KeyOut
sbit KeyOut1 = P2^3;
sbit KeyOut2 = P2^2;
sbit KeyOut3 = P2^1;
sbit KeyOut4 = P2^0;
//数码管编码
uchar code table[] = {
0xC0, //"0"
0xF9, //"1"
0xA4, //"2"
0xB0, //"3"
0x99, //"4"
0x92, //"5"
0x82, //"6"
0xF8, //"7"
0x80, //"8"
0x90, //"9"
0x88, //"A"
0x83, //"B"
0xC6, //"C"
0xA1, //"D"
0x86, //"E"
0x8E //"F"
};
uchar key = 0;
//16个按键初始化1
uchar keysta[4][4] =
{
{1, 1, 1, 1}, //K1 - K4
{1, 1, 1, 1}, //K5 - K8
{1, 1, 1, 1}, //K9 - K 12
{1, 1, 1, 1} //K13 - K16
};
//16个按键的备份值初始值1
uchar keybackup[4][4] = {
{1, 1, 1, 1},
{1, 1, 1, 1},
{1, 1, 1, 1},
{1, 1, 1, 1}
};
void keymatrixScan();
void timer0_init();
void refresh();
void HC138_init();
void main()
{
timer0_init();
HC138_init();
while (1)
{
keymatrixScan();
}
}
/********timer0 init*************/
void timer0_init()
{
TMOD |= 0x01;
TMOD &= 0xF1; //1111 0001,配置T0方式1
TH0 = 0xFC;
TL0 = 0x67;//1ms
TR0 = 1;//start T0
EA = 1; //open main int
ET0 = 1;//open T0 int
}
/***********HC138 init*********/
void HC138_init()
{
ADDR3 = 1;
ENLED = 0;//使能U3
}
/***********刷新数码管************/
void refresh()
{
static uchar j = 0;//刷新数码管
P0 = 0xFF;//消隐
switch(j)
{
case 0: ADDR2 = 0; ADDR1 = 0; ADDR0 = 0;
break;
case 1: ADDR2 = 0; ADDR1 = 0; ADDR0 = 1;
break;
case 2: ADDR2 = 0; ADDR1 = 1; ADDR0 = 0;
break;
case 3: ADDR2 = 0; ADDR1 = 1; ADDR0 = 1;
break;
case 4: ADDR2 = 1; ADDR1 = 0; ADDR0 = 0;
break;
case 5: ADDR2 = 1; ADDR1 = 0; ADDR0 = 1;
break;
default:
break;
}
P0 = table[key]; //在此处送入显示的数据,很正常的显示出来,当放到while(1)中时会出现抖动
j++;
if (j >= 6)
{
j = 0;
}
}
/**********矩阵按键检测***********/
void keymatrixScan()
{
//16个按键检测
uchar i = 0, j = 0;
for (i = 0; i < 4; i++) //4行
{
for (j = 0; j < 4; j++) //4列
{
if (keysta[j] != keybackup[j]) //检测第i行第j列按键是否有动作
{
if (keybackup[j] == 0) //若第i行第j列的按键的前一个状态为0,则由0-1,即按键弹起
{
key = i * 4 + j;//按键定位
}
//备份当前按键的值,以备下一次比较
keybackup[j] = keysta[j];
}
}
}
}
/**********timer0 int****************/
void timer0_int() interrupt 1 using 3
{
static uchar keybuf[4][4] = {
{0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF}
};//16个按键的扫描缓冲区
static uchar keyout = 0;//按键的列,即KeyOut1 - KeyOut4
uchar i = 0;
TH0 = 0xFC;
TL0 = 0x67; //1ms
refresh();
//扫描第keyout列的按键的值
keybuf[keyout][0] = (keybuf[keyout][0] < 1) | KeyIn1;//将按键1的扫描值存入keybuf中
keybuf[keyout][1] = (keybuf[keyout][1] < 1) | KeyIn2;
keybuf[keyout][2] = (keybuf[keyout][2] < 1) | KeyIn3;
keybuf[keyout][3] = (keybuf[keyout][3] < 1) | KeyIn4; //每1ms扫描一列,4ms扫描四列,共扫描四位,设定扫描16ms,即每个按键扫描4次
//更新消抖后按键的值
for (i = 0; i < 4; i++) //4行, 一列4个按键
{
if ((keybuf[keyout] & 0x0F) == 0x00) //按键的缓冲区的低四位都是0,因为16ms只扫描了4次,移入了四位状态值
{
keysta[keyout] = 0;//按键按下
}
else if ((keybuf[keyout] & 0x0F) == 0x0F) //按键的缓冲区的第四位都是1
{
keysta[keyout] = 1;//第keyout列第i行的按键弹起
}
}
//列++
keyout++;
//keyout 0-3
/*if (keyout >= 4)
keyout = 0;
*/
keyout &= 0x03;//当keyout到4则会等于3
//通过keyout列数选中列
switch(keyout)
{
case 0: KeyOut1 = 0; KeyOut4 = 1; KeyOut2 = 1; KeyOut3 = 1; //选中第一列,开发板上的第一行
break;
case 1: KeyOut2 = 0; KeyOut1 = 1; KeyOut3 = 1; KeyOut4 = 1;
break;
case 2: KeyOut3 = 0; KeyOut1 = 1; KeyOut2 = 1; KeyOut4 = 1;
break;
case 3: KeyOut4 = 0; KeyOut1 = 1; KeyOut2 = 1; KeyOut3 = 1;
break;
default:
break;
}
}
单片机矩阵按键定时器消抖程 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)