找回密码
 注册

QQ登录

只需一步,快速开始

查看: 23580|回复: 28

自制FC无线手柄

  [复制链接]
发表于 2019-5-22 14:16:45 | 显示全部楼层 |阅读模式
本帖最后由 雷精灵2046 于 2019-6-14 09:28 编辑   k7 m7 P+ Y6 F" J. y5 i
$ o4 Q& }! \, I% E/ Q+ v, M/ ]
没有用复杂的分立元件搭建发射接收电路,直接用的现成的2.4G无线模块jdy-40。
3 @6 W9 I8 P  e- }% m6 L; I
! w. X) T$ ~# ^( b- R2 \( N
  N0 E  j  @7 ~1 ]4 s发射端靠3.7V锂电池供电,用了一片SOP8封装的STC单片机,负责产生连发脉冲,同时负责检测电池电量,电压低于3V左右的时候触发低压中断,低压指示LED就会亮起来告知该充电了。平时发射模块和单片机均处于睡眠状态,有按键按下才会唤醒,从而实现省电。实测睡眠状态下整机电流约1~2uA。板子洗了一下稍微干净了一点。因为对于微功耗设备来说,焊接残余的助焊剂可能会增加漏电流。
* ~) t$ S! e, b* h  [6 R; C6 V. ]) @. h# V, q$ i
买了一个火花的FC山寨手柄,去掉里面的牛屎板子,并修正一下塑料挡板,把锂电池和充电模块装进去。
) N2 V) O9 D) L1 x% S) w' @为了减少体积,充电模块裁剪得十分小,并且更换了充电电阻使之适应这个小小的锂电池。这么小容量的电池,也不需要多么大的充电电流是吧?
/ M+ e1 B% ?# U& P) B* H' g然后统统用热熔胶粘上。充电电流比较小,所以发热很少,不会熔化热熔胶。
- F6 W8 a$ J' V+ R0 c6 h. o( M. N; T& M$ }6 }" ^, w. u

" I+ R" [8 i0 O+ w4 L9 }* o- {2 L: Z
" S% \$ [/ D# N最后把按键、导电橡胶和电路板装上去。3 k& ?; D, b( d8 Y, h5 Y
精心裁剪了电路板,正好扣上,不会阻碍其他元件,也不会影响后盖和拧螺丝。
" v  g6 B8 o$ C7 \) j- t& W5 c* g, w) q5 U( s
3 Y5 e0 m: Q0 U: K
完工!4 D2 Z6 N; ?! e' S1 [6 T+ H

. J/ q; }2 w$ ^7 d6 N' W
$ F+ x9 l: R$ P  q* U这是充电的MicroUSB插座。旁边的小孔用于透出低压报警LED的光线。2 R! M+ v5 v# V5 m' }/ `9 V. M
6 I( \2 f$ l+ E. _5 C
8 i7 x2 h% w1 B3 ~5 Z
接收端用一片DIP16封装的STC单片机模拟CD4021。为啥要用单片机模拟而不是直接用CD4021?因为jdy-40模块接收端在有按键按下的时候输出高电平,无按键按下输出低电平,和普通手柄正好相反。当然我也可以用两片74HC00或者74HC04之类的逻辑门进行反相,但那就增加了芯片的数量。对于FC手柄这种工作频率并不高的设备来说,STC单片机完全可以胜任模拟工作。
9 v) y6 g: I' X0 w4 F, c9 ?: ?# L5 _3 O  N/ t3 U# H. I

# n2 j3 s2 R7 w, _" c+ K9 i! i
" O( h% w4 d) D电路设计有点小小的错误,所以有几根飞线。原本设计使用低压差LDO是XC6206,结果在做这个接收模块的时候,买的LDO居然找不到了!无奈只好用了AMS1117。幸好对于接收模块来说是5V降到3.3V,1117可以胜任。要是发射端手柄的话,3.7V降到3.3V,那就非得用6206不可了。
. `" d" g. [9 r( D# D2 ?4 @9 g; s0 V) y" y4 O! ]
实测十分灵敏,延迟极小几乎感觉不出来。可惜这山寨手柄的手感并不佳,尤其是方向键,软塌塌的。看来我得买个剪线手柄改装。& |7 V" T3 z2 _+ p5 }% k

* }+ a, L0 p6 I4 E& j这是电路图,有兴趣的朋友可以参考。( z0 N4 ]1 M$ R- h, b
+ g7 I, K" e& w8 y1 h
- Y5 G" F: S8 ^( U$ s
我信奉开源主义,十分痛恨把技术藏着掖着。好东西大家分享嘛!所以两个单片机的源代码大公开!4 `" ^# X3 c& L" `/ q' T
编译器:Keil 51。
4 ]6 ^* b) x2 D& P* d/ t
6 k8 {  H+ j8 f' k! q发射端:
$ r+ v8 w; A$ k: X0 M( Y1 O9 a  m$ i4 q
  1. #include <INTRINS.H>2 s' l, C3 p4 o( s% \, }0 N
  2. #include "STC15W.h"7 Q0 k$ g1 w+ \* a; s/ F7 M

  3. 4 j& s9 P# @& T2 E
  4. * i  e1 |2 J! Y# S
  5. /*, z% g4 s+ \1 N+ o/ ~
  6. --------------------------
    5 F- L* H  [: e* ^# p+ y% l- ]
  7. |1 (OUT)        \__/   (INT1) 8|
    + x3 r; K8 q) @1 K! I
  8. |                                                   |. q7 H. [0 n0 ^! h9 H' O/ d8 I
  9. |2 (VCC)                   (INT0) 7|
    * o  e6 o; g$ ?+ ~! ]
  10. |                 STC15W204S                   |* A/ u2 i7 b& u3 f# a
  11. |3 (LED)                         (TXD) 6|
    . Q8 k2 p% j+ b; E
  12. |                                                   |
    5 v" w) Q- l# i" a# E! y$ ]. `
  13. |4 (GND)                         (RXD) 5|1 V; T. t! d9 g6 K- e
  14. --------------------------
    3 a. e: u, ~2 f. @3 R& d- w
  15. . ?# J) R( c9 q: [
  16. LED ---|<|---[===]--- VCC
    ' C+ K- m. b7 O( a
  17.            Red          330- F/ x& J5 z: q% a' {% ]* X

  18. 5 n" r2 `( Z2 u, U4 w$ Z  V8 Y
  19. Fosc = 6MHz) w) S# Z! a( `6 j+ M/ e. w3 b6 S2 i
  20. */; A; N* K' G! G) a
  21. 6 N6 ?* L3 e7 h* z

  22. 7 u. q1 u% x+ ^
  23. // 矩形波输出脚. N6 O* F, N( g+ P
  24. sbit OUT = P5^4;" H0 u$ }. C" g5 M" ^
  25. // 低压指示灯引脚3 {  }: n+ w: W2 Z2 K
  26. sbit LED = P5^5;
    0 E' j; I4 Q/ a' W6 ]

  27. - }" T: n6 m% o; c9 y
  28. // 停机标志位
    7 b5 Q3 I% o; g% `- a/ F
  29. bit isReadyToHalt = 0;& ^% r1 z  r4 ]  M+ i  {1 }
  30. ; l! o6 y2 E# B' z3 D+ J
  31. // 矩形波次数累计* ~+ Z& ^4 T: o
  32. static volatile unsigned char count = 0;
    ; e9 {4 a1 H) l

  33. / i+ l8 ~' N# f. p0 Y) D+ ^
  34. ' L0 L# ~* l/ h$ |0 r7 K+ [& i
  35. static void GPIO_Init(){
    0 x+ |3 q/ R% V8 l$ }) H
  36.         // P3口设置为准双向,默认靠内部弱上拉输出高电平
    , u& Y( E/ Q' X& q
  37.         P3M0 = 0;
    ! v3 _: _1 t+ t, U! I  D$ Z; }
  38.         P3M1 = 0;! w# D+ k4 v/ l
  39.         P3 = 0xFF;4 W8 T% b6 e  ]9 J
  40.         // P5口设置为准双向,默认靠内部弱上拉输出高电平
    " h( D: x3 ?. X" ]$ K6 y
  41.         P5M0 = 0;
    3 B9 i' k7 t, k* ^; b7 [" s( v6 q
  42.         P5M1 = 0;0 q$ h4 v+ m- [9 ^$ k
  43.         P5 = 0xFF;
    ! S2 N" y9 S7 Y# X$ y
  44. }- A: I% z; j+ A+ ?% s
  45. $ O9 ~  Q% N2 Y) D9 J9 E
  46. static void Timer0_Init(){
    1 ?! o; }* P# S" \
  47.         // 16毫秒@6.000MHz
      k2 H$ C# ^( u4 o& u* Q5 i+ m
  48.         AUXR &= 0x7F;        // 定时器时钟12T模式) f  T4 L5 {# w# j+ q6 ^
  49.         TMOD &= 0xF0;        // 设置定时器模式  r8 d1 D/ x6 _" v$ D5 a
  50.         TL0 = 0xC0;                // 设置定时初值2 w( L) g" l4 l3 Q8 w1 @5 @' U
  51.         TH0 = 0xE0;                // 设置定时初值
    ; I6 j- j" i) n1 E- r
  52.         TF0 = 0;                // 清除TF0标志
    " R  H) n/ h/ V7 Y! `7 y% r" u
  53.         TR0 = 1;                // 定时器0开始计时
    9 h4 O. x( v+ W0 J& m. O
  54. }
    4 H6 |* m  a) b* o3 \

  55. 6 G/ C" U6 b, O3 K9 }" \: _  ]
  56. static void Interrupt_Init(){  I% z+ K5 I2 ?7 r
  57.         // INT0中断触发类型为下降沿触发
    8 Z+ }) V( E, H
  58.         IT0 = 1;! E" I1 v# _* x, \/ t
  59.         // 允许INT0中断
    - ~% Y: P+ k0 ], T
  60.         EX0 = 1;
    5 y& d& {' z' P$ G/ r0 J
  61.         // INT1中断触发类型为下降沿触发
    7 L. N  u8 A9 I, C9 |3 T; X0 g/ m6 V
  62.         IT1 = 1;5 h* q9 d0 ]1 P: u9 Z( h
  63.         // 允许INT1中断; I8 w9 K- H+ `3 J0 R! N
  64.         EX1 = 1;# c7 a5 A; X. ~  [; r( @( V7 o
  65.         // 允许定时器0中断0 l, Y5 {# d  M; Q
  66.         ET0 = 1;# W0 ^/ n- T& G, P
  67.         // 允许全局中断
    ( q; t4 N2 N/ O  h+ m5 x; p
  68.         EA = 1;
    # b. v& x- ~; {5 {( R+ c2 w
  69. }
    1 Z$ A" |7 U: L" f
  70. 6 J/ F2 @, C: \  {5 d" v
  71. static void INT0_Isr() interrupt 0{5 g" y, f2 y# u6 }. {0 f
  72.         // 矩形波次数累计归零
    ' [; ]4 C8 _- K# \; s
  73.         count = 0;$ [/ M: U+ W3 ~- s* p2 V! K) j
  74.         // 重开定时器0中断" w5 {& y% a& x8 k; y
  75.         ET0 = 1;
    6 L2 U4 H/ v7 ?8 O
  76. }  T* j$ s) |2 e2 ~& c  |/ ~8 M* a1 C

  77. ( s, N$ b4 e4 Y- V+ s: w
  78. static void Timer0_Isr() interrupt 1{6 r1 v) p6 S6 N$ ?4 h9 Q( h
  79.         // 输出矩形波
    5 g8 W+ U* s3 U. a- I" \  P; d
  80.         OUT = ~OUT;- s6 J4 r: {- Q" }4 ^
  81.         // 累计矩形波次数
    7 ?3 h0 `5 q" ~( W" r
  82.         count++;6 x: e5 j4 _. ~/ U
  83.         // 超过250个矩形波,准备停机, ]: |, z; ~( |. K( u4 q
  84.         if(count > 250){
    , t; \3 ]7 t7 f3 m5 X- B& c
  85.                 count = 0;4 S1 h2 m6 d0 T( p2 D2 O+ G, R
  86.                 isReadyToHalt = 1;1 ^, ]; \$ ^4 f1 ?' o& o( T
  87.         }
    5 x9 ?' w4 W. i/ s4 E: W. k- m
  88. }( ^' [! X  N5 h

  89. # I8 L5 O* _; B
  90. static void INT1_Isr() interrupt 2{
    / K: {  g% K: f% B/ |
  91.         // 矩形波次数累计归零2 w, q2 C, }4 w) c5 Y! z* c& @% B
  92.         count = 0;
    $ t) E8 k0 X) @" C- m7 a
  93.         // 重开定时器0中断
    * t$ w) Q+ n, i9 R5 i4 o
  94.         ET0 = 1;
    . U* k. S! S8 C# @) F% j8 x- z$ {
  95. }
    7 J( I$ g9 Q( w8 U: ]0 Y

  96. ' d% j. k8 s: Z( x: V

  97. * L# ?; ?1 q1 c# v' G
  98. void main(){
    7 x4 q9 n  F, z* f0 U+ {
  99.         // 初始化P3和P5口% T. K( j/ W7 f
  100.         GPIO_Init();) D% Q6 \7 Z% o; g7 h# d
  101.         // 初始化定时器0. Z9 I& |- O( g; ]" T
  102.         Timer0_Init();
    9 o, s& X+ f& l/ ~" Y" ?
  103.         // 初始化中断
    8 `1 A( q( y, ?6 `. c9 ]: B0 m
  104.         Interrupt_Init();
    " g: F! l$ b% ^$ b8 n5 |
  105.        
    4 w* p1 k& c  j2 ?' O
  106.         while(1){
    3 H# |  `9 r) \9 Y: [
  107.                 // 检测电量. o0 W) w, s- m; p1 i& M4 l$ d
  108.                 if(PCON & (1 << 5)){
    9 ~9 W1 ]# g+ O' m* N0 O: _
  109.                         // 如果电量低,低压指示灯亮. s- c3 k% L1 Q* x6 [" Q& P7 m
  110.                         LED = 0;
    % D; R7 C; b0 P2 x; F! j
  111.                         // 清电量检测硬件标志位9 ^6 t( Z9 Z# c* ?& k% @0 u
  112.                         PCON &= ~(1 << 5);3 D4 h9 p6 s6 `$ v
  113.                 }else{2 S0 J5 S" N4 K9 |0 P
  114.                         // 电量正常,低压指示灯灭+ k' Y" ^0 ^* x- I. I
  115.                         LED = 1;
    , M8 N! W4 e0 ^/ J0 O' D7 \
  116.                 }
    * d9 T2 a( o( E  y% p* y7 a1 ^

  117. 8 M  a  v" U0 ?; c& F
  118.                 // 检测到停机标志
    2 m; t$ n/ g1 e4 }2 x$ K
  119.                 if(isReadyToHalt == 1){
    6 R. P( F6 n! p# j! W: W2 ^
  120.                         // 暂时关闭定时器0中断6 I  `+ b7 W6 R1 k
  121.                         ET0 = 0;
    8 j. D1 R' T; x0 Y4 s3 n
  122.                         // 停机之前先把矩形波输出脚置低电平,以方便INT0和INT1唤醒CPU
    7 r$ o3 t4 y# l% L& y5 m
  123.                         OUT = 0;
    # K: F8 n+ ]( E, b; N
  124.                         // 停机之前先把低压指示灯灭掉,以省电( f) k4 y) ], y8 r: q- E$ l' {( s; b" C
  125.                         LED = 1;3 R9 p/ V. m2 w. p
  126.                         // 进入停机模式+ r; f; `- @; h  N
  127.                         PCON |= 0x02;( n2 @$ w, [% s" ?; T: F# p/ v
  128.                         _nop_();
    . V0 I2 T' H( y" j! S2 ~: ^' ]
  129.                         _nop_();
    / _. C0 X. B8 D4 E% w# M$ \3 V: D
  130.                         _nop_();, Z  c" e  d! n- F* R$ o/ a
  131.                         _nop_();
    ( V; s( Y8 Q1 {) y! V% C) A
  132.                         // 唤醒,清标志位
    " e2 A6 D- ~2 P) q" x
  133.                         isReadyToHalt = 0;
    5 ]' t8 E! F1 G/ T) u& _0 k' o
  134.                         // 重开定时器0中断
    5 R' I* H. I$ X3 C) k( ^2 a- R
  135.                         ET0 = 1;$ v0 o. d: a+ D2 E/ G# }8 O. g
  136.                 }
    : Z7 I# `' ]6 v* Y+ l
  137.         }& b+ m8 ~8 ?) ~+ R: H
  138. }
    2 c0 ^/ l( `: J7 T
复制代码

' I+ ?! x2 f: y: w. N+ O硬件参数配置:% L5 {6 n1 P5 S3 O7 I, X5 l
) R# t5 _* p. a" E, ]
6 z4 s% E  H: C  I+ h
接收端:
5 o5 ?- F6 w! Y0 n' h9 L: e* d
  1. #include <INTRINS.H>( j5 i7 \- F- u5 j0 z% Y5 k
  2. #include "STC15W.h"& {% Q9 D4 g- z! ~

  3. & `' K. f: @9 y4 D6 z( l* Y% @
  4. 5 Y5 t1 u' F5 o2 Y: O
  5. /*5 y5 q# E$ }, q
  6. 7 C' e7 q/ M, ~" x/ u3 L
  7. *---------------------------*$ R* a0 J* X& q4 D
  8. |1 (GPIO2)         \__/  (GPIO1)16|0 ^) N0 s, t9 q* t/ \0 ]
  9. |                                                        |1 P% t9 o' N( t. H7 H
  10. |2 (GPIO3)                   (GPIO0)15|
    7 y# j9 Y* c3 t; u3 E# A
  11. |                                                        |
    8 m) {' K) W0 N; ?$ s  n: i
  12. |3 (GPIO4)                                  14|
    ( U2 p' ^8 ?4 \0 S  G
  13. |                                                        |
    & \! g8 D7 v" ?& \5 }
  14. |4 (GPIO5)                        (DATA)13|
    # h4 p* K, ?- ]  e5 E7 f5 ?
  15. |                  STC15W204S                |
    6 V/ o; l4 Z& {0 v1 x
  16. |5 (GPIO6)                   (LATCH)12|
    9 M+ }  {6 V  g0 h9 p4 n5 D/ z
  17. |                                                        |/ ?8 k/ q8 s1 n0 S' P
  18. |6 (VCC)                         (CLK)11|
    * z  X0 m6 e' G+ ]0 |3 x% z
  19. |                                                          |
    & N! L) N. x$ Z9 b
  20. |7 (GPIO7)                         (TXD)10|
    7 c8 R" L" l" i) \7 ^: E3 P/ B
  21. |                                                        |( F( R  z, D' m* F1 M) c8 q' _
  22. |8 (GND)                         (RXD) 9|
    : z( K  X* }0 j; T* X6 r
  23. *---------------------------*
    9 y- \9 }, K) G& h
  24. Fosc = 12MHz
    ! Z) `* W; ~$ L% |

  25. + L* H! q2 F, i8 w) u9 t
  26. P1.0 -> 上* |' j! A& ^. R/ e3 B
  27. P1.1 -> 左; T, p9 P+ @/ x; q. |- E6 G# f
  28. P1.2 -> 下( ?# V3 I5 ~4 t5 m4 r$ q6 |2 ^1 C
  29. P1.3 -> 右
    ) k6 T7 K" J5 E8 b; D2 C. e
  30. P1.4 -> SEL, l3 l: m' ~0 o4 }
  31. P1.5 -> STA
    ) |" a! G2 R# M% b# M
  32. P5.4 -> B
    . M+ V7 t+ v) _" g; }! r* T
  33. P5.5 -> A" k! @1 M& e9 P8 v- X9 H
  34. # @) l( h: D8 ]! n1 _" T
  35. */
    $ v  ~: x# a( }

  36. ; h2 o# H1 E, M+ T! k

  37. ' \& o1 e/ K( _+ S
  38. sbit CLK        = P3^2;
    ( O) K6 s8 ^& x# |' s% ~$ H. B6 y: Y
  39. sbit LATCH        = P3^3;- p( Z: ^$ ]& K7 n  o6 }& K
  40. sbit DATA        = P3^6;
    8 o8 i( c5 U) g  D* u5 H

  41. . W2 @% e: Y$ [  o: r  a
  42. bit isReady = 0;5 j) j$ K% f2 G6 Y9 P
  43. static unsigned char key = 0;/ u4 z: b/ t) @, K
  44. static unsigned char buf = 0;        // 双缓冲。这个缓冲区保存从P1和P5组合而来的键值' E+ r* @6 u2 [9 h' X: j$ m4 o6 P
  45. static unsigned char bufReady = 0;        // 双缓冲。这个缓冲区保存上面那个缓冲区的备份+ P: Y8 M3 f/ y+ V5 r  r
  46. static const unsigned char data mask[] = {0x80, 0x40, 0x10, 0x20, 0x01, 0x04, 0x02, 0x08};        // A B SELECT START UP DOWN LEFT RIGHT。为提升速度,这个表放到RAM中7 B3 U: j# L9 o0 A0 g0 \# d4 S
  47. static unsigned char idx = 0;6 R! W7 s# N7 S9 F6 X
  48. / ~/ q- z7 [. T. k3 V& ~
  49. 3 z/ W" K( U6 F! Q
  50. static void GPIO_Init(){3 y6 [  E4 c1 w  v2 G" l+ r4 ]
  51.         // P1口和P5口用于接收并行信号,全部初始化为准双向,依靠内部弱上拉输出高电平
    ' U9 s% F6 H" T, Q  x$ V# T; t
  52.         P1M0 = 0;1 m& l5 i" [) H/ n" b
  53.         P1M1 = 0;8 J4 ?' ?% C8 q
  54.         P1= 0xFF;5 q- }+ h1 E  `2 y, I
  55.         P5M0 = 0;% T6 f9 C+ D3 x- v/ u3 N
  56.         P5M1 = 0;
    0 Y3 T9 {, \6 l( U- M% l7 t  q6 r
  57.         P5= 0xFF;$ E" @" ]% w6 b2 }9 t
  58.         // P3口初始化为准双向2 D, e  Z8 Q. I6 [8 C
  59.         P3M0 = 0;' J7 _, N5 S5 i$ D7 j3 T5 I' [9 m1 _
  60.         P3M1 = 0;6 p' C' }* B& N
  61.         P3 = 0xFF;
    / U5 H. b( K) Q$ f4 n# @
  62. }
    $ H8 z# x  v. @& h: Q
  63. 3 p" j2 G' R. t
  64. static void Interrupt_Init(){
    ) z! P6 F; H, f5 \
  65.         // INT0中断(CLK)触发类型为上升沿+下降沿2 ]- [4 E5 G0 S3 y$ P3 h3 N' l7 \
  66.         IT0 = 0;
    6 w+ o4 a4 M$ {$ J( b
  67.         // 允许INT0中断
    ( c1 \5 a7 F% [  u) K* r
  68.         EX0 = 1;
    5 H6 B4 S" Y+ L
  69.         // INT1中断(LATCH)触发类型为上升沿+下降沿$ c1 Y) O& Q" l" Y# l! d( Y' @
  70.         IT1 = 0;4 {% I2 F  R( ?7 P- c; F7 L
  71.         // 允许INT1中断
    * ]8 Y& k# d  _# D! o+ J* V
  72.         EX1 = 1;
    & O  d4 l) ]  {/ g, d
  73.         // 开启全局中断
    6 }" e! s& t( }. g4 J; q
  74.         EA = 1;; x6 q2 h# ]6 G, m7 g6 y9 T) r7 ?
  75. }
    ; [5 r% l0 h, a( }
  76. - S+ Y" p  }5 h2 k3 _8 a
  77. static void INT0_Isr() interrupt 0{
    , p/ t3 H5 F. u" F% k" H7 ~
  78.         // 只有已经成功锁存才允许CLK移位! N$ U/ l$ F" U
  79.         if(isReady == 0)& q3 z! e$ X( U$ S1 o
  80.                 return;
    % b( Y6 v: U6 ?6 t3 v3 O1 V
  81.         // 读当前引脚电平,如果是低电平则说明是下降沿,此时直接忽略该中断1 c) y2 X: o' a
  82.         if(CLK == 0)8 d, _8 C& |- n! C% Y* Q
  83.                 return;
    $ G2 h) J7 Z1 Z1 }
  84.         // CLK上升沿到来的时候,取锁存值的下一位输出
    ' b/ b$ T0 t& `3 K; j
  85.         idx++;+ ?" l! ?# Y- R
  86.         DATA = key & mask[idx];" T5 r$ i% A0 F+ C; S7 m/ f/ d6 h" h
  87.         // 如果已经完成7次移位,则一轮读取完成" t5 n( ?: F; H
  88.         if(idx >= 7)
    / u% T+ |& Q4 D+ E
  89.                 isReady = 0;
    , t% L7 W: M7 Q8 _( n
  90. }
    $ v- m& r) t! e3 H7 f

  91. : f& J9 y$ W3 C( I
  92. static void INT1_Isr() interrupt 2{
    ! t$ M1 q& ]% L: U0 p) X
  93.         // 读当前引脚电平,如果是低电平则说明是下降沿,此时直接忽略该中断8 U4 E- Z) q- l, x! A
  94.         if(LATCH == 0)/ E1 D1 j3 X9 P' c1 e% F, p. E  c
  95.                 return;
    5 W/ s& S5 n, e- g3 v9 s
  96.         // 当LATCH上升沿到来的时候,锁存所有按键状态,同时把键值A输出到DATA
    ) d. ?4 z9 D2 _
  97.         key = bufReady;7 g% g/ X1 r" P! c( Z2 Y
  98.         DATA = key & 0x80;//mask[0];        // 为了加速运算,直接取表中的值而不是读表
    6 \- J4 J+ i7 \& g+ @# Y' i0 I6 T/ S& [
  99.         idx = 0;6 c( j$ _0 }/ |8 v$ ^7 I
  100.         // 允许CLK进行移位
      D7 d5 l& ]( Y. g
  101.         isReady = 1;
    9 I  p+ ?! T3 r) {3 Q2 f3 d. A  p  P
  102. }7 H3 f" ]4 `6 e% O& t) |
  103. 5 ^) n  J- y7 e7 k7 X* A
  104. void main(){
    ) e$ \, c& l) A, S5 s/ ?
  105.         GPIO_Init();/ |- K& E$ L7 |( n; W9 \
  106.         Interrupt_Init();5 G; g2 y, j3 ~4 j4 U6 f3 {2 _
  107.         % b. Z7 R1 D0 o3 g4 q; R
  108.         while(1){
    ! y9 N/ g% @! u  F5 l
  109.                 //PCON |= 0x01;        // 进入省电模式2 U1 Q7 J9 o* D: w
  110.                 //_nop_();
    % [2 h  e2 b# E5 R! }
  111.                 //_nop_();! Z& }1 H6 J' m9 E* v+ z& D! Z
  112.                 //_nop_();
    " K8 c$ H/ J9 Q9 U
  113.                 //_nop_();8 I+ W+ Y+ z: f# T/ ^# f
  114.                 buf = ~((P1 & 0x3F) | ((P5 << 2) & 0xC0));
    3 v$ x0 t  ~. Y+ I+ Z- J. ]
  115.                 bufReady = buf;: w- A6 C+ B) P8 r9 O. z+ F- `
  116.         }8 C8 e; y, g, y
  117. }
    / f% D- I8 a4 }2 h4 ?
复制代码

9 `; m$ j! b, T# @. A9 |% S! p硬件参数配置无特殊要求,晶振频率选择12M即可。* |9 Z( [3 M' ]+ s) x* m
: [/ `6 u2 m3 E" z; ~9 H
这是编译好的固件。

本帖子中包含更多资源

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

×

评分

参与人数 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* [. n2 ^  r4 U$ t' T3 S
不错的设计,想问一下楼主,FC的15针公头怎么解决?普通的公头太短了,插不进去FC的扩展接口。 ...

8 q. k4 ]  r/ \1 N. P+ a坛友的改造方案
回复

使用道具 举报

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

使用道具 举报

发表于 2019-5-25 12:07:18 | 显示全部楼层
精彩,楼主动手强,也写得很详细。
1 o; H2 G6 l6 E* T$ h0 [8 b1 R2.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
& @- `- v+ X' t2 x2 t7 \精彩,楼主动手强,也写得很详细。* k! ]) `0 {: O# T  o
2.4G方案是目前无线的最低延迟吗?
' q* A0 d% _+ V0 U% g: P
我没用过其他无线手柄,所以实在不知道我自己做的这个手柄到底是不是最低延迟。
' w  F& ?: T1 F( u( P不过根据网上的说法,延迟高低主要是由通信协议的复杂程度,以及数据传输速率决定的。这个模块虽然是2.4G无线模块,但由于协议很简单,所以延迟比较低。  o# n2 I3 I' Y+ R- j2 d& C3 f
我用这个手柄玩一些ACT游戏,比如超级马里奥、忍者龙剑传、热血系列,完全感觉不到延迟,和游戏机自带的手柄没有任何区别。唯一的区别就是这个手柄是用火花山寨手柄改造的,外壳是垃圾回收塑料,粗糙+脆弱,导电橡胶弹性不佳,手感不是一般的差。1 U! {- E' C3 V; F
我手里还有十几张板子,等我有空了我再做一套,到时候买一个好一点的手柄改造。
回复

使用道具 举报

 楼主| 发表于 2019-5-29 16:56:14 | 显示全部楼层
ppad 发表于 2019-5-28 17:273 q/ N% M. u* Q" V  T
给技术帝赞一个,有半成品发布吗,自己焊接改造就可以,编程实在不会啊 ...
1 j6 L3 z: V8 z! {" ^
很可惜,我手里没有多余的单片机了,LDO也找不到了,锂电池以及充电模块更是没有了。反正就是该用到的元件基本都没了,所以没法发布半成品。8 ]' {9 Y. h- `' J; m: \7 C1 A5 l
两个板子倒是有十几张剩余。
9 [% h5 j4 j* Y- }3 d: e: v. Y7 o你要是有USB转TTL串口板,完全可以自己买这两种单片机,然后我给你编译好的固件,你自己用串口板下载到单片机里面就行了。两个2.4G无线模块也得通过串口板用AT命令设置参数,不过好在我在设计电路的时候就已经预留好了串口,可以直接在线下载和在线设置参数。总的来说并不麻烦。
回复

使用道具 举报

 楼主| 发表于 2019-5-29 17:00:34 | 显示全部楼层
孙大师 发表于 2019-5-28 18:558 j( Q# j. s6 {3 A. N
非常好,楼主是技术帝,到目前我都还没开发fc的无线套件,等空了,开发一套套件,等玩家自己组装。 ...
. ]. R/ i! U: e7 ]2 ^9 }
能得到孙大师的赞誉,不胜荣幸!
  j( t6 r* _- [8 s' U# O不如开发一个多功能手柄,比如用SFC手柄改造,L/R键配合其他组合键可以用来切换2P~4P、调节连发速度、软重启等各种功能。接收端插到15PIN扩展口。
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-1-24 22:03 , Processed in 0.108720 second(s), 14 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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