ps2手柄SPI_STM32_HAL使用方法

一 PS2 手柄介绍

PS2采用的是SPI通信协议,SPI是串行外设接口的缩写,是一种高速的、全双工、同步的通信总线,并且在芯片的管脚上只占用四根线(DI、DO、CS、CLK),节约了芯片的管脚,同时为PCB的布局上节省空间。
在这里插入图片描述
在这里插入图片描述

二 cubemx配置

1.RCC中打开HSE
在这里插入图片描述
外部晶振是8HZ,主频选择168Mhz
在这里插入图片描述
这里选择SPI3,是因为SPI3是挂载在APB1下的,这里可以仔细看看clock configuration的配置。然后prescaler选择256,最大分频,目的是为了降低速度。
我的主频是选择168MHz,尝试过如果选择SPI1,也就是挂载在APB2上的话,ps2手柄无法正常读取。(可能是速率太快)

PS2_SPI时序分析

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/8de13b3e22884dbb815134c0034bf95e.png在这里插入图片描述
先看SPI时序,可以判断出是SPI模式2
1.先看空闲时的CLK电平,CS拉高就是空闲,此时CLK是高电平。所以时钟极性CPOL是1(红色箭头)
2.看一个数据采集是发生在第一个跳变沿还是第二个跳变沿,发生在第一个跳变沿泽始终相位CPHA=0,第二个跳变沿则是CPHA = 1 。这里看蓝色箭头,发生在了第一个跳变沿。
3.判断低位先行(LSB)还是高位先行(MSB),这里只要看数据,一般都是8位,这里看红红色方框,一开始的是bit0,所以是低位先行。
0 1 2 3 4 5 6 7就是低位先行
7 6 5 4 3 2 1 0就是高位先行

CPOL = 1:空闲时,时钟线是高电平,第1个跳变沿是下降沿,第2个跳变沿是上升沿
CPHA = 0:数据在第1个跳变沿(下降沿)采样
判断方法:CS低电平时是工作状态,CS高电平则进入空闲状态,图中可以看出CS高电平时CLK是高电平,所以CPOL=1;(选择High)
第一个下降沿是指蓝色的箭头,通俗的意思就是DO和DI的移出和移入在CLK的第一个下降沿之前就是CPHA=0;否则就是看绿色的箭头CPHA=1;
再看红色的方框,bit0到bit7是从左到右,也是就低位先行LSB

模拟SPI读取分析

//读取手柄数据
void PS2_ReadData(void)
{
	volatile u8 byte=0;
	volatile u16 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;
			DELAY_TIME;
			CLK_L;
			DELAY_TIME;
			CLK_H;
		      if(DI)
		      Data[byte] = ref|Data[byte];
		}
        delay_us(16);
	}
	CS_H;
}

在这里插入图片描述

硬件SPI

void PS2_Get(void)    //接受ps2数据
{
	short i = 0;
	
	HAL_GPIO_WritePin(SPI3_CS_GPIO_Port,SPI3_CS_Pin,GPIO_PIN_RESET);  //拉高,开始通讯
		
	HAL_SPI_TransmitReceive(&hspi3,&cmd[0],&PS2data[0],1,0xffff); // 发送0x01,请求接受数据
	vTaskDelay(1);
	HAL_SPI_TransmitReceive(&hspi3,&cmd[1],&PS2data[1],1,0xffff); // 发送0x42,接受0x01(PS2表示开始通信)
	vTaskDelay(1);
	HAL_SPI_TransmitReceive(&hspi3,&cmd[2],&PS2data[2],1,0xffff); // 发送0x00,接受ID(红绿灯模式)
	vTaskDelay(1);
	for(i = 3;i <9;i++)
	{
		HAL_SPI_TransmitReceive(&hspi3,&cmd[2],&PS2data[i],1,0xffff); // 接受数据
		vTaskDelay(1);
		
	}
	
	HAL_GPIO_WritePin(SPI3_CS_GPIO_Port,SPI3_CS_Pin,GPIO_PIN_SET);  //拉低,准备下次通讯
	
}
void All_Button(void)  //给每一个按键赋值,实现全按键无冲突
{
	uint8_t loc = 1;
	uint8_t set = 0;
	uint8_t but = PS2data[3];

  for(loc = 8;loc > 0;loc--)  //位运算读取前八位
  {
		loc -= 1;
		All_But[set] = (PS2data[3]&(1<<loc))>>loc;
		loc += 1;
		set++;
  }
	for(loc = 8;loc > 0;loc--)   //位运算读取后八位
  {
		loc -= 1;
		All_But[set] = (PS2data[4]&(1<<loc))>>loc;
		loc += 1;
		set++;
  }
	for(set = 0;set < 16;set++)    //因为协议上按键按下为0,未按下为1,故需要对其进行反转
	{
		if(All_But[set] == 1)  All_But[set] = 0;
		else  All_But[set] = 1;			 
	}
	

}

在这里插入图片描述

  • 10
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值