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手柄实现对手柄的按键和模拟值的读取。 很简单,库已经封装好了,直接就可以了。 文件 一、cubemx配置 这个很简单,不需要…...
【TI毫米波雷达笔记】sdk传参时的type避坑
【TI毫米波雷达笔记】sdk传参时的type避坑 这个函数要传一个结构体进去 然后结构体里面有个adcoutcfg结构体变量 adcoutcfg结构体里面共有三个变量 一个adcbitformat结构体 另外两保留 点开adcbitformat结构体发现是个32位段 一共四级结构体 那么请问 为什么adcoutcfg变量不直…...
【算法挨揍日记】day02——双指针算法_快乐数、盛最多水的容器
202. 快乐数 202. 快乐数https://leetcode.cn/problems/happy-number/ 题目: 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为: 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个…...
【Hilog】鸿蒙系统日志源码分析
【Hilog】鸿蒙系统日志源码分析 Hilog采用C/S结构,Hilogd作为服务端提供日志功能。Client端通过API调用(最终通过socket通讯)与HiLogd打交道。简易Block图如下。 这里主要分析一下。Hilog的读、写、压缩落盘,以及higlog与android…...
keil下载程序具体过程4:flash下载算法
引言 本篇文章将介绍flash算法文件,阐述从jlink如何下载镜像文件写入到内部的falsh。 一、XIP 在谈flash下载算法文件时,先说明XIP是什么。 芯片的启动方式有很多种:可以从RAM中启动、内部的flash、外部的flash等等(还有从sd卡、…...
如何快速的让自己从月入2000变成月入两万?
从月入2000变成月入两万 前言我们可以这么做:1.提升自己的技能:2.寻找更好的工作机会:寻找更好的工作机会是一个重要的目标,以下是几个建议: 3.开展副业或兼职工作:4.创业或投资: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文件没有提示问题
注意:这里说的没有提示,是针对application.properties和application.yml文件 解决办法:在idea的插件面板中,禁用或卸载 wl Spring Assistant插件即可解决问题。...
前端懒加载
懒加载的概念 懒加载也叫做延迟加载、按需加载,指的是在长网页中延迟加载图片数据,是一种较好的网页性能优化的方式。在比较长的网页或应用中,如果图片很多,所有的图片都被加载出来,而用户只能看到可视窗口的那一部分…...
【手动配置ip地址后,电脑仍自动分配ip的问题】
现象 手动给电脑分配了一个ipv4地址,但是电脑会自动分配一个169开头的ipv4,导致虽然可以上网,但访问不了局域网内其他的设备(我配置的另一个网关,所以可以上网) 原因 ip地址冲突了,把电脑的i…...
移远RM500U-CN模块直连嵌入式ubuntu实现拨号上网
目录 1 平台: 2 需要准备的资料 3 参考文档 4 编译环境与驱动移植 4.1 内核驱动添加厂家ID和产品ID 4. 2.添加零包处理 4.3 增加复位恢复机制 4.4 增加批量输出 批量输出 URB 的数量和容量 的数量和容量 4.5 内核配置与编译 5 QM500U-CN拨号(在开…...
【JavaWeb】MySQL基础操作
1 通用语法规则 SQL语句可以单行或者多行书写,以分号结尾SQL语句不区分大小写,关键字建议使用大写单行注释 --注释内容(通用) # 注释内容(MySQL独有)多行注释 /* 注释内容 */ 2 语句 数据库 -- 查…...
【Tool】虚拟机安装与调试与设置与主机共享文件
前言 安装了vm17,实现了与主机文件共享, 步骤 下载虚拟机(试用版) 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是客户端发送请求,然后服务端进行响应的单向通道网络传输协议; SSE( Server-sent Events )则相反,只能是服务器向客户端发送消息,如果客户端需要向服务器发送消息,则需要一…...
【资料分享】全志科技T507工业核心板硬件说明书(一)
目 录 前言 1硬件资源 1.1CPU 1.2ROM 1.3RAM 1.4时钟系统 1.5电源 1.6LED...
JavaScript类
JavaScript 类(class) 类是用于创建对象的模板。 我们使用 class 关键字来创建一个类,类体在一对大括号 {} 中,我们可以在大括号 {} 中定义类成员的位置,如方法或构造函数。 每个类中包含了一个特殊的方法 constructor(),它是类…...
One-4-All: Neural Potential Fields for Embodied Navigation 论文阅读
论文信息 题目:One-4-All: Neural Potential Fields for Embodied Navigation 作者:Sacha Morin, Miguel Saavedra-Ruiz 来源:arXiv 时间:2023 Abstract 现实世界的导航可能需要使用高维 RGB 图像进行长视野规划,这…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...
基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...
PostgreSQL——环境搭建
一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在࿰…...
Web后端基础(基础知识)
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 优点:维护方便缺点:体验一般 CS架构:Client/Server,客户端/服务器架构模式。需要单独…...
WebRTC调研
WebRTC是什么,为什么,如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...
