/********************************************************
实验: PS2键盘实验
说明: 按PS2键盘上的按键,LCD1602显示PS2键盘的键码
CPU型号: ATMEGA128A
晶振频率: 8MHZ
日期: 2011-3-12
联系方法: MCU.2000@163.com
********************************************************/
#include<iom128v.h>
#include<macros.h>
#include"scancodes.h"
#define uchar unsigned char
#define uint unsigned int
//**************************************************
//*****************LCD 1602引脚定义****************
//**************************************************
#define LCD_DATA_PORT PORTA //定义LCD的D0-D7所在端口
#define LCD_DATA_POUT DDRA=0xFF //定义LCD数据端口为输出
#define LCD_DATA_PIN DDRA=0x00 //定义LCD数据端口为输入(在读LCD状态时用到)
#define LCD_BUSY PINA & 0X80
#define LCD_Control_PORT PORTB //定义LCD的EN RW RS所在端口方便后面操作
#define LCD_Control_POUT DDRB|=(BIT(5)+BIT(6)+BIT(7))
#define LCD_Control_PIN DDRB&=~(BIT(5)+BIT(6)+BIT(7))
#define LCD_EN_1 PORTB|=BIT(7)
#define LCD_EN_0 PORTB&=~BIT(7)
//LCD读写控制引脚
#define LCD_RW_1 PORTB|=BIT(6)
#define LCD_RW_0 PORTB&=~BIT(6)
//LCD指令或数据选择引脚
#define LCD_RS_1 PORTB|=BIT(5)
#define LCD_RS_0 PORTB&=~BIT(5)
#define PS2_CTL_PIN DDRD &=~(BIT(2)+BIT(3))
//**************************************************
//******************PS2键盘引脚定义****************
//**************************************************
#define PS2_DAT_1 PORTD|=BIT(2);
#define PS2_CLK_1 PORTD|=BIT(3);
//**************************************************
//******************定义变量***********************
//**************************************************
uchar IntNum = 0; //中断次数计数
uchar KeyV; //键值
uchar DisNum = 0; //显示用指针
uchar Key_UP = 0; //Key_UP是键松开标识
uchar Shift = 0; //Shift是Shift键按下标识
uchar BF = 0; //标识是否有字符被收到
//用于清屏
const uchar Cls[] = {" "};
//产品编号
const uchar model_name[] = {" PS2 keyboard"};
//***********************************************
//函 数 名:Delay5Ms();
//入口参数:无
//出口参数:无
//函数作用:5毫秒延时函数
//说 明:
//***********************************************
void Delay5Ms(void)
{
uint TempCyc = 5552;
while(TempCyc--){;}
}
//***********************************************
//函 数 名:Delay400Ms();
//入口参数:无
//出口参数:无
//函数作用:400毫秒延时函数
//说 明:
//***********************************************
void Delay400Ms(void)
{
uchar TempCycA = 5;
uint TempCycB;
while(TempCycA--)
{
TempCycB=7269;
while(TempCycB--){;}
}
}
//***********************************************
//函 数 名:check_busy();
//入口参数:无
//出口参数:无
//函数作用:LCD读忙函数
//说 明:
//***********************************************
void check_busy(void)
{
LCD_DATA_PIN;
LCD_RS_0; //设置为指令
LCD_RW_1; //设置为读指令
while(1)
{
LCD_EN_1; //使能LCD
if(LCD_BUSY){break;} //PA7为零,说明所有操作已完成则是不忙状态
LCD_EN_0; //禁止LCD
}
LCD_EN_0; //禁止LCD
LCD_DATA_POUT; //设置RA口为输出口
}
//***********************************************
//函 数 名:WriteDataLCM(uchar data);
//入口参数:data
//出口参数:无
//函数作用:写LCD单个数据函数
//说 明:
//***********************************************
void WriteDataLCM(uchar data)
{
check_busy(); //等待忙标志结束
LCD_RS_1 ; //设置为数据
LCD_RW_0; //设置为写指令
LCD_EN_1; //使能LCD
Delay5Ms();
LCD_DATA_PORT = data; //写数据到RA端口
Delay5Ms();
LCD_EN_0; //禁止LCD
}
//***********************************************
//函 数 名:WriteCommandLCM(uchar command);
//入口参数:WDLCM,BuysC
//出口参数:无
//函数作用:写LCD指令函数
//说 明:
//***********************************************
void WriteCommandLCM(uchar command)
{
check_busy(); //等待忙标志结束
LCD_RS_0; //设置为指令
LCD_RW_0; //设置为写指令
LCD_EN_1; //使能LCD
Delay5Ms();
LCD_DATA_PORT= command; //写指令到RA端口
Delay5Ms();
LCD_EN_0; //禁止LCD
}
//***********************************************
//函 数 名:LCMInit();
//入口参数:无
//出口参数:无
//函数作用:LCD初始化函数
//说 明:
//***********************************************
void LCMInit(void)
{
LCD_DATA_PORT = 0;
WriteCommandLCM(0x38); //显示模式设置,开始要求每次检测忙信号
Delay5Ms();
WriteCommandLCM(0x08); //关闭显示
Delay5Ms();
WriteCommandLCM(0x01); //显示清屏
Delay5Ms();
WriteCommandLCM(0x06); //显示光标移动设置
Delay5Ms();
WriteCommandLCM(0x0F); //显示开及光标设置
Delay5Ms();
}
//***********************************************
//函 数 名:DisplayOneChar(uchar X, uchar Y, uchar DData);
//入口参数:X, Y, DData
//出口参数:无
//函数作用:按指定位置显示一个字符函数
//说 明:
//***********************************************
void DisplayOneChar(uchar X, uchar Y, uchar DData)
{
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
if (Y) X |= 0xC0; //当要显示第二行时地址码+0xC0;
X |= 0x80; //算出指令码
WriteCommandLCM(X); //发命令字
Delay5Ms();
WriteDataLCM(DData); //发数据
}
//***********************************************
//函 数 名:DisplayListChar(uchar X, uchar Y, const uchar *DData);
//入口参数:X, Y, *DData
//出口参数:无
//函数作用:按指定位置显示一串字符函数
//说 明:
//***********************************************
void DisplayListChar(uchar X, uchar Y, const uchar *DData)
{
uchar ListLength;
ListLength = 0;
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大 于1
while (DData[ListLength]>0x19) //若到达字串尾则退出
{
if (X <= 0xF) //X坐标应小于0xF
{
DisplayOneChar(X, Y, DData[ListLength]); //显示单个字符
ListLength++;
X++;
}
}
}
//***********************************************
//函 数 名:Decode(uchar ScanCode);
//入口参数:ScanCode
//出口参数:无
//函数作用:查找键盘代码函数
//说 明:如SHIFT+G为12H 34H F0H 34H F0H 12H,
// 也就是说shift的通码+G的通码+shift的
// 断码+G的断码
//***********************************************
void Decode(uchar ScanCode)
{
uchar TempCyc;
if (!Key_UP) //当键盘松开时
{
switch (ScanCode)
{
//当收到0xF0,Key_UP置1表示断码开始
case 0xF0 : Key_UP = 1; break;
//左 SHIFT