假期在家拆了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,这个很令人纳闷,我玩热血格斗时,多键同时按是常有的事,如果碰上这种不支持多键同时按的手柄,不知人家是怎么处理的。
下面是串口调试助手得到的图。
简单测试程序: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
文章评论(0条评论)
登录后参与讨论