AVR单片机 实验五 矩阵键盘扫描实验

AVR单片机 实验五 矩阵键盘扫描实验

1 实验目的
掌握矩阵式键盘扫描方法与定时器中断原理,以实现多键输入判别及4位数码管显示的应用。
2 实验内容
(1) 实现矩阵式键盘扫描。
(2) 设定定时中断,实现按键除抖动作,并显示于数码管。
实验电路:

AVR单片机 实验五 矩阵键盘扫描实验
AVR单片机 实验五 矩阵键盘扫描实验
AVR单片机 实验五 矩阵键盘扫描实验

3 实现依 Keypad (4 x 4键盘) 所按下的键值 (‘0’~‘F’) 先后顺序由右至左插入显示于4个数码管上; 起始时,所有七段灯皆不显示。请写出相关代码。
#include <iccioavr.h>
#include <macros.h>
#include <stdio.h>
#include <iom16v.h>
void Show();
char Keyscan();
unsigned char seg[16]={0xf9,0xa4,0xb0,0x88, 0x99,0x92,0x82,0x83, 0xf8,0x80,0x90,0xc6, 0x86,0xc0,0x8e,0xa1}; //段码09,AF
unsigned char buf[4]={0xff,0xff,0xff,0xff}; //显示数组内容预设不亮值
unsigned char en[4]={ 0xf9,0xc0,0xa4,0xf8 }; //4位数码管扫描码
unsigned char scan[4]={0x7f,0xbf,0xdf,0xef}; //键盘扫描码
unsigned char cmp[16]={0x77,0x7b,0x7d,0x7e, 0xb7,0xbb,0xbd,0xbe, 0xd7,0xdb,0xdd,0xde, 0xe7,0xeb,0xed,0xee};
unsigned char i,j,key=0x0f; //键值起始值
unsigned char ix=0,si=0,flg=0; //数码管扫描指针﹑按键扫描指针﹑计时终了标志
int cnt=0; //消抖计数变量

void main()
{
DDRA=0xff; //设PA0~PA7全部为输出
PORTA=0xff; //令数码管所有段灯皆不亮
DDRB=0xff; //设PB0~PB3为输出
PORTB=0xff; //关闭所有数码管
DDRD=0xf0; //设PD0~PD3为输入, PD4~PD7为输出
PORTD=0xff; //设PD4~PD7起始为"Hi", PD0~PD3上拉电阻有效
GICR=0x00; //禁止任何外部中断
TCCR0=0x0c; //设T/C0为CTC模式,分频系数为256
TCNT0=0; //T/C0计数器内容清0
OCR0=31; //设置OCR0以产生约1ms的定时
TIMSK=0x02; //允许T/C0的比较匹配中断
SREG|=0x80; //致能中断

do{
key=Keyscan(); //调用键盘扫描函数
if(key!=0x0f)
{
for(i=0;i<=15;i++) //若有按键被按下,逐一检查键值
{
if(keycmp[i]) //比较键值
{
if (cnt == 0 && flg) {
for (j = 3; j >= 1; j–) buf[j] = buf[j-1];
buf[0] = seg[i];
}
break;
}
}
}
if(flg
1) //1ms定时标志是否设定?
{
Show(); //调用数码管动态扫描显示函数
flg=0; //解除1ms定时标志
}
}while(1);
}
char Keyscan( ) //键盘扫描函数
{
unsigned char val=0x0f,x,y;
if(cnt==0) //若未在按键抖动状态下
{
for (x = 0; x < 4; x++) {
PORTD = scan[x];
for (y = 0; y < 4; y++) {
if ((PIND & (1 << y)) == 0) {
cnt = 350;
val = PIND;
break;
}
}
if (val != 0x0f) break;
}
return(val); //返回键值
}
}

void Show() //数码管动态显示扫描函数
{
PORTB=PORTB|0x0f; //关闭所有数码管
PORTA=buf[ix]; //送出段码至数码管
PORTB=PORTB&en[ix]; //显示该位数码管
ix++; //数码管位指针切换至下一位
if(ix>3)
ix=0; //若已到最后1位, 则数码管位指针清0
}

#pragma interrupt_handler TC0_SUB: 20 //T/C0比较匹配中断服务程序
void TC0_SUB()
{
if(cnt>0)
cnt=cnt-1; //消抖计数器减1
flg=1; //设置1ms标志位,以表示1ms已终了
}