单片机 > 单片机程序设计 > 详情

PS2无线手柄解码 附单片机程序

发布时间:2020-06-09 发布时间:
|

参考前辈大虾的资料,用Atmega128A对PS2无线手柄进行解码,并在8位数码管上显示按键值

自己总结如下:
蹬蹬蹬。。。主角登场:
无线PS2手柄+遥控接收器+便于接线的转接板
 


遥控接收器和转接板插接在一起后的样子 

转接板上的接线引脚有以下几个:
DAT->手柄到单片机 同步传送于时钟下降沿 时序图中的DI
CMD->单片机到手柄  同步传送于时钟下降沿 时序图中的DO      
CS->提供手柄触发信号,通讯期间处于低电平
CLK->时钟信号,由单片机发出

 


引用其他资料的说明如下:
1.“通讯过程中, 一串数据通讯完成后 CS 才会由低转高,不是 1 个字节通讯完成后就由低转高,在通讯期间,一直处于低电平。”
2.“在时钟下降沿时,完成数据的发送与接收,发送和接收是同时完成的。当单片机想读手柄数据或向手柄发送命令时,将会拉低 CS 线电平,并发出一个命令“0x01”;手 柄会回复它的 ID “0x41=绿灯模式,0x73=红灯模式”;在手柄发送 ID 的同时,单片机将传送 0x42,请求数据;随后手柄发送出 0x5A,告诉单片机‘数据来了’”
3.“一个通讯周期有 9 个字节(8 位),这些数据是依次按位传送”


  以上说白了就是:
  按照时序图,每次通讯周期,都是先给手柄(也就是单片机给接收器)通过CMD引脚(DO)依次发9组数据,分别是:
  0x01,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00

  与此同时,通过DAT引脚(DI)收到相对位的9组数据,程序中我将收到的数据存在了re_code[ ]这个数组中;
  手柄上的按键码值被存储的位置如下:
  re_code[3]==0xEF  //左4个按键的 上
  re_code[3]==0xBF  //左4个按键的 下
  re_code[3]==0x7F  //左4个按键的 左
  re_code[3]==0xDF  //左4个按键的 右
  re_code[3]==0xFE  //SELECT键
  re_code[3]==0xF7  //START键

  re_code[4]==0xEF  //右4个按键的 △
  re_code[4]==0xBF  //右4个按键的 ×
  re_code[4]==0x7F  //右4个按键的 □
  re_code[4]==0xDF  //右4个按键的 ○

  re_code[4]==0xFB  //左1,2个按键的 L1
  re_code[4]==0xFE  //左1,2个按键的 L2
  re_code[4]==0xF7  //右1,2个按键的 R1
  re_code[4]==0xFD  //右1,2个按键的 R2

没有按键按下时,以上各位数组中的值为FF,按键按下数组值变化,并且支持按键组合键值输出。
当手柄MODE LED灯不亮时,左右摇杆功能等同左四右四按键

当按下MODE键手柄MODE LED红灯亮起
 

这个时候,左右两个摇杆就能线性输出了,有点像汽车油门有个逐渐变化量
左右摇杆处于中位时的左右值为80,上下值为7F

  re_code[5] 00——80——FF 右摇杆从左到右
  re_code[6] 00——7F——FF 右摇杆从上到下
  re_code[7] 00——80——FF 左摇杆从左到右
  re_code[8] 00——7F——FF 左摇杆从上到下

--------------------------------------------------------------------------------------------------
数码管从左至右每2位对应的分别是
左摇杆的左右值(re_code[7] 里的值)
左摇杆的上下值(re_code[8] 里的值)
左4个按键的键值(re_code[3] 里的值)
右4个按键及侧面LR的键值(re_code[4] 里的值)
正常模式时,如图左侧的小红灯(MODE LED)不亮,头四位数码管不会变化只显示FFFF
 


按下←键的显示
 


按下右侧 “×” 键的键值显示
 


按下【MODE】按钮,小红灯亮起,摇杆处于中间位置时的数码管显示
807F就显示了左侧摇杆位于中位的左右值和上下值
 


左摇杆被摇动时的线性值显示
 

 



程序中柄遥控接收器接口定义:
// DAT->  in  PD0     设置为输入
// CMD-> out PD1   设置为输出        
// CS->    out PD2
// CLK->  out PD3



这个PS2手柄还有震动功能,本次没有弄出来,还请哪位大虾指点一二。
为了不浪费大家的黑币(我的黑币就总不够用),我就直接将程序贴出来了,如下,不对的地方还请指正——————————————————————————————————————————————————————

#include  

#include

#define uchar unsigned char

#define uint unsigned int


#define cmd_set     (PORTD |=(1<

#define cmd_clr     (PORTD &=~(1<

#define cs_set        (PORTD |=(1<

#define cs_clr        (PORTD &=~(1<

#define clk_set       (PORTD |=(1<

#define clk_clr       (PORTD &=~(1<


  //DO数据

uchar scan[9]={0x01,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00};

  //存放DI数据

uchar re_code[9];                                             

uint m;


//共阴数码管段码 

uchar ddd[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};

//位码

uchar www[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};                                                                                


void port_init(void)

{

  DDRE=0xff;

  PORTE=0x00;  //段选


  DDRB=0xff; 

  PORTB=0xff;  //位选        

        

  //PD0->DAT输入;PD1->CMD输出;PD2->CS输出;PD3->CLK输出

  DDRD  =(0<

  PORTD =0;

}


void delay(uint n)

{

        uint i;

        for(i=0;i

}


uchar scanout(uchar command)   //向手柄发送命令并接受反馈的子程序

{

    uchar i,j=1;

    uchar res=0; 

    for(i=0;i<8;i++)     //逐位接收     

    {

          if(command&0x01)      cmd_set;

          else                            cmd_clr;

          command=command>>1;

          delay(1);

          clk_clr;

          delay(1);                              //这里延时很关键,太多了手柄就反应迟钝了

          if(PIND&0x01) res=res+j;      //这里就开始同步接收DI值了 

          j=j<<1; 

          clk_set;

          delay(2);                 

    }

    return res;        

}

void Read_PS2(void)        //向手柄发送DO并将反馈DI存入re_code[ ]中

{

         uchar i;

         cs_clr;

         for(i=0;i<9;i++)        re_code=scanout(scan);

         cs_set;        

}                                              

void main(void)

        port_init();

        delay(50);

  while(1)

         {

         Read_PS2(); 

         delay(200);

         

         m=re_code[3]*256+re_code[4];

                 

         PORTE=ddd[m/256/16];

         PORTB=www[3];

         delay(50);

         PORTE=ddd[m/256%16];

         PORTB=www[2];

         delay(50);

         PORTE=ddd[m%256/16];

         PORTB=www[1];

         delay(50);

         PORTE=ddd[m%256%16];

         PORTB=www[0];

         delay(50);

                 

         PORTE=ddd[out[7]/16];

         PORTB=www[7];

         delay(50);

         PORTE=ddd[out[7]%16];

         PORTB=www[6];

         delay(50);

         PORTE=ddd[out[8]/16];

         PORTB=www[5];

         delay(50);

         PORTE=ddd[out[8]%16];

         PORTB=www[4];

         delay(50);        


关键字:PS2  无线手柄  解码  单片机


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
ARM基础知识八