原创 FC手柄的控制[转]

2011-1-14 11:22 3372 11 11 分类: 工程师职场

    假期在家拆了N个FC游戏机手柄(注意是以前小霸王学习机上的15针的手柄,9针的好像有点区别,手头没有9针的,没有研究),认真研究了一下它的驱动,现在写出来,以后可能会用得到,呵呵。
先看控制板,用螺丝刀拆开手柄的塑料壳,看到一个电路板,上面有按键,还有一个黑点,以及5根线,从靠近黑点到远离黑点颜色依次为黄、红、白(或黑)、蓝、棕。这几根线是有特殊意义的,在我拆的几个手柄中,无一例外,都是按上面的顺序排列的。将手柄插到机器上检测各线电压发现红线电平最低,黄线总是+5V相对红线,所以这两个就是电源线了。拔下来,外接+5V电源,经过LED测试(所谓LED测试,是我常用的一种判断芯片输入输出引脚的方法,其实就是在引脚上接一个发光二极管串联一个470欧电阻,若不管上拉还是下拉LED都不亮,那一定是输入引脚,一般芯片的输入电阻很大,是不会让LED点亮的。若LED亮,则证明引脚为输出。判断输入输出有利于了解芯片时序,减少意外的发生),发现只有棕线是手柄输出的,我估计是DATA线。剩下两根一个是串行时钟CLK,一个是锁存,都是输入引脚,只好猜测了。最后发现白线是锁存,蓝线是CLK。列出如下:

1黄 2红 3白 4蓝 5棕
+5V GND LATCH CLK DATA

常规状态下,LATCH为低电平,CLK为高电平,DATA为高电平,这也是初始化端口时的状态。
单片机读取键值时序很简单,LATCH先发送一个高脉冲,(我发送1~10us宽度的,都没问题)数据将锁存到手柄内部的移位寄存器,然后在CLK时钟下降沿数据将从DATA低位在先连续发出。按键映射到数据的对应位上,有键按下则对应位为0,无键按下则为1.即不按任何键时,读取数据为0xFF。
以下是数据位图
D0 D1 D2 D3 D4 D5 D6 D7
A键 B键 选择 开始 上 下 左 右
其中A键就是超级玛丽中的“跳跃”键,B键就是“火炮”键!这个是常识,呵呵
还有就是A键和连_发A键,B键和连_发B键的区别。当你按下A键不放时,读取的数据将始终是0xFE,一直不变。但如果你按下连_发A键时,读取的数据在两次0xFE之间隔着一个或两个0xFF,让主机认为你是在连续多次按下A键。这就是二者的区别了。
大部分按键支持多键同时按下,这样就有多个位同时有效,在程序中要考虑这种情况,注意有的手柄每次只能锁存一个按键,若有多个按键同时按下,则为0xFF,这个很令人纳闷,我玩热血格斗时,多键同时按是常有的事,如果碰上这种不支持多键同时按的手柄,不知人家是怎么处理的。

下面是串口调试助手得到的图。
 

 


最后附上15针母头的线分布图,让针_孔面向你
 

 

 

 



简单测试程序:main.c@GCC20081205
#include <avr/io.h>
#include <util/delay.h>
#include "usart.h"
#define FC_PORT   PORTC
#define FC_DIR    DDRC
#define FC_PIN    PINC
#define FC_LATCH  0x80
#define FC_CLK   0x40
#define FC_DATA   0x20
#define FC_LATCH_0 FC_PORT&=~FC_LATCH
#define FC_LATCH_1 FC_PORT|=    FC_LATCH
#define FC_CLK_0   FC_PORT&=~FC_CLK
#define FC_CLK_1   FC_PORT|=    FC_CLK
#define FC_DATA_IN (FC_PIN&FC_DATA)

void FC_Init(void)
{
FC_DIR|=FC_LATCH|FC_CLK;
FC_DIR&=~FC_DATA;
FC_PORT|=FC_DATA|FC_CLK;
FC_PORT&=~FC_LATCH;
}
unsigned char FC_Getdata(void)
{
unsigned char i,t=0;
FC_LATCH_1;
_delay_us(1);
FC_LATCH_0;
for(i=0;i<8;i++)
{
  t>>=1;
  FC_CLK_0;
  if(FC_DATA_IN)
  {
   t|=0x80;
  }
  _delay_us(1);
  FC_CLK_1;
  _delay_us(1);
}
return t;
}
unsigned char i;
void main(void)
{
FC_Init();
USART_Init(25);
print_str("Hello world\r\n");
while(1)
{
  i=FC_Getdata();
  i^=0xff;
  if(i)
  {
   switch(i)
   {
    case 0x80:
     print_str("Right\r\n");
     break;
    case 0x40:
     print_str("Left\r\n");
     break;
    case 0x10:
     print_str("Up \r\n");
     break;
    case 0x20:
     print_str("Down\r\n");
     break;
    case 0x04:
     print_str("Select\r\n");
     break;
    case 0x08:
     print_str("Start\r\n");
     break;
    case 0x01:
     print_str("ButtonA\r\n");
     break;
    case 0x02:
     print_str("ButtonB\r\n");
     break;
    default:
     print_hex(i);
     print_str("\r\n");
     break;  
   }
  }
  _delay_ms(100);
}
}

做人要厚道微笑,转自:http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=3904285&bbs_id=1000

 

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
我要评论
0
11
关闭 站长推荐上一条 /3 下一条