51单片机PS2键盘解码实验--C51源代码

发布者:温雅如风最新更新时间:2019-02-19 来源: eefocus关键字:51单片机  PS2键盘  解码实验  C51 手机看文章 扫描二维码
随时随地手机看文章

#include

#include "KBCODE.H"

#define LCM_RS    P2_0

#define LCM_RW    P2_1 //定义LCD引脚

#define LCM_E     P2_2

#define LCM_Data  P0

#define Busy 0x80 //用于检测LCM状态字中的Busy标识

#define Key_Data  P3_2 //定义Keyboard引脚

#define Key_CLK   P3_3

void LCMInit(void);

void DisplayOneChar(unsigned char X,unsigned char Y,unsigned char DData);

void DisplayListChar(unsigned char X,unsigned char Y,unsigned char code *DData);

void Delay5Ms(void);

void Delay400Ms(void);

void Decode(unsigned char ScanCode);

void WriteDataLCM(unsigned char WDLCM);

void WriteCommandLCM(unsigned char WCLCM,BuysC);

unsigned char ReadStatusLCM(void);

unsigned char code cdle_net[] = {"RICHMCU PS2 TEST"};

unsigned char code email[] = {"WWW.RICHMCU.COM"};

unsigned char code Cls[] =   {"                "};

static unsigned char IntNum = 0; //中断次数计数

static unsigned char KeyV; //键值

static unsigned char DisNum = 0; //显示用指针

static unsigned char Key_UP=0, Shift = 0;//Key_UP是键松开标识,Shift是Shift键按下标识

static unsigned char BF = 0; //标识是否有字符被收到

 

void main(void)

{

    unsigned char TempCyc;

 

    Delay400Ms(); //启动等待,等LCM讲入工作状态

    LCMInit(); //LCM初始化

 

    DisplayListChar(0, 0, cdle_net);

    DisplayListChar(0, 1, email);

    for(TempCyc=0; TempCyc<10; TempCyc++) {

        Delay400Ms(); //延时

    }

    DisplayListChar(0, 1, Cls);

 

    IT1 = 0; //设外部中断1为低电平触发

    EX1 = 1; //开中断

    EA = 1;

 

    while(1) {

        if(BF)

            Decode(KeyV);

        else {

            EA = 1; //开中断

        }

    }

}

 

//写数据

void WriteDataLCM(unsigned char WDLCM)

{

    ReadStatusLCM(); //检测忙

    LCM_Data = WDLCM;

    LCM_RS = 1;

    LCM_RW = 0;

    LCM_E = 0; //若晶振速度太高可以在这后加小的延时

    LCM_E = 0; //延时

    LCM_E = 1;

}

 

//写指令

void WriteCommandLCM(unsigned char WCLCM,BuysC) //BuysC为0时忽略忙检测

{

    if(BuysC) 

        ReadStatusLCM(); //根据需要检测忙

    LCM_Data = WCLCM;

    LCM_RS = 0;

    LCM_RW = 0;

    LCM_E = 0;

    LCM_E = 0;

    LCM_E = 1;

}

 

 

//读状态

unsigned char ReadStatusLCM(void)

{

    LCM_Data = 0xFF;

    LCM_RS = 0;

    LCM_RW = 1;

    LCM_E = 0;

    LCM_E = 1;

    while(LCM_Data & Busy); //检测忙信号

 

    return(LCM_Data);

}

 

void LCMInit(void) //LCM初始化

{

    LCM_Data = 0;

    WriteCommandLCM(0x38,0); //三次显示模式设置,不检测忙信号

    Delay5Ms();

    Delay5Ms();

    WriteCommandLCM(0x38,0);

    Delay5Ms();

    Delay5Ms();

    WriteCommandLCM(0x38,0);

    Delay5Ms();

    Delay5Ms();

 

    WriteCommandLCM(0x38,1); //显示模式设置,开始要求每次检测忙信号

    WriteCommandLCM(0x08,1); //关闭显示

    WriteCommandLCM(0x01,1); //显示清屏

    WriteCommandLCM(0x06,1); // 显示光标移动设置

    WriteCommandLCM(0x0F,1); // 显示开及光标设置

}

 

//按指定位置显示一个字符

void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData)

{

    Y &= 0x1;

    X &= 0xF; //限制X不能大于15,Y不能大于1

    if(Y)

        X |= 0x40; //当要显示第二行时地址码+0x40;

    X |= 0x80; //算出指令码

    WriteCommandLCM(X, 1); //发命令字

    WriteDataLCM(DData); //发数据

}

 

//按指定位置显示一串字符

void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData)

{

    unsigned char 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++;

        }

    }

}

 

//5ms延时

void Delay5Ms(void)

{

    unsigned int TempCyc = 5552;

    while(TempCyc--);

}

 

//400ms延时

void Delay400Ms(void)

{

    unsigned char TempCycA = 5;

    unsigned int TempCycB;

    while(TempCycA--) {

        TempCycB=7269;

        while(TempCycB--);

    }

}

 

void Keyboard_out(void) interrupt 2

{

    if[[IntNum > 0) && (IntNum < 9]] {

        KeyV >>= 1;//因键盘数据是低>>高,结合上一句所以右移一位

        if(Key_Data) {

            KeyV |= 0x80;//当键盘数据线为1时为1到最高位

        }

    }

    IntNum++;

    while(!Key_CLK);//等待PS/2CLK拉高

    if(IntNum > 10) {

        IntNum = 0;//当中断10次后表示一帧数据收完,清变量准备下一次接收

        BF = 1;//标识有字符输入完了

        EA = 0;//关中断等显示完后再开中断

    }

}

void Decode(unsigned char ScanCode) 

//注意:如SHIFT+G为12H 34H F0H 34H F0H 12H,也就是说shift的通码+G的通码+shift的断码+G的断码

{

    unsigned char TempCyc;

 

    if(!Key_UP) {//当键盘松开时

        switch(ScanCode) {

            case 0xF0 ://当收到0xF0,Key_UP置1表示断码开始

                Key_UP = 1;

                break;

            case 0x12:// 左 SHIFT

                Shift = 1;

                break;

            case 0x59:// 右 SHIFT

                Shift = 1;

                break;

            default:

                if(DisNum > 15) {

                    DisplayListChar(0,1,Cls);//清LCD第二行

                    DisNum = 0;

                }

            if(Shift == 1) {//如果按下SHIFT

                for(TempCyc = 0;(Shifted[TempCyc][0]!=ScanCode)&&(TempCyc<59); TempCyc++); //查表显示

                if(Shifted[TempCyc][0] == ScanCode) 

                {

                    DisplayOneChar(DisNum,1,Shifted[TempCyc][1]);

                }

                DisNum++;

            }

            else {//没有按下SHIFT

                for(TempCyc = 0; (UnShifted[TempCyc][0]!=ScanCode)&&(TempCyc<59);TempCyc++); //查表显示

                if(UnShifted[TempCyc][0] == ScanCode) {

                    DisplayOneChar(DisNum,1,UnShifted[TempCyc][1]);

                }

                DisNum++;

            }

            break;

        }

    }

    else {

        Key_UP = 0;

        switch(ScanCode) {//当键松开时不处理判码,如G 34H F0H 34H 那么第二个34H不会被处理

            case 0x12:// 左 SHIFT

                Shift = 0;

                break;

            case 0x59:// 右 SHIFT

                Shift = 0;

                break;

            default:

                break;

        }

    }

    BF = 0;//标识字符处理完了

}

unsigned char code UnShifted[61][2] = {

    0x1C, 'a',

    0x32, 'b',

    0x21, 'c',

    0x23, 'd',

    0x24, 'e',

    0x2B, 'f',

    0x34, 'g',

    0x33, 'h',

    0x43, 'i',

    0x3B, 'j',

    0x42, 'k',

    0x4B, 'l',

    0x3A, 'm',

    0x31, 'n',

    0x44, 'o',

    0x4D, 'p',

    0x15, 'q',

    0x2D, 'r',

    0x1B, 's',

    0x2C, 't',

    0x3C, 'u',

    0x2A, 'v',

    0x1D, 'w',

    0x22, 'x',

    0x35, 'y',

    0x1A, 'z',

    0x45, '0',

    0x16, '1',

    0x1E, '2',

    0x26, '3',

    0x25, '4',

    0x2E, '5',

    0x36, '6',

    0x3D, '7',

    0x3E, '8',

    0x46, '9',

    0x0E, '`',

    0x4E, '-',

    0x55, '=',

    0x5D, '\\',

    0x29, ' ',

    0x54, '[',

    0x5B, ']',

    0x4C, ';',

    0x52, '\'

};


关键字:51单片机  PS2键盘  解码实验  C51 引用地址:51单片机PS2键盘解码实验--C51源代码

上一篇:c51单片机扩展64K的RAM
下一篇:C51的指令与时序的一点总结

推荐阅读最新更新时间:2024-03-16 16:24

超声波测距51单片机12864液晶显示
超声波测距的模块,51单片机接上12864液晶,HC-SR04超声波模块,就可以了,具体程序没怎么看,超声波模块的硬件也不晓得,今天先贴个图,贴个程序吧(程序是淘宝买的模块附赠的)。 超声波测距51单片机12864液晶显示源程序: #include #include //引脚定义 sbit RX = P1 ^ 1; sbit TX = P1 ^ 2; sbit CS = P3 ^ 3; //片选 高电平有效 单片LCD使用时可固定高电平 sbit SID = P3 ^ 4; //数据 sbit SCLK = P3 ^ 5; //时钟 //Function
[单片机]
超声波测距<font color='red'>51单片机</font>12864液晶显示
8051单片机存储器地址分配
一、程序存储器空间 MCS-51单片机具有64kB程序存储器寻址空间,它是用于存放用户程序、数据和表格等信息。 1、对于内部无ROM的8031单片机,它的程序存储器必须外接,空间地址为64kB,此时单片机的使能端端必须接地。强制CPU从外部程序存储器读取程序。 2、对于内部有ROM的8051等单片机,正常运行时,则需接高电平,使CPU先从内部的程序存储中读取程序,当PC值超过内部ROM的容量时,才会转向外部的程序存储器读取程序。 8051片内有4kB的程序存储单元,其地址为0000H 0FFFH,单片机启动复位后,程序计数器的内容为0000H,所以系统将从0000H单元开始执行程序。但在程序存储中有些特殊的单元,这
[单片机]
课程设计,键盘扫描显示程序(c51
//课程设计,键盘扫描显示程序 //由于开发板中使用了锁存器,在proteus中仿真的话,加上锁存器的话,会出现乱码,并且//不成功,所以,就不贴图了,不过以下代码,在事物板上测试成功 //实验代码为实现按键扫描,并显示在数码管上 //实验班上共有4个按键,分别接在p3.4,p3,5,p3.6.p3.7上,因此并没有用到矩阵键盘扫描,//控制起来比较简单,6数码管观通过锁存器接在P0口上。 #include reg52.h #define uchar unsigned char #define uint unsigned int sbit dula=P2^6; //数码管段选控制位 sbit wela=
[单片机]
51单片机STC89C52 红外解码
/******************************** **For:Car mp3 IrControler **Author:YWZ **Date:2013/10/16 ********************************/ #include reg52.h typedef unsigned char U8; typedef unsigned int U16; U8 code aHexIndex ={ '0','1','2','3', '4','5','6',
[单片机]
#51单片机# UART串口通信的基本应用、模块介绍和串口程序
UART串口通信的基本应用 通信的三种基本类型: 单工通信:值允许一方向另一方传送星系,另一方不能回传信息。例:电视遥控器、收音机广播 半双工通信:数据可在双方之间相互传播,但同一时刻只能一方传给另一方。例:对讲机 全双工通信:发送数据的同时也可接收数据,两者同步进行。例:电话 UART模块介绍 通常情况下,我们关心的是通信的结果而非过程。51单片机内部存在UART模块,可自动接收数据,接收完毕,会发出通知信号。要使用这个模块,需要配置对应的具有特殊功能的寄存器。 51单片机的UART串口结构由串行口控制寄存器SCON、发送和接收电路三部分构成。 先来了解串口控制寄存器SCON SCON——串行控制寄存
[单片机]
#<font color='red'>51单片机</font># UART串口通信的基本应用、模块介绍和串口程序
基于8051单片机开发的湿度计设计
  在本文中,单片机开发工程师分享了一个基于8051单片机开发的湿度计,这个方案比较简单,以供单片机初学者学习。   湿度传感器也称为湿度计,在本单片机方案中,其电路可以以5%的精度感测20%至95%的相对湿度(RH),湿度信息可以显示在16×2 LCD显示屏上。另外,在本单片机方案中,还提供了一个继电器,也就是说当湿度超过某个跳变点时,该继电器将被激活,执行某些操作。   一、DHT11湿度传感器   DHT11是一款低成本的湿度兼温度传感器,具有数字输出。电容法用于感测湿度,而热敏电阻用于测量温度。传感器可以以5%的分辨率感测20%至95%的相对湿度。温度测量最高可达50°C,分辨率为2°C。与单片机的通信是通过单线进
[单片机]
基于80<font color='red'>51单片机</font>开发的湿度计设计
教你如何 51单片机控制mg995舵机
这是我的小车雏形,还没完成,之前就一直卡在舵机控制部分,今天终于搞定了。接下来我就将我注意的所有部分说出来,和大家分享一下我的经验: 1 单片机,舵机,电源共地; 2 用两个稳压芯片进行供电,将电源分开来; 3 舵机信号端没有直接连接单片机IO口,我串了一个10K的电阻,也就是这一步之后我就可以控制我的舵机了。 之前听很多人说是信号端直接连IO口也可以控制的,但是我就是一直都不可以了,今天我就串了一个10K的电阻之后意外发现可以控制舵机了 所以我就发这个帖子出来,和大家分享,同时感谢那些帮我思考的人,感谢你们~~ 需要比较清楚的电路的人可以留言,如果我看需要的人很多的话我就传上来吧~~~ 基于大众的要求,要求资料,那我就把我
[单片机]
教你如何 <font color='red'>51单片机</font>控制mg995舵机
80c51是几位单片机 80c51单片机有几个中断源
  80c51是几位单片机   80C51是一种8位微处理器,也被称为8051,由Intel公司推出。它是最早的商用单片机之一,由于它的简单易用、灵活可靠,被广泛应用于许多嵌入式系统中。在80C51系列中,最常见的型号包括AT89C51和AT89S52等。   80c51单片机寻址范围有多少   80C51单片机的寻址范围取决于其具体的型号和存储器结构。在最常见的AT89C51和AT89S52型号中,其寻址范围如下:   内部RAM寻址范围:0x00-0x7F(128字节)   内部ROM寻址范围:0x0000-0xFFFF(64KB)   特殊功能寄存器(SFR)寻址范围:0x80-0xFF(128字节)   外部扩展RAM
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved