【正点原子STM32连载】 第四十一章 游戏手柄实验 摘自【正点原子】STM32F103 战舰开发指南V1.2

news2025/7/19 11:26:10

1)实验平台:正点原子stm32f103战舰开发板V4
2)平台购买地址:https://detail.tmall.com/item.htm?id=609294757420
3)全套实验源码+手册+视频下载地址: http://www.openedv.com/thread-340252-1-1.html#

第四十一章 游戏手柄实验

FC游戏机(又称:红白机/小霸王游戏机)发行了很多经典的游戏,给不少人的童年留下了无限乐趣。本章,我们将向大家介绍如何通过STM32来驱动FC游戏机手柄,将FC游戏机的手柄作为战舰STM32开发板的输入设备(综合实验可以直接通过这个手柄来玩FC游戏)。
在本章中,我们将使用STM32驱动FC手柄,将手柄的按键键值等信息通过TFT LCD模块显示出来。本章分为如下几个部分:
41.1 游戏手柄简介
41.2 硬件设计
41.3 软件设计
41.4 下载验证

41.1 游戏手柄简介

FC游戏机曾经是一统天下(现在也还是很多人玩),红极一时,那时任天堂单是FC机的主机的发售收入就超过全美国的电视台的收入的总和。本章,我们将使用STM32来驱动FC手柄,实现手柄控制信号的读取,我们先来了解一下FC手柄。
FC手柄,大致可分为两种:一种手柄插口是11针的,一种是9针的。但11针的现在市面上很少了(因为11针手柄是早期FC组装兼容机最主要的周边),现在几乎都是9针FC组装手柄的天下,所以我们本章使用的是9针FC手柄,该手柄还有一个特点,就是可以直接和DB9的串口公头对插!这样与开发板的连接就简单了。FC手柄的外观如图41.1.1所示:
在这里插入图片描述

图41.1.1 FC手柄外观图
这种手柄一般有10个按键(实际是8个键值):上、下、左、右、Start、Select、A、B、A连发、B连发。这里的A和A连发是一个键值,而B和B连发也是一个键值,只是连发按键当你一直按下的时候,会不停的发送(方便快速按键,比如发炮弹之类的功能)。
FC手柄的控制电路,由1个8位并入串出的移位寄存器(CD4021),外加一个时基集成电路(NE555,用于连发)构成。不过现在的手柄,为了节约成本,直接就在PCB上做绑定了,所以你拆开手柄,一般是看不到里面有四四方方的IC,而只有一个黑色的小点,所有电路都集成到这个里面了,但是他们的控制和读取方法还是一样的。
9针手柄实际上只有5根线起作用,不同的文档里命名会有一些差别,分别如下:
VCC = 5V供电
GND = 地线
LATCH = 锁存信号,由主机发送
CLOCK = 时钟信号,有些文档会叫PULSE,由主机发送
DATA = 串行数据线 低电平有效。
我们可以把它看为键盘,标准的FC手柄的控制读取时序和接线图如图41.1.2所示:
在这里插入图片描述

图41.1.2 FC手柄读取时序和接线图
从上图可看出,读取手柄按键值的信息十分简单:先Latch(锁存键值),然后就得到了第一个按键值(A),之后在Clock的作用下,依次读取其他按键的键值,总共8个按键键值。标准的NES手柄高低电平周期12us,占空比为50%,且按键按下后DATA上的电平为负,不同手柄可能有差异,但时序差不多,我们编程时参考这个时序来实现即可。
有了以上了解,我们就可以通过STM32的IO来驱动FC手柄了。
41.2 硬件设计

  1. 例程功能
    本实验采用STM32的3个普通IO连接FC手柄的Clock、Data和Latch信号,本章实验功能简介:在主函数不停的查询手柄输入,一旦检测到输入信号,则在LCD模块上面显示键值和对应的按键符号。同样我们也是用LED0来指示程序正在运行。
  2. 硬件资源
    1)LED灯
    LED0 - PB5
    2)串口1 (PA9/PA10连接在板载USB转串口芯片CH340上面)
    3)正点原子 2.8/3.5/4.3/7/10寸TFTLCD模块(仅限MCU屏,16位8080并口驱动)
    4)FC游戏手柄
    Clock(PD3)、Data(PB10)和Latch(PB11)
    战舰STM32开发板板载了一个FC手柄接口(COM3),其实就是一个DB9接公头插座,FC手柄接口和COM3公用一个接口,通过开发板上的K1开关来选择,如图41.2.1所示。
    在这里插入图片描述

图41.2.1 COM3功能选择示意图
当K1打到上面(JOYPAD)时,COM3作为FC手柄接口,当K1打到下面(RS232)时,COM3作为RS232串口。COM3接口与MCU的连接原理图如41.2.2所示:
在这里插入图片描述

图41.2.2 FC手柄接头与STM32的连接电路图
图41.2.2中,COM3就是用来连接FC手柄,该接头采用标准的DR9座,当K1开关打到上面的时候,COM_TX连接U3_TX、COM_RX连接U3_RX,然后通过P8,连接在PB11和PB10上面。所以要将FC手柄通过COM3连接在STM32上面,必须K1开关打到上面,并且P8需要用跳线帽连接PB10(TX)和COM3_RX、PB11(RX)和COM3_TX。
图中的D3稳压二极管,是为了防止COM3做RS232使用时,高压烧坏MCU的IO口。
本例程使用FC手柄(JOYPAD)功能时,COM_TX是LAT(Latch)信号,COM_RX是DAT(Data)信号,JOY_CLK是CLK(Clock)信号,分别连接在STM32的PB11、PB10和PD3上面,这里JOY_CLK和OV_SCL信号线共用PD3,所以FC手柄和摄像头模块得分时复用PD3才可以。
在设置好开发板的连接后(P8跳线帽:PB10(TX)和COM3_RX连接、PB11(RX)和COM3_TX连接,K1开关打JOYPAD位置),将FC手柄插入COM3插口即可。
41.3 程序设计
41.3.1 程序流程图
在这里插入图片描述

图41.3.1.1 游戏手柄实验程序流程图
41.3.2 程序解析

  1. joypad驱动代码
    这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。JOYPAD驱动源码包括两个文件:joypad.c和joypad.h。joypad.h和前面定时器输入捕获功能的.h头文件代码相似,这里就不介绍了,详见本例程源码。
    下面我们直接介绍joypad.c的程序,下面是与红外遥控初始化相关的函数,其定义如下:
/**
 * @brief     	初始化手柄接口
 * @param      	无
 * @retval     	无
 */
void joypad_init(void)
{
    JOYPAD_CLK_GPIO_CLK_ENABLE(); 	/* CLK所在IO时钟初始化 */
    JOYPAD_LAT_GPIO_CLK_ENABLE(); 	/* LATCH所在IO时钟初始化 */
    JOYPAD_DATA_GPIO_CLK_ENABLE();	/* DATA 所在IO时钟初始化 */

    GPIO_InitTypeDef gpio_init_struct;
    gpio_init_struct.Pin = JOYPAD_CLK_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;
    gpio_init_struct.Pull = GPIO_PULLUP;
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_MEDIUM;
 HAL_GPIO_Init(JOYPAD_CLK_GPIO_PORT, &gpio_init_struct);

gpio_init_struct.Pin = JOYPAD_LAT_GPIO_PIN;
HAL_GPIO_Init(JOYPAD_LAT_GPIO_PORT, &gpio_init_struct);

    gpio_init_struct.Pin = JOYPAD_DATA_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_INPUT;
    gpio_init_struct.Pull = GPIO_PULLUP;
gpio_init_struct.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(JOYPAD_DATA_GPIO_PORT, &gpio_init_struct);
}

/**
 * @brief    	手柄延迟函数
 * @param     	t    : 要延时的时间
 * @retval    	无
 */
static void joypad_delay(uint16_t t)
{
    while (t--);
}

/**
 * @brief      	读取手柄按键值
 *   @note     	FC手柄数据输出格式:
 *              	每给一个脉冲,输出一位数据,输出顺序:
 *              	A -> B -> SELECT -> START -> UP -> DOWN -> LEFT -> RIGHT.
 *              	总共8位, 对于有C按钮的手柄, 按下C其实就等于 A + B 同时按下.
 *              	按下是1,松开是0.
 * @param      	无
 * @retval     	按键结果, 格式如下:
 *              	[7]:右
 *              	[6]:左
 *              	[5]:下
 *              	[4]:上
 *              	[3]:Start
 *              	[2]:Select
 *              	[1]:B
 *              	[0]:A
 */
uint8_t joypad_read(void)
{
    volatile uint8_t temp = 0;
uint8_t t;

    JOYPAD_LAT(1);          		/* 锁存当前状态 */
    joypad_delay(80);
JOYPAD_LAT(0);

    for (t = 0; t < 8; t++) 		/* 移位输出数据 */
    {
        temp >>= 1;
        if (JOYPAD_DATA == 0)
        {
            temp |= 0x80;   		/* LOAD之后,就得到第一个数据 */
        }

        JOYPAD_CLK(1);      		/* 每给一次脉冲,收到一个数据 */
        joypad_delay(80);
        JOYPAD_CLK(0);
        joypad_delay(80);
}

    return temp;
}

有了以上函数,那我们在应用程序中初始化控制手柄的IO后,就可以利用joypad_read()返回的键值来设计其它的应用程序了,如同我们使用开发板上的按键一样简单。
2. main.c代码
在main.c里面编写如下代码。

/* 手柄按键符号定义 */
const char *JOYPAD_SYMBOL_TBL[8] = {"Right", "Left", "Down", "Up", 
"Start", "Select", "A", "B"};

int main(void)
{
    uint8_t key;
uint8_t t = 0, i = 0;

    HAL_Init();                             		/* 初始化HAL库 */
    sys_stm32_clock_init(RCC_PLL_MUL9);		/* 设置时钟, 72Mhz */
    delay_init(72);                        		/* 延时初始化 */
    usart_init(115200);                   		/* 串口初始化为115200 */
    led_init();                            		/* 初始化LED */
    lcd_init();                            		/* 初始化LCD */
joypad_init();                        		/* 游戏手柄初始化 */

    lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);
    lcd_show_string(30, 70, 200, 16, 16, "JOYPAD TEST", RED);
    lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
    lcd_show_string(30, 110, 200, 16, 16, "KEYVAL:", RED);
lcd_show_string(30, 130, 200, 16, 16, "SYMBOL:", RED);

    while (1)
    {
        key = joypad_read();

        if (key) 		/* 手柄有按键按下 */
        {
            lcd_show_num(116, 130, key, 3, 16, BLUE);	/* 显示键值 */

            for (i = 0; i < 8; i++)
            {
                if (key & (0X80 >> i))
                {
/* 清除之前的显示 */
               	lcd_fill(30 + 56, 130, 30 + 56 + 48, 150 + 16, WHITE); 
                	lcd_show_string(30 + 56, 130, 200, 16, 16, 
(char *)JOYPAD_SYMBOL_TBL[i], BLUE);/*显示符号*/
                }
            }
        }

        delay_ms(10);
        t++;

        if (t == 20)
        {
            t = 0;
            LED0_TOGGLE(); /* LED0闪烁 */
        }
    }
}

此部分代码也比较简单,初始化JOYPAD之后,就一直扫描FC手柄(joypad_read函数),然后只要接收到手柄的有效型号,就在LCD模块上显示出来。
41.4 下载验证
在代码编译成功之后,我们通过下载代码到正点原子战舰STM32开发板上,可以看到LCD显示如图41.4.1所示的内容:
在这里插入图片描述

图41.4.1程序运行效果图
此时我们按下FC手柄的按键,则可以看到LCD上显示了对应按键的键值以及对应的符号。如图41.4.2所示:
在这里插入图片描述

图41.4.2解码游戏手柄数据成功

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/685946.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【从零开始学习C++ | 第二十一篇】C++新增特性 (上)

目录 前言&#xff1a; 委托构造函数&#xff1a; 类内初始化&#xff1a; 空指针&#xff1a; 枚举类&#xff1a; 总结&#xff1a; 前言&#xff1a; C的学习难度大&#xff0c;内容繁多。因此我们要及时掌握C的各种特性&#xff0c;因此我们更新本篇文章&#xff0c;向…

部署vue element-ui admin报错(vue2)

部署vue element-ui admin报错(vue2) 目录 部署vue element-ui admin报错(vue2) 一、官方安装说明 二、部署报错的关键影响因素 2.1、“开发模板”版本 2.2、完整版 2.2.1、基础知识和基础依赖 2.2.2、原理-安装过程 三、完整版 3.3、win10环境 四、效果 4.1、win7…

云安全技术——kvm虚拟化技术

目录 10-1 kvm简介 10-2 在CentOS 7 图形化界面下安装KVM 使用IDEA开发读写MySQL数据库程序 实验目的 了解 CentOS7图形化界面的部署方法 了解 KVM的组成和作用 了解 KVM的技术架构 了解KVM的安装方法 了解 KVM创建虚拟机的方法 了解KVM的常用管理命令 实验要求 能部署图形化…

为什么建议孩子学Python?理由都在这!

近几年&#xff0c;越来越多的家长选择让孩子学习编程&#xff0c;以此提高孩子的逻辑思维、信息素养等综合能力。 Python作为一种计算机程序设计语言&#xff0c;在科技行业中有广泛的应用&#xff0c;逐渐成为少儿编程教育中必学课程之一。今天&#xff0c;编编就为大家详细…

【开发者指南】如何在MyEclipse中编辑HTML或JSP文件?(二)

在上文中&#xff08;点击这里回顾>>&#xff09;&#xff0c;我们为大家介绍了HTML / JSP编辑器、智能代码完成和内容辅助等功能&#xff0c;本文将继续介绍Emmet支持、Outline 视图功能等。 MyEclipse v2023.1正式版下载 如果您有HTML或JSP文件要编辑&#xff0c;这里…

chatgpt赋能python:Python聊天程序:现代化交流的必备工具

Python聊天程序&#xff1a;现代化交流的必备工具 在信息技术快速发展的现代社会&#xff0c;聊天作为一种流行的交流方式已经取代了传统的语音电话和短信。由于智能手机和电脑的广泛普及&#xff0c;越来越多的人习惯于使用聊天软件来与朋友、家人和同事保持联系。因此&#…

GBASE南大通用携手麒麟软件、索信达 共推金融信创联合解决方案

在国家信创战略推动下&#xff0c;我国正逐步实现基础硬件-基础软件-行业应用软件的国产化替代。信创浪潮中&#xff0c;各产业链以及不同垂直细分领域的创新主体&#xff0c;正以开放、创新、团结的姿态&#xff0c;形成高凝聚力的生态合作&#xff0c;共推信创产业发展&#…

【Java】JVM学习(三)

JVM的整体内存结构 本地方法栈 本地方法栈跟 Java 虚拟机栈的功能类似&#xff0c;Java 虚拟机栈用于管理 Java 函数的调用&#xff0c;而本地方法栈则用于管理本地方法的调用。但本地方法并不是用 Java 实现的&#xff0c;而是由 C 语言实现的(比如Object.hashcode方法)。 …

PCA(主成分分析)

PCA(Principal Component Analysis)是一种常用的数据分析方法。PCA通过线性变换将原始数据变换为一组各维度线性无关的表示&#xff0c;可用于提取数据的主要特征分量&#xff0c;常用于高维数据的降维。数据降维是无监督学习的另外一个常见问题。 数据的向量表示及降维问题 …

PostgreSQL 如何对索引进行分析和处理

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到2群&#xff08;共…

智慧煤矿4G物联网方案,矿山矿井远程监控管理4G网关应用

随着经济发展煤矿需求不断激增&#xff0c;矿山矿井普遍处于偏远山区&#xff0c;生产管理、人员安全、生产效率是每个矿山矿井都需要考虑的问题&#xff0c;利用网关对现场终端设备连接组网&#xff0c;实现智慧煤矿远程管理。 各矿山矿井分布范围比较广泛&#xff0c;户外环境…

《Opencv3编程入门》学习笔记—第八章

《Opencv3编程入门》学习笔记 记录一下在学习《Opencv3编程入门》这本书时遇到的问题或重要的知识点。 第八章 图像轮廓与图像分割修复 一、查找并绘制轮廓 一个轮廓一般对应一系列的点&#xff0c;也就是图像中的一条曲线&#xff0c;其表示方法可能根据不同的情况而有所不…

FFmpeg 播放器实现音视频同步的几种方式

我们基于 FFmpeg 利用 OpenGL ES 和 OpenSL ES 分别实现了对解码后视频和音频的渲染&#xff0c;本文将实现播放器的最后一个重要功能&#xff1a;音视频同步。 老人们经常说&#xff0c;播放器对音频和视频的播放没有绝对的静态的同步&#xff0c;只有相对的动态的同步&#…

深度学习管理工具

1. mlflow https://zhuanlan.zhihu.com/p/363673389 官方文档&#xff1a; https://www.mlflow.org/docs/latest/index.html https://zhuanlan.zhihu.com/p/67173051 在跟踪实验时&#xff0c;通过运行 mlflow ui 后在 http&#xff1a;// localhost&#xff1a;5000 中进行…

ranger,hive,hdfs的三者的权限管理

ranger&#xff0c;hive&#xff0c;hdfs的三者的权限管理 情况一&#xff1a;连接datagrip 用户在hdfs上的权限 可以看出只给了用户write权限&#xff0c;尝试登录xwq用户&#xff0c;在datagrip上登录成功 经过实验验证&#xff1a;要想使用datagrip或者hive-cli登录hive…

C++11【一】

文章目录 一、C11简介二、右值引用三、可变参数模板四、 empacle_back(移动构造/赋值)五、简单特性 一、C11简介 C11是C编程语言的一个版本&#xff0c;于2011年发布。C11引入了很多新特性&#xff0c;比如&#xff1a;类型推导(auto关键字)、Lambda表达式、线程库、列表初始化…

电源浪涌保护器加装后备保护器的作用

随着现代化技术的发展&#xff0c;信息化系统集成度越来越高。设备敏感度高&#xff0c;抗冲击能力低&#xff0c;极易受到电涌脉冲的危害。电涌保护器&#xff08;SPD&#xff09;作为专业的防电涌产品&#xff0c;应用越来越广&#xff0c;SPD的应用涉及很多的专业知识&#…

孩子创新思维秘籍

头脑风暴最重要的原则之一就七个字&#xff0c; 要数量&#xff0c;不要质量。 意思就是说&#xff0c;你尽可能的去胡思乱想&#xff0c;胡说八道&#xff0c;天马行空就对了。 我们从这一大堆古灵精怪的玩意儿里面去筛选那些真正有价值的东西&#xff0c;可以拓展的方案。 然…

【技术选型】Redis的几种集群方案、及优缺点对比

文章目录 背景一、主从模式二、哨兵模式三、Redis Cluster四、各大厂的Redis集群方案客户端分片代理分片Codis 五、Redis集群方案解决方案六、Redis集群方案原理总结 背景 在服务开发中&#xff0c;单机都会存在单点故障的问题&#xff0c;及服务部署在一台服务器上&#xff0…

GCP学习笔记(二)——大数据和机器学习

文章目录 一、数据读取和处理1.Pub/Sub代码实践PublishingSubscribing 2. Dataflow使用Python搭建Pipeline 3. Dataproc4. Cloud Data Fusion5. 其他工具Cloud Composer &#xff08;Apache Airflow&#xff09;Cloud Scheduler 二、可视化与分析1. Looker2. Looker Studio3. B…