📄 mykey.c
字号:
/* 此函数每次执行都产生一个扫描信号(四位,任一时刻只有一位为 '0')加于列线上,同时读取行线上的电平值以判断扫描信号为 '0'的列上是否有键按下。如果此函数被执行4次后,即经过一轮扫描后,没有发现按键被按下,则输出16(键盘值从0到15,因此16用以指示无效值)。另外,用LastNum存上次读到的按键值,CurrentNum存本次读到的按键值,如果两次读到的按键值同,亦输出16 。换句话说,无论用户按一个键按多久,都只返回一个有效值,当成一次按键。*/
/*注:此函数一般用于定时器中断中或主循环中,即本函数需隔一定的时间(10ms为宜)被执行一次,才能起到键盘扫描的作用。*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <inttypes.h> //程序头文件
uint8_t Keyboard(void) //键盘扫描函数,返回一个键值或16(无效值)
{
static uint8_t ScanCode=0xF7,TempNum=16,LastNum=16,CurrentNum=16,Times=0;
switch(ScanCode) // 扫描信号
{
case 0xF7:ScanCode=0xFB; break; // 扫描信号:0111→1011
case 0xFB:ScanCode=0xFD; break; // 1011→1101
case 0xFD:ScanCode=0xFE; break; // 1101→1110
case 0xFE:ScanCode=0xF7; break; // 1110→0111
default: ScanCode=0xF7; break;
}
/*在main()函数里需将DDRC设成0x0F,即PC7~PC4为输入,PC3~PC0为输出。
下面PORTC=ScanCode意味着,将PC7~PC4设为带上拉功能的输入,
而PC3~PC0输出扫描信号。*/
PORTC=ScanCode;
switch(PINC) // 解读行列电平值与按键值的关系
{
/*TempNum记录读到的键值,由于此键值需经进一步处理,
所以是暂时数值(TempNum)。Times用以记录没有读到有效键值的次数,
如果次数达到4次(即扫描一轮后没有发现有效键值),
就表示没有键按下。*/
case 0xE7:TempNum=0;Times=0;break;
case 0xD7:TempNum=1;Times=0;break;
case 0xB7:TempNum=2;Times=0;break;
case 0x77:TempNum=3;Times=0;break;
case 0xEB:TempNum=4;Times=0;break;
case 0xDB:TempNum=5;Times=0;break;
case 0xBB:TempNum=6;Times=0;break;
case 0x7B:TempNum=7;Times=0;break;
case 0xED:TempNum=8;Times=0;break;
case 0xDD:TempNum=9;Times=0;break;
case 0xBD:TempNum=10;Times=0;break;
case 0x7D:TempNum=11;Times=0;break;
case 0xEE:TempNum=12;Times=0;break;
case 0xDE:TempNum=13;Times=0;break;
case 0xBE:TempNum=14;Times=0;break;
case 0x7E:TempNum=15;Times=0;break;
default:{
Times++;
if (Times==4)
{ TempNum=16;
Times=0;
}
}break;
}
/*对读到的键值进行处理,每个有效键值仅返回一次*/
LastNum=CurrentNum;
CurrentNum=TempNum;
if (CurrentNum==LastNum) return(16);//相同的输入,认为是一次输入,这次返回无效值
else return(CurrentNum); //返回键值
}
SIGNAL(SIG_OVERFLOW0) //定时器0
{ uint8_t Keynum=16;
TCNT0=0xB2;
Keynum=Keyboard(); //读取键盘值
if(Keynum!=16) //如果不是无效值,将它写入B端口显示
switch(Keynum)
{ case 0:PORTB=0x3f;break;
case 1:PORTB=0x06;break;
case 2:PORTB=0x5b;break;
case 3:PORTB=0x4f;break;
case 4:PORTB=0x66;break;
case 5:PORTB=0x6d;break;
case 6:PORTB=0x7d;break;
case 7:PORTB=0x07;break;
case 8:PORTB=0x7f;break;
case 9:PORTB=0x6f;break;
case 10:PORTB=0x77;break;
case 11:PORTB=0x7c;break;
case 12:PORTB=0x39;break;
case 13:PORTB=0x5e;break;
case 14:PORTB=0x79;break;
case 15:PORTB=0x71;break;
default:PORTB=0x00;break;
}
PORTD=0x3e; //用最后一个数码管
}
int main(void)
{
DDRC=0x0F; //初始化,PC7~PC4输入,PC3~PC0输出
PORTC=0xFF; //上拉及其输出值
DDRD=0xFF; //输出
PORTD=0x00; //初值
DDRB=0xFF;
PORTB=0x00;
TCCR0=5;
TCNT0=0xB2;
TIMSK=(1<<TOIE0);//开中断
sei();
for (;;) //死循环,等待信号变化
{}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -