找回密码
 注册

QQ登录

只需一步,快速开始

查看: 24332|回复: 32

自制FC无线手柄

  [复制链接]
发表于 2019-5-22 14:16:45 | 显示全部楼层 |阅读模式
本帖最后由 雷精灵2046 于 2019-6-14 09:28 编辑 3 U  b9 ?& w, S7 `) l

! t9 f' O+ w1 V. B6 T3 E& V没有用复杂的分立元件搭建发射接收电路,直接用的现成的2.4G无线模块jdy-40。
# Z0 v9 r) c2 Z/ o( r8 Z& g- e7 n& Y

( w% b) K& V! x1 t9 h2 v. @" G发射端靠3.7V锂电池供电,用了一片SOP8封装的STC单片机,负责产生连发脉冲,同时负责检测电池电量,电压低于3V左右的时候触发低压中断,低压指示LED就会亮起来告知该充电了。平时发射模块和单片机均处于睡眠状态,有按键按下才会唤醒,从而实现省电。实测睡眠状态下整机电流约1~2uA。板子洗了一下稍微干净了一点。因为对于微功耗设备来说,焊接残余的助焊剂可能会增加漏电流。
- t1 V8 k3 p0 T/ B8 B, V
' J% a' p" }* `2 T4 i- Y) h/ {; O买了一个火花的FC山寨手柄,去掉里面的牛屎板子,并修正一下塑料挡板,把锂电池和充电模块装进去。& w" `* z0 |( s' n1 t5 ?# g" M/ A
为了减少体积,充电模块裁剪得十分小,并且更换了充电电阻使之适应这个小小的锂电池。这么小容量的电池,也不需要多么大的充电电流是吧?3 {+ w8 f7 z7 l  A6 u* m
然后统统用热熔胶粘上。充电电流比较小,所以发热很少,不会熔化热熔胶。  A5 i/ N' j/ @# K6 c8 |! W$ |
; W5 ?# |6 M2 a2 I1 R+ R0 P
" V; ~9 K* Z) ?' H7 E! M
% N2 E6 h0 h( e6 [
最后把按键、导电橡胶和电路板装上去。
0 d; E, j6 n* k( k* ]精心裁剪了电路板,正好扣上,不会阻碍其他元件,也不会影响后盖和拧螺丝。
6 y+ }8 w* k. g. C2 f
; V4 o) I; U# V  v" ?  [1 `2 U6 Y' d  h" J0 }+ v7 _1 ]9 }
完工!5 s8 z+ J  C6 s2 `4 D

9 h6 N5 K  h+ w' x# X
8 g9 H) r# [- r这是充电的MicroUSB插座。旁边的小孔用于透出低压报警LED的光线。# [/ p- L, @, l9 t' M. ]' N, [
# x/ \% x: Q4 Y* R/ `) G7 y

3 W6 q5 l: O+ w2 C' S2 }接收端用一片DIP16封装的STC单片机模拟CD4021。为啥要用单片机模拟而不是直接用CD4021?因为jdy-40模块接收端在有按键按下的时候输出高电平,无按键按下输出低电平,和普通手柄正好相反。当然我也可以用两片74HC00或者74HC04之类的逻辑门进行反相,但那就增加了芯片的数量。对于FC手柄这种工作频率并不高的设备来说,STC单片机完全可以胜任模拟工作。2 D( I" J: k: x3 p7 |

6 r! a9 a3 u; t5 Z; j2 {. \
& H" G) j( \  k' ^& U% g7 D# @4 X2 D* B/ Z$ X
电路设计有点小小的错误,所以有几根飞线。原本设计使用低压差LDO是XC6206,结果在做这个接收模块的时候,买的LDO居然找不到了!无奈只好用了AMS1117。幸好对于接收模块来说是5V降到3.3V,1117可以胜任。要是发射端手柄的话,3.7V降到3.3V,那就非得用6206不可了。  y/ g; ?$ }# A
% l  G0 Q# v2 t# y7 Y; f& m7 E
实测十分灵敏,延迟极小几乎感觉不出来。可惜这山寨手柄的手感并不佳,尤其是方向键,软塌塌的。看来我得买个剪线手柄改装。7 k) N* ]/ n) w& W+ R  D

5 O' S1 R; `! s: I3 x2 h! L; W6 f这是电路图,有兴趣的朋友可以参考。
; C4 F* y; j; P' H3 i& N0 ]% Z, V: W0 D2 A. H, w5 a
- y, t/ o2 a5 `6 `  _: r
我信奉开源主义,十分痛恨把技术藏着掖着。好东西大家分享嘛!所以两个单片机的源代码大公开!& Y& e/ e! E  {8 J/ a$ W# {
编译器:Keil 51。
3 i* Q* @. g2 y6 r5 f) {
1 l8 H, d4 P% i: q4 G发射端:
7 U1 u9 D3 [8 O
  1. #include <INTRINS.H>6 e9 U2 p, o, g  n% O2 h5 e
  2. #include "STC15W.h": R0 P* V5 \  C- r# w, e

  3. 2 ~9 o. U' _! A( N, a+ o7 ?) A* }
  4. ' A* T2 v  O) @0 ?4 ?' g4 D
  5. /*2 R0 A' f( ~8 Y0 u! `
  6. --------------------------/ X7 S9 @, j. S- l' r5 }% z
  7. |1 (OUT)        \__/   (INT1) 8|
    ; X, _( C& ]  I) p3 e& a! o
  8. |                                                   |
    " K0 H) ?, D2 I3 x; S3 K
  9. |2 (VCC)                   (INT0) 7|+ R, Y2 Y; m+ `* g( }' P
  10. |                 STC15W204S                   |. ^9 R$ o% ?* c' E, E6 }
  11. |3 (LED)                         (TXD) 6|/ Y/ @9 {& k4 r0 ~6 E' E
  12. |                                                   |
    ) J) Y$ M) `* T2 V( @6 x$ y
  13. |4 (GND)                         (RXD) 5|
    7 p$ k. t4 U" J; r
  14. --------------------------
    + `7 ]2 \1 D: a, b* S

  15. " X; J, I( ?/ z- B& \
  16. LED ---|<|---[===]--- VCC) F( ~; j1 @& V# `, Y
  17.            Red          3303 R1 q  q0 P& B+ C/ ^5 r/ x

  18. # ^  R; l$ c$ {% ?$ `
  19. Fosc = 6MHz2 R- G  R/ e5 Y# v7 f# T: r5 ?% h
  20. */' n: v# r5 A  I+ g
  21. & @  o+ Z+ B8 O0 Y
  22. 7 `% F/ B4 ]7 c- @( k
  23. // 矩形波输出脚
    2 ]% n5 h& B4 T( S& i
  24. sbit OUT = P5^4;" R7 r8 c$ d4 A9 X1 O
  25. // 低压指示灯引脚+ A: ]& n/ j( x2 w# L, A8 D
  26. sbit LED = P5^5;
    ) O7 ~; d% _9 ?. R: h, `  Z8 s+ ?
  27. * P( Q, R, D: _+ L
  28. // 停机标志位8 Z, ?4 i, Y& g8 G9 J, [
  29. bit isReadyToHalt = 0;8 C. x6 c/ E$ g3 O# M
  30. * d3 B1 t6 n8 ~% x7 X( {2 f
  31. // 矩形波次数累计
    % P1 J( r0 [- a$ Q: E7 o
  32. static volatile unsigned char count = 0;
    ) W2 E; G$ `1 x6 [- y6 R

  33. ! k  N- l+ _* G6 I& ~. [
  34. ' p( \+ O/ u) n& q
  35. static void GPIO_Init(){
    ; P. L' y' z) T3 _" y0 g
  36.         // P3口设置为准双向,默认靠内部弱上拉输出高电平
    # H1 U1 w, ?' Q- |& l
  37.         P3M0 = 0;7 q$ p: n9 ]1 K! G# K/ i
  38.         P3M1 = 0;0 |" P9 ^! @8 Q: ?3 \) C  `' y
  39.         P3 = 0xFF;* g, y: u: l% Z$ \
  40.         // P5口设置为准双向,默认靠内部弱上拉输出高电平7 {$ r/ I2 B/ y- ^: e1 s/ ?$ L+ @
  41.         P5M0 = 0;
    : [& f6 A9 F- e1 v2 H! B4 a
  42.         P5M1 = 0;8 |( ^1 }4 H+ D2 `6 \6 ~
  43.         P5 = 0xFF;
    ; s4 ?5 l- \- j) e
  44. }
    # v& _! z. ~2 }+ @$ b6 m1 k) l

  45. # n- G* A3 `* S4 N( d, o
  46. static void Timer0_Init(){
    : X9 Q5 U+ E* x1 Y9 j  |  I8 Z
  47.         // 16毫秒@6.000MHz0 c" n* P4 Y# |4 a+ y. P
  48.         AUXR &= 0x7F;        // 定时器时钟12T模式4 v( ?" h6 u, k# s
  49.         TMOD &= 0xF0;        // 设置定时器模式
    $ O! p3 K! D/ A# N
  50.         TL0 = 0xC0;                // 设置定时初值
    / t$ |9 u6 Z; L' T% n, V! ]
  51.         TH0 = 0xE0;                // 设置定时初值% n8 R! L& H3 D, c
  52.         TF0 = 0;                // 清除TF0标志
      t2 s8 {4 v1 C! l5 X- I8 O
  53.         TR0 = 1;                // 定时器0开始计时
    % K9 [; w- O- w! U' b6 X
  54. }9 t  V1 t- Z8 B, h* d

  55. - @# h, D, d' C$ y( E2 |9 a
  56. static void Interrupt_Init(){
    ) S) T. l) T3 a$ C0 U9 D
  57.         // INT0中断触发类型为下降沿触发5 F6 u* R8 I8 h# M* ]. O: R
  58.         IT0 = 1;
    % o3 P9 x/ T3 ]( @" f
  59.         // 允许INT0中断
    . y- C3 ]$ X: r/ h/ W
  60.         EX0 = 1;
    , g! a2 `' `) s+ d
  61.         // INT1中断触发类型为下降沿触发
    3 ]) F6 B6 t  E' _1 s6 L) C
  62.         IT1 = 1;
    " O; z) o; G$ y* d! z; {6 M
  63.         // 允许INT1中断
    6 i3 j% }. q( V) p" p( E' @6 Y
  64.         EX1 = 1;% k* n- Q! b1 ^6 T. A- \+ U5 [
  65.         // 允许定时器0中断# M( g& Y: @2 I' ~' ]6 E
  66.         ET0 = 1;
    ( M% L1 Q4 s2 [: I
  67.         // 允许全局中断& W2 `2 e/ T# \% G7 t0 V+ ^3 z
  68.         EA = 1;9 T" j+ o; t% k( R
  69. }
    1 }# P& m' }; k6 N

  70. ! C8 }- W4 ?9 x2 R% y
  71. static void INT0_Isr() interrupt 0{2 a1 t  r$ E# h) l) K
  72.         // 矩形波次数累计归零
    % |+ f1 u2 g) w4 n, `( F' z
  73.         count = 0;
    3 y! z& @! i1 B' E5 U' I* m
  74.         // 重开定时器0中断
    ( m6 e+ n; a: {* L
  75.         ET0 = 1;
    + j% e7 f' K0 J
  76. }
    3 M, e5 @- V; x% a5 K
  77. , C" [4 F- Q6 Q0 |4 K) L
  78. static void Timer0_Isr() interrupt 1{
    & A9 m' }6 Z8 k5 `5 M+ l# \
  79.         // 输出矩形波
      `- V# i4 C. n5 H3 \8 S
  80.         OUT = ~OUT;# F1 ?1 P0 o) b! a9 I
  81.         // 累计矩形波次数6 A2 _3 ~2 p4 r9 }
  82.         count++;. k! [7 w1 e! y2 w# q# _
  83.         // 超过250个矩形波,准备停机' m' X/ M3 t$ @; t+ h
  84.         if(count > 250){8 g+ f& @7 \7 r2 X. b6 @/ f
  85.                 count = 0;
    6 i% j! j  P. a  }
  86.                 isReadyToHalt = 1;
    . d; F" d5 l' _6 `
  87.         }
    9 G% v) T8 P5 a7 K+ J! J2 s# Y
  88. }. d0 V$ u: `7 S5 S$ f% [8 E
  89. : T5 q2 ~+ {# ]  y( k
  90. static void INT1_Isr() interrupt 2{9 z5 n' f* A: f! z" V' c3 j, P
  91.         // 矩形波次数累计归零
    7 U6 W' c4 K, s4 ?
  92.         count = 0;
    1 t) S0 `# ~" v) M+ F- ]
  93.         // 重开定时器0中断' o! U. Z) _1 w3 M* a4 z1 c. r7 F4 k
  94.         ET0 = 1;
    ' q( d# X0 ?: J! L' ]3 O
  95. }! r* P0 ~& l3 d9 s5 ?( M
  96. * h: `5 B5 h7 q! _: W
  97. 4 n2 t9 \2 E2 s' p" ?9 B9 z
  98. void main(){( Z1 o8 n" I+ }
  99.         // 初始化P3和P5口: O- l; _! i4 T0 w$ O
  100.         GPIO_Init();7 }. M2 L8 E8 q6 |; R/ K
  101.         // 初始化定时器0. s5 i9 b# }) s* }
  102.         Timer0_Init();
    ! o# r% [* f2 X2 E& T5 b9 L0 F* e
  103.         // 初始化中断3 r5 _8 `& @+ X2 o' E
  104.         Interrupt_Init();$ G7 S; F8 J' j. n
  105.        
    : V3 k/ Y$ k' J5 |' l  ?+ @
  106.         while(1){1 e0 B/ G2 l9 O
  107.                 // 检测电量
    5 H0 L3 n* D( x, J: N3 k
  108.                 if(PCON & (1 << 5)){
    & U- E/ B$ o! E4 E$ E
  109.                         // 如果电量低,低压指示灯亮
    ! l  f1 B! W/ d# }8 M5 M
  110.                         LED = 0;: _; W  |4 a1 G) P7 b( d
  111.                         // 清电量检测硬件标志位& ?+ B4 h, t5 N1 o
  112.                         PCON &= ~(1 << 5);
    3 m2 ^3 w2 q/ _; J' B8 K
  113.                 }else{- R! v7 L* y' }9 }9 ?
  114.                         // 电量正常,低压指示灯灭
    6 j# G( g5 g7 h; v. e
  115.                         LED = 1;
    2 W6 z& n0 u# p* l* T& a
  116.                 }
    + U: ~0 t5 M1 l4 b% a7 S, r' {# J

  117. ! B0 s( s# v% t# o8 w0 t
  118.                 // 检测到停机标志
    6 E8 f  Q6 Z& O7 {) _
  119.                 if(isReadyToHalt == 1){2 W& h0 s, r2 A; c2 f& \8 v
  120.                         // 暂时关闭定时器0中断8 j2 U& V! B+ I6 H' K
  121.                         ET0 = 0;
    6 |+ g2 \+ z8 K$ ]0 O% ~
  122.                         // 停机之前先把矩形波输出脚置低电平,以方便INT0和INT1唤醒CPU$ }6 C- p- C7 q/ \  m. z$ h% f
  123.                         OUT = 0;
    * y' b/ S7 y0 }& n& Q
  124.                         // 停机之前先把低压指示灯灭掉,以省电8 m0 ?  C, r# Z. k" C
  125.                         LED = 1;
    # z- Z0 P, K( e$ o3 C+ |
  126.                         // 进入停机模式4 N8 G0 R" U) r
  127.                         PCON |= 0x02;6 {1 K- W; B/ W- ]" I
  128.                         _nop_();
    4 s9 ]6 \$ d# y1 x
  129.                         _nop_();
    2 }+ Q: X/ p3 r$ a
  130.                         _nop_();+ @0 o( Y, k( l% T/ ?8 `& Q+ i, H
  131.                         _nop_();0 p, P8 X" Y6 S' j6 x
  132.                         // 唤醒,清标志位
    & F# _7 p" M- {4 h6 ~/ u
  133.                         isReadyToHalt = 0;5 L2 }; x$ D+ I5 t4 p: f, F
  134.                         // 重开定时器0中断8 V) {, `  E7 B% P7 [9 ]+ {
  135.                         ET0 = 1;
    + |, _' V/ U) E/ H% c0 s
  136.                 }. g! J* E: W6 n4 U- E
  137.         }9 ^4 `5 w- ~0 s! Z+ i9 r, d  y- m
  138. }1 |, T9 y( k& R, e) g( c( ^
复制代码
& W( A& B# \+ m1 d# B
硬件参数配置:
) `* ?; w, I; Y4 P0 V$ ]. _
5 b- v# |$ V2 m. ^1 S; |+ L! _: _
8 ~1 {$ m5 w# L* y接收端:) s/ [8 t0 N# n' P7 m7 G8 g
  1. #include <INTRINS.H># s8 g) n, o$ ?5 v/ ?( z1 e
  2. #include "STC15W.h"1 B* g' `6 i& d/ L$ z

  3. : W2 p0 f1 X# S$ a

  4. 1 W$ W- d* i2 V5 P) b( ^8 e- B* ]! k+ x
  5. /*
    9 x  |- r4 ]+ Y/ @2 `9 I

  6. 4 Q1 a, h8 ]5 D1 I
  7. *---------------------------*
    3 @3 p3 [6 J3 N( ^" c
  8. |1 (GPIO2)         \__/  (GPIO1)16|
    ' z* c" a- v* a+ M5 ~6 s% k
  9. |                                                        |
    " N% r8 r, C5 O+ n# e3 M) h' T
  10. |2 (GPIO3)                   (GPIO0)15|
    : _" z1 H: y3 ]
  11. |                                                        |, L) j9 R% Q' {5 W9 ^4 q& a# l( v
  12. |3 (GPIO4)                                  14|: J% U! p  {: q3 }4 _+ u
  13. |                                                        |
    : x, l+ E- `" a. P2 F5 c
  14. |4 (GPIO5)                        (DATA)13|- r( `; I3 J1 u3 R
  15. |                  STC15W204S                |/ Q- s& _7 K' I# U1 b
  16. |5 (GPIO6)                   (LATCH)12|# U+ J$ F$ U6 D9 d- N5 s- `; k$ a
  17. |                                                        |5 K# y0 ~9 X: ]- x2 L6 |4 L
  18. |6 (VCC)                         (CLK)11|
    " r# C$ H" i: e5 F9 \8 _% k: [
  19. |                                                          |
    - ]" d5 H& L- {: T8 ?* V0 v- Q
  20. |7 (GPIO7)                         (TXD)10|
    * c+ ^7 G, ~. L4 j6 F2 U$ R
  21. |                                                        |0 t8 F" W6 I. V6 W# W6 E( ~1 i
  22. |8 (GND)                         (RXD) 9|8 Z4 c; O, U' f  R4 r1 ^' y- _" j
  23. *---------------------------*9 R4 K5 ?; o  y2 |% ?' j) ]' n/ @5 w
  24. Fosc = 12MHz
    6 s0 U! k: \* r8 o6 o: t0 f
  25. ' E1 l& D5 q2 O
  26. P1.0 -> 上
    & X; w5 B6 E/ H
  27. P1.1 -> 左
    3 Q: ?" v4 L) \8 L
  28. P1.2 -> 下1 F  i9 Y0 \! s5 C$ ^  Z8 w# a) p( _1 B( F
  29. P1.3 -> 右
    & {  t, F" }1 T- i
  30. P1.4 -> SEL
    . P2 \( _1 y% R  `6 r$ [6 k
  31. P1.5 -> STA) ?8 F( `0 ~- U9 Z, _
  32. P5.4 -> B
    * h$ C6 j3 y9 o: I! I2 c, O) w
  33. P5.5 -> A9 O/ N- v' k/ j8 |2 C
  34. " g# l3 \5 w! ?+ @: r3 a# u- _
  35. */
    2 S' a3 T0 a% ?2 L( w. H/ \: r
  36. % m% L) J9 K) {5 o( r

  37. / n% y6 @. [% P5 g4 u
  38. sbit CLK        = P3^2;
    & |1 g4 Z( q8 k; j+ \; u7 n
  39. sbit LATCH        = P3^3;
    / ~, q- E. a# Y/ j
  40. sbit DATA        = P3^6;
    " s, I& u0 b* r) w8 e$ X" l
  41. , _+ f+ N) V2 x7 ~- b! p$ W/ C# m: V
  42. bit isReady = 0;- C+ S, a0 O  l6 {
  43. static unsigned char key = 0;2 o2 d7 I1 R* K6 @) y
  44. static unsigned char buf = 0;        // 双缓冲。这个缓冲区保存从P1和P5组合而来的键值% |% q( L; n1 _& ^
  45. static unsigned char bufReady = 0;        // 双缓冲。这个缓冲区保存上面那个缓冲区的备份! M% O1 ?: U8 W8 j5 @) z- N1 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中
    ; C# X& e2 O9 z# d% e: ?5 J
  47. static unsigned char idx = 0;
      [0 P; L; n# _$ r. s0 l& i  i7 v
  48. " C) i" o2 w# i( H1 n4 {2 \) O6 S) L& d

  49. 6 }7 W- J$ k4 q0 w( s
  50. static void GPIO_Init(){$ i, b/ Y  t) y5 H7 I! Y  b
  51.         // P1口和P5口用于接收并行信号,全部初始化为准双向,依靠内部弱上拉输出高电平
    - |, Q; ^' z3 u1 _% ?7 \% h0 i
  52.         P1M0 = 0;3 ~9 L2 l" T$ j0 `) x+ m0 {
  53.         P1M1 = 0;, Y" t9 w6 X; i5 m! P4 N
  54.         P1= 0xFF;; }% X0 G5 {9 H  ^- v' J; O
  55.         P5M0 = 0;
    4 r( |2 ~2 K+ G4 t4 G
  56.         P5M1 = 0;
    1 ?4 K! ^% k7 v0 T# h8 _/ Y9 [
  57.         P5= 0xFF;
    ; _0 U, H; w) N7 I8 T
  58.         // P3口初始化为准双向- x; Z! Q( J* p8 x4 N
  59.         P3M0 = 0;+ I# J0 o* c6 E$ J& X" v
  60.         P3M1 = 0;& l( L7 B  j& ?2 s( M, @2 Q
  61.         P3 = 0xFF;
    $ @3 K/ l5 }) M; W, W
  62. }
    9 w5 i2 h1 C6 X% [3 _; }& }+ A

  63. & b& K% }& k0 z* x7 T
  64. static void Interrupt_Init(){
    ( F) \$ l6 x& a9 D
  65.         // INT0中断(CLK)触发类型为上升沿+下降沿
    + T: I+ J$ @2 g  d+ Q% t8 F
  66.         IT0 = 0;
    % ?- ~1 D# m& T4 N' z+ q
  67.         // 允许INT0中断
    # K+ y  O9 w& b/ w! x) o' [5 @4 j
  68.         EX0 = 1;! j7 t5 C0 F% v4 C
  69.         // INT1中断(LATCH)触发类型为上升沿+下降沿/ m; t  ]5 Z( n* |5 l3 p& D8 l
  70.         IT1 = 0;
    ! ?/ C0 F' d# ]. |
  71.         // 允许INT1中断
    5 I% `! O; H3 F! G( @
  72.         EX1 = 1;$ z) r% H. c! P/ A. ?8 t) L
  73.         // 开启全局中断
    & X3 E6 a0 u8 V* e3 w3 r/ a
  74.         EA = 1;3 a* t; T/ q0 r7 r; o
  75. }3 e- |7 Y( O1 X5 m; V1 y" w
  76. 4 ]3 x: [) r1 z6 R- ~1 ]
  77. static void INT0_Isr() interrupt 0{7 b# ~- t  G. S7 ~
  78.         // 只有已经成功锁存才允许CLK移位
    1 a+ i( l. S9 g- U. {2 X
  79.         if(isReady == 0)+ Z, B; f5 P% k; l+ ?* c* t* u
  80.                 return;
    / M1 t1 `* c8 E/ I# m  j
  81.         // 读当前引脚电平,如果是低电平则说明是下降沿,此时直接忽略该中断7 Y: n, ~" ~2 ]9 w# f  c6 D7 v8 k
  82.         if(CLK == 0); R3 z2 m! B! a0 u: h: \  q" v7 w
  83.                 return;4 o3 x# l8 ?# R' j4 R* ?
  84.         // CLK上升沿到来的时候,取锁存值的下一位输出& r2 ~" O# c$ m7 d$ ?2 F
  85.         idx++;
      i& M, b# b3 K" M  J. |% W% b
  86.         DATA = key & mask[idx];0 Q4 Y  H1 q) R0 ]7 ]( ]) `
  87.         // 如果已经完成7次移位,则一轮读取完成
    " f& E3 J0 g% k! S- F/ {
  88.         if(idx >= 7)6 N5 A( K1 m! A1 b+ t; \5 N
  89.                 isReady = 0;1 J4 J3 x% s6 c4 q+ f- W* l
  90. }
    6 M; n2 F/ s2 X- O

  91. 4 H$ K1 J# U+ R, g) h+ p
  92. static void INT1_Isr() interrupt 2{
    1 b. d! t; o* y. t6 l$ O
  93.         // 读当前引脚电平,如果是低电平则说明是下降沿,此时直接忽略该中断/ _" J( Q$ J: H7 I' n  p
  94.         if(LATCH == 0)
    * r" x1 ~5 c! _. p
  95.                 return;
    . @3 H" u: @% _- [+ u- o
  96.         // 当LATCH上升沿到来的时候,锁存所有按键状态,同时把键值A输出到DATA9 ^1 m" u$ M' {( ?
  97.         key = bufReady;) j! r' I% n; o: J
  98.         DATA = key & 0x80;//mask[0];        // 为了加速运算,直接取表中的值而不是读表
    * G8 N# m* N8 D) y4 q( ?! B8 S
  99.         idx = 0;4 Z0 d( i& |( [  b+ @
  100.         // 允许CLK进行移位* Q& J6 Q; ~: R% N  W. q/ H
  101.         isReady = 1;
    5 {' W3 k4 {) G3 L
  102. }
    $ ~" {( I+ u2 _8 L; h/ G% |
  103. 0 h* y8 r$ I+ H
  104. void main(){( _( N: n8 k; Z  }; `( s
  105.         GPIO_Init();
    9 E) o' _+ I6 e4 k
  106.         Interrupt_Init();' {# K# C( ?$ Z# ^5 |  ^, P
  107.         / f( p4 S; c" l% J; H6 Y* Y+ m
  108.         while(1){
    $ i- x) a% R  N
  109.                 //PCON |= 0x01;        // 进入省电模式
    . ?# V3 ?4 x/ X
  110.                 //_nop_();' K( @4 e2 e! `6 v. E
  111.                 //_nop_();
    / f" S9 h3 q* D( P4 e' o
  112.                 //_nop_();
    ' a; [. i; }( D# C/ A
  113.                 //_nop_();
    1 O- Z: U6 c$ a' R5 R
  114.                 buf = ~((P1 & 0x3F) | ((P5 << 2) & 0xC0));
    - W3 s3 o' @. e2 R& r
  115.                 bufReady = buf;
    % r; X& c$ [9 [# N( `5 ?$ s
  116.         }
      ^( J! |: r9 Q) g; b( {/ e
  117. }
    % C+ f* n  n; m% |
复制代码

# N/ W8 Y. h! d0 b硬件参数配置无特殊要求,晶振频率选择12M即可。
( S8 U& E+ L' [7 O: ~
% b6 w, W: d7 m) c3 q这是编译好的固件。

本帖子中包含更多资源

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

×

评分

参与人数 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' I; X0 R: E: n2 ], R
不错的设计,想问一下楼主,FC的15针公头怎么解决?普通的公头太短了,插不进去FC的扩展接口。 ...
( Z  ^# ]: [9 g! Y2 K; O
坛友的改造方案
回复

使用道具 举报

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

使用道具 举报

发表于 2019-5-25 12:07:18 | 显示全部楼层
精彩,楼主动手强,也写得很详细。# \6 G: I- \8 z$ L4 `  C# g$ q, J( c
2.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
! ~" I1 G5 @0 C2 q9 C4 \: L" |精彩,楼主动手强,也写得很详细。
$ D: `& D8 b9 ?2 D2.4G方案是目前无线的最低延迟吗?

$ j1 h1 s; [' R- W" T我没用过其他无线手柄,所以实在不知道我自己做的这个手柄到底是不是最低延迟。
$ s, |* x2 z$ g' I不过根据网上的说法,延迟高低主要是由通信协议的复杂程度,以及数据传输速率决定的。这个模块虽然是2.4G无线模块,但由于协议很简单,所以延迟比较低。" e* D. v4 _' _+ E
我用这个手柄玩一些ACT游戏,比如超级马里奥、忍者龙剑传、热血系列,完全感觉不到延迟,和游戏机自带的手柄没有任何区别。唯一的区别就是这个手柄是用火花山寨手柄改造的,外壳是垃圾回收塑料,粗糙+脆弱,导电橡胶弹性不佳,手感不是一般的差。
/ L% a$ Q$ L5 x, B0 y. |我手里还有十几张板子,等我有空了我再做一套,到时候买一个好一点的手柄改造。
回复

使用道具 举报

 楼主| 发表于 2019-5-29 16:56:14 | 显示全部楼层
ppad 发表于 2019-5-28 17:27
3 J1 L9 i% S8 Z给技术帝赞一个,有半成品发布吗,自己焊接改造就可以,编程实在不会啊 ...
) t/ _; P8 ]  j& K9 s8 B$ G% k' l
很可惜,我手里没有多余的单片机了,LDO也找不到了,锂电池以及充电模块更是没有了。反正就是该用到的元件基本都没了,所以没法发布半成品。2 ^) r: f4 k* X+ K. `1 X2 g/ Z
两个板子倒是有十几张剩余。
$ H6 Z* l+ {, D& I+ ?你要是有USB转TTL串口板,完全可以自己买这两种单片机,然后我给你编译好的固件,你自己用串口板下载到单片机里面就行了。两个2.4G无线模块也得通过串口板用AT命令设置参数,不过好在我在设计电路的时候就已经预留好了串口,可以直接在线下载和在线设置参数。总的来说并不麻烦。
回复

使用道具 举报

 楼主| 发表于 2019-5-29 17:00:34 | 显示全部楼层
孙大师 发表于 2019-5-28 18:553 L% d. ]1 C3 @
非常好,楼主是技术帝,到目前我都还没开发fc的无线套件,等空了,开发一套套件,等玩家自己组装。 ...
9 E) k1 I: t6 ^  `
能得到孙大师的赞誉,不胜荣幸!1 K2 K3 {5 h& R2 K' m, G, ^
不如开发一个多功能手柄,比如用SFC手柄改造,L/R键配合其他组合键可以用来切换2P~4P、调节连发速度、软重启等各种功能。接收端插到15PIN扩展口。
回复

使用道具 举报

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

本版积分规则

Archiver|手机版|小黑屋|Video Game Do It Yourself ( 闽ICP备14000865号-1|闽公网安备35018102240098号 )

GMT+8, 2026-3-27 17:07 , Processed in 0.103787 second(s), 14 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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