|
本帖最后由 ryuby 于 2017-11-26 09:48 编辑
参考前辈大虾的资料,用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 <iom128v.h>
#include <macros.h>
#define uchar unsigned char
#define uint unsigned int
#define cmd_set (PORTD |=(1<<PD1))
#define cmd_clr (PORTD &=~(1<<PD1))
#define cs_set (PORTD |=(1<<PD2))
#define cs_clr (PORTD &=~(1<<PD2))
#define clk_set (PORTD |=(1<<PD3))
#define clk_clr (PORTD &=~(1<<PD3))
//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<<PD0)|(1<<PD1)|(1<<PD2)|(1<<PD3) ;
PORTD =0;
}
void delay(uint n)
{
uint i;
for(i=0;i<n;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);
}
}
下面图片中那个红色的atmega128小板就是前些日子被我熔丝位写错导致昏迷后又救回来的那位。。。
|
评分
-
查看全部评分
|