找回密码
 注册

QQ登录

只需一步,快速开始

查看: 24894|回复: 32

自制FC无线手柄

  [复制链接]
发表于 2019-5-22 14:16:45 | 显示全部楼层 |阅读模式
本帖最后由 雷精灵2046 于 2019-6-14 09:28 编辑 ) ^9 w( m5 w8 q1 R. \( ]

' Q5 u& d; e) E$ H. _9 r$ @没有用复杂的分立元件搭建发射接收电路,直接用的现成的2.4G无线模块jdy-40。: o% u% l/ W! g& Z# [7 g+ C0 L
* h# E1 S/ P5 O' V

6 Z" t% J- X! O' C' ?2 p3 d发射端靠3.7V锂电池供电,用了一片SOP8封装的STC单片机,负责产生连发脉冲,同时负责检测电池电量,电压低于3V左右的时候触发低压中断,低压指示LED就会亮起来告知该充电了。平时发射模块和单片机均处于睡眠状态,有按键按下才会唤醒,从而实现省电。实测睡眠状态下整机电流约1~2uA。板子洗了一下稍微干净了一点。因为对于微功耗设备来说,焊接残余的助焊剂可能会增加漏电流。
& |/ I# V. o) r- T9 h& ?% f' Z. ^1 h
买了一个火花的FC山寨手柄,去掉里面的牛屎板子,并修正一下塑料挡板,把锂电池和充电模块装进去。
$ W! n9 s( u% d1 e) L' T! e+ S+ y为了减少体积,充电模块裁剪得十分小,并且更换了充电电阻使之适应这个小小的锂电池。这么小容量的电池,也不需要多么大的充电电流是吧?* Y  M- R4 ]; Y  Q, v
然后统统用热熔胶粘上。充电电流比较小,所以发热很少,不会熔化热熔胶。
2 O) ]* {8 v8 O0 C% m0 M& N0 E1 t5 ?4 C( V
. {: P3 N" `) ^8 i: b2 P; \0 {
7 A# F: ?% }( J$ k% p, r
最后把按键、导电橡胶和电路板装上去。
0 N, ]9 F* U* W精心裁剪了电路板,正好扣上,不会阻碍其他元件,也不会影响后盖和拧螺丝。
) W$ j- Q) @, K, R# [! u2 U) b$ b) R9 o, N
9 D5 I% F3 ^" f$ g1 O! \
完工!
; _. ?# F* L$ V$ G4 l- l: b
. k* B# U. x9 w( d6 `- I( P6 M
1 o' R5 r4 M& Z8 j8 b4 @2 ]这是充电的MicroUSB插座。旁边的小孔用于透出低压报警LED的光线。
0 c# N$ a+ y% b/ b! ^
7 O! k3 [2 a& @& i4 j
4 A2 B8 ]  v3 P, H: n接收端用一片DIP16封装的STC单片机模拟CD4021。为啥要用单片机模拟而不是直接用CD4021?因为jdy-40模块接收端在有按键按下的时候输出高电平,无按键按下输出低电平,和普通手柄正好相反。当然我也可以用两片74HC00或者74HC04之类的逻辑门进行反相,但那就增加了芯片的数量。对于FC手柄这种工作频率并不高的设备来说,STC单片机完全可以胜任模拟工作。8 {! I4 M! P  O( A' K
: W: o, X" n8 T. m
) W9 j! ^' K' v. F& T

! t4 t5 M: [% Z6 c4 {; o电路设计有点小小的错误,所以有几根飞线。原本设计使用低压差LDO是XC6206,结果在做这个接收模块的时候,买的LDO居然找不到了!无奈只好用了AMS1117。幸好对于接收模块来说是5V降到3.3V,1117可以胜任。要是发射端手柄的话,3.7V降到3.3V,那就非得用6206不可了。/ j3 j! w+ B8 o( l4 b) R0 f) \, C

- s8 A7 s1 d1 V0 `/ O3 E1 E" M实测十分灵敏,延迟极小几乎感觉不出来。可惜这山寨手柄的手感并不佳,尤其是方向键,软塌塌的。看来我得买个剪线手柄改装。5 O5 K" ]8 l9 q
6 r, p' K& [0 u% X: Y! ]* P
这是电路图,有兴趣的朋友可以参考。
# C% R: c$ F9 @# y" ~3 [: T$ _/ ^2 m
0 ]2 _) v/ i# T2 l, R
我信奉开源主义,十分痛恨把技术藏着掖着。好东西大家分享嘛!所以两个单片机的源代码大公开!% e7 `& f- q8 b
编译器:Keil 51。
8 S! i+ B' N: S8 A' Z# O, S0 a% E- \) z6 g5 B+ k2 ?  ^# I
发射端:
1 n7 \3 C  S$ h
  1. #include <INTRINS.H>
    0 z5 a& c! G8 ^# A/ J2 z
  2. #include "STC15W.h"" b/ s9 t3 a3 }' H

  3. 0 b1 b1 a/ x  ~/ E- |7 G+ H

  4.   |9 v7 X0 M; G3 S- I3 p: W+ e
  5. /*1 u  _: p$ \: p6 T" V" |- y
  6. --------------------------4 j1 ?9 O: S8 i5 Z5 D2 l. M
  7. |1 (OUT)        \__/   (INT1) 8|
    $ S) Q6 y2 b6 Z
  8. |                                                   |
    9 I+ i, x8 d4 p6 ~
  9. |2 (VCC)                   (INT0) 7|' a$ E- ?0 C! |
  10. |                 STC15W204S                   |
    . A0 y( U+ C: Q
  11. |3 (LED)                         (TXD) 6|6 x# ^( u' ~! w9 c" u
  12. |                                                   |
    - L! z2 {; Y1 |& `$ C; @; l
  13. |4 (GND)                         (RXD) 5|
    - H9 A& A4 L7 H6 L% L8 l0 f
  14. --------------------------% {% x; y! p$ s" Q$ m
  15. ) y  l+ r6 z% |* p
  16. LED ---|<|---[===]--- VCC2 O8 y: \( ~: J4 q1 k
  17.            Red          3305 k( u! L3 K# T

  18. 5 f3 c, b. n! U/ {) h0 P' k- F4 E
  19. Fosc = 6MHz
    7 d6 U% u1 e4 v5 U( L; c
  20. */0 e( A% f7 E9 J5 x$ U8 ^5 e

  21. & w1 V4 O* i" i  n, j( v
  22. 2 Y  L' x3 _8 K' N* a- m9 \
  23. // 矩形波输出脚
    2 ?* `! I% g$ G
  24. sbit OUT = P5^4;
    8 Q) x6 K' y2 R$ ~! Y6 e
  25. // 低压指示灯引脚( x. d& z8 g; B: D. x3 f1 r
  26. sbit LED = P5^5;
    . F! H3 D; K) ^6 H2 m% B* X. F+ s
  27. ) P2 A0 T! q* A
  28. // 停机标志位
    " K7 o/ j, ?8 e4 \
  29. bit isReadyToHalt = 0;
    $ \( ?2 J1 Z1 `" o! j) J6 X
  30. ! s2 N) V: i, V
  31. // 矩形波次数累计
    9 |0 `8 V* Y9 k1 t0 F
  32. static volatile unsigned char count = 0;" O" e: m$ ~7 F* q$ ]1 u

  33. ' u) N$ o9 j: w% g

  34. " o( k1 A% S4 I$ c8 J
  35. static void GPIO_Init(){
    6 E7 B+ F0 y3 _% Q/ R9 _) h2 x
  36.         // P3口设置为准双向,默认靠内部弱上拉输出高电平$ S) n: B5 p# [. v+ A4 E2 O& n1 S
  37.         P3M0 = 0;9 W+ C+ A: j; V* ]* m
  38.         P3M1 = 0;
    ) N1 m* Y; v) T$ j
  39.         P3 = 0xFF;
      x4 e- t; ^, @1 c, B) ~
  40.         // P5口设置为准双向,默认靠内部弱上拉输出高电平* Z+ Y' @- ~+ ]( z  ~
  41.         P5M0 = 0;
    . ^  Q2 P% ~) H/ m* P, s9 D5 U, l
  42.         P5M1 = 0;
    6 n+ {- E  g' ]. i1 o0 q! ?3 y: K+ g
  43.         P5 = 0xFF;
    - A; m5 z6 f# F! y) W
  44. }
    % V; l0 _0 L5 A8 I0 [$ D

  45. . H- \2 \5 r# u( R0 \1 I
  46. static void Timer0_Init(){
    5 H) S4 G6 l; m" V1 A" t) I
  47.         // 16毫秒@6.000MHz
    + O( f' m$ p- g8 E% G
  48.         AUXR &= 0x7F;        // 定时器时钟12T模式" Z/ k6 B9 d* V# k
  49.         TMOD &= 0xF0;        // 设置定时器模式
    ' Y' v9 c3 e: n9 o) j+ x; {
  50.         TL0 = 0xC0;                // 设置定时初值( e# h9 K, V) [
  51.         TH0 = 0xE0;                // 设置定时初值: P- E+ I4 }  g& c- }& j* G
  52.         TF0 = 0;                // 清除TF0标志
    / O7 @* |. P! N! P
  53.         TR0 = 1;                // 定时器0开始计时
    & d( \/ T' p) E' ?5 D
  54. }
    ( C2 T$ G) k/ a4 v2 ?% k4 ]
  55. . ~; y# ^3 s/ z  m. a4 {
  56. static void Interrupt_Init(){
    ( Y/ Y8 l$ r5 z0 y5 ]3 ~- y& o; A
  57.         // INT0中断触发类型为下降沿触发, [; q& l/ N3 N; N; b
  58.         IT0 = 1;
    4 o$ C) ^3 M- z; N+ a
  59.         // 允许INT0中断0 \% R( B! h$ [# X
  60.         EX0 = 1;, I9 s9 @0 f- C1 \6 p* C( w
  61.         // INT1中断触发类型为下降沿触发& t/ Y4 c( Q5 _
  62.         IT1 = 1;
    6 f" J* |! t0 K
  63.         // 允许INT1中断
    , O! K6 W3 y' X# y; a
  64.         EX1 = 1;  }! ?! m5 a& W
  65.         // 允许定时器0中断
    + g! z# r4 i7 d0 }& ^) t
  66.         ET0 = 1;# u( w( t: ]) o6 F' s
  67.         // 允许全局中断9 O: M$ h& C* d8 X  l0 H# r
  68.         EA = 1;
    ( n4 e/ `0 K" u6 p; @
  69. }8 r5 k2 z1 ^% o+ c* N% D6 j
  70. 3 y4 _' S' o) v+ @
  71. static void INT0_Isr() interrupt 0{
    1 B8 _4 F% t# ^$ O- k
  72.         // 矩形波次数累计归零+ H  n2 ~+ e4 ?" }1 c) K1 S4 O! h
  73.         count = 0;
    7 k1 j& T6 t( l; ~+ i. c2 [, N* @
  74.         // 重开定时器0中断0 K8 z* |( @$ T2 ?, M7 a
  75.         ET0 = 1;6 t; X9 J# o& D* V5 r4 ^- K
  76. }8 d" z( b/ @* ?6 |8 |$ n+ h# B- @0 q

  77. & o8 b% ?& C6 m, z/ w. R
  78. static void Timer0_Isr() interrupt 1{
    % k. x* B; v+ ^; j7 s3 e9 p# h( G
  79.         // 输出矩形波) a1 b1 s2 `2 D/ @# q7 m( b1 B
  80.         OUT = ~OUT;* ]1 E7 e, z% T4 l& S
  81.         // 累计矩形波次数
    2 m" A+ R- S+ p$ @! o; H
  82.         count++;
    9 h( c& ^* i5 Z0 r
  83.         // 超过250个矩形波,准备停机
    , I4 c. ~8 l' N) X' J
  84.         if(count > 250){/ ^( ~% ?% b7 c& p9 K* t
  85.                 count = 0;8 i- s% K: d7 H; F$ Q$ N/ \$ @( |
  86.                 isReadyToHalt = 1;
    * T6 [; F: k4 N: }
  87.         }# v7 |' B9 ], ^4 a' f5 R
  88. }
    5 n# {& a( |1 ~0 I5 i: G
  89. ) @% n1 _' F& x! e# l& Z" Z  U5 D
  90. static void INT1_Isr() interrupt 2{
    ) |, O' h/ L8 a7 M! d; A" I
  91.         // 矩形波次数累计归零
    ( T: N: \0 q" K3 W. ~- a$ f0 j
  92.         count = 0;" o! {7 Y6 e: Y# d+ |' r
  93.         // 重开定时器0中断& Y3 |- c3 l4 W/ K% T8 K5 G
  94.         ET0 = 1;
    ) d, ?# O# B. S( A& ~
  95. }7 X/ `; {5 Q( I, G9 N. l/ \5 Z

  96. , @; }% ^7 p0 d' r+ Z' [

  97.   D: K* O$ C& [# E: `
  98. void main(){0 s* ~$ s3 f4 d* O* I
  99.         // 初始化P3和P5口
    ( [# |6 A: q$ K4 q* @/ @
  100.         GPIO_Init();8 b1 y6 t% @9 v3 i1 J
  101.         // 初始化定时器0
    5 f) L. d% ~9 b5 ^3 K5 `
  102.         Timer0_Init();- q2 L% E" R. J" l8 t
  103.         // 初始化中断7 C* i3 N6 I6 Q% Y6 m( u# ?
  104.         Interrupt_Init();6 ~; A& m5 H" }. Z1 d/ L+ r: J% {4 n
  105.        
    % H& h( h1 z  w  b- w
  106.         while(1){% q3 }) i8 B; `3 V4 f. j' p
  107.                 // 检测电量) w% h& m+ p9 ?. s$ O* U+ W, B# B
  108.                 if(PCON & (1 << 5)){
    # w7 Q& `% q* m. b7 k+ g
  109.                         // 如果电量低,低压指示灯亮- I9 p0 ^' t$ M! x
  110.                         LED = 0;
    / h% r3 @3 J6 ?: E% R3 g
  111.                         // 清电量检测硬件标志位  M: @% V$ @7 n5 n4 m/ J3 F
  112.                         PCON &= ~(1 << 5);
    & {% [) y/ h; @
  113.                 }else{) i+ ]% A* b: u3 O# T9 F3 a$ U9 l
  114.                         // 电量正常,低压指示灯灭
    . m7 E( l; W3 p. M6 ]
  115.                         LED = 1;3 a4 S; I8 M6 W% @# ~! ?. }# X) S+ V
  116.                 }# M* b2 m' o. C/ [2 D/ r6 [2 z1 U

  117. 4 c- l! H, ?/ ^' J- ?8 w3 v) u" J
  118.                 // 检测到停机标志
    & q4 Y3 F' i! i5 E% t
  119.                 if(isReadyToHalt == 1){
    & I$ {% C7 I  \6 v# n0 f) e4 v. V
  120.                         // 暂时关闭定时器0中断
    * Z" o# X- A  O% ~3 l" G9 ^
  121.                         ET0 = 0;$ e0 i3 E2 a' l, C6 w( ^
  122.                         // 停机之前先把矩形波输出脚置低电平,以方便INT0和INT1唤醒CPU
    ( h' ?( D7 F/ }# u
  123.                         OUT = 0;
    + `; G7 X& B" A0 b
  124.                         // 停机之前先把低压指示灯灭掉,以省电3 p4 z3 j( c! J( E2 v
  125.                         LED = 1;
    3 I; L; o5 Y4 j; ]( `& m( g* t
  126.                         // 进入停机模式
    ( }7 b' S! i( i3 S& f$ W4 ]
  127.                         PCON |= 0x02;
    8 c9 D9 t. Y) D; x& i
  128.                         _nop_();
    7 B# _$ _4 l& W! R, Z& A
  129.                         _nop_();
    ; ]4 {( _+ T" f: x
  130.                         _nop_();) b0 m" h+ I9 u, l  H0 G
  131.                         _nop_();
    7 _1 ^' ]# a) Y. d7 e8 t
  132.                         // 唤醒,清标志位' [- r8 V4 j! @  r' t  x9 Y0 t
  133.                         isReadyToHalt = 0;# P7 N3 [- Z( E4 h6 G
  134.                         // 重开定时器0中断# j" r; @3 q0 O
  135.                         ET0 = 1;
    # }% k: t  Q/ |/ c0 v. c
  136.                 }
    1 d/ R# ^% J0 g  z/ _: {  y' I8 w
  137.         }
    " a- Q, q( r# w3 N- H+ q+ I- G1 o
  138. }$ O+ q( b- z2 k7 s: T
复制代码

. F9 J/ {; J; [3 x+ P; W硬件参数配置:, R9 w, a2 J' r

+ ~) J  o& y% H* p1 c- _6 S& p$ Y( H- q$ q
接收端:* v. f0 V# @5 ~% M
  1. #include <INTRINS.H>
    9 B* K+ O: x/ u7 n+ M
  2. #include "STC15W.h"5 y; Z+ {  p% l* S4 W
  3.   Q) F6 X4 s2 G2 t
  4. : s1 i$ T! A7 I
  5. /*& x; S% |; C1 M! f
  6.   d& G& m) N; R" _5 [( b' H
  7. *---------------------------*' B2 Z6 ]2 D5 y0 S' M* h( c( v
  8. |1 (GPIO2)         \__/  (GPIO1)16|4 d4 V# O* m, V0 W6 C8 d& A- {
  9. |                                                        |
    6 s/ x7 ?5 i# @/ Q, W4 h
  10. |2 (GPIO3)                   (GPIO0)15|
    8 {3 A7 I) d! V/ g. r0 N4 K
  11. |                                                        |
    % N! K$ d  B4 I5 \% s1 L
  12. |3 (GPIO4)                                  14|0 X/ X" \  o, H- b4 X% N
  13. |                                                        |, }" n+ q* S" J' [; I) ~; N  r3 h" j
  14. |4 (GPIO5)                        (DATA)13|( R# f+ P* H6 o' N5 p: q7 ]
  15. |                  STC15W204S                |
    " W$ Q! s2 t* O# v& Y
  16. |5 (GPIO6)                   (LATCH)12|
    5 G( N7 w* ^' q. O2 L- M
  17. |                                                        |4 l5 ]: x6 H- x( I% h- a
  18. |6 (VCC)                         (CLK)11|4 D" F8 J$ G. Q" E' l$ }
  19. |                                                          |0 Z4 @0 d1 H, e; q# [# a* b
  20. |7 (GPIO7)                         (TXD)10|
    & q+ M& x: S( o9 b
  21. |                                                        |
    4 c& G$ A9 [  l% ?
  22. |8 (GND)                         (RXD) 9|% p0 U: l; }" R2 M9 y
  23. *---------------------------*
    2 ~* q1 [- d! Y: ^; E8 l
  24. Fosc = 12MHz
    & Q" F& S% [) ?: u/ E  |5 R

  25. . ]1 N  z  G% z2 S
  26. P1.0 -> 上
    ( {- V' Z# z7 J( A0 Y$ p: Y+ D
  27. P1.1 -> 左. \8 T; g- o, F" p- J/ @
  28. P1.2 -> 下
    ; L$ b5 u, b' X4 O) b, y
  29. P1.3 -> 右
    " m" o  h! |+ `/ i
  30. P1.4 -> SEL6 L$ G: r- A* @! h
  31. P1.5 -> STA
    & h6 z6 N0 \2 G3 j8 g
  32. P5.4 -> B( `- l2 f: ^& `7 a
  33. P5.5 -> A
    ) \) n% x  Z: y. P
  34. " o  f" c9 U8 @
  35. */) j0 C/ U& E0 L- U8 [% H3 \

  36. 3 Q! p: w# C0 D7 i& }
  37. 5 g6 J4 ?& k) C  O/ S  }( n
  38. sbit CLK        = P3^2;6 f1 J7 u( s4 ~' M7 z( y
  39. sbit LATCH        = P3^3;
    % u2 y% C' U4 R) f* I
  40. sbit DATA        = P3^6;
    ! [. y; s+ r- ?$ w2 m3 Q

  41. 2 z9 P3 q0 W: m% f8 ^
  42. bit isReady = 0;
    6 ^, _( V% G8 s0 U3 G, q
  43. static unsigned char key = 0;: J2 W4 n; Y, ]- @! E
  44. static unsigned char buf = 0;        // 双缓冲。这个缓冲区保存从P1和P5组合而来的键值
    + f1 ^+ N7 B" H) A( ?0 ?; l  `
  45. static unsigned char bufReady = 0;        // 双缓冲。这个缓冲区保存上面那个缓冲区的备份1 J4 J+ f! t. l+ p9 }( s
  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/ o9 X6 P' ?8 ^
  47. static unsigned char idx = 0;
      @/ ]$ o9 `" N+ W6 {7 ~! G4 ?) S: S

  48. / s7 U) x; d  A+ i5 |0 o

  49. # p$ a1 u1 I% E5 \
  50. static void GPIO_Init(){
    7 H7 L" i4 e# D9 B$ H0 E
  51.         // P1口和P5口用于接收并行信号,全部初始化为准双向,依靠内部弱上拉输出高电平
    ' j* r5 \- k$ i2 B) y2 A" c
  52.         P1M0 = 0;& E$ L; ?, M4 S. k) D% F! R
  53.         P1M1 = 0;
    5 A! z" \* U8 I2 p1 Y. f# z# \/ Z4 b" \
  54.         P1= 0xFF;
    5 B/ K1 R6 y1 b& Z: j/ E, D1 q! }
  55.         P5M0 = 0;
    3 u; I; D, P- n! U
  56.         P5M1 = 0;
    2 Y7 j2 D- N. v- {( t% F$ A
  57.         P5= 0xFF;
    ! v( O& P6 R7 [2 D7 N( o2 W; ^2 \4 s
  58.         // P3口初始化为准双向
    + H( I  l+ r+ e$ G
  59.         P3M0 = 0;+ b# v+ v! @1 o7 ~2 z4 h% m
  60.         P3M1 = 0;
    : r/ l1 _: d  `- H  E2 `. o
  61.         P3 = 0xFF;
    " r9 o3 q& x! p1 v  b
  62. }* ~4 Q; K3 {# u( V

  63. . E1 O+ M/ k1 E/ Y
  64. static void Interrupt_Init(){: D* G6 p& O- h5 G0 S
  65.         // INT0中断(CLK)触发类型为上升沿+下降沿
    % {) f9 e, P0 ?! ^
  66.         IT0 = 0;/ y# d# p7 B$ L) j- k
  67.         // 允许INT0中断
    , Z: @! t/ _3 n/ u
  68.         EX0 = 1;
      p4 l" @& T( G( d; `* C% y
  69.         // INT1中断(LATCH)触发类型为上升沿+下降沿8 I& X9 G& ]" D
  70.         IT1 = 0;' e$ B- p0 n7 K; V/ ^
  71.         // 允许INT1中断' n& ]0 ~% b& |( T) [# |
  72.         EX1 = 1;
    ( O% b# s  o0 n
  73.         // 开启全局中断: r# _3 J! t* p8 [
  74.         EA = 1;
    * E$ C. |5 p3 Y  U' V. `3 e
  75. }
    & T. p5 ], B& G' C  s
  76. + U/ t' z1 g7 ]8 i; j! F8 i
  77. static void INT0_Isr() interrupt 0{
    , Y# O6 Q. g" k- O, S1 c- G/ M  g
  78.         // 只有已经成功锁存才允许CLK移位; ?8 E  u8 d: }. ^8 r0 [( p
  79.         if(isReady == 0)
    * H- x# g4 Q6 O8 O
  80.                 return;
    8 L) }/ p8 m3 S9 v  ]3 S) ]4 p
  81.         // 读当前引脚电平,如果是低电平则说明是下降沿,此时直接忽略该中断/ _; M* y, g+ V) t+ V$ b
  82.         if(CLK == 0)2 p1 `% ^/ Q. b% I* ^" N8 q- w; S$ s
  83.                 return;" y! s& V. y# [6 y- N
  84.         // CLK上升沿到来的时候,取锁存值的下一位输出
    , b, N' U1 K+ h* o6 e
  85.         idx++;% z1 S* B4 ~, F9 B) w
  86.         DATA = key & mask[idx];
    " K5 ~- s+ ~: Q4 T
  87.         // 如果已经完成7次移位,则一轮读取完成) R+ K2 ^' q6 @% Q0 t
  88.         if(idx >= 7)" u% h! Q, _' L1 p
  89.                 isReady = 0;
    , e6 C+ D/ n3 t# d
  90. }% [! }0 z! f2 F

  91. . ^% K; ?8 c2 ]+ b& v/ F2 X
  92. static void INT1_Isr() interrupt 2{( S/ i) K- N" V: h+ p; d2 a
  93.         // 读当前引脚电平,如果是低电平则说明是下降沿,此时直接忽略该中断2 d9 Q0 w+ W3 r; Q% n
  94.         if(LATCH == 0)
    , J7 X5 t% B# J$ }0 y( e0 q
  95.                 return;
    , X" t7 l# O3 F% F
  96.         // 当LATCH上升沿到来的时候,锁存所有按键状态,同时把键值A输出到DATA5 [  w7 S3 }0 r+ E- ?: w
  97.         key = bufReady;) ?& Q! Y1 t0 P7 n5 M
  98.         DATA = key & 0x80;//mask[0];        // 为了加速运算,直接取表中的值而不是读表7 A1 E) E& t9 H; ?' r" F# I2 W
  99.         idx = 0;
    0 w% x, C: L& f9 `# E) ^
  100.         // 允许CLK进行移位$ ]1 k; u5 S5 u% s) B
  101.         isReady = 1;
    7 F- Z  C/ G  X8 b/ V8 t+ v1 m
  102. }
    2 }1 @" Y5 }. s6 I
  103. 9 R/ L4 f( R# R' l/ N" F3 b: E. k
  104. void main(){" i9 e; C; c3 s; ^4 {9 d0 J
  105.         GPIO_Init();
    1 Q& Y7 ^5 w! N; {  K
  106.         Interrupt_Init();- C& q- x3 @! w) C# f. M
  107.         2 B% H$ ^* V' K( A  h% f
  108.         while(1){$ T, n# [$ @- w. ?! q
  109.                 //PCON |= 0x01;        // 进入省电模式% T8 k3 n6 }- m& Y6 C3 |1 i6 B
  110.                 //_nop_();
    / Z% J8 r  l# ?" ~1 j
  111.                 //_nop_();- @# C5 j2 z) Q) S5 P* X
  112.                 //_nop_();
    , C3 K/ q3 y5 Z9 c3 k
  113.                 //_nop_();& l, K/ c6 l5 A# r, n
  114.                 buf = ~((P1 & 0x3F) | ((P5 << 2) & 0xC0));
    + I7 d0 p$ D) q2 H6 i& Q  x
  115.                 bufReady = buf;
    8 w6 J' z& f5 D
  116.         }
    4 j# }+ E# a+ a, `- J# W; J2 t
  117. }8 P1 [8 }' i* D+ V% S+ b0 K1 k" _
复制代码

, v; {6 I/ b- o  n硬件参数配置无特殊要求,晶振频率选择12M即可。
5 C% C) w0 ~$ _- Q" _7 k) Q' B1 b3 d% S% O
这是编译好的固件。

本帖子中包含更多资源

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

×

评分

参与人数 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. Y, k5 o2 c2 u% E' W
不错的设计,想问一下楼主,FC的15针公头怎么解决?普通的公头太短了,插不进去FC的扩展接口。 ...

5 Y$ v; L$ x& @* h& }5 X坛友的改造方案
回复

使用道具 举报

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

使用道具 举报

发表于 2019-5-25 12:07:18 | 显示全部楼层
精彩,楼主动手强,也写得很详细。
8 _# W  s2 F# h- e) ?/ X* Q5 a: h$ s2.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
" ^0 q1 }1 N) W6 \* y6 G9 s精彩,楼主动手强,也写得很详细。
8 V" b! w  q- J7 c& C: g4 z9 ^0 t2.4G方案是目前无线的最低延迟吗?

4 `8 e: u4 p( t& R我没用过其他无线手柄,所以实在不知道我自己做的这个手柄到底是不是最低延迟。
' M7 S4 _" z8 b+ [, {9 ^5 F不过根据网上的说法,延迟高低主要是由通信协议的复杂程度,以及数据传输速率决定的。这个模块虽然是2.4G无线模块,但由于协议很简单,所以延迟比较低。) v1 w5 z& N0 n5 ?/ `
我用这个手柄玩一些ACT游戏,比如超级马里奥、忍者龙剑传、热血系列,完全感觉不到延迟,和游戏机自带的手柄没有任何区别。唯一的区别就是这个手柄是用火花山寨手柄改造的,外壳是垃圾回收塑料,粗糙+脆弱,导电橡胶弹性不佳,手感不是一般的差。
6 a2 C) S, m# d# x8 V' }2 l我手里还有十几张板子,等我有空了我再做一套,到时候买一个好一点的手柄改造。
回复

使用道具 举报

 楼主| 发表于 2019-5-29 16:56:14 | 显示全部楼层
ppad 发表于 2019-5-28 17:27
3 Z. L  ~7 I. k1 [5 t; i给技术帝赞一个,有半成品发布吗,自己焊接改造就可以,编程实在不会啊 ...
# l8 |+ O" H7 _5 l% ]/ Y) K
很可惜,我手里没有多余的单片机了,LDO也找不到了,锂电池以及充电模块更是没有了。反正就是该用到的元件基本都没了,所以没法发布半成品。+ d5 ^. h! `+ Q, V
两个板子倒是有十几张剩余。9 |( o2 F* V2 m5 ^
你要是有USB转TTL串口板,完全可以自己买这两种单片机,然后我给你编译好的固件,你自己用串口板下载到单片机里面就行了。两个2.4G无线模块也得通过串口板用AT命令设置参数,不过好在我在设计电路的时候就已经预留好了串口,可以直接在线下载和在线设置参数。总的来说并不麻烦。
回复

使用道具 举报

 楼主| 发表于 2019-5-29 17:00:34 | 显示全部楼层
孙大师 发表于 2019-5-28 18:55( A+ j. r; b4 C2 {4 @
非常好,楼主是技术帝,到目前我都还没开发fc的无线套件,等空了,开发一套套件,等玩家自己组装。 ...

# D4 r' E) O. B8 ~* c# b$ {1 x) \能得到孙大师的赞誉,不胜荣幸!
* V" ^& r9 j6 T  z7 e* ]& F; e0 c  T1 k不如开发一个多功能手柄,比如用SFC手柄改造,L/R键配合其他组合键可以用来切换2P~4P、调节连发速度、软重启等各种功能。接收端插到15PIN扩展口。
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-5-15 18:06 , Processed in 0.142881 second(s), 14 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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