打印

【连载】STM32开发指南--第三十三章 FC游戏手柄控实验

[复制链接]
6088|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
正点原子|  楼主 | 2013-3-21 22:18 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 正点原子 于 2013-3-21 22:19 编辑

第三十三章  游戏手柄实验
        相信80后小时候都有玩过FC游戏机(又称:红白机/小霸王游戏机),那是一代经典,给我们的童年带了了无限乐趣。本章,我们将向大家介绍如何通过STM32来驱动FC游戏机手柄,将FC游戏机的手柄作为战舰STM32开发板的输入设备(综合实验可以直接通过这个手柄来玩FC游戏)。
在本章中,我们将使用STM32驱动FC手柄,将手柄的按键键值等信息通过TFTLCD模块显示出来。本章分为如下几个部分:
33.1 游戏手柄简介
33.2 硬件设计
33.3 软件设计
33.4 下载验证
33.1游戏手柄简介

       FC游戏机曾今是一统天下(现在也还是很多人玩),红极一时,那时任天堂单是FC机的主机的发售收入就超过全美国的电视台的收入的总和。本章,我们将使用STM32来驱动FC手柄,实现手柄控制信号的读取,我们先来了解一下FC手柄。
       FC手柄,大致可分为两种:一种手柄插口是11针的,一种是9针的。但11针的现在市面上很少了(因为11针手柄是早期FC组装兼容机最主要的周边),现在几乎都是9针FC组装手柄的天下,所以我们本章使用的是9针FC手柄,该手柄还有一个特点,就是可以直接和DR9的串口头对插!这样同开发板的连接就简单了。FC手柄的外观如图33.1.1所示:
图33.1.1 FC手柄外观图
       这种手柄一般有10个按键(实际是8个键值):上、下、左、右、Start、Select、A、B、A连发、B连发。这里的A和A连发是一个键值,而B和B连发也是一个键值,只是连发按键当你一直按下的时候,会不停的发送(方便快速按键,比如发**弹之类的功能)。
FC手柄的控制电路,由1个8位并入串出的移位寄存器(CD4021),外加一个时基集成电路(NE555,用于连发)构成。不过现在的手柄,为了节约成本,直接就在PCB上做绑定了,所以你拆开手柄,一般是看不到里面有四四方方的IC,而只有一个黑色的小点,所有电路都集成到这个里面了,但是他们的控制和读取方法还是一样的。
9针手柄的读取时序和接线图如图33.1.2所示:

图33.1.2 FC手柄读取时序和接线图
       从上图可看出,读取手柄按键值的信息十分简单:先Latch(锁存键值),然后就得到了第一个按键值(A),之后在Clock的作用下,依次读取其他按键的键值,总共8个按键键值。
       有了以上了解,我们就可以通过STM32的IO来驱动FC手柄了。
33.2 硬件设计
本实验采用STM32的3个普通IO连接FC手柄的Clock、Data和Latch信号,本章实验功能简介:在主函数不停的查询手柄输入,一旦检测到输入信号,则在LCD模块上面显示键值和对应的按键符号。同样我们也是用LED0来指示程序正在运行。
所要用到的硬件资源如下:
1)  指示灯DS0
2) TFTLCD模块
3)  FC手柄
前两个,在之前的实例已经介绍过了,FC手柄属于外部器件。战舰STM32开发板板载了一个FC手柄接口(就是一个DR9接头,在开发板上标号为JOY_PAD),该接口与MCU的连接原理图如33.2.1所示:
图33.2.1 FC手柄接头与STM32的连接电路图
图中,JOY_PAD就是用来连接FC手柄的,该接头采用标准的DR9座,战舰STM32开发板上有2个DR9座,一个用来接FC手柄(有JOY_PAD字样,LCD左上),另外一个用来接RS232串口(有COM字样,LCD右上),这两个头千万不要接错!否则可能烧坏手柄或者烧坏STM32
从上图我们知道,手柄的CLK(Clock)、LAT(Latch)和DAT(Data)分别连接在STM32的PC12、PC8和PC9上面,这里与SDIO部分信号线共用了,所以当使用SDIO的时候,就不能使用FC手柄了。因为信号线都是直连的,所以我们在开发板上不需要做配置,只需要将FC手柄插入JOY_PAD插口即可。
开发板配套的手柄,见图33.1.1。

33.3 软件设计
打开上一章的工程,首先在HARDWARE文件夹下新建一个REMOTE的文件夹。然后新建一个joypad.c和joypad.h的文件保存在JOYPAD文件夹下,并将这个文件夹加入头文件包含路径。
打开joypad.c文件,输入如下代码:
#include "joypad.h"
//初始化手柄接口.
void JOYPAD_Init(void)
{
      RCC->APB2ENR|=1<<4;//先使能外设PORTC时钟     
       GPIOC->CRH&=0XFFF0FF00;
       GPIOC->CRH|=0X00030083;   
       GPIOC->ODR|=3<<8;
       GPIOC->ODR|=1<<12;
}
//读取手柄按键值.
//FC手柄数据输出格式:
//每给一个脉冲,输出一位数据,输出顺序:
//A->B->SELECT->START->UP->DOWN->LEFT->RIGHT.
//总共8位,对于有C按钮的手柄,按下C其实就等于A+B同时按下.
//按下是0,松开是1.
//返回值:
//[0]:右
//[1]:左
//[2]:下
//[3]:上
//[4]:Start
//[5]:Select
//[6]:B
//[7]:A
u8 JOYPAD_Read(void)
{
       u8 temp=0;
       u8 t;
       JOYPAD_LAT=1;                              //锁存当前状态
      JOYPAD_LAT=0;
       for(t=0;t<8;t++)
       {
              temp<<=1;   
              if(JOYPAD_DAT)temp|=0x01;     //LOAD之后,就得到第一个数据
              JOYPAD_CLK=1;                     //每给一次脉冲,收到一个数据
             JOYPAD_CLK=0;
       }
       return temp;
}
该部分代码仅2个函数,都比较简单,JOYPAD_Init函数用于初始化IO,即把PC8、PC9和PC12设置为正确的状态,以便同FC手柄通信。另外一个函数JOYPAD_Read就是按照图33.1.2所示的时序读取FC手柄,该函数的返回值就是手柄的状态。
保存joypad.c,然后把该文件加入HARDWARE组下。接下来打开joypad.h在该文件里面加入如下代码:
#ifndef __JOYPAD_H
#define __JOYPAD_H  
#include "sys.h"
//手柄连接引脚
#define JOYPAD_CLK PCout(12)      //时钟            PC9
#define JOYPAD_LAT PCout(8)        //锁存        PC8
#define JOYPAD_DAT PCin(9)         //数据        PC12   
void JOYPAD_Init(void);                   //初始化
u8 JOYPAD_Read(void);                    //读取键值                                   
#endif
这部分代码就不介绍了,我们保存joypad.h,然后在test.c里面修改主函数如下:
const u8*JOYPAD_SYMBOL_TBL[8]=
{"Right","Left","Down","Up","Start","Select","A","B"};//手柄按键符号定义
int main(void)
{           
       u8 key;
       u8 t=0,i=0;           
      Stm32_Clock_Init(9);    //系统时钟设置
       uart_init(72,9600);      //串口初始化为9600
       delay_init(72);                  //延时初始化
       LED_Init();                //初始化与LED连接的硬件接口
       LCD_Init();                  //初始化LCD
       usmart_dev.init(72);      //初始化USMART      
       JOYPAD_Init();            //手柄初始化
      POINT_COLOR=RED;//设置字体为红色
       LCD_ShowString(60,50,200,16,16,"WarShip STM32");   
       LCD_ShowString(60,70,200,16,16,"JOYPAD TEST");     
       LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");
       LCD_ShowString(60,110,200,16,16,"2012/9/12");
     LCD_ShowString(60,130,200,16,16,"KEYVAL:");         
   LCD_ShowString(60,150,200,16,16,"SYMBOL:");         
      POINT_COLOR=BLUE;//设置字体为红色
       while(1)
       {
              key=JOYPAD_Read();
              if(key!=0XFF)
              {
                     LCD_ShowNum(116,130,key,3,16);//显示键值
                     for(i=0;i<8;i++)
                     {
                            if((key&(1<<i))==0)
                            {
                                   LCD_Fill(60+56,150,60+56+48,150+16,WHITE);//清除之前的显示
                                   LCD_ShowString(60+56,150,200,16,16,(u8*)
JOYPAD_SYMBOL_TBL); //显示符号
                            }           
                     }               
              }
             delay_ms(10);
              t++;
              if(t==20)
              {
                     t=0;
                     LED0=!LED0;
              }
       }
}
此部分代码也比较简单,初始化JOYPAD之后,就一直扫描FC手柄(通过JOYPAD_Read函数实现),然后只要接收到手柄的有效信号,就在LCD模块上面显示出来。
至此,我们的软件设计部分就结束了。
33.4下载验证
在代码编译成功之后,我们通过下载代码到ALIENTEK战舰STM32开发板上,可以看到LCD显示如图33.4.1所示的内容:

图33.4.1程序运行效果图
此时我们按下FC手柄的按键,则可以看到LCD上显示了对应按键的键值以及对应的符号。如图33.4.2所示:

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


实验28 游戏手柄实验.rar (142.88 KB)

《STM32开发指南》第三十三章 FC游戏手柄实验.rar (580.23 KB)


沙发
aozima| | 2013-3-21 23:30 | 只看该作者
NB,学习了。

使用特权

评论回复
板凳
betbet| | 2013-3-25 18:49 | 只看该作者
很好。。

使用特权

评论回复
地板
sinadz| | 2013-3-25 21:45 | 只看该作者
LZ可以把这些连载整理成一本书了

使用特权

评论回复
5
正点原子|  楼主 | 2013-3-26 22:49 | 只看该作者
sinadz 发表于 2013-3-25 21:45
LZ可以把这些连载整理成一本书了

已经在出版了,5月份左右正式和大家见面。

使用特权

评论回复
6
longfenghugui| | 2014-8-21 15:20 | 只看该作者

使用特权

评论回复
7
springvirus| | 2015-6-9 12:39 | 只看该作者
顶,正需要FC手柄的驱动,谢谢!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:我的STM32开发板店铺:http://openedv.taobao.com 我的技术论坛论坛:www.openedv.com

91

主题

264

帖子

71

粉丝