本帖最后由 yidou 于 2010-3-25 20:59 编辑
- /*******************************************
- 文件:PS2_KB.C
- 环境:编译为ICC AVR6.25A,仿真为AVR Studio4.10
- 硬件:ATMEGA16芯片
- 日期:2006年12月10日
- 功能:驱动开发板上的PS2接口,实现PS2键盘(支持第2套扫描码)
- 备注:参考《AVR系列单片机C语言编程与应用实例》(清华大学出版社)
- /******************************************/
#include <IOM16V.H> //包含型号头文件
#include <MACROS.H> //包含"位"操作头文件
#include <STDIO.H> //标准输入输出头文件
#include <AVR_PQ1A.H> //包含自定义常量头文件
#include "YJ1602.C"
#pragma interrupt_handler Int0:2 //外部中断0中断函数声明
#pragma data:code //将译码表放在FLASH
const uchar unshifted[][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
- };
const uchar shifted[][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
- };
#pragma data:data //将以后的变量放在RAM
void Decode(uchar scancode);//声明函数原型- uchar edge, bitcount,ascii=' '; //edge为0下降沿中断,为1上升沿中断
//bitcount为位计数值
//ascii为翻译后的ASCII码,初值为空格
/*******************************************- 函数名称: Init_kb
- 功 能: 初始化PS2函数
- 参 数: 无
- 返回值 : 无
- /********************************************/
void Init_kb(void)- {
- MCUCR = 2; //设置INT0为下降沿触发中断
- edge = 0; //0为下降沿中断标志,1为上升沿中断标志
- bitcount = 11; //每次11位数据,一个起始位(0),8个数据位,一个奇偶校验位,一个停止位(1)
- DDRD&=~BIT(PD2); //配置中断管脚为输入
- PORTD|=BIT(PD2); //使能中断管脚的上拉
- DDRA&=~BIT(PA0); //配置键盘数据输入口为输入
- PORTA|=BIT(PA0); //使能数据输入管脚的上拉
- SREG|=BIT(GLOBAL);//打开全局中断
- GICR|=BIT(EXTINT0);
- }
/*******************************************- 函数名称: Disp_ascii
- 功 能: 在1602液晶上显示键盘上的ASCII码
- 参 数: ascii--将要显示的ASCII码
- 返回值 : 无
- /********************************************/
void Disp_ascii(uchar ascii)- {
- LCD1602_gotoXY(1,2);
- LCD1602_sendstr("KEY_ASCII:");
- LCD1602_sendbyte(iDat,ascii);
- }
/*******************************************- 函数名称: Int0
- 功 能: 外部中断0的中断服务函数,上升沿中断读入11位数据,下降沿调用解码程序
- 参 数: 无
- 返回值 : 无
- /********************************************/
void Int0(void)- {
static uchar data; // 声明局部静态变量来保存扫描码
if (!edge) // 如果是下降沿触发中断- {
if(bitcount < 11 && bitcount > 2) //3到10位是数据,起始位,校验位和停止位忽略- {
- data = (data >> 1); //右移保存数据
if(PINA&0x01)- {
- data|=0x80; //存储一个'1'
- }
- }
- MCUCR=3; //设置INT0为上升沿触发中断
- edge=1; //设置上升沿中断标志
- }
else
//如果是上升沿触发中断- {
- MCUCR=2; //设置INT0为下降沿触发中断
- edge=0; //设置下降沿中断标志
if(--bitcount==0) //如果11位全部接收完毕- {
- Decode(data); //将扫描码翻译成ASCII码
- bitcount = 11; //重新设为11位数据
- }
- }
- }
/*******************************************- 函数名称: Decode
- 功 能:
- 参 数: scancode--需要翻译的扫描码
- 返回值 : 无
- /********************************************/
void Decode(uchar scancode)- {
static uchar up=0,shift=0; //up为通、断码标志,shift为shift键按下标志- uchar i;
if (!up) //已接收的11位数据是通码(up为0)- {
switch (scancode)//开始翻译扫描码- {
case 0xF0: //键盘释放标志(随后的一个字节是断码)- up=1; //设置up为断码标志
break;
case 0x12: //左shift键按下- shift=1; //设置shift为按下标志
break;
case 0x59: //右shift键按下- shift=1; //设置shift为按下标志
break;
default:
if(!shift) //如果shift键没有按下- { //查找unshifted表,表中左列是扫描码,右列是对应的ASCII码
for(i=0;unshifted[0]!=scancode&&unshifted[0];i++);
if(unshifted[0]==scancode)- {
- ascii=unshifted[1];
- }
- }
else
//如果shift键按下- { //查找shifted表
for(i=0;shifted[0]!=scancode&&shifted[0];i++);
if(shifted[0]==scancode)- {
- ascii=shifted[1];
- }
- }
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码
- 参 数: 无
- 返回值 : 无
- /********************************************/
void main(void)- {
- Board_init( ); //初始化开发板
- LCD1602_initial( ); //初始化1602
- Init_kb(); //初始化PS2键盘接口
while(1)- {
- Disp_ascii(ascii); //显示翻译后的ASCII码
- }
}
来源:http://read.pudn.com/downloads93/sourcecode/embed/362725/19_PS2/PS2_KB.C__.htm |