×
单片机 > 单片机程序设计 > 详情

AVR 编程之矩阵键盘

发布时间:2020-08-27 发布时间:
|
#include   

#include

#define uchar unsigned char  
#define uint  unsigned int
uchar const table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,
0x77,0x7c,0x39,0x5e,0x79,0x71,0X00};// 显示段码值0123456789abcdef
void main()
{

uchar key=0;
uchar i=0;
DDRC|=BIT(7);
PORTC|=BIT(7);
DDRA=0XFF;
PORTA=0X00;
DDRB=0XFF;

while(1)
{
if(key_press())
key=keyscan();


ledshow(key,0);


}
}
uchar key_press()
{
uchar i;
DDRD=0XFF;
PORTD=0X0F;
DDRD=0XF0;
i=PIND;

if(i!=0X0F)
{
DDRD=0XFF;
return 1;
}
else
{
DDRD=0XFF;
return 0;
}
}


uchar keyscan()
{
uchar i,j,rkey;
delay (30);
if(key_press)
{
PORTD=0XF0;//先确定所在列,列拉高电平,行低电平
DDRD=0X0F;
//delay(1);
asm("NOP");
i=PIND;
switch(i)
{

case 0X70:rkey=0;break;
case 0XB0:rkey=1;break;
case 0XD0:rkey=2;break;
case 0XE0:rkey=3;break;
default:rkey=16;

}

PORTD=0X0F;//然后确定行,行拉高列拉低
DDRD=0XF0;
//delay(1);
asm("NOP");
j=PIND;
switch(j)
{
case 0X07:rkey+=12;break;
case 0X0B:rkey+=8;break;
case 0X0D:rkey+=4;break;
case 0X0E:rkey+=0;break;
default:rkey=16;
}

}
while(key_press());
return rkey;

}

void ledshow(int num,unsigned int i)
{
PORTA=i;
PORTB=table[num];
}

void delay(int ms)
{
  unsigned int i,j;
 for(i=0;i     {
    for(j=0;j<142;j++);
       }

}

 

注:读PIND前一定要加一个asm("NOP");或者先短暂延时,不然读不到正确的值!

DATASHEET:

不论如何配置DDxn,都可以通过读取PINxn 寄存器来获得引脚电平。如Figure 23 所示,
PINxn 寄存器的各个位与其前面的锁存器组成了一个同步器。这样就可以避免在内部时钟
状态发生改变的短时间范围内由于引脚电平变化而造成的信号不稳定。其缺点是引入了
延迟。Figure 24 为读取引脚电平时同步器的时序图。最大和最小传输延迟分别为tpd,max
和tpd,min。

下面考虑第一个系统时钟下降沿之后起始的时钟周期。当时钟信号为低时锁存器是关闭
的;而时钟信号为高时信号可以自由通过,如图中SYNC LATCH 信号的阴影区所示。时
钟为低时信号即被锁存,然后在紧接着的系统时钟上升沿锁存到PINxn 寄存器。如tpd,max
和tpd,min 所示,引脚上的信号转换延迟界于? ~ 1? 个系统时钟。
如Figure 25 所示,读取软件赋予的引脚电平时需要在赋值指令out 和读取指令in 之间有
一个时钟周期的间隔,如nop 指令。 out 指令在时钟的上升沿置位SYNC LATCH 信号。
此时同步器的延迟时间tpd 为一个系统时钟。

 



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
采用AT89C2051的数字可调稳压电源单片机源程序