4x4矩阵键盘工作原理及扫描程序_AVR单片机扫描4X4矩阵键盘并数码管显示程序

/*

program name :   keyboard ;

功能描述 :  扫描16个按键(4X4),并把键值显示在数码管上(两位);

要点 :  在扫描按键时运用了比较复杂的两个for()循环嵌套式

扫描方案,大大减少了程序量,循环嵌套方案让我纠结了好久,

键值有0~9,上,下,左,右,确认,清零;

体会:  又一个里程碑,泪奔啊...我似乎成了 代码男神  啊...;

实验用时:  约等于14小时(每天2小时X7天);

完成时间: 2013-11-19 23:58:22

*/

#include

#include

#define uint8  unsigned char      //宏定义8位数据类型;

#define uint16 unsigned int       //宏定义16位数据类型;

//  0 , 1  ,  2  , 3  , 4  , 5  , 6  ,

uint8 ak[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,

//    7  , 8  , 9 , 上  , 下   左 , 右  ;

0x07,0x7f,0x6f,0x62 ,0x54,0x21,0x0c};

uint8  ge=8,shi=8 ,si=0;

void bit(uint8 h)    //数码管位选使能函数;

{

PORTB|=0X02;   //数码管位选置1(透明状态);

if(h==0)

{

PORTB&=0XFD;   //清零(锁存状态);

}

}

void dat(uint8 u)   //数码管数据使能函数;

{

PORTB|=0X01;

if(u==0)

{

PORTB&=0XFE;

}

}

void buzz(uint8 k)    //蜂鸣器函数;

{

if(k==0)

{

PORTC&=~(0X80);

}

else  PORTC|=0X80;

}

void delay(uint8 j)          //1=1000个计数周期;

{

uint16  h=0;

while(j--)

{

for(h=0;h<1000;h++);

}

}

void mega16()       //初始化各个IO口;

{

DDRA=0XFF;    //PA输出;

DDRB=0XFF;    //PB输出;

PORTA=0X00;   //PA 输出全0;

delay(1);     //延时一下,1000个计数周期;

bit(0);          //数码管共阴极全零;

PORTA=0X3F;    //数码管数据口装载数据显示0;

PORTB=1<<2;    //打开led流水灯灯;

dat(0);        //锁存数码管数据口数据,八个数码管显示0;

delay(30);    //延时一下;

DDRD=0X0F;   //PD口高四位输入,第四位输出;

PORTD=0XFF;  //PD输入口内部上拉,输出口输出全1;

DDRC=0XFF;   //PC口全部输出模式;

PORTC=0X00;   //PC口输出全零;

}

void led()

{

static uint8 g=0;

PORTA=0Xff;  //向数码管输入显示数据时,必先将共阴极全部置一,

//否则数码管会出现阴影;

bit(0);     //八个数码管共阴极置一(低电平有效);

switch(g)

{  case 0:  PORTA=ak[ge] ;dat(0);PORTA=0XFE;break;//数码管个位;

case 1:  PORTA=ak[shi];dat(0);PORTA=0XFD;break; //数码管十位;

default: break;   //否则...

}

bit(0);

g++;

if(g==2)

{

g=0;

}

}

shu(uint8 c)

{

if(c<=2) {c++;}  //1~3;

else if(c==3) {ge=10;shi=10; return 0;}   //上;

else if(c==11){ge=c ; shi=c; return 0;}   //下;

else if(c==7) {ge=12,shi=12; return 0;}   //左;

else if(c==15) {ge=13,shi=13; return 0;}   //右;

else if(c==13){return 0;}      //enter 确认;  ;

else if(c==14){ge=0; shi=0;  return 0;}  //清零;

else if((c>=8)&&(c<=10)){c-=1;}  //7~9;

else if(c==12){ge=0;return 0;}

else { ;}    //4~6;

ge=c; shi=0;

}

key()

{

uint8  i=0 ,y=0,temp=0x10 ,v=0,ke=0 ,en[]={0xfe,0xfd,0xfb,0xf7};

//  temp用于检测每一行某个键是否按下; en数组是四列检测;

for(v=0;v<4;v++)     //v每加一代表检测一列;

{

PORTD=en[v];     //检测四列;

temp=0x10;

for(y=0;y<4;y++)    //y每加一,代表检测一列中的一个按键;

{

if((PIND&temp)==0)    //如果有键被按下,进入;

{

for(i=0;i<250;i++){led();}   //去抖延时并且扫描数码管;

if((PIND&temp)==0)        //再次确认有键被按下;

{

buzz(1);      //蜂鸣器开;

for(i=0;i<200;i++){led();}   //鸣响延时;

for(i=0;i<200;i++){led();}   //鸣响延时;

buzz(0);      //蜂鸣器关;

//===============生成键值部分================

if(v==1)y+=3;       //检测到第二行;        //

else if(v==2)y+=6;  //检测到第三行;        //

else if(v==3)y+=9;  //检测到第四行;        //

else {;}          //检测到第一行;        //

ke=v+y;    //生成键值;                     //

//===========================================

shu(ke);    // 发送键值;

while((PIND&temp)==0)led();   //等待按键弹起;

for(i=0;i<250;i++){led();}    //等待一下;

while((PIND&temp)==0)led();   //再次确认一下按键是否弹起;

return 0;    //结束函数;

}

}

temp=temp<<1;  //左移一下代表检测下一个按键;

}

}

}

void main(void)

{

mega16();  //初始化各个IO口;

buzz(1);   //蜂鸣器开;

delay(15); //延时1.5万计数周期;

buzz(0);   //蜂鸣器关;

PORTA=0xff;   //载入全1;

bit(0);       //把全1数据锁存在数码管共阴极(数码管灭);

delay(15);   //延时1.5万计数周期;

while(1)

{

led();  //扫描数码管;

key();  //扫描键盘;

}

}


版权声明:本文为weixin_30446969原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。