找回密码
 注册

QQ登录

只需一步,快速开始

查看: 23831|回复: 29

自制FC无线手柄

  [复制链接]
发表于 2019-5-22 14:16:45 | 显示全部楼层 |阅读模式
本帖最后由 雷精灵2046 于 2019-6-14 09:28 编辑
6 X: M% R9 w0 x4 v, \0 E
' h2 v5 r4 k2 p3 V/ z1 I没有用复杂的分立元件搭建发射接收电路,直接用的现成的2.4G无线模块jdy-40。
$ u/ \/ @$ k# L, D+ q7 C7 z2 J
2 w. m% o) W1 n' L" P7 Q
0 F7 m" d3 ^/ y1 w. b4 k# S+ z# p发射端靠3.7V锂电池供电,用了一片SOP8封装的STC单片机,负责产生连发脉冲,同时负责检测电池电量,电压低于3V左右的时候触发低压中断,低压指示LED就会亮起来告知该充电了。平时发射模块和单片机均处于睡眠状态,有按键按下才会唤醒,从而实现省电。实测睡眠状态下整机电流约1~2uA。板子洗了一下稍微干净了一点。因为对于微功耗设备来说,焊接残余的助焊剂可能会增加漏电流。  @" t: z: s' \9 [, r% K3 Z0 o
% @/ S* F" [& g6 D( ~' g3 O6 G
买了一个火花的FC山寨手柄,去掉里面的牛屎板子,并修正一下塑料挡板,把锂电池和充电模块装进去。" @6 K. s* E0 o6 O0 W5 E! o/ C# R
为了减少体积,充电模块裁剪得十分小,并且更换了充电电阻使之适应这个小小的锂电池。这么小容量的电池,也不需要多么大的充电电流是吧?8 M. `5 t  F. b
然后统统用热熔胶粘上。充电电流比较小,所以发热很少,不会熔化热熔胶。
8 I( z% I) N: @; \) d4 N8 Z# |. _! U$ `) `/ `$ m% B# T

, q1 T* X3 c4 w8 _
; b- _$ \1 [6 q! w: R- m' ]最后把按键、导电橡胶和电路板装上去。
! E4 `% G4 }! w$ c. M精心裁剪了电路板,正好扣上,不会阻碍其他元件,也不会影响后盖和拧螺丝。
6 |. T% q4 Q6 g& P
/ v5 v* o. Q! R, ]! ?3 u6 \. d( C" Q
完工!
& {) B* r' h5 @8 r6 B9 H; T6 S  b$ u" }1 m/ L5 n% r: r

! w, u  P: q! h' g$ `' t这是充电的MicroUSB插座。旁边的小孔用于透出低压报警LED的光线。
+ A! r2 r, }8 m; b
) a( A; O9 h6 u0 l+ V
* ?9 N7 I& j! H8 }5 d接收端用一片DIP16封装的STC单片机模拟CD4021。为啥要用单片机模拟而不是直接用CD4021?因为jdy-40模块接收端在有按键按下的时候输出高电平,无按键按下输出低电平,和普通手柄正好相反。当然我也可以用两片74HC00或者74HC04之类的逻辑门进行反相,但那就增加了芯片的数量。对于FC手柄这种工作频率并不高的设备来说,STC单片机完全可以胜任模拟工作。
! v# @, K; k! {; e5 d* c# R# j; K+ a
2 @# j# u) e6 ?: j: @1 i; O3 I8 M; M! K  s8 }; K

3 ?( r! p6 `+ U1 @& \电路设计有点小小的错误,所以有几根飞线。原本设计使用低压差LDO是XC6206,结果在做这个接收模块的时候,买的LDO居然找不到了!无奈只好用了AMS1117。幸好对于接收模块来说是5V降到3.3V,1117可以胜任。要是发射端手柄的话,3.7V降到3.3V,那就非得用6206不可了。2 h! b- G' o% ^' q$ S1 {' K/ g
! `0 }+ H4 ]8 S6 z
实测十分灵敏,延迟极小几乎感觉不出来。可惜这山寨手柄的手感并不佳,尤其是方向键,软塌塌的。看来我得买个剪线手柄改装。
, f2 @/ a3 k2 U  J4 ]+ a3 p5 p5 w' @! Q2 _# r5 V7 T: J; @
这是电路图,有兴趣的朋友可以参考。
$ |; @& {0 s+ B# @+ S* a+ c2 @) E5 J( w/ s2 _

* G5 j2 l) |$ Q9 h( `7 \我信奉开源主义,十分痛恨把技术藏着掖着。好东西大家分享嘛!所以两个单片机的源代码大公开!
/ e5 a; n9 o' n5 C) _4 q( a编译器:Keil 51。
) Z: j) b" i" T6 [5 O( d' Q, V; S; u5 c
发射端:
/ T4 w1 p( }6 o& b) b+ b1 }
  1. #include <INTRINS.H>
    * I+ Q3 y: n% \% E
  2. #include "STC15W.h"
    , t) t+ f; x6 s! R# P# _
  3. 9 J+ B; m# W" B! g* W5 N

  4. , |6 B, v8 I# U" h
  5. /*
    9 J" ?+ t  c$ w  M
  6. --------------------------' y$ W; ^' _% D
  7. |1 (OUT)        \__/   (INT1) 8|
    + W2 U  w9 h: Q/ @: z2 z
  8. |                                                   |
    2 S3 ]/ E7 t9 S$ j
  9. |2 (VCC)                   (INT0) 7|
    4 s) D, T( D# T: E. Q- ]2 B) c
  10. |                 STC15W204S                   |
    ! S# |1 y8 r' ^
  11. |3 (LED)                         (TXD) 6|5 ]+ M9 Q0 v1 D: F+ x
  12. |                                                   |
    5 U  Z: T! K2 P1 i3 `
  13. |4 (GND)                         (RXD) 5|5 {- q# {. r8 h, Z  a- [* H
  14. --------------------------5 Z+ h$ Z/ Y0 J: m: Q- t
  15. 5 X/ t; s2 @  E) z; H! R7 }
  16. LED ---|<|---[===]--- VCC# v; d% p# S+ q. M( a6 r
  17.            Red          330+ L- h; C' `: S3 U- ~
  18. " |* g. k1 x7 p, l' S7 X" Y
  19. Fosc = 6MHz
    + _  q9 [* p( Y0 G& j2 q
  20. */
    - ]/ d! [3 @! |8 L8 F4 F$ @4 ~
  21. * q6 S2 d9 I$ N
  22. 7 C% W! t* F: G2 [
  23. // 矩形波输出脚' ^9 p: V7 T0 z& o8 d
  24. sbit OUT = P5^4;) z) ]6 v, i1 S  \  i. Z
  25. // 低压指示灯引脚- E7 }# l! q4 |3 T9 J  h
  26. sbit LED = P5^5;4 L6 L0 w' M3 c$ x; Q

  27. $ v! V$ ^* j5 I4 Z/ z$ O% w
  28. // 停机标志位
    " ?9 y/ O: i0 U" j# m, z
  29. bit isReadyToHalt = 0;
    2 V4 D# b- d7 d& {

  30. ; z; a9 n1 T! ]; z
  31. // 矩形波次数累计: c* W/ `8 ?6 s7 W: u2 @
  32. static volatile unsigned char count = 0;
    ! O* r$ [! \) V; x. j  f
  33. ; {' t$ x0 D+ ]

  34. # J, e2 z  x$ O1 X: C3 L1 y, [
  35. static void GPIO_Init(){
    7 X. {# {9 _% r7 q; z
  36.         // P3口设置为准双向,默认靠内部弱上拉输出高电平" ~6 b/ H+ W1 m% X1 F
  37.         P3M0 = 0;: O; F. |4 z4 g$ Z+ V9 n% W
  38.         P3M1 = 0;1 F+ _1 [; Q0 n1 i6 L1 I" W3 V! r$ a2 Y
  39.         P3 = 0xFF;
    0 Z' @7 z! C% l) o1 T
  40.         // P5口设置为准双向,默认靠内部弱上拉输出高电平$ ]7 q2 D5 N+ j5 U" P% [( d  F
  41.         P5M0 = 0;
    # n# C9 p' y0 J1 c' c' g% h
  42.         P5M1 = 0;
    4 _* A* L: S2 ]5 A4 F- ~0 O
  43.         P5 = 0xFF;  z: Q& k0 U5 ]; ]9 t
  44. }
    ! z) s, l: f* k7 y  U1 g- k
  45. 6 g+ W9 w& j, x7 I5 T  [6 z/ j$ c' x, j
  46. static void Timer0_Init(){& P- \' D2 d5 _9 g
  47.         // 16毫秒@6.000MHz5 o. n" Y2 z4 l# n5 B5 l! R
  48.         AUXR &= 0x7F;        // 定时器时钟12T模式
    9 b: ?. L4 o  G
  49.         TMOD &= 0xF0;        // 设置定时器模式4 c. \/ u. e7 }+ O
  50.         TL0 = 0xC0;                // 设置定时初值
      e% X1 s7 `" p
  51.         TH0 = 0xE0;                // 设置定时初值/ K/ z" C1 W4 a% o6 F
  52.         TF0 = 0;                // 清除TF0标志
    ' R+ ?$ \, T' A5 P: S4 @# p/ W
  53.         TR0 = 1;                // 定时器0开始计时: Y3 r- ?# a0 \, a6 U
  54. }
    4 o( z" V  V4 g3 U; k. b7 E  p
  55. ; }1 W3 F/ P0 a5 B9 N
  56. static void Interrupt_Init(){
    7 J9 [- R4 l2 n" {
  57.         // INT0中断触发类型为下降沿触发- C+ v5 u( g7 g, o" l
  58.         IT0 = 1;8 r, e4 @" @9 ~
  59.         // 允许INT0中断4 U( E1 x; ]4 N$ }9 @
  60.         EX0 = 1;- E) H! x1 F, p3 s8 D& C# l
  61.         // INT1中断触发类型为下降沿触发
    , x! ]. l* d) T% E# `  D* b3 K6 r9 V+ F
  62.         IT1 = 1;
    * \) Y6 m8 Y  R* Y0 y" [
  63.         // 允许INT1中断
    + {- {3 ^8 @+ |$ q0 G# A  H* |
  64.         EX1 = 1;" f! d* [2 U' s, q
  65.         // 允许定时器0中断
    0 E+ n: d% m; ^, X/ w7 ?' `
  66.         ET0 = 1;# @) D/ x* z; x3 n
  67.         // 允许全局中断+ Y4 }& c0 E. p, o& q% V; i+ V3 `) x
  68.         EA = 1;1 z7 T6 y! o1 `8 z# c& N
  69. }
    5 o- m/ m) ~& F5 ?. n
  70. ; B8 r9 v' @2 b0 E% A7 H
  71. static void INT0_Isr() interrupt 0{
    $ Y6 q9 S  t4 S9 E& h( i, t
  72.         // 矩形波次数累计归零
    ; j5 ]0 \8 v" V
  73.         count = 0;
    $ U, o( i' e) ^- a8 A
  74.         // 重开定时器0中断
      X- b4 U) y. g: S3 r: j
  75.         ET0 = 1;
    1 J3 m* J" f: c# m; C! R
  76. }( |- K( O9 K" ?1 c) A6 P
  77. ! b4 Y/ |) }4 p+ o  L- `
  78. static void Timer0_Isr() interrupt 1{. }* V' X6 t# w% _  @& M2 O
  79.         // 输出矩形波
    # x% h7 T! E6 D( D* {$ ?
  80.         OUT = ~OUT;
    # F8 D  g$ @6 }
  81.         // 累计矩形波次数
    3 D. F9 Q, z, w
  82.         count++;4 F: @. g/ p+ @. X- C# \% I* K
  83.         // 超过250个矩形波,准备停机
    8 v# r# y- @0 x. x
  84.         if(count > 250){
    / S7 y) b$ g) }( O9 j
  85.                 count = 0;+ n$ L1 c' ]. Z2 o5 w: J. w
  86.                 isReadyToHalt = 1;
    + E+ p$ h. J+ m# z- b& K
  87.         }
    2 Y8 Y- R; y( z! w7 h* E' W
  88. }
    8 B7 ?5 F8 U$ c3 A& q
  89. ) T3 v' u- W. B+ a  C) t5 ^
  90. static void INT1_Isr() interrupt 2{
    " a6 R2 s# T2 M- b8 }, g$ J: f
  91.         // 矩形波次数累计归零
    - ]0 D; v& H3 M3 D6 V# s5 A0 q0 I
  92.         count = 0;
    ) B  d7 \6 }, V8 Q4 |
  93.         // 重开定时器0中断
    0 |! |3 |# \8 l; {. {# u$ \3 @
  94.         ET0 = 1;* S& ]+ c8 B  t, F8 ~& j' d
  95. }
    " L# }; h5 r7 g# L  W! |3 p
  96. - E2 ]* ~2 @' v2 p+ F$ y2 J' J
  97. 2 Y3 J/ I" f* v' a
  98. void main(){- [- }0 {& ~8 M. s7 `
  99.         // 初始化P3和P5口
    & L& C5 T! ~9 k! g
  100.         GPIO_Init();8 g" I' t* c/ x7 O" A3 n/ O
  101.         // 初始化定时器0
    # ]' M8 S; F0 d: p4 A) s
  102.         Timer0_Init();
    ) F/ ^- C6 M" g/ {* l$ f6 u
  103.         // 初始化中断+ o( b; B% {) _8 U  p, `8 _+ E( d
  104.         Interrupt_Init();" _$ X* {3 Q7 z" V: ], Q' }* S
  105.         * h% j8 f/ W9 `: e
  106.         while(1){( ]" A# |" C! K
  107.                 // 检测电量+ h. ]/ Z+ i- K. U
  108.                 if(PCON & (1 << 5)){4 ?/ W5 i% u1 c
  109.                         // 如果电量低,低压指示灯亮& I. t* D/ G9 Z, \: i
  110.                         LED = 0;
    4 s5 n# U6 Y$ _) v, g; H* S
  111.                         // 清电量检测硬件标志位7 j  u7 K# ?0 E5 F
  112.                         PCON &= ~(1 << 5);
    2 e! g3 @; K! [+ Q3 z. x# _9 _2 a! X% @
  113.                 }else{( Y; _. h6 f9 R
  114.                         // 电量正常,低压指示灯灭0 q( d$ {- g% x" o# S2 I$ H
  115.                         LED = 1;
    ( L, o) E. U; H: \- Q; ]
  116.                 }" ]0 z% R) e8 B2 E- Y

  117. $ s* y1 N0 E0 M, W2 m& j
  118.                 // 检测到停机标志
    " ^* q/ S. v, O/ R( g. k1 O1 ?: y
  119.                 if(isReadyToHalt == 1){
    ' q9 n' Z; s0 B% {
  120.                         // 暂时关闭定时器0中断1 u: O9 ~# x# I/ G5 P1 g; j, |
  121.                         ET0 = 0;7 K* d$ W, ~  t& C! W* b7 Q/ s
  122.                         // 停机之前先把矩形波输出脚置低电平,以方便INT0和INT1唤醒CPU
    # H2 q5 }& K9 C$ }' \8 M
  123.                         OUT = 0;
    4 G8 O) }- F! _
  124.                         // 停机之前先把低压指示灯灭掉,以省电
    0 V) D9 L2 f) Y' v1 U
  125.                         LED = 1;% @6 I+ O( ~: Y, o# M, g7 V: p
  126.                         // 进入停机模式
    & l. P: s' l; V
  127.                         PCON |= 0x02;+ B" @4 u% Y. k2 X% q- l
  128.                         _nop_();3 c, ^: k# q4 ~) W6 o
  129.                         _nop_();
    3 B  e- u* v* i4 v+ c7 Z8 }
  130.                         _nop_();
    0 r; l/ ]( l: H% l1 B2 i8 N
  131.                         _nop_();
    9 {: v0 p6 o) G9 q8 r. j) A3 s
  132.                         // 唤醒,清标志位
    # L+ \; z/ f) O& A7 @& W1 a1 o0 p
  133.                         isReadyToHalt = 0;  ^9 \5 Q3 z* }  b6 K1 b5 |
  134.                         // 重开定时器0中断
    / D4 T( G) `! z' g- S2 |6 S
  135.                         ET0 = 1;
    % r1 p4 `2 U' L. p" Q; b( K9 f, I( r
  136.                 }
    0 n4 W2 U; N: {& M9 k
  137.         }9 C/ f  f. C3 [
  138. }9 F/ H# q( a% [6 h' W
复制代码
5 H1 ~; Y- r* b- J5 O0 O8 [
硬件参数配置:6 Q' R! C) q1 Y: _, f5 m  c$ A  k* f

: }8 l5 ^! W0 z; W" x' x; g! Z4 F; b; K0 B
接收端:: f: g" m: d$ H8 F* a
  1. #include <INTRINS.H>
    ; h2 ~7 v; Q$ M8 y
  2. #include "STC15W.h"9 z* z  r" D  |; t0 T' a
  3. " J  m, D8 @1 I
  4. + w5 Q- C# L) B
  5. /*% T  V" q0 v) ?' T3 o* n/ P+ w

  6. ) V- Z1 C; [9 g$ T1 K* p
  7. *---------------------------*
    ' _/ L2 Y& i8 L! w6 E" u6 Q' p* t: K
  8. |1 (GPIO2)         \__/  (GPIO1)16|
    # \5 [- u, L$ a, u8 I5 \) H6 z1 g
  9. |                                                        |; F( l# }) X; ^2 K
  10. |2 (GPIO3)                   (GPIO0)15|7 q! i+ k! ~) x* d! L6 y
  11. |                                                        |
      I( B: j; ^+ Z
  12. |3 (GPIO4)                                  14|$ {" Y4 P/ H- H5 C, I
  13. |                                                        |: i% B% g! T. G" |( g
  14. |4 (GPIO5)                        (DATA)13|
    $ _& q" N$ [1 d  D
  15. |                  STC15W204S                |
    - [1 ?8 ?. @6 V/ {" a; S4 J$ V  R
  16. |5 (GPIO6)                   (LATCH)12|
    7 u" n8 W; G9 k0 m; ^+ {9 V
  17. |                                                        |
    9 g8 I" R9 T" S
  18. |6 (VCC)                         (CLK)11|
    ! J0 q9 B6 o9 u3 }- }# V
  19. |                                                          |7 d8 O3 r. k& z1 H# l- E% z; f$ m
  20. |7 (GPIO7)                         (TXD)10|
    8 ^4 U" x+ m; r5 L8 l; Y
  21. |                                                        |
    4 T9 q1 ?: B! D) u; A% z, ^
  22. |8 (GND)                         (RXD) 9|
    : L% {6 ?1 Q6 b4 e
  23. *---------------------------*
    * w( i- U! `$ K1 j8 k: Y
  24. Fosc = 12MHz
    3 F. D# a" h$ p

  25. & h) g* z5 T( V8 _4 c
  26. P1.0 -> 上$ l" x' c( s& B; d
  27. P1.1 -> 左
    ; N6 M2 _# a* U1 I
  28. P1.2 -> 下
    ) Z/ x- F" N4 `+ i% |1 a
  29. P1.3 -> 右
    4 h% K* Q. W* f) ~
  30. P1.4 -> SEL
    + l" }8 ?/ _- H" \  c2 o
  31. P1.5 -> STA( h. e/ N' _6 B! m2 i3 X
  32. P5.4 -> B" Y& _. o  e+ p3 M7 n
  33. P5.5 -> A
    ; Y) n8 k; H" ~5 U" j
  34. & L7 v$ O# W6 \" x5 S4 b% r- ~
  35. */. W9 r) W- G  `' d8 r2 }8 c

  36. 6 j. X' y( G, `  n
  37. ' m+ P: |+ Z0 L- n/ p+ V
  38. sbit CLK        = P3^2;- J' p1 n$ t% W8 F1 f, [
  39. sbit LATCH        = P3^3;
    0 ]1 B8 R9 ]  k1 W* b
  40. sbit DATA        = P3^6;2 R+ H3 ~; p0 Y

  41. . I" A% g* g! i. Z/ @* s
  42. bit isReady = 0;$ }7 U1 K5 Z# I& n" u1 [% m
  43. static unsigned char key = 0;$ u/ y- M; Z4 o
  44. static unsigned char buf = 0;        // 双缓冲。这个缓冲区保存从P1和P5组合而来的键值
    7 T, k) _, ~4 V/ S# O1 {
  45. static unsigned char bufReady = 0;        // 双缓冲。这个缓冲区保存上面那个缓冲区的备份
    ; V1 T  a1 Y* y% L& C: F
  46. static const unsigned char data mask[] = {0x80, 0x40, 0x10, 0x20, 0x01, 0x04, 0x02, 0x08};        // A B SELECT START UP DOWN LEFT RIGHT。为提升速度,这个表放到RAM中
    # b! j, m" S' p( Q9 n
  47. static unsigned char idx = 0;: Z- N$ L. ^2 d; O6 G( g5 I4 T: d
  48. : \7 p! z1 |) @' L- r

  49. 7 V' T3 X. V4 j" t1 u1 ~
  50. static void GPIO_Init(){7 C$ k, W' D) W& a0 u, d
  51.         // P1口和P5口用于接收并行信号,全部初始化为准双向,依靠内部弱上拉输出高电平
    & R, n* Q% W% ?% \( _  [7 f
  52.         P1M0 = 0;! R0 P) i! \  _9 n9 P
  53.         P1M1 = 0;: j/ o; d1 n7 P  P8 m- @# `2 k  N
  54.         P1= 0xFF;
    $ M; R" }3 a9 ~
  55.         P5M0 = 0;# s- m$ c1 f6 l7 c6 E' `' d
  56.         P5M1 = 0;
    : a8 s- u, _4 _: d
  57.         P5= 0xFF;2 I* c2 b9 G" ~8 B$ W- ^& w  h4 @
  58.         // P3口初始化为准双向) o  ]0 p) k( `# X8 k
  59.         P3M0 = 0;
    ; W+ \7 Q# w/ _7 o: |
  60.         P3M1 = 0;
      l& E4 O# G' @1 O
  61.         P3 = 0xFF;3 ^' m" R/ }9 G8 Z* G4 J
  62. }
    9 O7 V; ]5 y8 y1 p$ b

  63. 6 m  s  Z6 p5 ]; S$ v2 y
  64. static void Interrupt_Init(){4 |9 G4 }4 m2 `1 |5 C! d$ |' R5 ?; A
  65.         // INT0中断(CLK)触发类型为上升沿+下降沿0 I/ `9 {' ^/ @6 F) J/ x7 \
  66.         IT0 = 0;
    / k( j, g/ ]# e4 h. r- {
  67.         // 允许INT0中断
    " C4 \1 @+ C! b+ R6 n
  68.         EX0 = 1;
    : _6 i% t- L1 J1 n
  69.         // INT1中断(LATCH)触发类型为上升沿+下降沿
    - k% Z/ h# j- J$ k1 E2 l
  70.         IT1 = 0;
    9 [$ S; M( m9 J3 R6 }/ k
  71.         // 允许INT1中断
    8 k. e( F( w, z9 J4 R, ^
  72.         EX1 = 1;' c- C& S- D: l& h9 U: B
  73.         // 开启全局中断& E. i1 t! J9 ?0 J/ c
  74.         EA = 1;: O: W. Q# d% B0 B0 s. ~, L
  75. }& o6 s- Y. i  S$ a* ~6 u

  76. ! ~# E: j6 O! x. r7 a) i5 }4 `- T
  77. static void INT0_Isr() interrupt 0{& ~& m$ @0 }: y1 Z! }) n; P
  78.         // 只有已经成功锁存才允许CLK移位* [3 k' F5 e; P1 L+ j6 b
  79.         if(isReady == 0)$ M( H% i! [% V& l. Z1 e: E1 O" O& g  ]+ x
  80.                 return;
    7 a& ^" Q& C7 ~6 T* Q
  81.         // 读当前引脚电平,如果是低电平则说明是下降沿,此时直接忽略该中断
      B0 y- K9 I# z/ e8 x
  82.         if(CLK == 0)8 `; e* r1 ?  r6 b' F# r3 u) P( W7 v
  83.                 return;
    ' X4 ?% x" L/ W1 I- m
  84.         // CLK上升沿到来的时候,取锁存值的下一位输出
    9 b0 Y0 [/ W2 b; U
  85.         idx++;! s( C* o4 I! l6 D! `! Z& O
  86.         DATA = key & mask[idx];: o' O0 ?) r3 v
  87.         // 如果已经完成7次移位,则一轮读取完成; w) y. }% c& {
  88.         if(idx >= 7)
    * w2 J6 K5 U) {
  89.                 isReady = 0;# |( J' ~: G* A8 e* s
  90. }
    " `4 Q6 R: t' y4 _+ [0 d4 r

  91. ; j0 M$ \, `; `1 O4 U
  92. static void INT1_Isr() interrupt 2{
    2 T3 _9 p5 e9 e0 }
  93.         // 读当前引脚电平,如果是低电平则说明是下降沿,此时直接忽略该中断
    + x2 L7 c+ E& L8 r0 i
  94.         if(LATCH == 0)5 z1 n( C2 K) L2 f2 [6 ]5 V* ^
  95.                 return;+ x' Z, t- v5 y5 M* z9 D2 Z' `
  96.         // 当LATCH上升沿到来的时候,锁存所有按键状态,同时把键值A输出到DATA  }: x( K6 q5 e# y! p
  97.         key = bufReady;
    8 G7 h: v# Q2 y8 h
  98.         DATA = key & 0x80;//mask[0];        // 为了加速运算,直接取表中的值而不是读表
    " Y/ a+ ?3 W, ^9 o( L
  99.         idx = 0;/ M0 L# R  E; w' G, D) v% J
  100.         // 允许CLK进行移位
    0 T" d3 B- D" s8 F
  101.         isReady = 1;
    2 H6 t0 {$ X7 D" ?1 Z3 r
  102. }9 x4 _  b$ y9 v9 T6 F  S4 |% k
  103. $ z% l6 n) }. |# `: _5 Q
  104. void main(){
    . A9 G: b  b3 u! d: I; s
  105.         GPIO_Init();2 j* ~5 y1 W% ?8 r' y7 H9 `. ^- Q
  106.         Interrupt_Init();3 K) [0 \/ d: m; z- f+ h1 Y
  107.        
    # W6 c! J% g( s0 u1 `# e; M
  108.         while(1){+ A% i% ^3 v" a
  109.                 //PCON |= 0x01;        // 进入省电模式( s7 u5 f4 J9 e* m& |4 {7 t
  110.                 //_nop_();; {+ o! \0 R& {4 [: Q( E
  111.                 //_nop_();
    & _; S2 a/ L. g% T# n  g- }0 h  K
  112.                 //_nop_();
    3 k: k: H! a* t/ [  |5 d1 p# q2 C
  113.                 //_nop_();
    ) z& P+ F6 Z4 c+ Z/ s- {
  114.                 buf = ~((P1 & 0x3F) | ((P5 << 2) & 0xC0));! K7 T, ^) F' z/ I, b
  115.                 bufReady = buf;/ b+ {. @! \; |8 d0 t/ D
  116.         }, \6 B) @! L' g0 K  D; F
  117. }
    & S! f$ H7 s1 r# n5 w5 T
复制代码
, E8 d" A7 |/ |
硬件参数配置无特殊要求,晶振频率选择12M即可。. n) T) b7 t1 ]" A/ y1 K# @

4 P* p% [! i/ G这是编译好的固件。

本帖子中包含更多资源

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

×

评分

参与人数 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; f" F" N+ \6 Y. Z1 i& z' C
不错的设计,想问一下楼主,FC的15针公头怎么解决?普通的公头太短了,插不进去FC的扩展接口。 ...

1 s7 O4 Q% Y( E, U0 n% B坛友的改造方案
回复

使用道具 举报

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

使用道具 举报

发表于 2019-5-25 12:07:18 | 显示全部楼层
精彩,楼主动手强,也写得很详细。
( }5 G( h6 q; p" H+ ]  m& E4 W2.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
7 T/ W' {5 [( j精彩,楼主动手强,也写得很详细。& q2 g; Q: a6 c: J6 s0 x- ^3 e
2.4G方案是目前无线的最低延迟吗?

" m, @" z9 e- ?: n' j3 E我没用过其他无线手柄,所以实在不知道我自己做的这个手柄到底是不是最低延迟。+ O6 I2 d' m; c) n! _: m( ~- c: D
不过根据网上的说法,延迟高低主要是由通信协议的复杂程度,以及数据传输速率决定的。这个模块虽然是2.4G无线模块,但由于协议很简单,所以延迟比较低。
, N0 ]4 F/ |" k我用这个手柄玩一些ACT游戏,比如超级马里奥、忍者龙剑传、热血系列,完全感觉不到延迟,和游戏机自带的手柄没有任何区别。唯一的区别就是这个手柄是用火花山寨手柄改造的,外壳是垃圾回收塑料,粗糙+脆弱,导电橡胶弹性不佳,手感不是一般的差。
$ y, t& H$ e+ W7 ?! ~+ F; \我手里还有十几张板子,等我有空了我再做一套,到时候买一个好一点的手柄改造。
回复

使用道具 举报

 楼主| 发表于 2019-5-29 16:56:14 | 显示全部楼层
ppad 发表于 2019-5-28 17:27
$ Q- E* s' ]  q/ F3 X5 D给技术帝赞一个,有半成品发布吗,自己焊接改造就可以,编程实在不会啊 ...

! H8 m5 ?( X7 d3 w( G" ~很可惜,我手里没有多余的单片机了,LDO也找不到了,锂电池以及充电模块更是没有了。反正就是该用到的元件基本都没了,所以没法发布半成品。
7 y# S- p1 X5 `; T; b) g两个板子倒是有十几张剩余。6 i) O2 g* f8 |* J7 i
你要是有USB转TTL串口板,完全可以自己买这两种单片机,然后我给你编译好的固件,你自己用串口板下载到单片机里面就行了。两个2.4G无线模块也得通过串口板用AT命令设置参数,不过好在我在设计电路的时候就已经预留好了串口,可以直接在线下载和在线设置参数。总的来说并不麻烦。
回复

使用道具 举报

 楼主| 发表于 2019-5-29 17:00:34 | 显示全部楼层
孙大师 发表于 2019-5-28 18:55: s, j6 n8 h3 V  K2 m, a
非常好,楼主是技术帝,到目前我都还没开发fc的无线套件,等空了,开发一套套件,等玩家自己组装。 ...
5 \" _! V# t5 r
能得到孙大师的赞誉,不胜荣幸!
+ A. X9 x3 d4 ~7 g8 C* L% x不如开发一个多功能手柄,比如用SFC手柄改造,L/R键配合其他组合键可以用来切换2P~4P、调节连发速度、软重启等各种功能。接收端插到15PIN扩展口。
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-2-25 07:37 , Processed in 0.150889 second(s), 14 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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