📄 keyboard.c
字号:
#include <mega16.h>
// Standard Input/Output functions
#include <stdio.h>
bit F_DATA;
void Decode1(unsigned char scancode);
/*******************************************
文件:KeyBoard.C
环境:编译为CodeVision AVR
11.0592M日工晶振,串口通信速率为9600
硬件:ATMEGA16芯片
功能:实现PS2键盘(支持第2套扫描码)
备注:参考《AVR系列单片机C语言编程与应用实例》(清华大学出版社)
PD.2,INT0为时钟信号输入脚,PD.3为数据输入脚? 作者:邹家义
日期:2008年11月8日,15点29整理
使用扫描做
/******************************************/
const unsigned char unshifted[65][2] = //shift键没按下译码表
{
0x0e,'`',
0x15,'q',
0x16,'1',
0x1a,'z',
0x1b,'s',
0x1c,'a',
0x1d,'w',
0x1e,'2',
0x21,'c',
0x22,'x',
0x23,'d',
0x24,'e',
0x25,'4',
0x26,'3',
0x29,' ',
0x2a,'v',
0x2b,'f',
0x2c,'t',
0x2d,'r',
0x2e,'5',
0x31,'n',
0x32,'b',
0x33,'h',
0x34,'g',
0x35,'y',
0x36,'6',
0x39,',',
0x3a,'m',
0x3b,'j',
0x3c,'u',
0x3d,'7',
0x3e,'8',
0x41,',',
0x42,'k',
0x43,'i',
0x44,'o',
0x45,'0',
0x46,'9',
0x49,'.',
0x4a,'/',
0x4b,'l',
0x4c,';',
0x4d,'p',
0x4e,'-',
0x52,'\'',
0x54,'[',
0x55,'=',
0x5b,']',
0x5d,'\\',
0x61,'<',
0x69,'1',
0x6b,'4',
0x6c,'7',
0x70,'0',
0x71,'.',
0x72,'2',
0x73,'5',
0x74,'6',
0x75,'8',
0x79,'+',
0x7a,'3',
0x7b,'-',
0x7c,'*',
0x7d,'9',
0,0
};
flash unsigned char shifted[65][2]= //shift键按下译码表
{
0x0e,'~',
0x15,'Q',
0x16,'!',
0x1a,'Z',
0x1b,'S',
0x1c,'A',
0x1d,'W',
0x1e,'@',
0x21,'C',
0x22,'X',
0x23,'D',
0x24,'E',
0x25,'$',
0x26,'#',
0x29,' ',
0x2a,'V',
0x2b,'F',
0x2c,'T',
0x2d,'R',
0x2e,'%',
0x31,'N',
0x32,'B',
0x33,'H',
0x34,'G',
0x35,'Y',
0x36,'^',
0x39,'L',
0x3a,'M',
0x3b,'J',
0x3c,'U',
0x3d,'&',
0x3e,'*',
0x41,'<',
0x42,'K',
0x43,'I',
0x44,'O',
0x45,')',
0x46,'(',
0x49,'>',
0x4a,'?',
0x4b,'L',
0x4c,':',
0x4d,'P',
0x4e,'_',
0x52,'"',
0x54,'{',
0x55,'+',
0x5b,'}',
0x5d,'|',
0x61,'>',
0x69,'1',
0x6b,'4',
0x6c,'7',
0x70,'0',
0x71,'.',
0x72,'2',
0x73,'5',
0x74,'6',
0x75,'8',
0x79,'+',
0x7a,'3',
0x7b,'-',
0x7c,'*',
0x7d,'9',
0,0
} ;
unsigned char edge, bitcount,ascii1=' '; //edge为0下降沿中断,为1上升沿中断
//bitcount为位计数值
//ascii为翻译后的ASCII码,初值为空格
/*******************************************
函数名称: Init_kb
功 能: 初始化PS2函数
参 数: 无
返回值 : 无
/********************************************/
void Init_kb()
{
DDRA=0xff;
DDRB=0xff;
DDRD=0xff;
edge = 0; //0为下降沿标志,1为上升沿标志
bitcount = 11; //每次11位数据,一个起始位(0),8个数据位,一个奇偶校验位,一个停止位(1)
DDRD.2=0; //配置中断管脚为输入
PORTD.2=1; //使能中断管脚的上拉 正常为高电平
DDRD.3=0; //配置键盘数据输入口为输入
PORTD.3=1; //使能数据输入管脚的上拉
}
/*******************************************
函数名称: Decode
功 能:
参 数: scancode--需要翻译的扫描码
返回值 : 无
/********************************************/
void Decode1(unsigned char scancode)
{
static unsigned char up=0,shift=0; //up为通、断码标志,shift为shift键按下标志
unsigned char i;
if (!up) //已接收的11位数据是通码(up为0)
{
switch (scancode)//开始翻译扫描码
{
case 0xF0: //键盘释放标志(随后的一个字节是断码)
up=1; //设置up为断码标志
break;
case 0x12: //左shift键按下
shift=1; //设置shift为按下标志 //如果CAPLOCK键按下,按下shift键后,读到的为unshift码,小写字母
break;
case 0x59: //右shift键按下
shift=1; //设置shift为按下标志
break;
default:
if(!shift) //如果shift键没有按下
{ //查找unshifted表,表中左列是扫描码,右列是对应的ASCII码
for(i=0;unshifted[i][0] !=scancode&&unshifted[i][0];i++); //当i>64时,即查完后scancode&&unshifted[i][0]==0,
if(unshifted[i][0]==scancode) //且unshifted[i][0]==0,就会跳出循环//理解错误,本身就是这个意思? { //此句可用unshifted[i][0] !=scancode&&(unshifted[i][0]==0);
ascii1=unshifted[i][1]; //或unshifted[i][0] !=scancode&&(i<65);
printf("%c",ascii1); //可以在这里设置一个标志,有数据输入了,主程序中读ASCII1即可
}
}
else //如果shift键按下
{ //查找shifted表
for(i=0;shifted[i][0] != scancode && shifted[i][0];i++);
if(shifted[i][0]==scancode)
{
ascii1=shifted[i][1];
printf("%c",ascii1);
}
}
break;
}
}
else //已接收的11位数据是断码(up为1)
{ //这是断码处理程序,和通码处理是一样的
up = 0; //将断码标志复位
switch (scancode) //检测shift键释放
{
case 0x12 : //左shift键
shift = 0;
break;
case 0x59 : //右shift键
shift = 0;
break;
default:
break;
}
}
}
/*******************************************
函数名称: main
功 能: 实现PS2键盘的驱动,在1602液晶上显示键盘上的ASCII码
参 数: 无
返回值 : 无
/********************************************/
KEY_CHULI()
{ static unsigned char data1; // 声明局部静态变量来保存扫描码
if (!edge) // 如果是下降沿触发中断
{
if(bitcount < 11 && bitcount > 2) //3到10位是数据,起始位,校验位和停止位忽略
{
data1 = (data1 >> 1); //右移保存数据
if(PIND.3)
{
data1|=0x80; //存储一个'1',如果传输的是“1”,最高位置1
} //因为PS2协议是从低位到高位传输的,所以每传输一位,都放在最左边,传输之前先右移
}
// MCUCR=3; //设置INT0为上升沿触发中断
edge=1; //设置上升沿中断标志
}
else //如果是上升沿触发中断,11位传完后要解码
{
// MCUCR=2; //设置INT0为下降沿触发中断
if(PIND.2==1)
edge=0; //设置下降沿中断标志
if(--bitcount==0) //如果11位全部接收完毕
{
Decode1(data1); //将扫描码翻译成ASCII码
bitcount = 11; //重新设为11位数据
}
}
}
/*******************************************
函数名称: main
功 能: 实现PS2键盘的驱动,在1602液晶上显示键盘上的ASCII码
参 数: 无
返回值 : 无
/********************************************/
void main(void)
{
F_DATA=1;
// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud rate: 9600
UCSRA=0x00;
UCSRB=0x18;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x47;
Init_kb(); //初始化PS2键盘接口
printf("OK,GOOD!\n");
while(1)
{
// Disp_ascii(ascii1); //显示翻译后的ASCII码
if(PIND.2!=F_DATA)
{
F_DATA=PIND.2;
KEY_CHULI();
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -