找回密码
 注册

QQ登录

只需一步,快速开始

查看: 26027|回复: 32

自制FC无线手柄

  [复制链接]
发表于 2019-5-22 14:16:45 | 显示全部楼层 |阅读模式
本帖最后由 雷精灵2046 于 2019-6-14 09:28 编辑 2 `& P  {) C; k6 Q, O

/ y* X5 }$ m/ c5 a9 F) }没有用复杂的分立元件搭建发射接收电路,直接用的现成的2.4G无线模块jdy-40。# R- Q' q" t# e5 G" m/ M0 V" m

, k+ q9 x9 Z% H3 ~
3 N; ~% ~/ ], U  q7 C1 `+ Y: H发射端靠3.7V锂电池供电,用了一片SOP8封装的STC单片机,负责产生连发脉冲,同时负责检测电池电量,电压低于3V左右的时候触发低压中断,低压指示LED就会亮起来告知该充电了。平时发射模块和单片机均处于睡眠状态,有按键按下才会唤醒,从而实现省电。实测睡眠状态下整机电流约1~2uA。板子洗了一下稍微干净了一点。因为对于微功耗设备来说,焊接残余的助焊剂可能会增加漏电流。
2 U1 S# d( q* i& z* [5 z
9 L0 R' z; z; I" t  E买了一个火花的FC山寨手柄,去掉里面的牛屎板子,并修正一下塑料挡板,把锂电池和充电模块装进去。+ t6 r% V* I- z3 D2 _3 S3 R5 o
为了减少体积,充电模块裁剪得十分小,并且更换了充电电阻使之适应这个小小的锂电池。这么小容量的电池,也不需要多么大的充电电流是吧?
- D' x9 T( p% ?# S) [+ r然后统统用热熔胶粘上。充电电流比较小,所以发热很少,不会熔化热熔胶。
" P( O3 w! E" z3 |$ x$ b/ y
, q: r3 M5 s' c6 V' h0 q0 f1 F9 A" u7 U& h4 y
  F+ H( V: S, Y9 f# [# F
最后把按键、导电橡胶和电路板装上去。4 X8 p) a( e" a0 S' O8 g
精心裁剪了电路板,正好扣上,不会阻碍其他元件,也不会影响后盖和拧螺丝。
9 V# {2 F1 M: p4 s$ ^8 C" [& h6 Y* u/ o: n. x* ?$ _
- Z, e9 L! _+ Q8 `* C
完工!) T- B  @& W5 W* x. H

7 H$ K9 g- V7 p  }& w, M. F5 q4 ]4 z, b  D) E% ^
这是充电的MicroUSB插座。旁边的小孔用于透出低压报警LED的光线。
( d  U2 v' x+ v2 D6 C
" G+ u4 j6 }: w# G" D
; D3 B" X! U8 ]4 h4 y接收端用一片DIP16封装的STC单片机模拟CD4021。为啥要用单片机模拟而不是直接用CD4021?因为jdy-40模块接收端在有按键按下的时候输出高电平,无按键按下输出低电平,和普通手柄正好相反。当然我也可以用两片74HC00或者74HC04之类的逻辑门进行反相,但那就增加了芯片的数量。对于FC手柄这种工作频率并不高的设备来说,STC单片机完全可以胜任模拟工作。- t' m" a3 H1 h% {1 P: O

* p% E# k6 H/ f. j
2 l/ x/ c7 _' O0 q' }8 a
, ?3 I0 T5 ]) H, u( A  C( D电路设计有点小小的错误,所以有几根飞线。原本设计使用低压差LDO是XC6206,结果在做这个接收模块的时候,买的LDO居然找不到了!无奈只好用了AMS1117。幸好对于接收模块来说是5V降到3.3V,1117可以胜任。要是发射端手柄的话,3.7V降到3.3V,那就非得用6206不可了。
6 G$ K3 C8 d" j: o" a
4 d; F& F0 h) y% c" |实测十分灵敏,延迟极小几乎感觉不出来。可惜这山寨手柄的手感并不佳,尤其是方向键,软塌塌的。看来我得买个剪线手柄改装。" V3 |0 g& H" `9 b' f3 p

5 G- E' l  c9 \7 Y4 Q7 z% r' d3 R这是电路图,有兴趣的朋友可以参考。' I, @( m( v8 Q; Q% C

0 h/ _( L; P: s# {9 X& \( k+ d  h' B
我信奉开源主义,十分痛恨把技术藏着掖着。好东西大家分享嘛!所以两个单片机的源代码大公开!  p! Q5 v1 y' O/ @
编译器:Keil 51。/ I" h, z( ^* W, j8 ~
: p8 `4 Y8 m0 N) ]* i
发射端:
7 z. s3 z/ B1 z- ~& A1 c$ m
  1. #include <INTRINS.H># c. d$ \) \4 C  O+ Z% u+ a# N! |  `
  2. #include "STC15W.h"
    - @! F; j4 |, f/ ^6 p

  3. ! y- w- H( d- E8 _3 m* J

  4. 5 x7 k8 g# Q7 ]
  5. /*8 f3 G# s# q8 P4 y! r
  6. --------------------------7 U9 Q7 P  @3 g9 t
  7. |1 (OUT)        \__/   (INT1) 8|
    6 T; R  P1 [; m$ q0 t/ V2 L
  8. |                                                   |# r- M& d2 b# Y8 {% M. T0 B
  9. |2 (VCC)                   (INT0) 7|2 ?  ^; m# Z7 v4 P+ x- {
  10. |                 STC15W204S                   |
    5 _2 X3 W$ y( v; q
  11. |3 (LED)                         (TXD) 6|: r8 S' |7 e5 p+ o3 R
  12. |                                                   |: f! A, @' m& h, d. _
  13. |4 (GND)                         (RXD) 5|
    " i& ~# t7 |& }2 h
  14. --------------------------3 J' @5 N! F+ X, e1 W: V

  15. , K6 w# x# w+ i7 V
  16. LED ---|<|---[===]--- VCC
    ! D! l) k9 Q# d8 {# w
  17.            Red          330
    ! M/ a9 d- B  }* ?; H3 N

  18. ; d% i0 d1 M6 J) ?& v- i; b
  19. Fosc = 6MHz
    0 J' `9 o8 ]9 [4 V2 N% {% s
  20. */
    2 J) [# m) w  v/ w' g

  21. 8 F0 @1 \0 l6 e: }- D* b5 {
  22. 4 I" O; D9 }$ W& n! |: p8 x" n
  23. // 矩形波输出脚
    - h, U1 N$ [/ |/ ]8 K( f# @, \1 I
  24. sbit OUT = P5^4;
    2 U- y1 F9 \! a  `' O- N" b
  25. // 低压指示灯引脚
    - \6 ]6 [3 m/ S8 @& Y+ O, z
  26. sbit LED = P5^5;
    3 c6 O$ d& a8 m+ e) x# J4 L
  27. , M' h( S, p& R: T4 p- M5 o  ?" F$ j
  28. // 停机标志位
    ) i" e  D: X+ d* Z! w
  29. bit isReadyToHalt = 0;
    3 l, ~8 f1 k' P9 }4 D6 u% d
  30. 7 Z5 `8 X% P3 F  A: H) F: h
  31. // 矩形波次数累计
    : u- T. F% o* P) `& l3 g+ s- S
  32. static volatile unsigned char count = 0;1 z0 s: M- Z4 M$ l& F

  33. 8 i9 O0 F" r0 E9 F) b( T; N5 z

  34. # m) [/ D5 H0 J$ g0 s' v3 k/ `7 o
  35. static void GPIO_Init(){
    0 e9 P0 z+ T6 m
  36.         // P3口设置为准双向,默认靠内部弱上拉输出高电平
    $ Y# ~: \7 u; l! U
  37.         P3M0 = 0;
    3 ^  J; l- s6 Q" w! z: Q2 t9 _6 S
  38.         P3M1 = 0;7 O* a& O0 i6 }6 i) d1 G# c
  39.         P3 = 0xFF;5 Q6 w) e2 U7 W: `3 a& y
  40.         // P5口设置为准双向,默认靠内部弱上拉输出高电平$ D' u/ D. c! n
  41.         P5M0 = 0;
    8 V3 m, u  O+ G4 o6 z2 e( U1 s; C
  42.         P5M1 = 0;
    9 R  J) W# ?! {  a5 }- t- [6 _" ~9 J
  43.         P5 = 0xFF;0 Z, ~2 A. C) Q6 C8 l1 W+ s
  44. }: ^" u) g7 a4 E3 z
  45. 0 f6 U% b1 f; u- N2 Z: D' g- y
  46. static void Timer0_Init(){
    + u. [- `  }" E" W. u1 y) J( u
  47.         // 16毫秒@6.000MHz2 T( C3 j& t" j7 z1 j$ t6 P
  48.         AUXR &= 0x7F;        // 定时器时钟12T模式7 p6 H3 b% C; B4 [: I: I6 T' E
  49.         TMOD &= 0xF0;        // 设置定时器模式
    9 l$ f0 A+ Q$ z, C1 v  s: p
  50.         TL0 = 0xC0;                // 设置定时初值
    / j5 ]( c2 j- r$ E; F) ~2 x
  51.         TH0 = 0xE0;                // 设置定时初值' k5 M3 j3 F3 j# |: b1 v
  52.         TF0 = 0;                // 清除TF0标志! o! }& c; I9 z. b$ W4 E2 F
  53.         TR0 = 1;                // 定时器0开始计时! d( u  n4 x; {  ^. _; A3 b
  54. }' X  ~( a. _# d  C+ b* I
  55. 2 G9 P6 j: V2 K: J
  56. static void Interrupt_Init(){
    ! I0 K6 K2 V$ \! H4 O* I5 ]
  57.         // INT0中断触发类型为下降沿触发
    $ ?* @2 w5 G: q$ b
  58.         IT0 = 1;' ?3 M( F/ [- s+ z
  59.         // 允许INT0中断9 ]7 v" {2 j4 n# ]' t
  60.         EX0 = 1;
    ; K1 E5 F& N2 `) f- U  b, `
  61.         // INT1中断触发类型为下降沿触发
    ) G6 i: T* q5 T! G9 X2 e9 V- V: {& t
  62.         IT1 = 1;
    % b' _# s6 E% [. I4 {" j7 C; L
  63.         // 允许INT1中断0 y6 [- x% b; R  h
  64.         EX1 = 1;
    ! s( s7 @9 o; X! o* t, A
  65.         // 允许定时器0中断
    8 g1 n) _# [* g) @7 A
  66.         ET0 = 1;
    ! D! p' W: t! d) ^# `6 ~! M
  67.         // 允许全局中断
    , E% _# A  W2 e& {4 }" f
  68.         EA = 1;
    9 q/ B: P3 T9 [% Q
  69. }* M5 B' L, n8 B5 w* H
  70. ; i  }( m, X- M% M  T" S' [8 i
  71. static void INT0_Isr() interrupt 0{3 z6 y! P& a3 t6 G
  72.         // 矩形波次数累计归零
    7 U5 b, r  y1 F) T4 {9 s" o4 x# q% f
  73.         count = 0;! t4 t9 n6 p7 U5 G: t
  74.         // 重开定时器0中断8 O1 Y3 e8 U: y* Z/ c
  75.         ET0 = 1;- `) |$ @" n+ K( e$ t
  76. }$ g8 L% v8 L7 _/ q: N

  77. . @4 L/ ~! \2 f* @. q+ ?+ l# R* _
  78. static void Timer0_Isr() interrupt 1{- M3 D0 ^: e' k8 R& T* [3 B4 Y$ U
  79.         // 输出矩形波2 j2 n6 ~3 ?* b- J  n
  80.         OUT = ~OUT;/ ?) H" W) c  K/ P" }! g
  81.         // 累计矩形波次数5 q! n, X7 f: ]) a0 r
  82.         count++;
    7 T, t" c3 J( m1 }
  83.         // 超过250个矩形波,准备停机
    + D7 k$ m. N. m3 }5 o  x8 `
  84.         if(count > 250){6 f2 N0 R: o* |# t6 n: O
  85.                 count = 0;( [: s! h# U  J
  86.                 isReadyToHalt = 1;
    7 ?: ?, z; W% }
  87.         }
    ; q, ]' ]" h3 W7 x: B
  88. }, z5 z, Z: R5 l) D7 ?0 o% A; q
  89. . j' N; ?3 `8 U5 a+ f
  90. static void INT1_Isr() interrupt 2{
    ( q" M3 f* ?4 d4 f6 A/ O* [* i
  91.         // 矩形波次数累计归零
    + F, {2 d; r1 F; |
  92.         count = 0;+ C# \: G, D" w( J- j6 o
  93.         // 重开定时器0中断8 ~( \; w: m6 d. M( \* u
  94.         ET0 = 1;
    2 h: P# K3 {4 h" P  o$ V/ M- u
  95. }3 y. P1 A. A# t2 h& E

  96. $ L  E: }9 `) |, u8 B4 x
  97. * U# l0 h$ }- h1 B- O' `" p! g$ D
  98. void main(){3 _- [5 R) @( B
  99.         // 初始化P3和P5口0 [6 |* }2 _+ \6 o
  100.         GPIO_Init();% ~. k$ l# k. J
  101.         // 初始化定时器0
    " b* D( q' H/ S4 r
  102.         Timer0_Init();& F$ }+ J$ i$ h; X/ ^/ a( }& }
  103.         // 初始化中断. C' z% J  H( \9 t. R0 H" F/ g6 p0 N/ x
  104.         Interrupt_Init();
    ! ~, w4 k0 E: C/ e1 ^
  105.        
    ) k9 y$ z! R, b% W: k2 S
  106.         while(1){
    + ~, X  c6 E: y+ N0 [; Q
  107.                 // 检测电量
    " j+ F, S1 m  P% n2 ^  f2 x
  108.                 if(PCON & (1 << 5)){
    + v' ^! C( u7 p
  109.                         // 如果电量低,低压指示灯亮3 w9 `- a8 M$ j, s- {+ z
  110.                         LED = 0;
    - \- @9 z# B7 u! A+ A7 _
  111.                         // 清电量检测硬件标志位; H2 I) z: [% `
  112.                         PCON &= ~(1 << 5);+ M4 ?& `0 y4 T# ~
  113.                 }else{. i7 I! H: ]* u# A' O2 n
  114.                         // 电量正常,低压指示灯灭* z) r9 T  F8 U  v
  115.                         LED = 1;
    * r' m) q8 y* S& n
  116.                 }! @6 p" F/ R% W. v3 Y( \) ~2 c  `0 G9 q4 r

  117. 2 ~% x2 l. G4 t$ S
  118.                 // 检测到停机标志
    ( U  Y( ]! q- U- s
  119.                 if(isReadyToHalt == 1){
    0 L/ E8 U( j+ Y6 R0 ]  M2 {6 Z9 b) S
  120.                         // 暂时关闭定时器0中断
    " k. X9 q; E4 c' T
  121.                         ET0 = 0;
    5 k- S# v  v1 L' O/ t, R8 M- G" q
  122.                         // 停机之前先把矩形波输出脚置低电平,以方便INT0和INT1唤醒CPU. b/ D2 X. t# I7 r
  123.                         OUT = 0;
    7 Y& G  W! g% q
  124.                         // 停机之前先把低压指示灯灭掉,以省电
    1 [5 R1 c- ~5 ^) H( `1 j2 w0 v& d# v3 D
  125.                         LED = 1;
    ) y; G7 j4 _. d( k: o
  126.                         // 进入停机模式+ i$ l2 s1 b9 M# P; w# n  m6 p% a
  127.                         PCON |= 0x02;, W$ S+ a/ v7 D1 p$ y3 r4 r+ O- A  n+ P$ K
  128.                         _nop_();
    2 X1 s( E' P0 T, X! a
  129.                         _nop_();7 g& L* i; o" o+ V: `
  130.                         _nop_();
    $ t* z" U/ j7 d( h+ W1 d
  131.                         _nop_();
    3 o& K7 y6 z% S- e' Q" S
  132.                         // 唤醒,清标志位
    - m8 g- u$ e, d$ J: B) i
  133.                         isReadyToHalt = 0;
    8 O8 `: `; S/ {7 V
  134.                         // 重开定时器0中断* J/ ?( v% X5 b9 m/ m
  135.                         ET0 = 1;
    : @$ W1 Z* {/ ~1 J$ s! D
  136.                 }
    2 P: K( C6 P" G. b( k1 C3 b3 V
  137.         }/ ~2 t. \) N) D
  138. }: j; c2 b- B; X- b# r. o
复制代码
/ @7 ?. H8 R/ w% [/ L. g) C  T
硬件参数配置:  @# I. m4 d. a, T* j& u

$ J, S$ p$ c- @0 ]/ L5 k9 _: i, C6 g7 @1 x% B
接收端:( q$ c9 D- b& e0 K2 _& e  X
  1. #include <INTRINS.H>) ]9 b2 V: _. P7 z
  2. #include "STC15W.h"
    ; _+ l6 N' |$ R! Q
  3. 2 z, [  \: o0 O: D' ?8 T
  4. ) o; Q/ I! g8 B2 v2 F( X( _8 u1 Q
  5. /*
    ' r5 g  k3 U+ F) ], f

  6. ! p' g/ {0 E2 B$ E/ p
  7. *---------------------------*
    - z9 P! l& Z. I
  8. |1 (GPIO2)         \__/  (GPIO1)16|$ ?% F4 j, D. T
  9. |                                                        |
    8 y+ E0 t1 r( D6 p0 _+ P* O
  10. |2 (GPIO3)                   (GPIO0)15|
    : J0 d2 M+ R0 h% g0 W# y' v
  11. |                                                        |
    # y3 \( H7 [& |: m& P- z, d: r
  12. |3 (GPIO4)                                  14|/ r( S( {0 H. t! u2 n
  13. |                                                        |" S" v0 R+ ~1 l* n+ e% e+ C
  14. |4 (GPIO5)                        (DATA)13|8 ], Z5 B5 L0 U7 j8 V: _
  15. |                  STC15W204S                |& v/ o" \+ ^. M2 S3 v$ Y  B
  16. |5 (GPIO6)                   (LATCH)12|
    & c7 {3 d$ \* C+ ~+ x5 e
  17. |                                                        |+ A) z" j1 d9 X* I
  18. |6 (VCC)                         (CLK)11|
    - Q5 }$ |9 W. P; `
  19. |                                                          |! d% ?# E$ a- F  t
  20. |7 (GPIO7)                         (TXD)10|- j: j6 n2 ]& ^; M5 H+ m# Y7 i
  21. |                                                        |
    ( J1 _0 a5 E5 i+ G5 W- F; L! Q
  22. |8 (GND)                         (RXD) 9|
      q! ^# p7 d! d9 b0 ]- [
  23. *---------------------------*. [6 z& F/ q# g) T% m4 }; |2 h
  24. Fosc = 12MHz
    . W5 y$ r* ]1 V1 [% W
  25. 6 ^' p0 Z4 p2 P4 O0 w' c
  26. P1.0 -> 上
    3 J9 e: J% n' ~! f* r
  27. P1.1 -> 左
    - {5 F1 K4 Z# ?/ o% Z+ ~7 S9 @
  28. P1.2 -> 下( b) ^5 \: U8 Q( N
  29. P1.3 -> 右
    . G) x2 e% {% Q4 j
  30. P1.4 -> SEL4 w- A; f' Y+ y8 N( ^9 F; n
  31. P1.5 -> STA
    9 x( |8 H5 c" T3 y# c& x' q
  32. P5.4 -> B
    / w, d1 q; S  s( u# h, f! n
  33. P5.5 -> A" P4 W- |2 b4 a' \' `+ N

  34. ( [  v. m! c) L$ X: h, {
  35. */5 F; E  V) K) e  r8 m
  36. ( R( m. q( W" d( Z) Q* R
  37. ! S8 {4 J7 ~' a* G0 C( W0 w
  38. sbit CLK        = P3^2;
    * z1 H# \) `" B& ?" S% B  P5 A5 {) {! b" a
  39. sbit LATCH        = P3^3;* ?% S9 J/ B+ C9 M$ |2 J3 `" T3 G
  40. sbit DATA        = P3^6;* O* x7 }- Q  d( i
  41. * t% E! j* [+ h2 o9 d+ r0 C
  42. bit isReady = 0;
    . H% R* k; J7 ^- o' a" \- b& ~+ h: ~
  43. static unsigned char key = 0;0 M: D# k; a: Z# r" v3 b
  44. static unsigned char buf = 0;        // 双缓冲。这个缓冲区保存从P1和P5组合而来的键值
      h2 r, R. h2 y  Q
  45. static unsigned char bufReady = 0;        // 双缓冲。这个缓冲区保存上面那个缓冲区的备份
    % L  z4 k* g- M4 O  [  O+ h
  46. static const unsigned char data mask[] = {0x80, 0x40, 0x10, 0x20, 0x01, 0x04, 0x02, 0x08};        // A B SELECT START UP DOWN LEFT RIGHT。为提升速度,这个表放到RAM中
    ! m! _. n) r: ?2 B
  47. static unsigned char idx = 0;  ?5 ?4 ^& m  Q- D( l
  48. ) R' \$ l/ ~' D+ c# @

  49. 4 `) Q6 S" B# v
  50. static void GPIO_Init(){, ]/ e+ \6 G  a
  51.         // P1口和P5口用于接收并行信号,全部初始化为准双向,依靠内部弱上拉输出高电平% |/ r1 x: N; @6 H
  52.         P1M0 = 0;" B: e2 g) n2 n* W! z
  53.         P1M1 = 0;) q9 V* s2 t2 T- y/ K0 S
  54.         P1= 0xFF;/ Y; r# ^: E& N
  55.         P5M0 = 0;' C7 U4 \+ s' L2 T1 ]! A
  56.         P5M1 = 0;
    0 t0 m9 e+ m+ V
  57.         P5= 0xFF;8 A9 b# _( }6 \
  58.         // P3口初始化为准双向
    3 [' x# y/ ?3 g9 W% T1 g
  59.         P3M0 = 0;$ z! [2 T4 k# I' K9 l
  60.         P3M1 = 0;/ b% q  F: A1 T; B- f
  61.         P3 = 0xFF;9 u/ V' U. E" {3 k4 ^; z
  62. }
    4 g2 I) P9 `4 j9 [5 {4 H, u

  63. 2 S4 D; y* Y) q
  64. static void Interrupt_Init(){1 R7 N* t2 B- F3 D: u
  65.         // INT0中断(CLK)触发类型为上升沿+下降沿
    ' m3 \3 }. E  T) t: X
  66.         IT0 = 0;( W6 w6 F1 V1 D# r" y, q! R) w
  67.         // 允许INT0中断1 C- }- q# A9 A: _) G. r# ?7 {
  68.         EX0 = 1;
    9 w* Y- \2 I9 q. B* `5 R
  69.         // INT1中断(LATCH)触发类型为上升沿+下降沿- J& m! f% M' n
  70.         IT1 = 0;: \$ L* B# M7 S, N' j3 E9 {- j
  71.         // 允许INT1中断8 c; Q; K6 i+ j. j" K
  72.         EX1 = 1;3 L1 D$ [/ H* R1 r( Y+ p/ f% D4 X
  73.         // 开启全局中断
    - u9 X; _) K5 T, l; y4 p
  74.         EA = 1;5 A4 j9 f1 @& j: p
  75. }) h; c  H3 e  m" C2 e6 x2 r

  76. 1 N( F& V8 V5 I. c9 i
  77. static void INT0_Isr() interrupt 0{; [' T: ^+ ?' N# P
  78.         // 只有已经成功锁存才允许CLK移位
    : i/ n( C' d- I
  79.         if(isReady == 0)* X7 F; R3 J1 |# t8 x+ B- w
  80.                 return;
    ' h0 [0 F- u7 T. l2 }& X& p7 [4 W& g
  81.         // 读当前引脚电平,如果是低电平则说明是下降沿,此时直接忽略该中断
    2 ?. K" J# j1 ]: s+ m/ w& i
  82.         if(CLK == 0)/ A2 a9 Z8 Y: t. q' L
  83.                 return;% G, h8 t; f6 T/ u2 g! }; l
  84.         // CLK上升沿到来的时候,取锁存值的下一位输出$ f- I3 F5 v/ K( u
  85.         idx++;% V4 r( {) I  q' I1 j' C* y9 G
  86.         DATA = key & mask[idx];
    , Y$ z( L, f! b. V9 W2 @% I
  87.         // 如果已经完成7次移位,则一轮读取完成
    & w( A3 @2 b, D, \# X! u  M
  88.         if(idx >= 7)
    1 H, b5 Z% I# S! N
  89.                 isReady = 0;* W7 h! g! ?  K  o
  90. }
    ' K* p2 `  S' r

  91. ' F! T4 S9 ?5 q; Z8 q" v- a; r4 U; M
  92. static void INT1_Isr() interrupt 2{  A- {, D. Z5 c0 z: `. |
  93.         // 读当前引脚电平,如果是低电平则说明是下降沿,此时直接忽略该中断8 Q5 r& ^/ e9 H- L3 f' `" p
  94.         if(LATCH == 0)- q/ R5 \  S+ O8 d
  95.                 return;
    0 w! W. n( L( T5 e$ W4 \+ U. ~5 v
  96.         // 当LATCH上升沿到来的时候,锁存所有按键状态,同时把键值A输出到DATA
    ! L; J2 e8 E% ^; b1 N
  97.         key = bufReady;) |( K: T, `' F0 w# Y% o( ~
  98.         DATA = key & 0x80;//mask[0];        // 为了加速运算,直接取表中的值而不是读表
    $ T) l# }; U8 H
  99.         idx = 0;) j# V6 |# R& M* P
  100.         // 允许CLK进行移位" ^+ p' L+ j2 _: t: t
  101.         isReady = 1;5 l4 r$ @% m% F. g! B
  102. }
    3 _) x8 ~: W6 N3 w

  103. . f% S6 C0 n8 G- r% V
  104. void main(){4 M3 V0 u. n8 ^, Q  A/ Y5 f
  105.         GPIO_Init();% A, L. d. e  b- N2 o
  106.         Interrupt_Init();4 f: }. {6 `: r) a! m
  107.        
    : l9 H. a$ y- `0 g6 g
  108.         while(1){
    # m6 ~- H+ Q0 H# |" Y3 @: s
  109.                 //PCON |= 0x01;        // 进入省电模式
    ! j9 a7 o5 T( t0 t; W+ ?4 @2 B
  110.                 //_nop_();
      X0 Y4 E, k1 }. E: e
  111.                 //_nop_();
    . U) Z0 f2 o5 O+ \/ I8 |# V
  112.                 //_nop_();
    , K* ^$ q2 u  w! s+ I1 ^
  113.                 //_nop_();
    ; D' U0 d: `% O  b
  114.                 buf = ~((P1 & 0x3F) | ((P5 << 2) & 0xC0));
    , @5 h5 j6 h1 Y( P+ G( B% F$ ?$ G
  115.                 bufReady = buf;  r- v2 P: h+ K5 w8 O2 |
  116.         }, w: c8 ?( U; B
  117. }% J0 J7 O( s2 }% U& ]$ [
复制代码

4 U3 j# _% O& u" {) j. G硬件参数配置无特殊要求,晶振频率选择12M即可。  e4 l9 q% C+ j5 A$ R

# I: o+ `3 @& @  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# G; ?6 D4 j. X1 X2 v0 ?) l1 Q8 W
不错的设计,想问一下楼主,FC的15针公头怎么解决?普通的公头太短了,插不进去FC的扩展接口。 ...

  T1 u" i6 R: u; n5 F坛友的改造方案
回复

使用道具 举报

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

使用道具 举报

发表于 2019-5-25 12:07:18 | 显示全部楼层
精彩,楼主动手强,也写得很详细。; W0 V% u; f# p) C* c2 w
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
/ k: U* T- V5 G9 Y+ M: p& r* E精彩,楼主动手强,也写得很详细。* {% U$ I( S) X& ]
2.4G方案是目前无线的最低延迟吗?
0 p" b! w3 F8 z) `; v, M. _- s" n
我没用过其他无线手柄,所以实在不知道我自己做的这个手柄到底是不是最低延迟。: }+ H. u5 w& T7 p
不过根据网上的说法,延迟高低主要是由通信协议的复杂程度,以及数据传输速率决定的。这个模块虽然是2.4G无线模块,但由于协议很简单,所以延迟比较低。; X9 E& U7 {+ h$ `6 U
我用这个手柄玩一些ACT游戏,比如超级马里奥、忍者龙剑传、热血系列,完全感觉不到延迟,和游戏机自带的手柄没有任何区别。唯一的区别就是这个手柄是用火花山寨手柄改造的,外壳是垃圾回收塑料,粗糙+脆弱,导电橡胶弹性不佳,手感不是一般的差。* s9 z' F/ i4 U+ k% q1 c
我手里还有十几张板子,等我有空了我再做一套,到时候买一个好一点的手柄改造。
回复

使用道具 举报

 楼主| 发表于 2019-5-29 16:56:14 | 显示全部楼层
ppad 发表于 2019-5-28 17:27
6 W$ N" h4 U+ f/ z7 I) n! w给技术帝赞一个,有半成品发布吗,自己焊接改造就可以,编程实在不会啊 ...
9 L! w- _. i- }3 i8 Z
很可惜,我手里没有多余的单片机了,LDO也找不到了,锂电池以及充电模块更是没有了。反正就是该用到的元件基本都没了,所以没法发布半成品。+ H  a4 }7 C. f7 X& v+ k
两个板子倒是有十几张剩余。  W8 }8 J% S- s7 \7 i5 k
你要是有USB转TTL串口板,完全可以自己买这两种单片机,然后我给你编译好的固件,你自己用串口板下载到单片机里面就行了。两个2.4G无线模块也得通过串口板用AT命令设置参数,不过好在我在设计电路的时候就已经预留好了串口,可以直接在线下载和在线设置参数。总的来说并不麻烦。
回复

使用道具 举报

 楼主| 发表于 2019-5-29 17:00:34 | 显示全部楼层
孙大师 发表于 2019-5-28 18:55
+ ^! I: s* @! q, f非常好,楼主是技术帝,到目前我都还没开发fc的无线套件,等空了,开发一套套件,等玩家自己组装。 ...
0 V' s& o: R! J& J/ m
能得到孙大师的赞誉,不胜荣幸!
$ K. B+ W0 e' E1 n7 D( z6 q不如开发一个多功能手柄,比如用SFC手柄改造,L/R键配合其他组合键可以用来切换2P~4P、调节连发速度、软重启等各种功能。接收端插到15PIN扩展口。
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-7-22 16:52 , Processed in 0.115369 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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