当前位置: 首页 > news >正文

stm32 cubemx ps2无线(有线)手柄

文章目录

  • 前言
  • 一、cubemx配置
  • 二、代码
    • 1.引入库
      • bsp_hal_ps2.c
      • bsp_hal_ps2.h
    • 2.主函数


前言

本文讲解使用cubemx配置PS2手柄实现对手柄的按键和模拟值的读取。
很简单,库已经封装好了,直接就可以了。

文件
在这里插入图片描述


一、cubemx配置

这个很简单,不需要走协议,只要配置gpio就可以了
在这里插入图片描述

二、代码

1.引入库

使用我的两个库

bsp_hal_ps2.c

/* 包含头文件 ----------------------------------------------------------------*/
#include "bsp_hal_ps2.h"/* 私有类型定义 --------------------------------------------------------------*//* 私有宏定义 ----------------------------------------------------------------*/
#define DI()    HAL_GPIO_ReadPin(PS2_DI_GPIO_Port, PS2_DI_Pin)           //PB12  输入#define DO_H()  HAL_GPIO_WritePin(PS2_DO_CMD_GPIO_Port, PS2_DO_CMD_Pin, GPIO_PIN_SET)        //命令位高
#define DO_L()  HAL_GPIO_WritePin(PS2_DO_CMD_GPIO_Port, PS2_DO_CMD_Pin, GPIO_PIN_RESET)        //命令位低#define CS_H()  HAL_GPIO_WritePin(PS2_CS_SEL_GPIO_Port, PS2_CS_SEL_Pin, GPIO_PIN_SET)       //CS拉高
#define CS_L()  HAL_GPIO_WritePin(PS2_CS_SEL_GPIO_Port, PS2_CS_SEL_Pin, GPIO_PIN_RESET)       //CS拉低#define CLK_H() HAL_GPIO_WritePin(PS2_CLK_GPIO_Port, PS2_CLK_Pin, GPIO_PIN_SET)      //时钟拉高
#define CLK_L() HAL_GPIO_WritePin(PS2_CLK_GPIO_Port, PS2_CLK_Pin, GPIO_PIN_RESET)      //时钟拉低
/* 私有变量 ------------------------------------------------------------------*/
const uint8_t Comd[2]={0x01,0x42};	//开始命令。请求数据
const uint16_t MASK[16] = {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
};	//按键值与按键明
/* 扩展变量 ------------------------------------------------------------------*/
_u_PS2_Data PS2_Data={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; //数据存储数组
/* 私有函数原形 --------------------------------------------------------------*//* 函数体 --------------------------------------------------------------------*/
static void delay_us(int16_t us)
{for(int i=0; i<us*10; i++){;}
}
//向手柄发送命令
static uint8_t PS2_Cmd(uint8_t CMD)
{volatile uint16_t ref=0x01;uint8_t Data;Data = 0;for(ref=0x01; ref<0x0100; ref<<=1){if(ref&CMD){DO_H();                   //输出以为控制位}else DO_L();CLK_H();                        //时钟拉高delay_us(10);CLK_L();delay_us(10);CLK_H();if(DI()){Data = ref|Data;}}return Data;
}
//short poll
static void PS2_ShortPoll(void)
{CS_L();delay_us(16);PS2_Cmd(0x01);  PS2_Cmd(0x42);  PS2_Cmd(0X00);PS2_Cmd(0x00);PS2_Cmd(0x00);CS_H();delay_us(16);	
}//进入配置
static void PS2_EnterConfing(void)
{CS_L();delay_us(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();delay_us(16);
}//发送模式设置
static void PS2_TurnOnAnalogMode(void)
{CS_L();PS2_Cmd(0x01);  PS2_Cmd(0x44);  PS2_Cmd(0X00);PS2_Cmd(0x01); //analog=0x01;digital=0x00  软件设置发送模式PS2_Cmd(0xEE); //Ox03锁存设置,即不可通过按键“MODE”设置模式。//0xEE不锁存软件设置,可通过按键“MODE”设置模式。PS2_Cmd(0X00);PS2_Cmd(0X00);PS2_Cmd(0X00);PS2_Cmd(0X00);CS_H();delay_us(16);
}
//振动设置
static void PS2_VibrationMode(void)
{CS_L();delay_us(16);PS2_Cmd(0x01);  PS2_Cmd(0x4D);  PS2_Cmd(0X00);PS2_Cmd(0x00);PS2_Cmd(0X01);CS_H();delay_us(16);	
}
//完成并保存配置
static void PS2_ExitConfing(void)
{CS_L();delay_us(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();delay_us(16);
}
//清除数据缓冲区
void PS2_ClearData(void)
{PS2_Data.DATE.ID = 0;PS2_Data.DATE.verify = 0;PS2_Data.DATE.key1_U.byte = 0xff;PS2_Data.DATE.key2_U.byte = 0xff;PS2_Data.DATE.PSS_RX = 0;PS2_Data.DATE.PSS_RY = 0;PS2_Data.DATE.PSS_LX = 0;PS2_Data.DATE.PSS_LY = 0;
}
//判断是否为红灯模式
//返回值;0,红灯模式
//		  其他,其他模式
uint8_t PS2_RedLight(void)
{uint8_t Data;CS_L();PS2_Cmd(Comd[0]);  //开始命令Data = PS2_Cmd(Comd[1]);  //请求数据CS_H();PS2_Data.DATE.ID = Data;if( Data == 0X73) return 0 ;else return 1;
}//读取手柄数据
void PS2_ReadData(void)
{volatile uint8_t byte=0;volatile uint16_t ref=0x01;uint8_t data;CS_L();PS2_Cmd(Comd[0]);  //开始命令PS2_Data.DATE.ID = PS2_Cmd(Comd[1]);  //请求数据for(byte=1;byte<8;byte++)          //开始接受数据{data = 0;for(ref=0x01;ref<0x100;ref<<=1){CLK_H();delay_us(10);CLK_L();delay_us(10);CLK_H();if(DI()){data = ref|data;}} PS2_Data.byte[byte] = data;delay_us(16);}CS_H();	
}//对读出来的PS2的数据进行处理      
//只处理了按键部分         
//默认数据是红灯模式  只有一个按键按下时
//按下为0, 未按下为1
uint8_t PS2_DataKey(void)
{uint8_t index;uint16_t Handkey;PS2_ClearData();PS2_ReadData();if(PS2_Data.DATE.verify == 0x5a){Handkey=(PS2_Data.byte[3]<<8)|PS2_Data.byte[2];     //这是16个按键  按下为0, 未按下为1for(index=0;index<16;index++){	    if((Handkey&(1<<(MASK[index]-1)))==0){return index+1;}}}return 0;          //没有任何按键按下
}//得到一个摇杆的模拟量	 范围0~256
//返回1得取成功,0得取失败
uint8_t PS2_AnologData(_e_RockerSelect button,uint8_t *qdata)
{PS2_ClearData();PS2_ReadData();if(PS2_Data.DATE.verify == 0x5a){if(button == PSS_RX) *qdata = PS2_Data.DATE.PSS_RX;else if(button == PSS_RY) *qdata = PS2_Data.DATE.PSS_RY;else if(button == PSS_LX) *qdata = PS2_Data.DATE.PSS_LX;else *qdata = PS2_Data.DATE.PSS_LY;return 1;}else{return 0;}
}
/******************************************************
Function:    void PS2_Vibration(uint8_t motor1, uint8_t motor2)
Description: 手柄震动函数,
Calls:		 void PS2_Cmd(uint8_t CMD);
Input: motor1:右侧小震动电机 0x00关,其他开motor2:左侧大震动电机 0x40~0xFF 电机开,值越大 震动越大
******************************************************/
void PS2_Vibration(uint8_t motor1, uint8_t motor2)
{CS_L();delay_us(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();delay_us(16);  
}
//手柄配置初始化
void PS2_SetInit(void)
{CS_H();CLK_H();DO_H();PS2_ShortPoll();PS2_ShortPoll();PS2_ShortPoll();PS2_EnterConfing();		//进入配置模式PS2_TurnOnAnalogMode();	//“红绿灯”配置模式,并选择是否保存PS2_VibrationMode();	//开启震动模式PS2_ExitConfing();		//完成并保存配置CS_H();CLK_H();DO_H();
}

bsp_hal_ps2.h

#ifndef __BSP_HAL_PS2_H__
#define __BSP_HAL_PS2_H__/* 包含头文件 ----------------------------------------------------------------*/
#include "main.h"
/* 宏定义 --------------------------------------------------------------------*/
//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
/* 类型定义 ------------------------------------------------------------------*/
typedef enum
{PSS_RX = 0,PSS_RY,PSS_LX,PSS_LY,
}_e_RockerSelect;
typedef union
{uint8_t byte;struct{uint8_t SELECT  :1;uint8_t L3      :1;uint8_t R3      :1;uint8_t START   :1;uint8_t UP      :1;uint8_t RIGHT   :1;uint8_t DOWN    :1;uint8_t LEFT    :1;}bit;
}_u_key1;
typedef union
{uint8_t byte;struct{uint8_t L2        :1;uint8_t R2        :1;uint8_t L1        :1;uint8_t R1        :1;uint8_t TRI       :1;uint8_t CIRCLE    :1;uint8_t FORK      :1;uint8_t REC       :1;}bit;
}_u_key2;
typedef union
{uint8_t byte[8];struct{uint8_t ID;uint8_t verify;_u_key1 key1_U;_u_key2 key2_U;uint8_t PSS_RX;uint8_t PSS_RY;uint8_t PSS_LX;uint8_t PSS_LY;}DATE;
}_u_PS2_Data;/* 扩展变量 ------------------------------------------------------------------*/
extern _u_PS2_Data PS2_Data;
/* 函数声明 ------------------------------------------------------------------*/
void PS2_SetInit(void);
void PS2_ClearData(void);
void PS2_ReadData(void);
void PS2_Vibration(uint8_t motor1, uint8_t motor2);
uint8_t PS2_AnologData(_e_RockerSelect button,uint8_t *qdata);
uint8_t PS2_DataKey(void);
uint8_t PS2_RedLight(void);#endif  // __BSP_HAL_PS2_H__

2.主函数

初始化

	PS2_SetInit();uint8_t a;

主循环

		if( !PS2_RedLight()) {//判断手柄是否为红灯模式,是,指示灯LED点亮HAL_Delay(50);	 //延时很重要不可去for(a=0; a<8; a++)//清除数据缓冲区PS2_Data.byte[a] = 0x00;PS2_ReadData();//			y_axisbuff = (128 - PS2_Data.DATE.PSS_LY)*2;//最高速度256
//			x_axisbuff = (PS2_Data.DATE.PSS_LX - 128)*2;
//			yawbuff = ( -128+PS2_Data.DATE.PSS_RX)*2;//			if(ABS(y_axisbuff) < 50) y_axisbuff = 0; //限制遥控中间位置的误差
//		    if(ABS(yawbuff) < 50) yawbuff = 0;
//		    if(ABS(x_axisbuff) < 50) x_axisbuff = 0;}else{//判断手柄不是红灯模式,指示灯LED熄灭PS2_ClearData();}HAL_Delay(50);

相关文章:

stm32 cubemx ps2无线(有线)手柄

文章目录 前言一、cubemx配置二、代码1.引入库bsp_hal_ps2.cbsp_hal_ps2.h 2.主函数 前言 本文讲解使用cubemx配置PS2手柄实现对手柄的按键和模拟值的读取。 很简单&#xff0c;库已经封装好了&#xff0c;直接就可以了。 文件 一、cubemx配置 这个很简单&#xff0c;不需要…...

【TI毫米波雷达笔记】sdk传参时的type避坑

【TI毫米波雷达笔记】sdk传参时的type避坑 这个函数要传一个结构体进去 然后结构体里面有个adcoutcfg结构体变量 adcoutcfg结构体里面共有三个变量 一个adcbitformat结构体 另外两保留 点开adcbitformat结构体发现是个32位段 一共四级结构体 那么请问 为什么adcoutcfg变量不直…...

【算法挨揍日记】day02——双指针算法_快乐数、盛最多水的容器

202. 快乐数 202. 快乐数https://leetcode.cn/problems/happy-number/ 题目&#xff1a; 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为&#xff1a; 对于一个正整数&#xff0c;每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个…...

【Hilog】鸿蒙系统日志源码分析

【Hilog】鸿蒙系统日志源码分析 Hilog采用C/S结构&#xff0c;Hilogd作为服务端提供日志功能。Client端通过API调用&#xff08;最终通过socket通讯&#xff09;与HiLogd打交道。简易Block图如下。 这里主要分析一下。Hilog的读、写、压缩落盘&#xff0c;以及higlog与android…...

keil下载程序具体过程4:flash下载算法

引言 本篇文章将介绍flash算法文件&#xff0c;阐述从jlink如何下载镜像文件写入到内部的falsh。 一、XIP 在谈flash下载算法文件时&#xff0c;先说明XIP是什么。 芯片的启动方式有很多种&#xff1a;可以从RAM中启动、内部的flash、外部的flash等等&#xff08;还有从sd卡、…...

如何快速的让自己从月入2000变成月入两万?

从月入2000变成月入两万 前言我们可以这么做&#xff1a;1.提升自己的技能&#xff1a;2.寻找更好的工作机会&#xff1a;寻找更好的工作机会是一个重要的目标&#xff0c;以下是几个建议&#xff1a; 3.开展副业或兼职工作&#xff1a;4.创业或投资&#xff1a;5.构建个人品牌…...

使用 CycleGAN 进行图像到图像转换

介绍 在人工智能和计算机视觉领域,CycleGAN 是一项非凡的创新,它重新定义了我们感知和操作图像的方式。这种尖端技术彻底改变了图像到图像的转换,实现了领域之间的无缝转换,例如将马变成斑马或将夏日风景变成雪景。在本文中,我们将揭开 CycleGAN 的魔力,并探索其在各个领…...

Svg使用和注册components文件夹内部全部为全局组件

1.安装SVG依赖插件 pnpm install vite-plugin-svg-icons -D 2. 封装SvgIcon <template><div><svg :style"{ width: width, height: height }"><use :xlink:href"prefix name" :fill"color"></use></svg>…...

解决idea编辑application.yml文件或properties文件没有提示问题

注意&#xff1a;这里说的没有提示&#xff0c;是针对application.properties和application.yml文件 解决办法&#xff1a;在idea的插件面板中&#xff0c;禁用或卸载 wl Spring Assistant插件即可解决问题。...

前端懒加载

懒加载的概念 懒加载也叫做延迟加载、按需加载&#xff0c;指的是在长网页中延迟加载图片数据&#xff0c;是一种较好的网页性能优化的方式。在比较长的网页或应用中&#xff0c;如果图片很多&#xff0c;所有的图片都被加载出来&#xff0c;而用户只能看到可视窗口的那一部分…...

【手动配置ip地址后,电脑仍自动分配ip的问题】

现象 手动给电脑分配了一个ipv4地址&#xff0c;但是电脑会自动分配一个169开头的ipv4&#xff0c;导致虽然可以上网&#xff0c;但访问不了局域网内其他的设备&#xff08;我配置的另一个网关&#xff0c;所以可以上网&#xff09; 原因 ip地址冲突了&#xff0c;把电脑的i…...

移远RM500U-CN模块直连嵌入式ubuntu实现拨号上网

目录 1 平台&#xff1a; 2 需要准备的资料 3 参考文档 4 编译环境与驱动移植 4.1 内核驱动添加厂家ID和产品ID 4. 2.添加零包处理 4.3 增加复位恢复机制 4.4 增加批量输出 批量输出 URB 的数量和容量 的数量和容量 4.5 内核配置与编译 5 QM500U-CN拨号&#xff08;在开…...

【JavaWeb】MySQL基础操作

1 通用语法规则 SQL语句可以单行或者多行书写&#xff0c;以分号结尾SQL语句不区分大小写&#xff0c;关键字建议使用大写单行注释 --注释内容&#xff08;通用&#xff09; # 注释内容&#xff08;MySQL独有&#xff09;多行注释 /* 注释内容 */ 2 语句 数据库 -- 查…...

【Tool】虚拟机安装与调试与设置与主机共享文件

前言 安装了vm17&#xff0c;实现了与主机文件共享&#xff0c; 步骤 下载虚拟机&#xff08;试用版&#xff09; Download VMware Workstation Pro 双击安装 暂不激活或者 使用如下激活码 KRNJX-22GXY-HCW46-MWYHY-YWRDB RDHTN-YFFKY-8YVR7-Q996Y-K74X3 N2XRH-GCH84-MV…...

Spring中的接口使用

技术主题 在我们的项目中,经常会使用一些注解,注解带给我们代码简洁,本质是用于在代码中添加元数据信息,从而实现更加灵活、高效和可维护的代码结构。 技术原理 注解一@Target(ElementType.TYPE) 这个注解表示被它修饰的注解可以应用在类、接口、枚举等类型上。换句话说…...

爬虫017_urllib库_get请求的quote方法_urlencode方法_---python工作笔记036

按行来看get请求方式 比如这个地址 上面这个地址复制粘贴过来以后 可以看到周杰伦变成了一堆的Unicode编码了 所以这个时候我们看,我们说https这里,用了UA反爬,所以这里 我们构建一个自定义的Request对象,里面要包含Us...

Http、SSE、Websocket的区别

从传输方向上看 http是客户端发送请求&#xff0c;然后服务端进行响应的单向通道网络传输协议&#xff1b; SSE&#xff08; Server-sent Events &#xff09;则相反&#xff0c;只能是服务器向客户端发送消息&#xff0c;如果客户端需要向服务器发送消息&#xff0c;则需要一…...

【资料分享】全志科技T507工业核心板硬件说明书(一)

目 录 前言 1硬件资源 1.1CPU 1.2ROM 1.3RAM 1.4时钟系统 1.5电源 1.6LED...

JavaScript类

JavaScript 类(class) 类是用于创建对象的模板。 我们使用 class 关键字来创建一个类&#xff0c;类体在一对大括号 {} 中&#xff0c;我们可以在大括号 {} 中定义类成员的位置&#xff0c;如方法或构造函数。 每个类中包含了一个特殊的方法 constructor()&#xff0c;它是类…...

One-4-All: Neural Potential Fields for Embodied Navigation 论文阅读

论文信息 题目&#xff1a;One-4-All: Neural Potential Fields for Embodied Navigation 作者&#xff1a;Sacha Morin, Miguel Saavedra-Ruiz 来源&#xff1a;arXiv 时间&#xff1a;2023 Abstract 现实世界的导航可能需要使用高维 RGB 图像进行长视野规划&#xff0c;这…...

Python爬虫实战:研究MechanicalSoup库相关技术

一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

【第二十一章 SDIO接口(SDIO)】

第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

剑指offer20_链表中环的入口节点

链表中环的入口节点 给定一个链表&#xff0c;若其中包含环&#xff0c;则输出环的入口节点。 若其中不包含环&#xff0c;则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

自然语言处理——循环神经网络

自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元&#xff08;GRU&#xff09;长短期记忆神经网络&#xff08;LSTM&#xff09…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...

算法笔记2

1.字符串拼接最好用StringBuilder&#xff0c;不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...

uniapp 实现腾讯云IM群文件上传下载功能

UniApp 集成腾讯云IM实现群文件上传下载功能全攻略 一、功能背景与技术选型 在团队协作场景中&#xff0c;群文件共享是核心需求之一。本文将介绍如何基于腾讯云IMCOS&#xff0c;在uniapp中实现&#xff1a; 群内文件上传/下载文件元数据管理下载进度追踪跨平台文件预览 二…...