找回密码
 注册

QQ登录

只需一步,快速开始

查看: 24846|回复: 32

自制FC无线手柄

  [复制链接]
发表于 2019-5-22 14:16:45 | 显示全部楼层 |阅读模式
本帖最后由 雷精灵2046 于 2019-6-14 09:28 编辑 * _, S4 i' N5 `- i3 _& j
, I$ x( C1 l* ~7 g1 _! q! j
没有用复杂的分立元件搭建发射接收电路,直接用的现成的2.4G无线模块jdy-40。% b' {' ~1 t% t. K0 M  V6 }# M
0 }, \* I' f; Z0 G

/ _" f- C7 U) \1 f6 r发射端靠3.7V锂电池供电,用了一片SOP8封装的STC单片机,负责产生连发脉冲,同时负责检测电池电量,电压低于3V左右的时候触发低压中断,低压指示LED就会亮起来告知该充电了。平时发射模块和单片机均处于睡眠状态,有按键按下才会唤醒,从而实现省电。实测睡眠状态下整机电流约1~2uA。板子洗了一下稍微干净了一点。因为对于微功耗设备来说,焊接残余的助焊剂可能会增加漏电流。. Q' L4 R3 z2 f  O$ [
: ]* A  q( P) b9 j  H
买了一个火花的FC山寨手柄,去掉里面的牛屎板子,并修正一下塑料挡板,把锂电池和充电模块装进去。2 k, S; {: P9 i
为了减少体积,充电模块裁剪得十分小,并且更换了充电电阻使之适应这个小小的锂电池。这么小容量的电池,也不需要多么大的充电电流是吧?
8 t! }6 L% B$ A& e& A0 ~7 ~然后统统用热熔胶粘上。充电电流比较小,所以发热很少,不会熔化热熔胶。
- f+ S* F! f2 B% c6 |
# O+ Y' x) M- R# B
/ r5 ~9 O' _* d3 o6 O( n/ L- i) ?6 q
最后把按键、导电橡胶和电路板装上去。  p( i# P/ o1 |" ?& n/ ~2 B( q
精心裁剪了电路板,正好扣上,不会阻碍其他元件,也不会影响后盖和拧螺丝。$ @  [  M, D( k2 S/ V  n
9 i" i0 J& _! U8 H- b  n6 r  q2 X; p
7 G  a5 Y! z7 p  I0 L, {
完工!
- I3 u& c+ x7 [6 i+ ?
) I0 ~9 `6 R) o2 ^4 K% M8 A5 G6 e
5 F5 f5 k( @3 a+ k& V# j这是充电的MicroUSB插座。旁边的小孔用于透出低压报警LED的光线。- ~2 K5 Q6 W! u! p0 ~' u

! y2 g# G0 o* b) n% k5 r2 o. c4 @9 y. V) W! W$ n% j
接收端用一片DIP16封装的STC单片机模拟CD4021。为啥要用单片机模拟而不是直接用CD4021?因为jdy-40模块接收端在有按键按下的时候输出高电平,无按键按下输出低电平,和普通手柄正好相反。当然我也可以用两片74HC00或者74HC04之类的逻辑门进行反相,但那就增加了芯片的数量。对于FC手柄这种工作频率并不高的设备来说,STC单片机完全可以胜任模拟工作。: N' I7 m: w* N% q
; I: o4 |0 X' @  z7 D9 S
; x2 h) p7 g) p  u
" C8 Q9 n) y6 ]% C0 [6 u$ {+ }6 Q# t
电路设计有点小小的错误,所以有几根飞线。原本设计使用低压差LDO是XC6206,结果在做这个接收模块的时候,买的LDO居然找不到了!无奈只好用了AMS1117。幸好对于接收模块来说是5V降到3.3V,1117可以胜任。要是发射端手柄的话,3.7V降到3.3V,那就非得用6206不可了。
% u( B6 t2 h3 f. V
+ I$ p% R) R* y% d: O4 {; R" p/ g实测十分灵敏,延迟极小几乎感觉不出来。可惜这山寨手柄的手感并不佳,尤其是方向键,软塌塌的。看来我得买个剪线手柄改装。0 i' m5 B" h- j/ Q3 h6 B9 z
) |# f9 u0 G) y- z) c9 Y1 N
这是电路图,有兴趣的朋友可以参考。
' u4 q. u. E2 Z8 `
+ O0 r/ ]! m! [+ q. R& h* q. D' e0 @0 ]+ F. ]" ]- I$ V. B* j$ L
我信奉开源主义,十分痛恨把技术藏着掖着。好东西大家分享嘛!所以两个单片机的源代码大公开!
; J% i8 T/ P' ~编译器:Keil 51。
! L* Z5 m+ U  H! R5 \6 D& ~
; `4 u9 x5 \8 R  O8 V/ ?& f发射端:& E" u2 F8 V7 e. A
  1. #include <INTRINS.H>3 ?. \2 f: D6 b; q! f# k. o
  2. #include "STC15W.h"$ A- H3 K4 C6 b9 W; m& Y% M# w

  3. ; `0 G( x4 }. s- n7 M
  4. ( ^3 Q2 I$ j9 I3 o3 ?
  5. /*
    9 s: p4 C" a8 u  o9 x' r
  6. --------------------------
    % ?! P; u( e# _& N& S' K- |
  7. |1 (OUT)        \__/   (INT1) 8|
    3 b6 A/ t5 F# i, O+ B) O
  8. |                                                   |' Q$ h& Z( x4 q/ {/ n
  9. |2 (VCC)                   (INT0) 7|
    5 s) P1 M8 t8 l0 {
  10. |                 STC15W204S                   |
    8 v& j9 @8 b( A" j1 ~) E6 G3 s
  11. |3 (LED)                         (TXD) 6|6 |2 S( r1 u# J/ ?; e9 Z3 w0 ^5 p
  12. |                                                   |
    ) p) \' X: g/ c  H. \
  13. |4 (GND)                         (RXD) 5|! X. z9 u) ~0 _) |/ W6 {/ Y5 B
  14. --------------------------
    ( a, Y- c0 C: r% U6 m- I9 v! `% e

  15. 9 v2 g, M' a: N# u  h
  16. LED ---|<|---[===]--- VCC8 b  R. B8 T6 T0 h2 b
  17.            Red          330
    . r9 C1 R$ d* X- Y- _

  18. & N8 l, Q7 v. |* d
  19. Fosc = 6MHz4 G/ i& D2 L8 q% J# s4 O
  20. */
    1 E+ x9 S& Z+ t4 a* \$ u

  21. 2 b6 u) p) O9 m8 |

  22. 2 S  [: u6 [- z1 y4 Y
  23. // 矩形波输出脚
    ) d  I$ `+ d7 ~# a- A4 B, C
  24. sbit OUT = P5^4;- j! D9 J: s; _5 k( V8 r/ o6 L
  25. // 低压指示灯引脚
    $ b" L" \; Q* R/ [
  26. sbit LED = P5^5;) ?) ?/ G& W& v& Q) u
  27. / W# g/ z& f% \. }, [. R
  28. // 停机标志位
    9 e& c! `  V& f$ n
  29. bit isReadyToHalt = 0;) N5 B- s" Q; e0 P

  30. 0 c& q9 g, U. ]( F
  31. // 矩形波次数累计
    8 p" _/ i$ _2 s4 z# W/ c$ S
  32. static volatile unsigned char count = 0;& U" X0 [' Z, ~* v
  33. ) E" l7 w6 U( \! F

  34. 0 F- f9 m$ E2 n- J5 Y
  35. static void GPIO_Init(){4 v6 T! @# |, g5 ]; C- B
  36.         // P3口设置为准双向,默认靠内部弱上拉输出高电平: ?5 K8 p5 Y3 M/ q& P
  37.         P3M0 = 0;: s; H0 S* N2 |& @5 _: ?3 X* B
  38.         P3M1 = 0;
    5 B+ ?/ c# k6 E& f" ?; b: S
  39.         P3 = 0xFF;
    - r5 r) F' v+ y( z/ e" g2 \' J" S; ?
  40.         // P5口设置为准双向,默认靠内部弱上拉输出高电平" C# }- f  b4 ^/ ]' Q3 s5 K& Z. p
  41.         P5M0 = 0;6 ~' j4 w/ k' W
  42.         P5M1 = 0;
    7 e- i+ _* o, J. Q5 F4 h
  43.         P5 = 0xFF;
      j5 b2 b& D6 v3 i" b. r
  44. }
    & U9 U: d) C9 r5 P! Q4 @
  45. $ |1 `$ Y  v0 A" O
  46. static void Timer0_Init(){5 L9 D' B3 _2 _& h$ Q
  47.         // 16毫秒@6.000MHz, L+ ]% c" ^1 y8 W
  48.         AUXR &= 0x7F;        // 定时器时钟12T模式3 }# i' s1 I0 b  p
  49.         TMOD &= 0xF0;        // 设置定时器模式9 j; A& z( B9 _% s0 \. j
  50.         TL0 = 0xC0;                // 设置定时初值& K3 u3 K. l$ |3 ~$ t
  51.         TH0 = 0xE0;                // 设置定时初值
    6 B# Y8 C: F: O
  52.         TF0 = 0;                // 清除TF0标志  s" R" Q* z, u# C
  53.         TR0 = 1;                // 定时器0开始计时
    0 {$ q, k0 e# s8 l
  54. }
    / K" j% Y* [; t3 [! C& U* b3 K

  55. * G4 ^+ y9 e% i) z) X9 f5 F5 a
  56. static void Interrupt_Init(){# A+ |1 ^! I4 C
  57.         // INT0中断触发类型为下降沿触发7 D" Q: W# F/ ^
  58.         IT0 = 1;
    ( B' Y3 [1 h6 _
  59.         // 允许INT0中断
    ' \1 z2 Q$ c. Y
  60.         EX0 = 1;
    , k4 n+ A2 X  m9 L- K) h% H" b
  61.         // INT1中断触发类型为下降沿触发
    * I4 `8 T) E7 w5 K. H) e& f0 N
  62.         IT1 = 1;
    4 S% _" ?# f* N4 g$ z: @& X$ C1 n
  63.         // 允许INT1中断
    ; A# B: O. e/ d$ z% e2 U9 T
  64.         EX1 = 1;+ @/ G4 \& T% A0 d1 h8 o3 z
  65.         // 允许定时器0中断
    ' V% V/ p4 K0 J0 p- U8 n/ B
  66.         ET0 = 1;, f/ w% k( I5 i2 R# P7 L* g# s
  67.         // 允许全局中断
    0 g) T* m9 h. k: x5 @
  68.         EA = 1;
    2 i, w/ R- I  R9 d
  69. }) o0 ]7 O9 Z3 Z

  70. : B$ j- h% r0 {2 D0 V4 v3 l
  71. static void INT0_Isr() interrupt 0{  |( A9 Y: }; `! E2 S& N
  72.         // 矩形波次数累计归零; {9 x' t: d  s2 A* |
  73.         count = 0;+ M0 X" b9 x& i' R
  74.         // 重开定时器0中断' F4 {3 ^  u( o' A3 y
  75.         ET0 = 1;1 J2 F, c1 ]$ a. s2 i' X" c$ c2 X
  76. }, g& v# o# \! R* \, f$ w3 ~
  77. ; b5 A/ k: y& ~# d- n% T7 L! n2 L4 R
  78. static void Timer0_Isr() interrupt 1{
    ! q7 c/ g" L3 I* g6 B' q& u
  79.         // 输出矩形波
    3 A5 w- {- K6 s4 _2 R) }! n4 W" h9 h/ X
  80.         OUT = ~OUT;; t  U6 s: M) z9 C( Y5 P. {
  81.         // 累计矩形波次数
    : Q: u9 o- R5 g8 t2 w
  82.         count++;1 |' O" {! B4 O) p# m' i6 C  f
  83.         // 超过250个矩形波,准备停机
    6 _2 o# o0 M# y8 I' A5 B+ A) n3 X
  84.         if(count > 250){
    4 l7 f, l0 e) o9 P6 `
  85.                 count = 0;
    # w4 G3 R' E1 t6 m8 S+ `
  86.                 isReadyToHalt = 1;: ^( ?0 ]0 X+ T
  87.         }3 {5 h3 y6 W2 Y
  88. }
      i" E7 F: L) x7 a3 y( y
  89.   \. Z8 j$ Y+ Q$ D4 d& S+ k
  90. static void INT1_Isr() interrupt 2{
    2 ]: v2 n) [8 d) Z9 D7 g; ~! L% C
  91.         // 矩形波次数累计归零
      L7 t( u5 L& D# _+ Z
  92.         count = 0;
    " c+ X7 Y% P6 P0 X" Y( k" `8 U( A
  93.         // 重开定时器0中断) e5 ]- l3 _! y7 W- s& |
  94.         ET0 = 1;
    0 B0 L/ }% j1 w
  95. }
    6 s& n6 X4 A: j, Z: N4 M

  96. & h  N1 J% `' j  Q. X8 A
  97. . O. A6 _  G* d' D! h' T" Q
  98. void main(){: A$ {; L: a# Q  u$ v
  99.         // 初始化P3和P5口$ m' t0 i$ ^3 ^
  100.         GPIO_Init();
    $ o/ W0 U- B' I8 k" X9 O
  101.         // 初始化定时器06 x; J4 N+ G1 f" ^8 c  y
  102.         Timer0_Init();
    / ~) B; t/ J" G' x) S4 ^2 ?" i6 V# h
  103.         // 初始化中断3 l5 L* R% R- T6 h9 P5 V
  104.         Interrupt_Init();
    2 s7 h- a8 e0 _8 F& c8 C, ]
  105.         1 o+ j. s& D8 `$ F$ b' t7 E
  106.         while(1){- L; x+ P* ~9 J9 y2 \) S5 C
  107.                 // 检测电量8 q6 q0 L! U' U7 n$ ^% _
  108.                 if(PCON & (1 << 5)){
    . G- E" C8 T$ b
  109.                         // 如果电量低,低压指示灯亮" {, Z, H5 A1 B5 X. S  z
  110.                         LED = 0;2 ]3 Q* L/ i* m0 J, T
  111.                         // 清电量检测硬件标志位
      e' ]' j9 @. N1 Q
  112.                         PCON &= ~(1 << 5);
    ! n1 L* g: {  D
  113.                 }else{# f! B. T" y( }- f9 V! U
  114.                         // 电量正常,低压指示灯灭& `' s0 K1 v8 K; U& g7 [7 ^3 W
  115.                         LED = 1;* H4 l4 f* J; @1 Y) ^
  116.                 }
    / \1 ?% R) I- ]( g2 g3 |* E. q
  117. 2 S! a# I+ f1 Q8 L( N) c+ @
  118.                 // 检测到停机标志0 B7 B: t* r7 F! E" U6 M! F0 [! i( K
  119.                 if(isReadyToHalt == 1){
    - f2 Y+ C. W2 X8 \5 n! Q% O
  120.                         // 暂时关闭定时器0中断
    ; Z3 D. u. k5 B4 G6 w
  121.                         ET0 = 0;
    " w* x" S/ R$ ]1 ^
  122.                         // 停机之前先把矩形波输出脚置低电平,以方便INT0和INT1唤醒CPU
      U, B$ G& y# e/ o: M$ k! y
  123.                         OUT = 0;& i2 [* Q* a, |+ N  R! L6 c
  124.                         // 停机之前先把低压指示灯灭掉,以省电
    ( @: {+ j  _% E. L0 W4 e
  125.                         LED = 1;
    ( J  D0 e1 H" a# f+ f
  126.                         // 进入停机模式) v6 C$ z. a: I: L1 A* e. q
  127.                         PCON |= 0x02;) Y4 @) g8 O$ V+ Q
  128.                         _nop_();
    7 d; K( H3 ?# g: R) h/ |0 C6 H- a
  129.                         _nop_();
    $ X) f0 g. D8 m( D. e2 O
  130.                         _nop_();9 X0 D8 @$ D! p$ |5 a
  131.                         _nop_();
    ; X  V% a( S" \/ S4 V, k
  132.                         // 唤醒,清标志位6 h3 J- H' y4 E% L6 h% x
  133.                         isReadyToHalt = 0;8 ^0 O$ s. h$ {& h
  134.                         // 重开定时器0中断
    6 J! i. s8 W# L' z
  135.                         ET0 = 1;
    . d6 }, g2 K3 m
  136.                 }) |) h) o+ J7 K
  137.         }
    + r6 Z' Q+ Z; o4 L4 D9 d( B8 ?
  138. }. }! y9 q" H. d
复制代码

( b) {8 G) E/ K6 K8 O/ a7 g硬件参数配置:
& t6 a4 J' ^3 ]( n. ]1 x+ f( _7 a, Y) [* Z, k1 ^
1 }( i5 z5 ]. ~9 Q
接收端:
* X6 `+ b5 a* r; ^- O
  1. #include <INTRINS.H>
    * Y2 x1 W8 J: \( E% Q
  2. #include "STC15W.h"0 `. z9 k# ^, l0 i: @  ]5 K7 b) T) @

  3. * b8 a. Q, G" j! b( P: A! d
  4. # y+ \/ u( {% d6 a4 N
  5. /*9 n) V2 Y6 R2 o
  6. $ q' b) V$ i, o# O- q& t* z
  7. *---------------------------*
    7 z: X2 Y2 m- I# `' `
  8. |1 (GPIO2)         \__/  (GPIO1)16|& @( T) J' l# T9 V
  9. |                                                        |3 f9 Q, _  ^, s( [2 f9 t$ p
  10. |2 (GPIO3)                   (GPIO0)15|
    * {$ `, ]! G; |
  11. |                                                        |
    4 t$ `5 Z1 ]$ S: E
  12. |3 (GPIO4)                                  14|
    5 p, G0 C! B+ N6 B
  13. |                                                        |& ]7 c/ x6 o; P8 F# f
  14. |4 (GPIO5)                        (DATA)13|
    / j8 Z( Y* k( M
  15. |                  STC15W204S                |
      x0 A( {4 ?  }* O, J  {( s5 ~
  16. |5 (GPIO6)                   (LATCH)12|
    4 f% l! r# i. a+ m
  17. |                                                        |
    : p( r8 }' R5 s. ~8 e8 ?& y/ l
  18. |6 (VCC)                         (CLK)11|. C; D- b# x/ ?# K4 b5 S) S# o( w8 ~
  19. |                                                          |
    3 e. x. q1 @' X: b3 q( U5 J0 f, Y
  20. |7 (GPIO7)                         (TXD)10|
    " W2 c8 Z1 x0 C5 D2 \* C
  21. |                                                        |$ m3 {0 `- }0 |4 T% s5 k
  22. |8 (GND)                         (RXD) 9|/ c1 J- N! f2 V$ _, c( A) Y5 Q
  23. *---------------------------*
    9 `( ^& n9 u: j- o+ T) M
  24. Fosc = 12MHz
    ! }) t" f4 Y* m: I

  25. 8 Q' N9 z# B0 X
  26. P1.0 -> 上
    " q) Q) G# Q" Z9 p) y
  27. P1.1 -> 左  h- [% m" d4 P! D. @9 ]  R' G' u/ W; T
  28. P1.2 -> 下3 B: |) z% Q7 b, `( W" o4 P# h# U7 o
  29. P1.3 -> 右. r- _5 ^0 D& R# q
  30. P1.4 -> SEL
    $ I2 l' _6 O) v7 F8 V
  31. P1.5 -> STA  a; R7 D/ L7 I" [$ U/ b
  32. P5.4 -> B
    & a( }( `: ]% m! ]7 U2 z$ w: l- d
  33. P5.5 -> A1 @$ L1 _2 u1 S: \- j3 C# P
  34. $ y5 y) w+ ^" z* A5 Q+ ^- \
  35. */
    / ]) E- I2 d! s4 v& a( G
  36. 9 ^$ p2 Q2 b( l9 M% y! o

  37. - I1 k7 x) e) H
  38. sbit CLK        = P3^2;
    * s  U. P+ w) d8 [& Y' q$ z! ?
  39. sbit LATCH        = P3^3;
    / c& w( b/ b9 Y/ D; m6 d+ d
  40. sbit DATA        = P3^6;
    7 r3 G5 H/ \9 d. k+ t$ x7 d" P
  41. 2 F3 W8 z! J8 O- e4 f
  42. bit isReady = 0;6 n/ F, Y5 z# C2 y4 j) {
  43. static unsigned char key = 0;: \9 p* I2 a4 m6 o
  44. static unsigned char buf = 0;        // 双缓冲。这个缓冲区保存从P1和P5组合而来的键值- T) R9 A3 ^9 j3 C$ w$ p
  45. static unsigned char bufReady = 0;        // 双缓冲。这个缓冲区保存上面那个缓冲区的备份8 P, i0 C9 p% }9 M% U
  46. static const unsigned char data mask[] = {0x80, 0x40, 0x10, 0x20, 0x01, 0x04, 0x02, 0x08};        // A B SELECT START UP DOWN LEFT RIGHT。为提升速度,这个表放到RAM中' }/ n) o. v% A; s' H
  47. static unsigned char idx = 0;- e2 ]3 Q& p$ u: w, t0 Z4 h: X/ N

  48. 8 ?' A5 {6 h$ \. w9 n$ c0 {
  49. ) |  M- n' j' x! g
  50. static void GPIO_Init(){
    ! Q* t9 G) a+ j' ~6 p$ |, K
  51.         // P1口和P5口用于接收并行信号,全部初始化为准双向,依靠内部弱上拉输出高电平
    % f' i, F4 o) a. W& Y% g
  52.         P1M0 = 0;
    ; c1 }1 O7 y' R* K
  53.         P1M1 = 0;  L' z) N9 r$ l6 [: L% M
  54.         P1= 0xFF;
    - o( J4 h' E# R" i$ S. f$ A8 a4 B5 r
  55.         P5M0 = 0;# q6 \3 U. R. r
  56.         P5M1 = 0;1 k% ]  _5 H/ L5 W8 m( m
  57.         P5= 0xFF;, ]* W; Y9 E4 o5 v, V
  58.         // P3口初始化为准双向& E: ~: f/ Z* r6 W: I
  59.         P3M0 = 0;0 h; }& x( w9 M( Y
  60.         P3M1 = 0;
    . m1 N* U$ t4 ^
  61.         P3 = 0xFF;
    5 E% u- X. X1 k) o
  62. }7 q; x" d( O6 a- T
  63. : M  O5 v& C0 S8 d( m
  64. static void Interrupt_Init(){: e8 U( f( W: m
  65.         // INT0中断(CLK)触发类型为上升沿+下降沿
    2 h$ T9 b. c( i+ T" P' {* X; R
  66.         IT0 = 0;
    4 ]9 u: y/ `% e5 l, C" _9 I
  67.         // 允许INT0中断
    ! ~% l' _5 K1 ~# H3 s% n) J
  68.         EX0 = 1;
    ' M+ a, c0 F- i0 A- Z& l
  69.         // INT1中断(LATCH)触发类型为上升沿+下降沿' I1 a' J- T; m) S4 B4 x
  70.         IT1 = 0;0 u$ w" g7 E6 D. Q# L, d
  71.         // 允许INT1中断
    7 [/ B. m% `5 g: F* a
  72.         EX1 = 1;2 F% @- q5 R1 e3 f1 d4 y# y* \( J
  73.         // 开启全局中断1 S: J+ f" W/ W+ Y
  74.         EA = 1;
    $ U) \0 B- }7 Z/ s" d! e& U9 i
  75. }8 a" B) A- }4 X& }+ r

  76. # U% f0 f2 T# _2 K. v! b& U
  77. static void INT0_Isr() interrupt 0{* ]( N* c5 w) u6 g) G
  78.         // 只有已经成功锁存才允许CLK移位
    ' [' L1 P) D. O$ O
  79.         if(isReady == 0)
    3 b, a! H/ V6 I7 [
  80.                 return;
    2 `3 @- i' O% l/ Z, \+ Z
  81.         // 读当前引脚电平,如果是低电平则说明是下降沿,此时直接忽略该中断1 t* |  {6 N. h
  82.         if(CLK == 0)
    7 q/ P7 _7 r6 W4 {3 ^( c
  83.                 return;6 w: m, w. V2 w$ O2 m  }$ @, g, u
  84.         // CLK上升沿到来的时候,取锁存值的下一位输出
    5 t( D* F( I3 o4 x
  85.         idx++;
    ( u. {$ W$ n. H
  86.         DATA = key & mask[idx];
    4 _* D9 I  ~# [, s( m+ s
  87.         // 如果已经完成7次移位,则一轮读取完成
    6 _' `* a( Y8 o6 m/ Y# W- n6 h3 [
  88.         if(idx >= 7): M8 Q& n" p) a" g/ V( u
  89.                 isReady = 0;
      W% a! g9 `. L9 F8 T" R  a& L- d
  90. }* v- `0 p' H3 @* h7 _+ k& U: k
  91. 9 R. z+ t8 I6 S3 K
  92. static void INT1_Isr() interrupt 2{
    0 a. J/ F1 V$ q
  93.         // 读当前引脚电平,如果是低电平则说明是下降沿,此时直接忽略该中断
    0 F* s0 _# p. R- Y2 ]5 E
  94.         if(LATCH == 0)3 ?8 W+ e, d5 [3 b8 `, i1 p: i
  95.                 return;. q) I. m; W- S
  96.         // 当LATCH上升沿到来的时候,锁存所有按键状态,同时把键值A输出到DATA( B0 A  E4 o& p
  97.         key = bufReady;" h7 I5 T9 `" I: ^
  98.         DATA = key & 0x80;//mask[0];        // 为了加速运算,直接取表中的值而不是读表% b9 Y7 V1 a  r  ?
  99.         idx = 0;
    " Y5 W0 O" W$ y2 N3 N7 i
  100.         // 允许CLK进行移位
    * a2 D2 v1 w4 D( G1 {* s/ E$ d
  101.         isReady = 1;" x( n# `( G. y" \% D% p
  102. }
    0 b. J2 |0 v8 e; ^, O
  103. * n$ }6 t2 u$ q5 h% K/ p
  104. void main(){# e+ H1 s& Q% ~4 @" h5 d% w
  105.         GPIO_Init();
      `0 H4 t. x/ s. {, J8 ]: B
  106.         Interrupt_Init();( Z$ f8 o. T" I/ q9 ]  R9 k3 @
  107.        
    ! U# V8 ~1 z" ~: Q7 U* m. e
  108.         while(1){3 o8 V9 L" f% P$ x4 ]2 c% p2 O
  109.                 //PCON |= 0x01;        // 进入省电模式; p$ e9 z; K, n  m* y" W1 I0 }
  110.                 //_nop_();" b3 h! \  v) j0 [: k: W" z
  111.                 //_nop_();
    ' _4 ~, O- t3 ]1 e3 Q
  112.                 //_nop_();/ H/ l/ E1 u4 a, e
  113.                 //_nop_();) q3 c6 z) P& p& @; U- x& c
  114.                 buf = ~((P1 & 0x3F) | ((P5 << 2) & 0xC0));1 k! L/ S# C3 z; o/ }" f# D- n3 g
  115.                 bufReady = buf;
    - e0 t" c& l" X' i' r8 m8 F8 G
  116.         }2 z4 c1 L1 `$ b: v$ ^  A7 h5 ^
  117. }1 g7 ?" s0 D5 @; B
复制代码
6 x9 F8 j  g" b  D- ^
硬件参数配置无特殊要求,晶振频率选择12M即可。
3 c* M  K& E+ [( m1 W5 D0 Q' Q& j: B) S% D, K% E
这是编译好的固件。

本帖子中包含更多资源

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

×

评分

参与人数 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
- b, Y# x/ [& ^% g# Z9 W4 b: x不错的设计,想问一下楼主,FC的15针公头怎么解决?普通的公头太短了,插不进去FC的扩展接口。 ...

* b% P6 h3 G8 U( k- S! o* v9 [0 ], z坛友的改造方案
回复

使用道具 举报

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

使用道具 举报

发表于 2019-5-25 12:07:18 | 显示全部楼层
精彩,楼主动手强,也写得很详细。
1 P3 F# @8 g) P2 d, Y2.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 {3 V8 w* C2 [- s3 s6 A+ B( q( G1 b) }精彩,楼主动手强,也写得很详细。# f+ P: u' x; u/ r" i! L! i
2.4G方案是目前无线的最低延迟吗?
. O9 M$ |5 \  M. {
我没用过其他无线手柄,所以实在不知道我自己做的这个手柄到底是不是最低延迟。
3 Z, G2 |/ D/ ~. x不过根据网上的说法,延迟高低主要是由通信协议的复杂程度,以及数据传输速率决定的。这个模块虽然是2.4G无线模块,但由于协议很简单,所以延迟比较低。" d- ?% K. V( ^6 F
我用这个手柄玩一些ACT游戏,比如超级马里奥、忍者龙剑传、热血系列,完全感觉不到延迟,和游戏机自带的手柄没有任何区别。唯一的区别就是这个手柄是用火花山寨手柄改造的,外壳是垃圾回收塑料,粗糙+脆弱,导电橡胶弹性不佳,手感不是一般的差。
! q; ]! g8 ~  G2 m3 P我手里还有十几张板子,等我有空了我再做一套,到时候买一个好一点的手柄改造。
回复

使用道具 举报

 楼主| 发表于 2019-5-29 16:56:14 | 显示全部楼层
ppad 发表于 2019-5-28 17:27
" o/ T/ k" w/ _. ]给技术帝赞一个,有半成品发布吗,自己焊接改造就可以,编程实在不会啊 ...
  r/ V6 i  Z" Z9 t9 @1 A0 r1 a/ ^
很可惜,我手里没有多余的单片机了,LDO也找不到了,锂电池以及充电模块更是没有了。反正就是该用到的元件基本都没了,所以没法发布半成品。
, \, a" x$ D6 F$ H! s两个板子倒是有十几张剩余。
2 N2 r# T8 S3 s5 r! C& G2 O你要是有USB转TTL串口板,完全可以自己买这两种单片机,然后我给你编译好的固件,你自己用串口板下载到单片机里面就行了。两个2.4G无线模块也得通过串口板用AT命令设置参数,不过好在我在设计电路的时候就已经预留好了串口,可以直接在线下载和在线设置参数。总的来说并不麻烦。
回复

使用道具 举报

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

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-5-6 18:02 , Processed in 0.312181 second(s), 14 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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