PS2手柄遥控STM3

PS2手柄介绍

PS2手柄作为一种经典且常见的控制器,具有良好的手感和丰富的按键,适合用来控制STM32进行机器人、遥控车等项目。

手柄使用 SPI 串行通信,在本项目中使用软件模拟SPI,实现单片机与数字 摇杆手柄之间的通讯

PS2手柄连接STM32

1、硬件准备

PS2手柄、stm32f103c8t6最小系统板,oled使用江科大的例程

2、引脚说明与接线

我的接收器有六个引脚,从左往右依次为DI,DO,GND,VCC,CS,CLK;

DI/DAT 信号流向 从手柄到主机 此信号是一个 8bit 的串行数据 同步传送于时钟 的
下降沿。信号的读取在时钟由高到低的变化过程中完成。
DO/CMD 信号流向 从主机到手柄 此信号和 DI 相对 信号是一个 8bit 的串行数据
同步传送于时钟的下降沿。
GND 电源地
VDD 接收器工作电源 电源范围 3~5V
CS/SEL 用于提供手柄触发信号。在通讯期间, 处于低电平
CLK 时钟信号 由主机发出, 用于保持数据同步;
ACK 从手柄到主机的应答信号。此信号在每个 8bits 数据发送的最后一个周期变低并
CS 一直保持低电平 如果 CS 信号不变低 60 微秒 PS 主机会试另一个外设。在
编程 时未使用 ACK 端口。

通讯时序

SPI通信时序,我们使用软件模拟SPI,在CLK上升沿进行数据交换,DO发送数据,DI接收数据

接线:CS----->PA4           CLK-------->PA5            DI------->PA6                  DO------->PA7

3、PS2手柄通信原理

这是ps2手柄通信的一帧数据,在这一帧数据中包含九个字节,在DO发送的一帧数据中,
当主机想读手柄数据时 将会拉低 CS 线电平 并发出一个命令 0x01 ”; 手柄会回复
它的 ID 0x41= 模拟绿灯 0x73= 模拟红灯 ”; 在手柄发送 ID 的同时 主机将传送 0x42
请求数据 随后手柄发送出 0x5A 告诉主机 数据来了 idle : 数据线空闲, 该数据线无数据传送。
在DI接收的一帧数据中,包含手柄数据的是后六个字节,我们建立一个长度为9的Data[9]来接收DI数据,则Data[3]~Data[8]是我们需要解析的手柄数据,
当有按键按下 对应位为 0 ”, 其他位为 1 ”, 例如当键 SELECT 被按下时, Data[3]=11111110

4、程序设计

#include "PS_2.h"
#include "stm32f10x.h"                  // Device header
/*********************************************************     
**********************************************************/	 

unsigned int Handkey;	//定义按键

uint8_t ps2_mode;
uint8_t Comd[9]={0x01,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00};	//发送命令DO的数组
uint8_t Data[9]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; //接收数据DI的数组
uint8_t key_search[12] = {0x00,0x00,0x00,0x00,
						  0x00,0x00,0x00,0x00,
						  0x00,0x00,0x00,0x00};

unsigned int MASK[16][2]={
    {PSB_SELECT,0},
    {PSB_L3,0},
    {PSB_R3,0},
    {PSB_START,0},
    {PSB_PAD_UP,0},
    {PSB_PAD_RIGHT,0},
    {PSB_PAD_DOWN,0},
    {PSB_PAD_LEFT,0},
    {PSB_L2,0},
    {PSB_R2,0},
    {PSB_L1,0},
    {PSB_R1 ,0},
    {PSB_GREEN,0},
    {PSB_RED,0},
    {PSB_BLUE,0},
    {PSB_PINK,0}
	};	//定义按键键码

void PS2_Init(void)
{ 	
	PS2_GPIO_Init();//手柄GPIO初始化,SPI引脚GPIO初始化
	
	PS2_SCK(1);
	PS2_CS(1);
	PS2_ShortPoll();
	PS2_EnterConfing();		//进入手柄配置模式
	PS2_TurnOnAnalogMode();	//红灯或绿灯配置模式,并选择是否保存
	//PS2_VibrationMode();	//手柄震动马达设置
	PS2_ExitConfing();		//保存配置并退出
	ps2_mode_get();        //获取手柄模式
}

//发送命令
unsigned char PS2_Cmd(unsigned char ByteSend)
{    
	unsigned char i,j=1;
	unsigned char ByteReceive=0x00; 
	for (i = 0; i < 8; i++)       
	{
		 PS2_DO(ByteSend & (0x01 << i));//将数据一位一位的发送,不理解的可以举个例子算一下
		 

		 PS2_SCK(0);   	
		 PS2_Delay_US(100);
		 
		 if(PS2_DI()) 
		 {
			ByteReceive=ByteReceive+j;
		 }
		 j=j<<1;
		
		 PS2_SCK(1);   
		 PS2_Delay_US(1);		 
	}

	return ByteReceive;	
}

//读取手柄数据,核心函数
void PS2_ReadData(void)
{
	unsigned char byte=0;
	PS2_CS(0);
    PS2_Delay_US(10);

    for(byte = 0; byte < 9; byte++)
    {
		Data[byte] = PS2_Cmd(Comd[byte]);
    }
	PS2_CS(1);
	PS2_Delay_US(10);
}


unsigned char ps2_mode_get(void)
{	
	if( Data[1] == 0X73)  
	{
		ps2_mode = PSB_REDLIGHT_MODE;
	}
	else if ( Data[1] == 0X41)
	{
		ps2_mode = PSB_GREENLIGHT_MODE;
	}
	else
	{
		ps2_mode = PSB_LOSE;
	}
	return ps2_mode;
}


unsigned char ps2_key_serch()
{
	unsigned char index;
	unsigned char key_num = 0;
	//PS2_ClearData();
	PS2_ReadData();

	Handkey=(Data[4]<<8)|Data[3];    
	for(index=4;index<16;index++)
	{	    
		if((Handkey&(1<<(MASK[index][0]-1)))==0)
		{
			MASK[index][1] = 1; 
			key_num++;
		}
		else
		{
			MASK[index][1] = 0; 
		}
	}
	return key_num;
}

unsigned char ps2_get_key_state(unsigned char key_id)
{
	if (key_id < PSB_SELECT)
		return 0;
	else
		return MASK[key_id - 1][1];
}

unsigned char ps2_get_anolog_data(unsigned char button)
{
	return Data[button];
}




int rocker_value(unsigned char button)
{
    unsigned char get_value;
	int value;
	get_value=ps2_get_anolog_data(button);
	if(button==5)
	{
		value=128-get_value;
	}
	if(button==6)
	{
		value=127-get_value;
	}
	if(button==7)
	{
		value=128-get_value;
	}
	if(button==8)
	{
		value=127-get_value;
	}

    return value;
}
//Çå³ýÊý¾Ý»º³åÇø
void PS2_ClearData()
{
	unsigned char a;
	for(a=0;a<9;a++)
		Data[a]=0x00;
}

void PS2_Vibration(unsigned char motor1, unsigned char motor2)
{
	PS2_CS(0);
	PS2_Delay_US(100);
	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);
	PS2_CS(1);
	PS2_Delay_US(100);
}

//short poll
void PS2_ShortPoll(void)
{
	PS2_CS(0);
	PS2_Delay_US(100);
	PS2_Cmd(0x01);  
	PS2_Cmd(0x42);  
	PS2_Cmd(0X00);
	PS2_Cmd(0x00);
	PS2_Cmd(0x00);
	PS2_CS(1);
	PS2_Delay_US(100);	
}

//½øÈëÅäÖÃ
void PS2_EnterConfing(void)
{
    PS2_CS(0);
	PS2_Delay_US(100);
	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);
	PS2_CS(1);
	PS2_Delay_US(100);
}

void PS2_TurnOnAnalogMode(void)
{
	PS2_CS(0);
	PS2_Delay_US(100);
	PS2_Cmd(0x01);  
	PS2_Cmd(0x44);  
	PS2_Cmd(0X00);
	PS2_Cmd(0x01); 
	PS2_Cmd(0xEE); 
				   
	PS2_Cmd(0X00);
	PS2_Cmd(0X00);
	PS2_Cmd(0X00);
	PS2_Cmd(0X00);
	PS2_CS(1);
	PS2_Delay_US(100);
}

//Õñ¶¯ÉèÖÃ
void PS2_VibrationMode(void)
{
	PS2_CS(0);
	PS2_Delay_US(100);
	PS2_Cmd(0x01);  
	PS2_Cmd(0x4D);  
	PS2_Cmd(0X00);
	PS2_Cmd(0x00);
	PS2_Cmd(0X01);
	PS2_CS(1);
	PS2_Delay_US(100);	
}


void PS2_ExitConfing(void)
{
    PS2_CS(0);
	PS2_Delay_US(100);
	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);
	PS2_CS(1);
	PS2_Delay_US(100);
}

void PS2_GPIO_Init()
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);	
}

void PS2_CS(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)BitValue);
}


void PS2_SCK(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_5, (BitAction)BitValue);
}

void PS2_DO(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_7, (BitAction)BitValue);
}


uint8_t PS2_DI()
{
	return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6);
}

void PS2_Delay_US(uint32_t nCount)
{
  for(; nCount != 0; nCount--);
}

PS_2.c

#ifndef __PS_2_H__
#define __PS_2_H__

#include "stdint.h"

#define ANALOG_CENTER 0x80

#define PSB_LOSE				0
#define PSB_REDLIGHT_MODE		1
#define PSB_GREENLIGHT_MODE 	2

#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                
#define PSS_RY			6				
#define PSS_LX			7				
#define PSS_LY			8				

#define PSS_LX_MID	   0X80
#define PSS_LY_MID	   0X7F
#define PSS_RX_MID	   0X7F
#define PSS_RY_MID     0X80

extern unsigned char Data[9];
extern unsigned int MASK[16][2];
extern unsigned int Handkey;


	
/**/    void PS2_Init(void);  
	
/**/     unsigned char ps2_mode_get(void);   
    
/**/     void PS2_ReadData(void); 
    
/**/     unsigned char PS2_Cmd(unsigned char CMD);		  
    
/**/     unsigned char ps2_key_serch(void);		  
    
/**/ 	unsigned char ps2_get_key_state(unsigned char key_id);
	
/**/     unsigned char ps2_get_anolog_data(unsigned char button); 

    int  rocker_value(unsigned char button);
	
    void PS2_ClearData(void);	  
    
    void PS2_Vibration(unsigned char motor1, unsigned char motor2);

    void PS2_EnterConfing(void);	 
    
    void PS2_TurnOnAnalogMode(void); 
    
    void PS2_VibrationMode(void);    
    
    void PS2_ExitConfing(void);	     
    
    void PS2_SetInit(void);		   
  
    void PS2_ShortPoll(void);

	void PS2_CS(uint8_t BitValue);

	void PS2_SCK(uint8_t BitValue);
	
	void PS2_DO(uint8_t BitValue);

	void PS2_DI_H(void);

	void PS2_DI_L(void);
	
	uint8_t PS2_DI(void);
	
	void PS2_Delay_US(uint32_t nCount);
	
	void PS2_GPIO_Init(void);
	

#endif

PS_2.h

通过网盘分享的文件:PS2_Test.zip
链接: https://pan.baidu.com/s/1WpG4rWLI3GtejETR_nqz1g?pwd=r9w5 提取码: r9w5

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值