资讯详情

AVR单片机扫描4X4矩阵键盘并数码管显示程序

/* program name : keyboard ; 功能描述 : 扫描16个按键(4X4),并把键值显示在上(两位); 要点 : 在扫描按键时运用了比较复杂的两个for()循环嵌套式 扫描方案,大大减少了程序量,循环嵌套方案让我纠结了好久, 键值有0~9,上,下,左,右,确认,清零; 体会: 又一个里程碑,泪奔啊...我似乎成了 代码男神 啊...; 实验用时: 约等于14小时(每天2小时X7天); 完成时间: 2013-11-19 23:58:22 */ #include <iom16v.h> #include <macros.h>

#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口; {

A=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(); //扫描; } }

-电子元器件采购网(www.ruidan.com)是本土元器件目录分销商,采用“小批量、现货、样品”销售模式,致力于满足客户多型号、高质量、快速交付的采购需求。 自建高效智能仓储,拥有自营库存超过50,000种,提供一站式正品现货采购、个性化解决方案、选型替代等多元化服务。
锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台