技术热线: 4007-888-234

QLdsPIC3] PS2协议 {C30+dsPIC30F6014A]

更新时间: 2019-03-23
阅读量:3362

深圳市英锐恩科技有限公司:台湾麦肯单片机(Micon MDT单片机)亚太地区A级代理商

QLdsPIC3] PS2协议 {C30+dsPIC30F6014A]
//实验目的:熟悉MCU与PS2设备通信
//软件规划:
//         1,采用查询的方法检测PS2设备发送过来的时钟和数据
//         2,软件只检测字母(小写)数字(左边键盘)和数字键的通码,暂时不能检测断码。
//         3,不检测组合键盘
//         4,扫描按键结果送LCD1602显示
//硬件要求:
//         1,拨码开关S4全部置ON端
//         2,连接好键盘
//         3,跳线J18全部接通
#include             //dsPIC30F6014标准头文件

  _FOSC(0x0ffe5);                 //XT振荡,4倍频晶振.
  _FWDT(WDT_OFF);                 //关闭看门狗定时器
  _FBORPOR(PBOR_OFF & MCLR_EN);   //掉电复位禁止,MCLR复位使能。
  _FGS(CODE_PROT_OFF);            //代码保护禁止

unsigned char __attribute__((address(0x900))) recdata1;    //按键结果缓存单元1
unsigned char __attribute__((address(0x902))) recdata2;    //按键结果缓存单元2
unsigned char __attribute__((address(0x904))) result;      //按键的ASCII码保存单元
unsigned char __attribute__((address(0x906))) result1;
unsigned char __attribute__((address(0x908))) count;       //循环次数
unsigned int  __attribute__((address(0x90a))) temp;        //临时单元
unsigned char __attribute__((address(0x9a0))) loop;        //LCD显示次数计数器

#define rs LATBbits.LATB4            //定义LCD控制位(注意这里只能用LATB寄存器,不能直接用PORTB寄存器)
#define rw LATBbits.LATB5            //定义LCD的RW控制信号
#define e  LATBbits.LATB6            //定义LCD的使能信号E

unsigned char const noshift[80][2]=  //shift键不按下时按键的键码与ASCII对应表
{
//键盘码  ASCII码
    22     ,49,  // { 1 }
   30    ,50,  // { 2 }
    38    ,51,  // { 3 }
 37    ,52,  // { 4 }
 46     ,53,  // { 5 }
 54     ,54,  // { 6 }
 61     ,55,  // { 7 }
 62    ,56,  // { 8 }
 70     ,57,  // { 9 }
 69     ,48,  // { 0 }

 28     ,97,  // { a }
 50     ,98,  // { b }
 33     ,99,  // { c }
 35     ,100, // { d }
 36     ,101, // { e }
 43     ,102, // { f }
 52     ,103, // { g }
 51     ,104, // { h }
 67     ,105, // { i }
 59     ,106, // { j }

 66     ,107, // { k }
 75     ,108, // { l }
 58     ,109, // { m }
 49     ,110, // { n }
 68     ,111, // { o }
 77     ,112, // { p }
 21     ,113, // { q }
 45     ,114, // { r }
 27     ,115, // { s }
 44     ,116, // { t }

 60     ,117, // { u }
 42     ,118, // { v }
 29     ,119, // { w }
 34     ,120, // { x }
 53     ,121, // { y }
 26     ,122, // { z }
 84     ,91,  // { [ }
 91     ,93,  // { ] }
 76     ,59,  // { ; }
 82     ,39,  // { ' }

 65     ,44,  // { , }
 73     ,46,  // { . }
 74     ,47,  // { / }
 78     ,45,  // { - }
 85     ,61,  // { = }
 93     ,92,  // { \ }
 14     ,96,  // { ` }
 90     ,32,  // { enter }
 5      ,0,   // { f1 }
 6      ,1,   // { f2 }

 4      ,2,   // { f3 }
 12     ,3,   // { f4 }
 3      ,4,   // { f5 }
 11     ,5,   // { f6 }
 131    ,6,   // { f7 }
 10     ,7,   // { f8 }
 1      ,8,   // { f9 }
 9      ,9,   // { f10 }
 120    ,10,  // { f11 }
 7      ,11,  // { f12 }

 102    ,12,  // { back }
 224    ,13,  // { home }
 105    ,14,  // { end }
 125    ,15,  // { pageup }
 122    ,16,  // { pagedown }
 117    ,17,  // { up }
 114    ,18,  // { down }
 107    ,19,  // { left }
 116    ,20,  // { right }
 113    ,21,  // { del }

 112    ,22,  // { insert }
 225    ,23,  // { pause }
 118    ,24,  // { esc }
 13     ,25,  // { tab }
 88     ,26,  // { caps }
 20     ,27,  // { ctrl }
 17     ,28,  // { alt }
 41     ,29,  // { space }
 31     ,30,  // { win }
 47    ,31,   // { winright
};

unsigned char const addshift[47][2]=           //shift键按下时按键的键码与ASCII对应表
{
 14 ,126,   // { ~ }
 22 , 33,   // { ! }
 30 , 64,   // { @ }
 38 , 35,   // { # }
 37 , 36,   // { $ }
 46 , 37,   // { % }
 54 , 94,   // { ^ }
 61 , 38,   // { & }
 62 , 42,   // { * }
 70 , 40,   // { ( }

 69 , 41,   // { ) }
 78 , 95,   // { _ }
 85 , 43,   // { + }
 93 ,124,   // { | }
 84 ,123,   // { { }
 91 ,125,   // { } }
 76 , 58,   // { : }
 82 , 34,   // { " }
 65 , 60,   // { < }
 73 , 62,   // { > }

 74 , 63,   // { ? }
 28  ,65,    // { a }
 50  ,66,    // { b }
 33  ,67,    // { c }
 35  ,68,    // { d }
 36  ,69,    // { e }
 43  ,70, // { f }
 52  ,71, // { g }
 51  ,72, // { h }
 67  ,73, // { i }

 59  ,74, // { j }
 66  ,75, // { k }
 75  ,76, // { l }
 58  ,77, // { m }
 49  ,78, // { n }
 68  ,79, // { o }
 77  ,80, // { p }
 21  ,81, // { q }
 45  ,82, // { r }
 27  ,83, // { s }

 44  ,84, // { t }
 60  ,85, // { u }
 42  ,86, // { v }
 29  ,87, // { w }
 34  ,88, // { x }
 53  ,89, // { y }
 26  ,90, // { z }
};

void init();                          //I/O口初始化函数
void getkey();                        //读取按键键码函数
void judge();                         //键码转换成ASCII码
void lcd_display(unsigned char res);  //LCD显示函数

void lcd_init();                      //申明LCD初始化函数
void write_web();                     //申明显示公司web地址函数
void write(unsigned int x);           //申明显示1字节数据函数
void lcd_enable();                    //申明LCD显示设置函数
void delay();                         //申明延时函数

//************************初始化函数**************************
void init()
{
 TRISC=0X0018;
    TRISB=0X0000;                     //设置B口为输出
    TRISD=0X0000;                     //设置D口为输出
    result=0;
    result1=0;
}

//********************读取按键键码函数*************************
void getkey()
{
    unsigned char i;
 temp=0;
    for(count=1;count<21;count++)    //循环20次(第1字节的1bit起始位,8bit数据,1bit校验位,1bit停止位,第2字节的1bit起始位和8bit数据,忽略校验位和停止位)
       {
         while(PORTCbits.RC4);       //等待低电平
         while(!PORTCbits.RC4)       //低电平
          {
           for(i=0;i<15;i++);        //延时一定时间,保证下降沿足够时间
           if(count<10|count>12)     //只读取数据位,忽略起始位和校验位,停止位
             {
               temp=temp>>1;         //读取的数据右移1位(传输时低位在前)
               if(PORTCbits.RC3) temp=temp|0x8000;   //若为高,最高位加1
               else temp=temp&0x7fff;                //若为低,最高位清0
             }
           while(!PORTCbits.RC4);    //等待恢复为高电平(下降沿读取数据)
          }
       }
    recdata1=0;
    recdata2=0;
    recdata1=(unsigned char)temp&0x00ff;             //按键码低8位
    recdata2=(unsigned char)((temp>>8)&0x00ff);      //按键码高8位
}

//*********************按键码转ASCII码**************************
void judge()
{
   unsigned char i;
   if(!(recdata1==0xf0))                            //若按键码低8位为0XF0,则是按键的断码
   {
    if(recdata1==0x12)                              //shift有按下
    {
      if(recdata2=0xf0) return;                     //若只有shift按下,则返回
      for(i=0;i<47;i++)                             //查找shift按下时按键的ASCII码
        {
          if(addshift[i][0]==recdata2)
             {
               result=addshift[i][1];              //返回读取的ASCII码
               break;
             }
        }
    }
   else                                            //shift键没有按下
    {
      for(i=0;i<80;i++)
        {
          if(noshift[i][0]==recdata1)
             {
               result=noshift[i][1];
               break;
             }
        }
     }
 }
}


//*******************LCD初始化函数*******************************
void lcd_init()
 {
    PORTD=0X1;                 //清除显示
    lcd_enable();
    PORTD=0X38;                //8位2行5*7点阵
    lcd_enable();
    PORTD=0X0e;                //显示开,光标开,闪烁
    lcd_enable();
    PORTD=0X06;                //文字不动,光标右移
    lcd_enable();
    PORTD=0X80;                //产品名字显示地址
    lcd_enable();
 }
 
//*********************LCD显示函数*******************************
void lcd_display(unsigned char res)
 {
    unsigned char j;
         if(loop<16)           //一行只显示16字符
          {
           write(res);          //写一个字节数据函数送LCD显示
           loop++;
           for(j=0;j<5;j++)      //延时一段时间(主要是为了控制显示的速度)
            {
              delay();
            }
           }
         else
           {
             loop=0;
             PORTD=0X80;           //重头开始显示
             lcd_enable();
             write(res);          //写一个字节数据函数送LCD显示
           }
 }

//*****************写一个字节数据函数***************************
//在电平发生改变后需要插入一段延时时间,否则LCD反应不过来。
void write(unsigned int x)
 {
  PORTD=x;                   //待显示数据送PORTD口
  delay();                  
  rs=1;                      //该字节数据为数据,而不是命令
  delay();
  rw=0;                      //此次操作为写,而不是读
  delay();
  e=0;                       //拉低使能信号
  delay();                   //保持使能信号为低一段时间
  e=1;                       //拉高使能信号,建立LCD操作所需要的上升沿
  delay();
 }


//******************LCD显示设置函数*****************************
//在电平发生改变后需要插入一段延时时间,否则LCD反应不过来。
void lcd_enable()
 {
   delay();
   rs=0;                     //该字节数据为命令,而不是数据
   delay();
   rw=0;                     //此次操作为写,而不是读
   delay();
   e=0;                      //拉低使能信号
   delay();                  //保持使能信号为低一段时间
   e=1;                      //拉高使能信号,建立LCD操作所需要的上升沿
   delay();
}


//**********************延时函数*********************************
void delay()
 {
   unsigned int i;
   for(i=0;i<100;i++);
 }

//**********************主函数***********************************
int main(void)
{  
    unsigned char m, k=0;
    delay();
    delay();
    delay();
    delay();
    delay();               //延时一段时间,保证键盘,LCD等工作稳定
    init();                //调用I/O口初始化函数
    lcd_init();            //调用LCD初始化函数
    while(1)
     {
       getkey();           //调用读取按键码函数
       judge();            //调用按键码转ASCII码函数
       if(recdata1!=0x12) lcd_display(result);   //如按下键不为shift则送LCD显示
       for(m=0;m<100;m++)  //延长一段时间
       {
       delay();
       delay();
       }
     }
}