PS2手柄代码移植-合泰平台
1、PS2手柄端口及通讯协议
PS2手柄的通讯协议是SPI协议是一种高速的、全双工、同步的通信总线,并且在芯片的管脚上只占用四根线(DI、DO、CS、CLK),PS2手柄的通讯协议破解后在C51、STM32、Arduino、FPGA等平台上均有应用,其端口、通讯协议及使用方法的介绍在网上一搜一大堆,大家自行下载即可。
博主本科期间由于项目需求,需要在合泰芯片上实现ps2手柄控制的代码。于是将ps2的代码从别的平台上移植到合泰芯片平台上,具体型号为合泰HT66F70A(好像是开发板型号,不一定是芯片型号),如今整理出来,希望能帮助到有需要的朋友。
2、移植代码:文件主要包括三份:ps2.c、ps2.h、main.c
#include "PS2.h"
#include "HT66F70A.h"
//全局变量区
unsigned short int Handkey;
unsigned char Comd[2] = {0x01,0x42};//开始命令。请求数据
unsigned char Data[9] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; //数据存储数组
unsigned short int MASK[] = {
PSB_SELECT,
PSB_L3,
PSB_R3 ,
PSB_START,
PSB_PAD_UP,
PSB_PAD_RIGHT,
PSB_PAD_DOWN,
PSB_PAD_LEFT,
PSB_L2,
PSB_R2,
PSB_L1,
PSB_R1 ,
PSB_GREEN,
PSB_RED,
PSB_BLUE,
PSB_PINK
};//按键值与按键明
//手柄接口初始化 输入 DI->PB12
// 输出 DO->PB13 CS->PB14 CLK->PB15
void PS2_INIT(void)
{
//输入 DI->PB2
_pcc4 = 1;//PB12设置成输入 默认下拉
_pcpu4 = 0;
//DO->PB3 CS->PB4 CLK->PB5
_pcc5 = 0;//PB3、PB4、PB5 推挽输出
_pcc6 = 0;
_pcc7 = 0;
_pcpu5 = 0;
_pcpu6 = 0;
_pcpu7 = 0;
}
void PS2_Cmd(unsigned char CMD)
{
volatile unsigned short int ref = 0x01;
Data[1] = 0;
for(ref=0x01;ref<0x0100;ref<<=1)
{
if(ref&CMD)
{
DO_H; //输出以为控制位
}
else DO_L;
CLK_H; //时钟拉高
GCC_DELAY(5);//delay_us(50);
CLK_L;
GCC_DELAY(5);//delay_us(50);
CLK_H;
if(DI)
Data[1] = ref|Data[1];
}
GCC_DELAY(16);
}
//判断是否为红灯模式
//返回值;0,红灯模式
// 其他,其他模式
unsigned char PS2_RedLight(void)
{
CS_L;
PS2_Cmd(Comd[0]); //开始命令
PS2_Cmd(Comd[1]); //请求数据
CS_H;
if( Data[1] == 0X73) return 0 ;
else return 1;
}
//读取手柄数据
void PS2_ReadData(void)
{
volatile unsigned char byte=0;
volatile unsigned short int ref=0x01;
CS_L;
PS2_Cmd(Comd[0]); //开始命令
PS2_Cmd(Comd[1]); //请求数据
for(byte=2;byte<9;byte++) //开始接受数据
{
for(ref=0x01;ref<0x100;ref<<=1)
{
CLK_H;
GCC_DELAY(5);
CLK_L;
GCC_DELAY(5);//delay_us(50);
CLK_H;
if(DI)
Data[byte] = ref|Data[byte];
}
GCC_DELAY(16);//delay_us(16);
}
CS_H;
}
//对读出来的PS2的数据进行处理 只处理了按键部分 默认数据是红灯模式 只有一个按键按下时
//按下为0, 未按下为1
unsigned char PS2_DataKey(void)
{
unsigned char index;
PS2_ClearData();
PS2_ClearData();
PS2_ReadData();
Handkey=(Data[4]<<8)|Data[3]; //这是16个按键 按下为0, 未按下为1
for(index=0;index<16;index++)
{
if((Handkey&(1<<(MASK[index]-1)))==0)
return index+1;
}
return 0; //没有任何按键按下
}
//得到一个摇杆的模拟量 范围0~256
unsigned char PS2_AnologData(unsigned char button)
{
return Data[button];
}
//清除数据缓冲区
void PS2_ClearData()
{
unsigned char a;
for(a=0;a<9;a++)
Data[a]=0x00;
}
//short poll
void PS2_ShortPoll(void)
{
CS_L;
GCC_DELAY(16);//delay_us(16);
PS2_Cmd(0x01);
PS2_Cmd(0x42);
PS2_Cmd(0x00);
PS2_Cmd(0x00);
PS2_Cmd(0x00);
CS_H;
GCC_DELAY(16);
}
//进入配置
void PS2_EnterConfig(void)
{
CS_L;
GCC_DELAY(16);
PS2_Cmd(0x01);
PS2_Cmd(0x43);
PS2_Cmd(0x00);
PS2_Cmd(0x01);
PS2_Cmd(0x00);
PS2_Cmd(0x00);
PS2_Cmd(0x00);
PS2_Cmd(0x00);
PS2_Cmd(0x00);
CS_H;
GCC_DELAY(16);
}
//发送模式设置
void PS2_TurnOnAnalogMode(void)
{
CS_L;
//GCC_DELAY(16);
PS2_Cmd(0x01);
PS2_Cmd(0x44);
PS2_Cmd(0x00);
PS2_Cmd(0x01);//analog=0x01;digital=0x00 软件设置发送模式
PS2_Cmd(0xEE);//0x03锁存设置,即不可通过按键"MODE"设置模式
//0xEE不锁存软件设置,可通过按键"MODE"设置模式
PS2_Cmd(0x00);
PS2_Cmd(0x00);
PS2_Cmd(0x00);
PS2_Cmd(0x00);
CS_H;
GCC_DELAY(16);
}
//震动设置
void PS2_VibrationMode(void)
{
CS_L;
GCC_DELAY(16);
PS2_Cmd(0x01);
PS2_Cmd(0x4D);
PS2_Cmd(0x00);
PS2_Cmd(0x00);
PS2_Cmd(0x01);
CS_H;
GCC_DELAY(16);
}
//完成并保存配置
void PS2_ExitConfig(void)
{
CS_L;
GCC_DELAY(16);
PS2_Cmd(0x01);
PS2_Cmd(0x43);
PS2_Cmd(0x00);
PS2_Cmd(0x00);
PS2_Cmd(0x5A);
PS2_Cmd(0x5A);
PS2_Cmd(0x5A);
PS2_Cmd(0x5A);
PS2_Cmd(0x5A);
CS_H;
GCC_DELAY(16);
}
//手柄配置初始化
void PS2_SetInit(void)
{
PS2_ShortPoll();
PS2_ShortPoll();
PS2_ShortPoll();
PS2_EnterConfig();//进入配置模式
PS2_TurnOnAnalogMode();//"红绿灯"配置模式,并选择是否保存
PS2_VibrationMode();//开启震动模式
PS2_ExitConfig();//完成并保存配置
}
//只有PS2_VibrationMode();开启之后可用
//motor1:右侧小振动电机 0x00关,其他开
//motor2:左侧大震动电机 0x40~0xFF 电机开,值越大,震动越大
void PS2_Vibration(unsigned char motor1,unsigned char motor2)
{
CS_L;
GCC_DELAY(16);
PS2_Cmd(0x01);
PS2_Cmd(0x42);
PS2_Cmd(0x00);
PS2_Cmd(motor1);
PS2_Cmd(motor2);
PS2_Cmd(0x00);
PS2_Cmd(0x00);
PS2_Cmd(0x00);
PS2_Cmd(0x00);
CS_H;
GCC_DELAY(16);
}
#ifndef _PS2_H_
#define _PS2_H_
#define DI _pc4 //PB2 输入
#define DO_H _pc5=1 //命令位高
#define DO_L _pc5=0 //命令位低
#define CS_H _pc6=1 //CS拉高
#define CS_L _pc6=0 //CS拉低
#define CLK_H _pc7=1 //时钟拉高
#define CLK_L _pc7=0 //时钟拉低
//These are our button constants
#define PSB_SELECT 1
#define PSB_L3 2
#define PSB_R3 3
#define PSB_START 4
#define PSB_PAD_UP 5
#define PSB_PAD_RIGHT 6
#define PSB_PAD_DOWN 7
#define PSB_PAD_LEFT 8
#define PSB_L2 9
#define PSB_R2 10
#define PSB_L1 11
#define PSB_R1 12
#define PSB_GREEN 13
#define PSB_RED 14
#define PSB_BLUE 15
#define PSB_PINK 16
#define PSB_TRIANGLE 13
#define PSB_CIRCLE 14
#define PSB_CROSS 15
#define PSB_SQUARE 16
//#define WHAMMY_BAR 8
//These are stick values
#define PSS_RX 5 //右摇杆X轴数据
#define PSS_RY 6
#define PSS_LX 7
#define PSS_LY 8
extern unsigned char Data[9];
extern unsigned short int MASK[16];
extern unsigned short int Handkey;
void PS2_INIT(void);//PS2初始化
unsigned char PS2_RedLight(void);//判断是否为红灯模式
void PS2_ReadData(void);//
void PS2_Cmd(unsigned char CMD);//
unsigned char PS2_DataKey(void);//键值读取
unsigned char PS2_AnologData(unsigned char button); //得到一个摇杆的模拟量
void PS2_ClearData(void);//清除数据缓冲区
void PS2_ShortPoll(void);//short poll
void PS2_EnterConfig(void);//进入配置
void PS2_TurnOnAnalogMode(void);//发送模式设置
void PS2_VibrationMode(void);//震动设置
void PS2_ExitConfig(void);//完成并保存配置
void PS2_SetInit(void);//手柄配置初始化
void PS2_Vibration(unsigned char motor1,unsigned char motor2);//
#endif
#include "HT66F70A.h"
#include "Interrupt.h"
#include "TM.h"
#include "UART.h"
#include "PS2.h"
#include "Motor.h"
//全局变量区
extern char buff[num];
extern char Buff[32];
extern unsigned int count;
//函数声明区
void delay1s(void);
//主程序入口
void main()
{
//初始化区
_wdtc = 0xab;//看门狗失能
unsigned char key;
UART_INIT();
PS2_INIT();
MOTOR_INIT();
//TO DO
while(1)
{
key = PS2_DataKey();
GCC_DELAY(16);
switch(key)
{
case 1:GCC_DELAY(2000); if((key = PS2_DataKey()) == 1) Send( "1\r\n"); break;
case 2:GCC_DELAY(2000); if((key = PS2_DataKey()) == 2) Send( "2\r\n");break;
case 3:GCC_DELAY(2000); if((key = PS2_DataKey()) == 3) Send( "3\r\n");break;
case 4:GCC_DELAY(2000); if((key = PS2_DataKey()) == 4) Send( "4\r\n");break;
case 5:GCC_DELAY(2000); if((key = PS2_DataKey()) == 5) Send( "5\r\n");Motor(1,1,300);break;
case 6:GCC_DELAY(2000); if((key = PS2_DataKey()) == 6) Send( "6\r\n");Motor(1,1,300);break;
case 7:GCC_DELAY(2000); if((key = PS2_DataKey()) == 7) Send( "7\r\n");Motor(1,1,1000);break;
case 8:GCC_DELAY(2000); if((key = PS2_DataKey()) == 8) Send( "8\r\n");Motor(1,0,1000);break;
case 9:GCC_DELAY(2000); if((key = PS2_DataKey()) == 9) Send( "9\r\n");break;
case 10:GCC_DELAY(2000); if((key = PS2_DataKey()) == 10) Send("10\r\n");break;
case 11:GCC_DELAY(2000); if((key = PS2_DataKey()) == 11) Send("11\r\n");break;
case 12:GCC_DELAY(2000); if((key = PS2_DataKey()) == 12) Send("12\r\n");break;
case 13:GCC_DELAY(2000); if((key = PS2_DataKey()) == 13) Send("13\r\n");break;
case 14:GCC_DELAY(2000); if((key = PS2_DataKey()) == 14) Send("14\r\n");break;
case 15:GCC_DELAY(2000); if((key = PS2_DataKey()) == 15) Send("15\r\n");break;
case 16:GCC_DELAY(2000); if((key = PS2_DataKey()) == 16) Send("16\r\n");Motor_Stop(1);break;
default:break;
}
}
}
void delay1s(void) //误差 -1us
{
unsigned char a,b,c,n;
for(c=205;c>0;c--)
for(b=171;b>0;b--)
for(a=8;a>0;a--);
for(n=1;n>0;n--);
}