找回密码
 注册

QQ登录

只需一步,快速开始

查看: 21571|回复: 27

自制FC无线手柄

  [复制链接]
发表于 2019-5-22 14:16:45 | 显示全部楼层 |阅读模式
本帖最后由 雷精灵2046 于 2019-6-14 09:28 编辑 " I' U0 `( Y4 {
: @& c: ^7 p+ I. D- r4 E
没有用复杂的分立元件搭建发射接收电路,直接用的现成的2.4G无线模块jdy-40。: o5 N  a  Z/ g. }1 E

0 Y& u! |9 d4 r* m
" F, W" e, T- D发射端靠3.7V锂电池供电,用了一片SOP8封装的STC单片机,负责产生连发脉冲,同时负责检测电池电量,电压低于3V左右的时候触发低压中断,低压指示LED就会亮起来告知该充电了。平时发射模块和单片机均处于睡眠状态,有按键按下才会唤醒,从而实现省电。实测睡眠状态下整机电流约1~2uA。板子洗了一下稍微干净了一点。因为对于微功耗设备来说,焊接残余的助焊剂可能会增加漏电流。7 Q! U) X+ }% j9 p$ s
4 }& `0 B% F  b0 t6 X
买了一个火花的FC山寨手柄,去掉里面的牛屎板子,并修正一下塑料挡板,把锂电池和充电模块装进去。
7 H2 @/ t6 @* X. B9 j( \7 l为了减少体积,充电模块裁剪得十分小,并且更换了充电电阻使之适应这个小小的锂电池。这么小容量的电池,也不需要多么大的充电电流是吧?  b2 [; k. T: p. A3 U
然后统统用热熔胶粘上。充电电流比较小,所以发热很少,不会熔化热熔胶。, @5 x3 J- H$ l3 w
' Q: b4 x! \1 h$ P( `& b
3 F3 e$ H1 O. o
3 H5 l0 F: u2 T% f
最后把按键、导电橡胶和电路板装上去。3 [2 N# ]# T$ s1 l" I$ A
精心裁剪了电路板,正好扣上,不会阻碍其他元件,也不会影响后盖和拧螺丝。2 d( D; T3 }& ^7 ]8 W6 ?6 C

* C1 T% Z6 Y6 \9 }
7 w) \" M* ?# D& \" ?完工!
) l% O# k1 Z3 \7 {
/ @1 X6 T+ q3 Y5 Z
3 w' T7 `1 C3 ~( `/ l这是充电的MicroUSB插座。旁边的小孔用于透出低压报警LED的光线。
7 N" W/ ~+ D3 _" V4 M2 u+ {* I4 T) x3 x6 }& S

1 B6 Z6 H: ]: P7 p5 d接收端用一片DIP16封装的STC单片机模拟CD4021。为啥要用单片机模拟而不是直接用CD4021?因为jdy-40模块接收端在有按键按下的时候输出高电平,无按键按下输出低电平,和普通手柄正好相反。当然我也可以用两片74HC00或者74HC04之类的逻辑门进行反相,但那就增加了芯片的数量。对于FC手柄这种工作频率并不高的设备来说,STC单片机完全可以胜任模拟工作。
4 v* w/ ^$ K2 e: C; d7 |
6 _0 I: M6 |/ O6 m  l% d% Q$ f. d2 x
) B3 h) P, F. U8 w, I
" |& q- H+ b/ o+ R8 _& _电路设计有点小小的错误,所以有几根飞线。原本设计使用低压差LDO是XC6206,结果在做这个接收模块的时候,买的LDO居然找不到了!无奈只好用了AMS1117。幸好对于接收模块来说是5V降到3.3V,1117可以胜任。要是发射端手柄的话,3.7V降到3.3V,那就非得用6206不可了。
5 j$ E' h+ e( }- N5 `4 T% A7 A9 K/ `. U
实测十分灵敏,延迟极小几乎感觉不出来。可惜这山寨手柄的手感并不佳,尤其是方向键,软塌塌的。看来我得买个剪线手柄改装。
# f+ h$ H. w: w/ |& v6 w! ?3 S( `1 t) E
这是电路图,有兴趣的朋友可以参考。
$ G) g- E& k  Q' h
( K% \% \- k; X! U: a2 x% D& F( {3 u( h3 \
我信奉开源主义,十分痛恨把技术藏着掖着。好东西大家分享嘛!所以两个单片机的源代码大公开!, m9 s( p9 I& U& a
编译器:Keil 51。
2 w" z" H" C3 W) M% s& W+ ~" |: Z4 t: S" x- G3 C# e3 p0 h; e2 t. a
发射端:' Q1 z0 f# f5 X' _) o5 M
  1. #include <INTRINS.H>
    # u! ~) J7 ?9 T2 }5 m
  2. #include "STC15W.h"
    2 m3 t3 N' D3 [  T$ X4 l

  3. " `' E/ k; F) I0 B) D

  4. ' E" X/ R; a$ |$ H) }( Y9 O$ B
  5. /*
    7 i( ^- {4 r! Q1 X
  6. --------------------------6 `1 g  {" o! L5 K8 g: x7 G: n
  7. |1 (OUT)        \__/   (INT1) 8|* b5 {  |* L' _4 x! {
  8. |                                                   |( b, ?7 A! _/ c6 e$ _' h5 @
  9. |2 (VCC)                   (INT0) 7|0 u3 H3 ?1 t- E1 {& A# t! l9 Z: i
  10. |                 STC15W204S                   |
    ) u5 {) L5 j/ }1 L+ Y
  11. |3 (LED)                         (TXD) 6|' e8 u6 O; O$ M0 G; F4 r9 T- a" j+ v
  12. |                                                   |# r! M3 r8 B, A9 I% V
  13. |4 (GND)                         (RXD) 5|) R- }. D1 z: v! t$ ~
  14. --------------------------
    2 |% n5 }2 |; b* c
  15. 0 }- S: a" |" G
  16. LED ---|<|---[===]--- VCC
    ! h: k7 @' p8 q( o4 T" F
  17.            Red          330
    - i& V% [) k+ Q; o. C

  18. 0 V: G$ z" K8 u$ m" A" a* `, _
  19. Fosc = 6MHz/ \. R+ t: K3 h. C
  20. */1 K( d/ b: b3 W' o

  21. : |! `$ Y, a7 K2 z/ n+ ^! w4 d

  22. - s* }6 U$ G8 V: e( ?
  23. // 矩形波输出脚; f& n- N2 _3 s9 a% g
  24. sbit OUT = P5^4;
    8 _" d5 X. R, m$ P  m' ?
  25. // 低压指示灯引脚
    4 ^7 A* ~1 a5 m) C
  26. sbit LED = P5^5;
    / l7 e# B7 Y6 W; r5 q; E1 Z$ B
  27. ! V  U/ G! p# ^2 _
  28. // 停机标志位
    3 K+ W$ n& r1 a$ C
  29. bit isReadyToHalt = 0;
    + Q( k  F/ B& n$ H% E& L

  30. " ]! v0 A% y: ?2 H; C3 B
  31. // 矩形波次数累计( E  i) J* l% d; K
  32. static volatile unsigned char count = 0;
    6 E  d/ Q  h" J& r- {
  33. # ]. ^7 w; B1 k/ I( Q
  34. ; |' {! c+ [9 [9 R4 L
  35. static void GPIO_Init(){  F# M5 N+ R; M: W& Z& L: q( g! _
  36.         // P3口设置为准双向,默认靠内部弱上拉输出高电平
    - ]+ _( b& U. `7 o
  37.         P3M0 = 0;  I) G6 s  b' g7 a0 |8 E! h/ m8 R" r
  38.         P3M1 = 0;9 p; E8 P0 g+ f; A
  39.         P3 = 0xFF;
    4 w# c0 E1 f4 v4 C1 k4 I% Y1 Y
  40.         // P5口设置为准双向,默认靠内部弱上拉输出高电平
    0 y( K4 Y) \! v! S# p6 @5 {9 U
  41.         P5M0 = 0;
    / }2 L0 h! p; m- V9 Y1 l7 r
  42.         P5M1 = 0;- C' m) ?4 X8 v# ^& m
  43.         P5 = 0xFF;
    ; |' }9 R/ s- @+ f% J8 N; ~
  44. }
    * `# I- e; m! E) N' f3 _- {

  45. 9 R4 ^  x) r. L; ?
  46. static void Timer0_Init(){
    : x( i; ~* d$ A7 n3 c$ i  m& B
  47.         // 16毫秒@6.000MHz
    & d8 r$ d4 Z" ~( U3 ^
  48.         AUXR &= 0x7F;        // 定时器时钟12T模式
    : @( ?9 D4 u2 _: [
  49.         TMOD &= 0xF0;        // 设置定时器模式* I3 F0 x. ]) [1 d6 ^, M. p4 Z
  50.         TL0 = 0xC0;                // 设置定时初值9 i: R( ~/ ]3 {9 G- ^) Z2 u# f1 v
  51.         TH0 = 0xE0;                // 设置定时初值$ M7 C8 c0 f- {" f
  52.         TF0 = 0;                // 清除TF0标志
    & ~1 O" b, H( w
  53.         TR0 = 1;                // 定时器0开始计时
    ( p! Z/ w6 b. B# N
  54. }* t: g' R# y4 r: W" u' i% z5 n

  55.   e% |' ?) S7 M* s+ G3 C& `  T, E8 f
  56. static void Interrupt_Init(){! v% w* w- _* i* Z1 L. Q
  57.         // INT0中断触发类型为下降沿触发
    ( v" a+ Q% ^' f/ T) _
  58.         IT0 = 1;2 r; y, v, j% O
  59.         // 允许INT0中断
    - [6 m4 a: R8 F1 B3 p( Q) {% Z* r
  60.         EX0 = 1;, S) w. G' v$ X$ j$ g
  61.         // INT1中断触发类型为下降沿触发4 O1 n, e) b4 V# ^6 \  d  ?5 ]
  62.         IT1 = 1;/ t# Q8 Z1 L' E# G- I4 O6 I
  63.         // 允许INT1中断2 V$ @. {& G0 j' I
  64.         EX1 = 1;
    1 N+ U  a( s2 w( n) r: W
  65.         // 允许定时器0中断
    " d  X" y/ E# h4 o+ R
  66.         ET0 = 1;# {6 M. B5 e& T0 Q
  67.         // 允许全局中断* g) D; b6 N' y$ q
  68.         EA = 1;1 F- f$ x2 c, I/ E
  69. }" z2 R- f+ I& Q! l. O5 z% r
  70. % m% j) X" p) E& k+ h% O0 \, V
  71. static void INT0_Isr() interrupt 0{; A7 b% a# U$ F: a
  72.         // 矩形波次数累计归零
    / j  ]1 e8 P* K) x- d
  73.         count = 0;
    2 Z3 E: v! H* ?% S% r% m5 p) b
  74.         // 重开定时器0中断4 U' O6 b% @* m5 B' n% e
  75.         ET0 = 1;: `; f" H+ W* u
  76. }+ ]" n, @" b2 x! t# w. h) f
  77. + a6 m* ~% p% E0 ^
  78. static void Timer0_Isr() interrupt 1{
    : c# T; [! L5 r- |
  79.         // 输出矩形波( u$ H* K; [: e( H6 [% J/ z
  80.         OUT = ~OUT;( D& Y5 s4 {. [4 _" F! k: Q
  81.         // 累计矩形波次数
    # G$ o4 q: [' e8 ?! b, t" n
  82.         count++;
    # j2 Y' m1 S9 e+ [7 m2 I
  83.         // 超过250个矩形波,准备停机
    0 ~) L0 n, L) ^$ t
  84.         if(count > 250){& U6 d* x- \6 P3 ~
  85.                 count = 0;0 g; U! @3 W7 d6 o& b
  86.                 isReadyToHalt = 1;
    : Y, s, X. n( C2 D0 y, w1 X
  87.         }
    ; p- o' F+ N. F4 T7 x* ^9 C$ m1 a; ]
  88. }
    - h$ l9 x; k5 Q- @
  89. , l( D- a- n# Q0 B% Z
  90. static void INT1_Isr() interrupt 2{, b% i6 `: J2 g6 X
  91.         // 矩形波次数累计归零# v7 u6 e* _. F5 g0 b8 U
  92.         count = 0;
    7 n3 P/ M! h8 i, f
  93.         // 重开定时器0中断9 d* K, ^+ e4 A. A( }
  94.         ET0 = 1;
    ) J6 m( h" q6 L& x, b2 Q7 P! t* ^) @$ Q
  95. }
      Z& t' |& z& \& O6 b0 f

  96. . u, v4 Z: e1 L+ Z1 R9 s) i5 i

  97. ! y6 ?( v+ `( q, M  f/ b
  98. void main(){
    & ]; j, r+ V/ i7 o9 j
  99.         // 初始化P3和P5口- [/ e' L. O* x
  100.         GPIO_Init();" X3 A+ e$ q6 A+ U: l9 y8 a0 ^% g
  101.         // 初始化定时器0- T# S. d4 J4 m; E% E! ]
  102.         Timer0_Init();8 ^% N4 ~! s6 @4 U3 `
  103.         // 初始化中断+ {7 ^; d3 b$ ?% [% F/ {5 E7 K
  104.         Interrupt_Init();
    5 c3 \$ g. x. D3 d/ u& E: N; q# Y8 T, K' Y, h
  105.         * N6 ?, U& L, ^! ~6 L8 \7 F/ E5 Z
  106.         while(1){2 R2 I6 ]& l! a- R. c( C
  107.                 // 检测电量7 W/ z! Y. E1 h" v
  108.                 if(PCON & (1 << 5)){
    . O" v& [2 ]/ F" c/ M
  109.                         // 如果电量低,低压指示灯亮" K# k( j' m) F& ~  I9 V1 i" v
  110.                         LED = 0;
    6 {' W, K6 @3 o2 z& V
  111.                         // 清电量检测硬件标志位4 h- B4 `. d3 E' A. S: d
  112.                         PCON &= ~(1 << 5);
    6 B; t; r6 Z4 V1 V
  113.                 }else{
    4 ~  R* r2 |, n6 j; N
  114.                         // 电量正常,低压指示灯灭0 r' c9 f; r* M# j) w8 [
  115.                         LED = 1;/ n/ d2 _& ~/ J! x2 z
  116.                 }/ O  z, h: |" C# M0 h$ ]
  117. 8 w! z9 m& ~1 g
  118.                 // 检测到停机标志3 T1 m+ N# t- @& N; e# c, |: x9 V  D
  119.                 if(isReadyToHalt == 1){+ O7 ^4 ^7 Z% i: X7 p; g
  120.                         // 暂时关闭定时器0中断& `  q/ }+ V4 m" R
  121.                         ET0 = 0;
    5 S( K. a: A$ R7 W- X4 y
  122.                         // 停机之前先把矩形波输出脚置低电平,以方便INT0和INT1唤醒CPU
      B; G2 w: U7 @, Z" r  N, B
  123.                         OUT = 0;
    ) @8 }. @# O; i( h. C( g" x( ?) O
  124.                         // 停机之前先把低压指示灯灭掉,以省电
    : q# Q- _) v, g( i$ k0 c& Q+ I5 V3 @
  125.                         LED = 1;
    7 y/ O" r- y6 z8 r; T! `
  126.                         // 进入停机模式
    + \7 g' q( n' R, \* ]/ ?" l2 X
  127.                         PCON |= 0x02;9 k" n, A: I% y( x2 B. h$ F
  128.                         _nop_();
    ' p; v) b7 a9 X  r9 Y7 X: x6 q& X
  129.                         _nop_();
    6 ?& K1 v0 M5 Q+ A, _% |+ O
  130.                         _nop_();
    0 V/ ]4 W! M2 n0 l/ L2 v& M5 T
  131.                         _nop_();
    8 j. s4 g9 j8 e* b8 y$ z. _' M- n3 E* d
  132.                         // 唤醒,清标志位
    ) }2 h" L) Z' G+ U) u" y! u
  133.                         isReadyToHalt = 0;
    # K" `) g/ H- ^) H3 l4 j5 |. W# U- v) c
  134.                         // 重开定时器0中断4 r4 w8 T! G6 l6 {) D
  135.                         ET0 = 1;
    ( U. y& X: M+ F2 |5 ^3 l
  136.                 }
    + @$ s2 Z& x% L7 k5 d( T
  137.         }
    " f& w3 W% N, {2 W
  138. }1 r  Z1 o7 R4 ^/ S" j
复制代码
, r% q; D) L) S7 Q4 x
硬件参数配置:
# |! p2 g! O) k5 [2 k- p0 [; y1 K4 \/ F' d

4 e; Y" ^2 x! D: K$ x接收端:
, L7 Y9 O4 h. S+ _+ V) Q! ]" O1 G5 s
  1. #include <INTRINS.H>6 R4 ]& z' L  J9 R  p' y
  2. #include "STC15W.h") A8 a, v8 f3 p' Z) ^$ M8 y
  3. & ?2 z: X2 T* c1 y0 V& d4 z$ M5 `
  4. # R5 G) m3 a) \
  5. /*/ P; x# s' F3 z% y
  6. 1 ~' Z& ]/ }; ~5 s0 {7 W; `
  7. *---------------------------*
    ! \& |, b) i) }
  8. |1 (GPIO2)         \__/  (GPIO1)16|
    4 p/ q" l9 Q5 {% M; r, a
  9. |                                                        |
    $ D3 A" k' E1 p
  10. |2 (GPIO3)                   (GPIO0)15|  Q* S: U+ Y, P. v& w' d) J7 r# n3 r& _# L
  11. |                                                        |$ B7 ?3 g) o: I( _4 L
  12. |3 (GPIO4)                                  14|
    $ ~4 @) N( n$ N7 R
  13. |                                                        |+ A8 t+ v, `# t; r8 h/ [
  14. |4 (GPIO5)                        (DATA)13|
    6 d3 b- {0 [* F3 ~1 @+ H0 q9 K: y9 p
  15. |                  STC15W204S                |
    ( R" s: ?$ H7 E$ n* b
  16. |5 (GPIO6)                   (LATCH)12|, o; t1 P6 K& ^5 O% ?3 T9 C  Q
  17. |                                                        |7 p5 e1 p& k' h
  18. |6 (VCC)                         (CLK)11|
    % V' P" w/ k. s) T' d
  19. |                                                          |
    : U) {7 z1 v- h( n2 @6 |5 c
  20. |7 (GPIO7)                         (TXD)10|
    % f& g3 u7 i6 Y4 x" C  o
  21. |                                                        |7 u" t2 m$ }* v5 v) w9 ?& ^0 e& f
  22. |8 (GND)                         (RXD) 9|3 L( }& ?- _' V# y7 H- t
  23. *---------------------------*
    + Q# Q1 g! u' f$ U. }
  24. Fosc = 12MHz
    # t- k' @# j; M6 C
  25. , N/ n& g" |! Z8 w* t7 `1 M
  26. P1.0 -> 上
    0 b( ]( c; h8 `1 X
  27. P1.1 -> 左: q* l& Z9 Q% p, ^: |" P7 g
  28. P1.2 -> 下
    . c( [2 |5 H! s
  29. P1.3 -> 右
    2 @' y2 C1 Q& g' R4 }, S& @0 ~. _
  30. P1.4 -> SEL
    - g9 k' K& p5 _
  31. P1.5 -> STA
    6 y% N4 E2 A4 U6 ~( _5 E  m
  32. P5.4 -> B( P8 x2 Y6 B- m7 q8 T) I+ @* r
  33. P5.5 -> A
    * c: ~' i4 u1 f: v. s( Z8 a

  34. ) o/ X8 h0 Y$ p( \2 J2 z8 v; r
  35. */3 B6 r, D" u( z/ G- R

  36. . S& |  A, a1 Y8 b( }& m
  37. ! X3 E$ L! N! |' S3 ]8 m
  38. sbit CLK        = P3^2;
    + l# i: O# E: A3 ?/ ^
  39. sbit LATCH        = P3^3;" q3 K7 Q$ x! @/ S
  40. sbit DATA        = P3^6;" ~+ R9 Q& ~3 ?6 \9 k7 z. v; ?: d

  41. , T0 T6 c/ y7 D2 V& i
  42. bit isReady = 0;" l7 d2 ]) O3 I, @  I& _
  43. static unsigned char key = 0;1 X1 g5 b& e2 h* Z$ ~" M; D
  44. static unsigned char buf = 0;        // 双缓冲。这个缓冲区保存从P1和P5组合而来的键值
    9 I0 A( f7 c7 Y+ T8 ]: N( v
  45. static unsigned char bufReady = 0;        // 双缓冲。这个缓冲区保存上面那个缓冲区的备份/ T8 C: J+ Q5 w" P" {( t
  46. static const unsigned char data mask[] = {0x80, 0x40, 0x10, 0x20, 0x01, 0x04, 0x02, 0x08};        // A B SELECT START UP DOWN LEFT RIGHT。为提升速度,这个表放到RAM中' ]* Y( x' f5 Q! H7 b* p7 g
  47. static unsigned char idx = 0;
    : g2 m4 r! w) Q6 o  E% p# n+ ?& l
  48. " P; P, B  X  k: \. N& o2 |- [0 N

  49. ' F4 }+ s3 W3 s- v+ C" K9 ^
  50. static void GPIO_Init(){+ S) V# U6 h! P7 w$ ~# P# S
  51.         // P1口和P5口用于接收并行信号,全部初始化为准双向,依靠内部弱上拉输出高电平
    ; R2 p  B' c4 B# X
  52.         P1M0 = 0;
    6 @) J/ `" S% m6 J
  53.         P1M1 = 0;0 A9 z$ x" x- w% Z* J
  54.         P1= 0xFF;
    3 I( b8 a$ s3 Z, }& g0 \
  55.         P5M0 = 0;
    ! K( ]: c) `4 @7 }0 |
  56.         P5M1 = 0;
    9 r7 |# r' t2 v- X
  57.         P5= 0xFF;" k" Q% b: Q" J# p5 B5 s3 u" h
  58.         // P3口初始化为准双向* [; [7 B1 t2 @. M
  59.         P3M0 = 0;# F! l0 V, C( {9 X
  60.         P3M1 = 0;
    ) C4 O7 G  u1 }+ j4 v2 E, ~/ j  H
  61.         P3 = 0xFF;
    * i6 u" p: l. f* N3 n; O7 V* }+ c
  62. }
    7 @1 W" n$ m+ n+ ^0 G

  63. / u6 v! f8 V- _9 L' L4 ~
  64. static void Interrupt_Init(){0 V$ Z" g7 R+ O3 [7 Q4 t
  65.         // INT0中断(CLK)触发类型为上升沿+下降沿
    0 m8 f: v, a7 k3 o; C
  66.         IT0 = 0;
    9 T3 X7 I# f% Y8 Y1 D& E
  67.         // 允许INT0中断; R& P2 J& d5 u- Q+ ?4 d' w
  68.         EX0 = 1;/ t* T) W9 Z# r( k+ F. Y/ b2 T" F
  69.         // INT1中断(LATCH)触发类型为上升沿+下降沿
    0 }0 f% J! f8 d! x6 }! x2 P6 w( ?; V4 n
  70.         IT1 = 0;
    : A: d/ o1 K6 t5 w
  71.         // 允许INT1中断! j- C" d8 r' ?* W
  72.         EX1 = 1;/ S* Z: T. [4 G& p+ R  H+ I
  73.         // 开启全局中断
    0 E! u, G( K& P; `& \
  74.         EA = 1;1 l4 r4 G9 [1 D& m' z
  75. }7 f9 i0 Q+ Y# B
  76. 6 G3 T6 e# M6 e! }
  77. static void INT0_Isr() interrupt 0{
    + E+ Y0 z0 v" ?- B6 P  d
  78.         // 只有已经成功锁存才允许CLK移位
    " }$ h. F( V' s8 }! Y8 v* t
  79.         if(isReady == 0)
    2 o7 z. a% e/ P& t
  80.                 return;
    # p- ^2 r% S! Z9 U8 l/ I0 T
  81.         // 读当前引脚电平,如果是低电平则说明是下降沿,此时直接忽略该中断/ v" J0 x7 D! z
  82.         if(CLK == 0)! y! ]/ p, V5 x. n  m; t4 E' u- @
  83.                 return;# ~( U2 s, ]5 M, u, W
  84.         // CLK上升沿到来的时候,取锁存值的下一位输出
    7 R4 |: @) N, ~4 Y  e$ r" V
  85.         idx++;  x) O4 j/ o9 k1 S  Q+ n
  86.         DATA = key & mask[idx];- {- X8 K3 [3 q/ p6 B7 i3 ]0 P+ t7 x
  87.         // 如果已经完成7次移位,则一轮读取完成
    / B. o5 j: h3 z; U$ ~7 s2 P
  88.         if(idx >= 7)7 H0 W% I% e5 C7 q+ `
  89.                 isReady = 0;2 t! U" _; l0 |5 A, o7 m
  90. }$ t. K( Y2 o7 M' i
  91. + x, B0 \4 d' A1 z7 _5 I7 V5 C
  92. static void INT1_Isr() interrupt 2{
    % W4 j3 K( }, q. C& T# n
  93.         // 读当前引脚电平,如果是低电平则说明是下降沿,此时直接忽略该中断5 O) z7 Y5 I  Q# c' A" h
  94.         if(LATCH == 0)
    3 z: M; R$ k" z2 l9 `
  95.                 return;
    : O- y, \& M3 g  B0 S
  96.         // 当LATCH上升沿到来的时候,锁存所有按键状态,同时把键值A输出到DATA
      L0 n  l* v6 M% C2 d# z5 e
  97.         key = bufReady;! ]+ S% E8 J7 o* N
  98.         DATA = key & 0x80;//mask[0];        // 为了加速运算,直接取表中的值而不是读表' v! j: d: c2 J$ U
  99.         idx = 0;, G/ {8 m& K9 l* X& F/ q. d9 E
  100.         // 允许CLK进行移位* J$ h# |6 X8 j! t2 I
  101.         isReady = 1;
    % B, ^6 @" n( V# h
  102. }( P$ U2 o  |8 \/ N; ~; X, C* {1 k
  103. 4 O& F# @  g" }, [' y$ K! h! J
  104. void main(){9 w7 U) ^7 m/ }3 A  f4 d# R1 ]# J
  105.         GPIO_Init();
    " Q/ ?/ ]2 |1 Y* d
  106.         Interrupt_Init();
    0 Y* N3 ], k# u% W
  107.        
    " r" C" e7 X. S% \3 D
  108.         while(1){, D# u/ M+ l$ ?3 ^$ n
  109.                 //PCON |= 0x01;        // 进入省电模式. o8 E. G; N7 j0 @+ v% t2 ?3 T# Q0 R
  110.                 //_nop_();
      n$ v5 z8 P: ?, x* Y& a* g- B
  111.                 //_nop_();7 \6 \* ?, v* o& P/ i& l# _
  112.                 //_nop_();/ {" K' b( E5 g3 s
  113.                 //_nop_();
    3 t  I, t3 c  `4 _! ^: ^- }
  114.                 buf = ~((P1 & 0x3F) | ((P5 << 2) & 0xC0));
    2 l% m6 i5 A: W9 ?
  115.                 bufReady = buf;
    . C  ]' a5 _8 a% r. z$ `
  116.         }
    # o5 J' `0 x. d; f: U3 u
  117. }$ o0 p+ @3 D  [9 T8 k
复制代码
- h! s7 J1 Z- o
硬件参数配置无特殊要求,晶振频率选择12M即可。  W, ~# v; @# T

4 D6 I9 h+ b9 o# J这是编译好的固件。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×

评分

参与人数 3威望 +1 Diy币 +3 热血 +110 收起 理由
sion + 5 顶一个
5911 + 5
xunxun + 1 + 3 + 100

查看全部评分

回复

使用道具 举报

发表于 2019-5-23 10:05:23 | 显示全部楼层
不错的设计,想问一下楼主,FC的15针公头怎么解决?普通的公头太短了,插不进去FC的扩展接口。
回复

使用道具 举报

 楼主| 发表于 2019-5-23 11:27:39 | 显示全部楼层
69yuan 发表于 2019-5-23 10:05
8 W6 Z5 y! i4 w1 h" e8 s) e3 Y0 a9 I不错的设计,想问一下楼主,FC的15针公头怎么解决?普通的公头太短了,插不进去FC的扩展接口。 ...

, R; N7 }" T; S. ]/ L) Y坛友的改造方案
回复

使用道具 举报

发表于 2019-5-25 10:42:27 | 显示全部楼层
高手的无私奉贤值得表扬,辛苦了!
回复

使用道具 举报

发表于 2019-5-25 12:07:18 | 显示全部楼层
精彩,楼主动手强,也写得很详细。
8 c6 \5 p) o8 G( f2.4G方案是目前无线的最低延迟吗?
回复

使用道具 举报

发表于 2019-5-28 17:27:23 | 显示全部楼层
给技术帝赞一个,有半成品发布吗,自己焊接改造就可以,编程实在不会啊
回复

使用道具 举报

发表于 2019-5-28 18:55:54 | 显示全部楼层
非常好,楼主是技术帝,到目前我都还没开发fc的无线套件,等空了,开发一套套件,等玩家自己组装。
回复

使用道具 举报

 楼主| 发表于 2019-5-29 16:49:20 | 显示全部楼层
xunxun 发表于 2019-5-25 12:07
* }) t' o$ H2 \, s& s精彩,楼主动手强,也写得很详细。. z9 `0 e3 Z% j1 \8 V  @
2.4G方案是目前无线的最低延迟吗?

7 n* H- f1 Z- R2 P7 H! o0 K8 s0 n6 B1 D我没用过其他无线手柄,所以实在不知道我自己做的这个手柄到底是不是最低延迟。* _6 O  {( \+ E: e, B! Y
不过根据网上的说法,延迟高低主要是由通信协议的复杂程度,以及数据传输速率决定的。这个模块虽然是2.4G无线模块,但由于协议很简单,所以延迟比较低。' h0 z7 @6 h# y5 V5 k/ ]# K: D
我用这个手柄玩一些ACT游戏,比如超级马里奥、忍者龙剑传、热血系列,完全感觉不到延迟,和游戏机自带的手柄没有任何区别。唯一的区别就是这个手柄是用火花山寨手柄改造的,外壳是垃圾回收塑料,粗糙+脆弱,导电橡胶弹性不佳,手感不是一般的差。
+ o) F8 e1 m* b5 z( M我手里还有十几张板子,等我有空了我再做一套,到时候买一个好一点的手柄改造。
回复

使用道具 举报

 楼主| 发表于 2019-5-29 16:56:14 | 显示全部楼层
ppad 发表于 2019-5-28 17:27
$ |+ h. G# w; s" ?# X给技术帝赞一个,有半成品发布吗,自己焊接改造就可以,编程实在不会啊 ...
1 f; @9 e. f" b' I3 l& U
很可惜,我手里没有多余的单片机了,LDO也找不到了,锂电池以及充电模块更是没有了。反正就是该用到的元件基本都没了,所以没法发布半成品。3 X& W4 ?! ^& y
两个板子倒是有十几张剩余。2 w6 j+ v: }& {( Z8 a  W' `
你要是有USB转TTL串口板,完全可以自己买这两种单片机,然后我给你编译好的固件,你自己用串口板下载到单片机里面就行了。两个2.4G无线模块也得通过串口板用AT命令设置参数,不过好在我在设计电路的时候就已经预留好了串口,可以直接在线下载和在线设置参数。总的来说并不麻烦。
回复

使用道具 举报

 楼主| 发表于 2019-5-29 17:00:34 | 显示全部楼层
孙大师 发表于 2019-5-28 18:55' Y! V6 @3 U' O% r& f
非常好,楼主是技术帝,到目前我都还没开发fc的无线套件,等空了,开发一套套件,等玩家自己组装。 ...

) J# T* r" D! f: B能得到孙大师的赞誉,不胜荣幸!
  y& }% n# l2 y0 ?# s不如开发一个多功能手柄,比如用SFC手柄改造,L/R键配合其他组合键可以用来切换2P~4P、调节连发速度、软重启等各种功能。接收端插到15PIN扩展口。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|Video Game Do It Yourself ( 闽ICP备14000865号 )

GMT+8, 2025-5-10 18:11 , Processed in 0.099608 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表