本章分为如下几个部分:
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)< p="" style="margin: 0px;">
{
LCD_Fill(60+56,150,60+56+48,150+16,WHITE);//清除之前的显示
LCD_ShowString(60+56,150,200,16,16,(u8*)
JOYPAD_SYMBOL_TBL[i]); //显示符号
}
}
}
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解码游戏手柄数据成功