电玩DIY [ VG DIY ] - Video Game Do It Yourself

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 14765|回复: 27

自制FC无线手柄

  [复制链接]
发表于 2019-5-22 14:16:45 | 显示全部楼层 |阅读模式
本帖最后由 雷精灵2046 于 2019-6-14 09:28 编辑 / M, ^1 g& Q" O' ?4 e: u- `  b( l

1 k: d* R! Z$ b没有用复杂的分立元件搭建发射接收电路,直接用的现成的2.4G无线模块jdy-40。
/ O/ Y: Q3 d6 _, S+ ]8 G
; k8 v+ I' \& p+ ]7 y2 ]& x
- z) V! I) y, u( S: R+ m发射端靠3.7V锂电池供电,用了一片SOP8封装的STC单片机,负责产生连发脉冲,同时负责检测电池电量,电压低于3V左右的时候触发低压中断,低压指示LED就会亮起来告知该充电了。平时发射模块和单片机均处于睡眠状态,有按键按下才会唤醒,从而实现省电。实测睡眠状态下整机电流约1~2uA。板子洗了一下稍微干净了一点。因为对于微功耗设备来说,焊接残余的助焊剂可能会增加漏电流。% s, y! [1 W; p5 v4 @

: z, `* C+ H5 P/ r. g) o$ `买了一个火花的FC山寨手柄,去掉里面的牛屎板子,并修正一下塑料挡板,把锂电池和充电模块装进去。; d/ d" F9 t4 J
为了减少体积,充电模块裁剪得十分小,并且更换了充电电阻使之适应这个小小的锂电池。这么小容量的电池,也不需要多么大的充电电流是吧?
2 w( o9 P6 {( i1 d9 ^3 i: k然后统统用热熔胶粘上。充电电流比较小,所以发热很少,不会熔化热熔胶。
3 F4 o$ {6 u. J8 R8 A) I
% |, U4 W6 t9 Z7 l( C, Z4 U
' o* S2 \; k( L( W1 V8 m  b
( x/ ]1 G# F4 l' [最后把按键、导电橡胶和电路板装上去。! e4 Y+ e9 z. w4 v
精心裁剪了电路板,正好扣上,不会阻碍其他元件,也不会影响后盖和拧螺丝。
' x; i" ?% f$ Q
4 u8 {5 D. `- |8 ~+ E" Q+ l( v1 g/ k. t% s9 t( }
完工!" j0 ?7 \9 U% P7 V' W" I
: d/ T/ Z+ b6 t" e

4 b; |1 t  y+ W0 m0 K* Y这是充电的MicroUSB插座。旁边的小孔用于透出低压报警LED的光线。) X1 w& d! N! b) G1 \

; B, I5 j$ h* z( Q3 t2 }
6 w/ X5 V& |5 j接收端用一片DIP16封装的STC单片机模拟CD4021。为啥要用单片机模拟而不是直接用CD4021?因为jdy-40模块接收端在有按键按下的时候输出高电平,无按键按下输出低电平,和普通手柄正好相反。当然我也可以用两片74HC00或者74HC04之类的逻辑门进行反相,但那就增加了芯片的数量。对于FC手柄这种工作频率并不高的设备来说,STC单片机完全可以胜任模拟工作。; I- A. ^6 C7 g7 s4 k
2 P% m3 J9 C1 q
5 I( F& ?1 S) \

9 O/ I+ z; j; g$ q' B; C电路设计有点小小的错误,所以有几根飞线。原本设计使用低压差LDO是XC6206,结果在做这个接收模块的时候,买的LDO居然找不到了!无奈只好用了AMS1117。幸好对于接收模块来说是5V降到3.3V,1117可以胜任。要是发射端手柄的话,3.7V降到3.3V,那就非得用6206不可了。: S; r9 d: I2 J! l3 C/ L
" t0 Q8 ~, n) s' p% s7 Q" T; n4 D
实测十分灵敏,延迟极小几乎感觉不出来。可惜这山寨手柄的手感并不佳,尤其是方向键,软塌塌的。看来我得买个剪线手柄改装。+ g' g- A9 r0 q2 e
' @+ l6 m7 [8 `" `% S" R! E
这是电路图,有兴趣的朋友可以参考。! s( k0 c. g3 q) ~: H

- \; ^8 e7 m* |. Q$ L5 f9 y. w5 k/ m& [& f0 a1 m% N% A
我信奉开源主义,十分痛恨把技术藏着掖着。好东西大家分享嘛!所以两个单片机的源代码大公开!/ Y6 l# T/ |, e
编译器:Keil 51。& u! t, m' {1 l' D/ V) n* I: d

0 n6 u4 K. i1 E4 c发射端:
' Z  L3 N4 P( V  P
  1. #include <INTRINS.H>
    0 u! o/ j; ~. f+ T
  2. #include "STC15W.h"
    # g! Z  p# N5 Y  d2 w4 D3 H( ~
  3. : T  Z4 E. P) s) r3 i
  4. 1 [7 h# J# _2 Y6 v
  5. /*
    3 O3 L- @) x. L; H5 |+ `" J& O; U% b
  6. --------------------------
    6 V8 u/ F: d3 Z& y) _
  7. |1 (OUT)        \__/   (INT1) 8|
    + |) |+ ]  I( a+ `
  8. |                                                   |
    7 c* d3 Q& |. Y* G/ \' g" r
  9. |2 (VCC)                   (INT0) 7|
    ) h; p, f* k# W, O! s5 V7 q
  10. |                 STC15W204S                   |" b+ X) c  B, v; @
  11. |3 (LED)                         (TXD) 6|
    ; k. Y" k+ X8 f$ |
  12. |                                                   |" O0 X1 R  P% f
  13. |4 (GND)                         (RXD) 5|% a4 X. ]8 v% s
  14. --------------------------
    ) ]4 r8 N" g* E% H8 j$ q
  15. 7 e2 T; |( N& o$ H
  16. LED ---|<|---[===]--- VCC
    # ^% N. n9 _8 D) p7 p
  17.            Red          330  Q9 c8 W' x5 F8 D3 M' |" Y
  18. % I9 c% R0 T7 a  t$ @, P6 l
  19. Fosc = 6MHz
    0 x& F( J1 O! e% n) S8 X8 h
  20. */
    4 O6 _! g$ {$ c1 I8 h$ e6 ~

  21. 7 Q( q2 q) |+ h- e) |, R2 B
  22. - C9 g0 s9 c" M1 `
  23. // 矩形波输出脚, _; p) a2 t8 z; C& Y
  24. sbit OUT = P5^4;' M0 m# K& `" p; P
  25. // 低压指示灯引脚
    ( S& b, F2 [$ u# n1 P
  26. sbit LED = P5^5;
    % `2 a9 T" l5 Z3 n  O
  27. 3 e1 }% V1 Q5 k: b
  28. // 停机标志位6 y$ q2 R8 {! ^
  29. bit isReadyToHalt = 0;' k2 e# B/ Z- H% v
  30. & _" T7 @  Q7 @4 W4 u/ o8 Q
  31. // 矩形波次数累计  O( F% V! u) w1 I) `1 w' [& O% V5 s
  32. static volatile unsigned char count = 0;
    # [/ G0 O  L2 _" V. h
  33. 9 V' T) f9 |' m8 a
  34. ! u& n9 Y( a7 h- [7 _* O" X
  35. static void GPIO_Init(){
    ( S, e2 y8 N/ G
  36.         // P3口设置为准双向,默认靠内部弱上拉输出高电平/ K4 q. @* o" g; N
  37.         P3M0 = 0;
    . D& _# y. o) }0 ~, e1 b$ r
  38.         P3M1 = 0;
    0 v, Q$ S' h4 z5 c# f
  39.         P3 = 0xFF;
    8 Y; c0 e) h) B: B, W. M% F+ M
  40.         // P5口设置为准双向,默认靠内部弱上拉输出高电平
    2 J2 b; L# v- J+ ?# B& ^0 @
  41.         P5M0 = 0;; [+ ~/ q; V, x( R& Q& M" \$ L
  42.         P5M1 = 0;, s3 U) ^/ T( v7 F2 K! B1 c( V4 o
  43.         P5 = 0xFF;
    , l# |7 X; F7 M( z* r1 V/ R( t
  44. }7 M) i% G# c" q. t5 q, {8 o

  45. ; U1 q% O" x0 [) G
  46. static void Timer0_Init(){+ _8 t/ U6 w$ c9 n; u0 h
  47.         // 16毫秒@6.000MHz- P8 D+ o9 u* r
  48.         AUXR &= 0x7F;        // 定时器时钟12T模式* R8 M6 w3 D- L7 w2 ?
  49.         TMOD &= 0xF0;        // 设置定时器模式
    3 x$ k! D1 t/ l/ P3 F+ n+ I
  50.         TL0 = 0xC0;                // 设置定时初值8 E) w/ U; q) A  Q+ S
  51.         TH0 = 0xE0;                // 设置定时初值
    5 L2 C1 v5 }: z  j" c
  52.         TF0 = 0;                // 清除TF0标志
    6 H! U9 h# q" b. d* Y2 T2 U% j
  53.         TR0 = 1;                // 定时器0开始计时$ A% S: F# D* F1 H
  54. }
    0 x8 W6 m; s. g+ A9 `
  55. ) F3 e7 I' Z- b
  56. static void Interrupt_Init(){
    9 a+ I! a+ p0 n$ ^+ G! \6 O
  57.         // INT0中断触发类型为下降沿触发0 G( a. D1 N+ S* V- \- A* c0 `
  58.         IT0 = 1;0 V$ d: {  e- u, G2 s
  59.         // 允许INT0中断0 q8 o$ Y* b! I% J
  60.         EX0 = 1;
    . \* i- z( T3 V/ c
  61.         // INT1中断触发类型为下降沿触发2 a  w, ^% }+ m2 `' \9 _" r
  62.         IT1 = 1;
    6 g' }. m+ P- `2 i4 N4 g3 ]
  63.         // 允许INT1中断) k' _; R( C& ~: T
  64.         EX1 = 1;
    8 I: F0 ]8 g6 @/ f1 D4 b
  65.         // 允许定时器0中断; E! E: W6 Y# d/ I* H
  66.         ET0 = 1;
    ; O" X  |. c1 v) ]  A
  67.         // 允许全局中断0 N7 W0 S5 a+ p0 t
  68.         EA = 1;
    # x5 W- W, f: y7 k
  69. }3 S; l3 m8 l( W4 g: C0 H
  70. 4 R6 H0 ^9 z2 h9 y1 @$ X$ W
  71. static void INT0_Isr() interrupt 0{
      H) \! A: U% X- |+ ]) i
  72.         // 矩形波次数累计归零2 b/ Y- V5 U9 L! K) i
  73.         count = 0;
    * w. a2 d' O! K& b. @1 x
  74.         // 重开定时器0中断
    6 I' f5 [+ \* ^' O
  75.         ET0 = 1;3 l8 M) a4 g- ^, u; M
  76. }
    4 y: }; |+ S& q8 @. o* j
  77. . c0 T$ f4 P& X5 _2 ~; U. t: O
  78. static void Timer0_Isr() interrupt 1{
    1 C# h& g1 F* _, T  @6 l; _) x, ?
  79.         // 输出矩形波
    / D2 e+ `9 H! O( [1 h* S) G9 s
  80.         OUT = ~OUT;. Y" K% i3 b! {7 O$ j
  81.         // 累计矩形波次数5 ], q9 F" R" x+ E) P; L6 I
  82.         count++;' c* R2 M8 [* \5 q$ i  o  R% T+ ^
  83.         // 超过250个矩形波,准备停机6 ~+ k$ S2 \+ q5 K1 Y  R
  84.         if(count > 250){2 X0 x" |3 \9 C& H& I/ v# ]
  85.                 count = 0;
    1 `8 M# S8 ^3 l" x" K  V+ B
  86.                 isReadyToHalt = 1;
    * G$ i5 \9 D6 c, Z9 n% G2 T, A
  87.         }8 R% P+ W; S: `
  88. }
    / V6 @3 l' _- Q3 q
  89. $ t2 R. Y# f& K* }" b' `0 u5 o
  90. static void INT1_Isr() interrupt 2{4 h$ k& H4 d1 N
  91.         // 矩形波次数累计归零
    6 k; U) h% ~  d" ~+ x4 s7 _
  92.         count = 0;9 `- P: @, i3 p7 G8 H  f5 R" {- X
  93.         // 重开定时器0中断1 H: Y5 a2 j. y8 {+ I: A& B# ~* ?1 @
  94.         ET0 = 1;( H) |0 _) ?  W: ^" _: |
  95. }
    6 W; v2 {+ O( ~) W! F5 v

  96. / x9 z& O/ o0 U3 e7 t8 q( d

  97. 2 U; m& z- E5 H( o
  98. void main(){5 y$ d4 T" C' e3 A& n
  99.         // 初始化P3和P5口9 Z. l9 V& k* o2 j3 R- u1 B( H) Q
  100.         GPIO_Init();
    : Z5 F" x5 E( H0 ^' ~  ]& S! l! s
  101.         // 初始化定时器07 M4 i% _. l+ M0 ^) n2 l( z" |
  102.         Timer0_Init();
    " `" t1 x- k, q6 [5 h
  103.         // 初始化中断
    * P/ j" b) I# M. S+ e
  104.         Interrupt_Init();) A1 G- k9 j, O8 T/ n1 A: V/ a! S+ C$ q
  105.         7 y% F- \4 Q# m* H2 j1 x  I
  106.         while(1){7 ?, _' ~0 i4 `& Y
  107.                 // 检测电量
    * Z& K! ^7 g  Z4 W1 J. r: H
  108.                 if(PCON & (1 << 5)){3 H' G) E' p2 j- B! v( D9 v$ L5 t" x/ U
  109.                         // 如果电量低,低压指示灯亮. n5 j/ i" R" N
  110.                         LED = 0;
    & n3 u' G$ m7 V9 p* O: o* L+ z
  111.                         // 清电量检测硬件标志位
    " f/ T+ b* }7 w! c$ U8 @
  112.                         PCON &= ~(1 << 5);
    8 t& z! x$ ]* Z) r4 R) F
  113.                 }else{8 I/ K, ]; [* K% k6 q
  114.                         // 电量正常,低压指示灯灭% T0 O" v; A0 a- N8 Q
  115.                         LED = 1;: c7 \! V$ D% _9 L
  116.                 }
    / X. g; J5 L- i7 V( ?; S3 v4 Q6 x9 C" n

  117. ' R$ M9 X. l3 n, B9 Y3 P& I3 P  g
  118.                 // 检测到停机标志
    , X0 {* C# E; E
  119.                 if(isReadyToHalt == 1){3 O5 w  q0 g9 L8 u, B4 L7 `. u8 \
  120.                         // 暂时关闭定时器0中断
    2 T2 ~+ D; `( f4 B
  121.                         ET0 = 0;+ N" z; h3 k0 J2 ~! u
  122.                         // 停机之前先把矩形波输出脚置低电平,以方便INT0和INT1唤醒CPU8 k% D( q% J5 I4 @
  123.                         OUT = 0;
    ) k9 Y1 S& Y. d
  124.                         // 停机之前先把低压指示灯灭掉,以省电
    ( w, P% o; P8 O+ @  C- @  [
  125.                         LED = 1;8 r8 |8 i! }  G/ \
  126.                         // 进入停机模式- H" {. L% K( ~+ _) H/ J
  127.                         PCON |= 0x02;% \7 g/ G" p' h" A+ n6 o& T
  128.                         _nop_();9 f& P1 {7 y' r; m6 i# L
  129.                         _nop_();& E$ w5 U( d: D+ `* S8 R/ ^
  130.                         _nop_();- o" P* }5 `5 [9 D7 b6 z% N
  131.                         _nop_();
    5 h' Y" y; b$ E& b$ O$ a2 {& O
  132.                         // 唤醒,清标志位
    2 _5 z1 u. S6 r6 U+ O# u5 M0 W
  133.                         isReadyToHalt = 0;
    $ D1 B# n3 ?7 i2 N) b4 v
  134.                         // 重开定时器0中断
    1 r) b, i) u* P$ ?3 ^
  135.                         ET0 = 1;
    ; A3 f  z7 p6 P; {" N, t' Y
  136.                 }
    2 m/ S8 W6 `( U
  137.         }+ r3 x% O  Y" b7 K4 e6 k
  138. }
    . L" Z' w7 G  b+ E' [, r. [
复制代码

) _2 ]9 Q4 Y, K硬件参数配置:' g. r8 ?, n4 ~2 q- B: s9 w

. L( c9 O1 o0 g- L! v+ T9 P/ f
! O, {) q6 m0 x+ k. h' a1 V接收端:8 q" |" }' o8 Z9 Q9 J. i4 @& i
  1. #include <INTRINS.H>4 t) P* [) E/ E6 h  o
  2. #include "STC15W.h"
    3 H" F0 S# s# A! S. W0 J
  3. % {5 `" t, ~: r" O, i6 f
  4. ' V# g) W  w$ M
  5. /*( a9 r# h  D" ~  ^9 x4 x7 Q
  6. - D) _- l5 a0 [9 q* i  l" ^0 h5 P
  7. *---------------------------*
    % ]) D; a" N7 S5 x# T; Z
  8. |1 (GPIO2)         \__/  (GPIO1)16|
    4 V' I. [" N) S" _
  9. |                                                        |
    * I1 W+ `3 Y/ x/ b
  10. |2 (GPIO3)                   (GPIO0)15|
    6 j" {0 p* p+ K! B
  11. |                                                        |1 t/ ]5 h# O# ?
  12. |3 (GPIO4)                                  14|
    6 N! S) U) ]5 _6 Q% @7 b3 h
  13. |                                                        |
    / D6 ^4 M/ j) T+ `' e$ f
  14. |4 (GPIO5)                        (DATA)13|
    3 E0 s' U: ~& z- c. s
  15. |                  STC15W204S                |9 @+ B9 J# x; b$ V- J& P5 ~/ q  |
  16. |5 (GPIO6)                   (LATCH)12|
    % }5 j/ P' i; |2 }$ W
  17. |                                                        |, f. Y4 b0 s. C: M: F; a
  18. |6 (VCC)                         (CLK)11|4 X5 q) u/ Z" |: i* T! F
  19. |                                                          |' N, p/ H) e& \7 x: E
  20. |7 (GPIO7)                         (TXD)10|
    # b- x2 ^9 W+ |/ Z: ]6 H
  21. |                                                        |5 v, p. G8 @/ l& J4 Q
  22. |8 (GND)                         (RXD) 9|" N3 ]* [8 E4 f" q  \0 A
  23. *---------------------------*
    # d3 }; R7 A9 L# o3 b
  24. Fosc = 12MHz
    0 Y# P% a; d" x$ P

  25. 0 |5 P- P: P* b4 A; l: ^$ C! w
  26. P1.0 -> 上5 O3 e* c* |1 ^5 E
  27. P1.1 -> 左! _+ w. F+ {: Y0 B
  28. P1.2 -> 下; b" w4 t0 s; c: V4 C
  29. P1.3 -> 右0 L1 m+ g0 |2 g0 M- s
  30. P1.4 -> SEL
    ; M" T* T/ b5 l; [" p8 o- n2 }
  31. P1.5 -> STA8 |" x1 Q/ o0 r
  32. P5.4 -> B
    5 Q' a7 N1 i) @3 q
  33. P5.5 -> A% ^6 v. o& x9 k' e

  34. 9 W4 L6 f' @2 \" d( u# U3 F  o
  35. */9 @! h% P' P' \: I" ~
  36. $ L0 c7 w% |; O+ C$ J: U5 T
  37. 3 y2 a6 ^& v7 ?( ~1 N; p; n/ E
  38. sbit CLK        = P3^2;
    + h* ~$ e+ N( I8 O2 P% y
  39. sbit LATCH        = P3^3;' G& ^1 X: r3 G
  40. sbit DATA        = P3^6;
      b* ^# _) t2 |3 S/ `

  41. 1 [- k& Q0 z$ u8 b+ i! H" D* C
  42. bit isReady = 0;
    ( E) I% x: `( d6 X+ r* o% S7 V: X1 [
  43. static unsigned char key = 0;
    ) `2 P' `' [! `. V2 j- j7 t& e
  44. static unsigned char buf = 0;        // 双缓冲。这个缓冲区保存从P1和P5组合而来的键值
    " c3 O) }2 n, ?" g$ a( I
  45. static unsigned char bufReady = 0;        // 双缓冲。这个缓冲区保存上面那个缓冲区的备份6 g/ B" B6 B* V, w2 W# P
  46. static const unsigned char data mask[] = {0x80, 0x40, 0x10, 0x20, 0x01, 0x04, 0x02, 0x08};        // A B SELECT START UP DOWN LEFT RIGHT。为提升速度,这个表放到RAM中) f& P; m8 {3 J. E6 |& r: C; ^
  47. static unsigned char idx = 0;
      B2 A' Z; [0 s/ U) {
  48. 2 Z) U8 K4 e1 n) W$ [. f

  49. 7 T8 s* [2 A! o8 a- {
  50. static void GPIO_Init(){
    / Y- d+ b" U  x5 @5 o7 G
  51.         // P1口和P5口用于接收并行信号,全部初始化为准双向,依靠内部弱上拉输出高电平+ N: p2 \8 J( ?" V. U+ Q
  52.         P1M0 = 0;
    % A7 R+ ?3 l4 R# `( S4 F2 r4 l; h
  53.         P1M1 = 0;0 w( g2 u) q. G2 [  U: A% t2 W
  54.         P1= 0xFF;9 |& t; N! b5 m9 O( P
  55.         P5M0 = 0;
    - V" J- c4 e# L- H3 Q
  56.         P5M1 = 0;& J& c, W% Y6 y1 O* A. K
  57.         P5= 0xFF;
    6 b* ?: {# ~& W9 |: i0 E9 {
  58.         // P3口初始化为准双向% k8 H( G2 W8 b0 F  T
  59.         P3M0 = 0;* a4 [# a; j: A8 ]0 {7 U5 V
  60.         P3M1 = 0;) |0 N7 U8 E: ]$ O" ?1 Z
  61.         P3 = 0xFF;! F. C6 C1 y) k6 _7 k) X
  62. }) ^# ?6 G# F" ?8 o

  63. # N% X# b, N" W. P
  64. static void Interrupt_Init(){
    ' }% s7 v9 ]4 R) Q  ~: `
  65.         // INT0中断(CLK)触发类型为上升沿+下降沿8 e- Y" s  E/ {7 L
  66.         IT0 = 0;  j/ U  i8 B2 L4 A' P
  67.         // 允许INT0中断
    7 y/ x% G: y) {( M5 ?2 e5 l5 O
  68.         EX0 = 1;+ `0 e3 D1 l! \+ [. G. E9 c
  69.         // INT1中断(LATCH)触发类型为上升沿+下降沿
    - P, @0 r! Y6 u1 ~- L& x
  70.         IT1 = 0;
      G& j8 {& h7 y0 Z$ Y' H9 m8 N
  71.         // 允许INT1中断" i3 t: X/ S$ X) M1 P
  72.         EX1 = 1;
    - {# H5 c2 V+ _! B5 E9 k" s4 e8 [9 ]
  73.         // 开启全局中断
    : ]2 V5 F2 K$ w# z# `3 }
  74.         EA = 1;- }  a- t* I- F( I  L) ^# D: ?. d: O/ A
  75. }
    / S9 L; t- P! ^" p( p# @
  76. / U+ o7 r# I2 F# {. H" D
  77. static void INT0_Isr() interrupt 0{
    - c9 c# {# ]8 m7 W. y  |5 E
  78.         // 只有已经成功锁存才允许CLK移位  ^% A3 Z$ D- M; H$ ~0 F/ N
  79.         if(isReady == 0)
    * x  l9 ^4 S, J2 q
  80.                 return;+ M) Z, m3 m! P5 B
  81.         // 读当前引脚电平,如果是低电平则说明是下降沿,此时直接忽略该中断
    0 G* e' ?& K5 ~( e& Z0 s
  82.         if(CLK == 0)* g' U; p% f2 l9 m2 `/ {4 `" X: X* c
  83.                 return;
    * o0 n7 a0 C* |' k
  84.         // CLK上升沿到来的时候,取锁存值的下一位输出% L6 b, Q' ]0 c! P( D  |, h
  85.         idx++;
    1 Y( k$ H: `% P7 _1 b! R
  86.         DATA = key & mask[idx];
    , J' H" G" ^. X& Z( A
  87.         // 如果已经完成7次移位,则一轮读取完成
    " U) i% ~, {' a3 h7 k7 B) v& ~7 ~
  88.         if(idx >= 7)# X& A% c' O# j( i" D+ h. \
  89.                 isReady = 0;7 e3 a1 ]& s$ h' z
  90. }) b7 J; K1 R9 l# ~4 r! S2 H
  91. , A/ `% c% e3 t! n7 H/ g9 U
  92. static void INT1_Isr() interrupt 2{. G. ~: Y! I7 D8 v9 N
  93.         // 读当前引脚电平,如果是低电平则说明是下降沿,此时直接忽略该中断: I( [; H$ ?. Z$ i9 h3 y/ ^4 _) R
  94.         if(LATCH == 0)& n5 l3 {, H+ D2 ]( A
  95.                 return;. L5 A' E' z5 ^! F
  96.         // 当LATCH上升沿到来的时候,锁存所有按键状态,同时把键值A输出到DATA
    ! y) R/ f, ?7 W% C# j7 k
  97.         key = bufReady;
    / }8 |5 l$ c' @5 j9 e
  98.         DATA = key & 0x80;//mask[0];        // 为了加速运算,直接取表中的值而不是读表1 ~3 u0 S: c5 F+ `
  99.         idx = 0;
    0 M; d: O' I  g4 P" m/ {1 Y
  100.         // 允许CLK进行移位
    ) B- F1 k( \$ {& R. S
  101.         isReady = 1;
      u5 K: H) M7 B0 ?& ]
  102. }! \% E6 B; B8 Y+ p# [9 h

  103. 7 A3 H% P& H! x3 ?
  104. void main(){. {( Z) y2 _. m0 ]: P9 t4 h" S
  105.         GPIO_Init();
    , Q$ l& Q8 Q( a
  106.         Interrupt_Init();
    $ X1 l& m# T7 I* S9 i* V2 L4 h7 s
  107.        
    2 G3 H! M5 `+ ]  i5 C$ _: M# x
  108.         while(1){  P' a9 s# j: @. |
  109.                 //PCON |= 0x01;        // 进入省电模式& s3 m( u, [- R/ b. S: d
  110.                 //_nop_();
    : b) v3 [+ H4 z3 ?5 j5 F
  111.                 //_nop_();
    1 `, f4 E4 r. M7 w
  112.                 //_nop_();
    4 }: `, ]& x! ^& ?
  113.                 //_nop_();
    9 d3 B8 S* p5 r0 ?: |. z' D* g
  114.                 buf = ~((P1 & 0x3F) | ((P5 << 2) & 0xC0));
    1 G' x* D% v& b0 J. ], |( v
  115.                 bufReady = buf;
      M. S( ^: R* P# F
  116.         }
    # D! X0 L/ b8 g
  117. }
    3 l- p* J( I: s' B8 N' ?4 H
复制代码

( y4 j) o$ b! ]% V  s( @" O硬件参数配置无特殊要求,晶振频率选择12M即可。
  O" f+ a, s% f' i5 W3 p6 K$ N. E  w
这是编译好的固件。

本帖子中包含更多资源

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

x

评分

参与人数 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
9 i9 ^4 O  p, C  m  `, O9 H不错的设计,想问一下楼主,FC的15针公头怎么解决?普通的公头太短了,插不进去FC的扩展接口。 ...

2 y# g( P4 F4 n& K* x6 l, R坛友的改造方案
回复

使用道具 举报

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

使用道具 举报

发表于 2019-5-25 12:07:18 | 显示全部楼层
精彩,楼主动手强,也写得很详细。' {4 N( H/ c+ V0 q; G+ K- U/ \1 z
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: r7 ^" h( i' s+ t1 v; _, X
精彩,楼主动手强,也写得很详细。5 O& |/ t$ w1 ?& G/ ^+ D
2.4G方案是目前无线的最低延迟吗?

+ A! @/ o# |9 n我没用过其他无线手柄,所以实在不知道我自己做的这个手柄到底是不是最低延迟。
; U, S2 w& l9 H0 c/ i: g9 c不过根据网上的说法,延迟高低主要是由通信协议的复杂程度,以及数据传输速率决定的。这个模块虽然是2.4G无线模块,但由于协议很简单,所以延迟比较低。
  i2 I  G3 p% M2 j6 b我用这个手柄玩一些ACT游戏,比如超级马里奥、忍者龙剑传、热血系列,完全感觉不到延迟,和游戏机自带的手柄没有任何区别。唯一的区别就是这个手柄是用火花山寨手柄改造的,外壳是垃圾回收塑料,粗糙+脆弱,导电橡胶弹性不佳,手感不是一般的差。
# L( s! _2 ]8 T0 w7 i2 f我手里还有十几张板子,等我有空了我再做一套,到时候买一个好一点的手柄改造。
回复

使用道具 举报

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

使用道具 举报

 楼主| 发表于 2019-5-29 17:00:34 | 显示全部楼层
孙大师 发表于 2019-5-28 18:557 @: @: j/ T: c( G9 L6 {0 r6 `
非常好,楼主是技术帝,到目前我都还没开发fc的无线套件,等空了,开发一套套件,等玩家自己组装。 ...
4 c( m$ z5 Q( i8 p- K
能得到孙大师的赞誉,不胜荣幸!
3 a) h" V& M6 v% r& I不如开发一个多功能手柄,比如用SFC手柄改造,L/R键配合其他组合键可以用来切换2P~4P、调节连发速度、软重启等各种功能。接收端插到15PIN扩展口。
回复

使用道具 举报

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

本版积分规则

小黑屋|手机版|Archiver|Video Game Do It Yourself ( 闽ICP备14000865号 )

GMT+8, 2024-4-28 13:38 , Processed in 0.058229 second(s), 14 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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