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

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 14591|回复: 27

自制FC无线手柄

  [复制链接]
发表于 2019-5-22 14:16:45 | 显示全部楼层 |阅读模式
本帖最后由 雷精灵2046 于 2019-6-14 09:28 编辑 9 o+ ?: f$ A7 L
+ s) Z5 Z( Q3 E$ H1 i. c
没有用复杂的分立元件搭建发射接收电路,直接用的现成的2.4G无线模块jdy-40。9 j: Y5 d, B7 Y" p+ _6 A: F8 O% I; R
5 Z+ M0 O: }& _# |
4 I; l6 w1 ?( m( ~* ?' y$ o
发射端靠3.7V锂电池供电,用了一片SOP8封装的STC单片机,负责产生连发脉冲,同时负责检测电池电量,电压低于3V左右的时候触发低压中断,低压指示LED就会亮起来告知该充电了。平时发射模块和单片机均处于睡眠状态,有按键按下才会唤醒,从而实现省电。实测睡眠状态下整机电流约1~2uA。板子洗了一下稍微干净了一点。因为对于微功耗设备来说,焊接残余的助焊剂可能会增加漏电流。
1 l) d3 V3 l1 N8 v" Q3 W' E5 w, @3 P, n/ N; e
买了一个火花的FC山寨手柄,去掉里面的牛屎板子,并修正一下塑料挡板,把锂电池和充电模块装进去。, e6 X' j. p7 n' n3 g4 q
为了减少体积,充电模块裁剪得十分小,并且更换了充电电阻使之适应这个小小的锂电池。这么小容量的电池,也不需要多么大的充电电流是吧?
. e; r3 c9 g, O2 `, p然后统统用热熔胶粘上。充电电流比较小,所以发热很少,不会熔化热熔胶。
2 F9 a, y8 d& a
- d$ c$ Y- p; u# B. q" Q4 i* S
! B' A1 k  T, k+ Q3 ~2 J  m/ ]: c- F4 F
最后把按键、导电橡胶和电路板装上去。
2 [' P7 F3 b) S; O+ ~& O8 ?% M精心裁剪了电路板,正好扣上,不会阻碍其他元件,也不会影响后盖和拧螺丝。
( r8 o0 {" ^; s3 \! \% d
+ H; |2 @+ O3 l$ L! S
% U- }3 Z" B' m, r4 w: t7 R" {1 }完工!/ J! |0 `7 z# _

9 Y; c5 l0 o% J6 T0 ?# t
5 v- }2 p. F, W5 c$ y. t- [" S这是充电的MicroUSB插座。旁边的小孔用于透出低压报警LED的光线。8 ~. e3 e9 A1 t2 J7 \4 K

& y+ R8 c& q4 n& Z  K$ {; e7 Y/ l( n0 A% K0 t4 L
接收端用一片DIP16封装的STC单片机模拟CD4021。为啥要用单片机模拟而不是直接用CD4021?因为jdy-40模块接收端在有按键按下的时候输出高电平,无按键按下输出低电平,和普通手柄正好相反。当然我也可以用两片74HC00或者74HC04之类的逻辑门进行反相,但那就增加了芯片的数量。对于FC手柄这种工作频率并不高的设备来说,STC单片机完全可以胜任模拟工作。
; o9 e1 r0 R/ [2 R
$ v, }. h! s9 `3 U: E2 Z4 t* R: p6 y5 I! t8 m* m8 F

2 M# r% h/ Q7 R4 t" e电路设计有点小小的错误,所以有几根飞线。原本设计使用低压差LDO是XC6206,结果在做这个接收模块的时候,买的LDO居然找不到了!无奈只好用了AMS1117。幸好对于接收模块来说是5V降到3.3V,1117可以胜任。要是发射端手柄的话,3.7V降到3.3V,那就非得用6206不可了。, l% V3 W# J. J$ P4 `
  T0 F: d" \9 A) T5 F- H
实测十分灵敏,延迟极小几乎感觉不出来。可惜这山寨手柄的手感并不佳,尤其是方向键,软塌塌的。看来我得买个剪线手柄改装。& r- v4 }5 }; n8 V$ Z

# n+ [- p' B. K6 k5 G  K8 G这是电路图,有兴趣的朋友可以参考。
; s: o* i: T' X5 C% r, z  g
6 j, F  l1 c' U; T, q" h. _. i1 \1 ^: L9 g; O- A# }% U" c
我信奉开源主义,十分痛恨把技术藏着掖着。好东西大家分享嘛!所以两个单片机的源代码大公开!
- q1 P8 y) d2 N4 T编译器:Keil 51。0 h- k% L0 y0 \: \
8 D) O- a) G8 p/ C6 b% F# _
发射端:
/ q; y! z6 C- m2 e" B
  1. #include <INTRINS.H>: N+ l! k/ T2 w3 \, n% D8 `
  2. #include "STC15W.h"
    " i* N5 i. H; G1 W0 I  y  u2 y
  3. 5 v' x8 o; A6 o0 M! z+ p: n' q6 F
  4.   a" x. t& z8 ^8 {8 `) k! G
  5. /*, H9 |7 i( L& k8 T& D
  6. --------------------------
    & B" i" R* o* C
  7. |1 (OUT)        \__/   (INT1) 8|) _& A! N* m6 w+ t
  8. |                                                   |$ s4 O1 d3 A# M2 ?1 B; i* O& P
  9. |2 (VCC)                   (INT0) 7|! W- t& O# `7 V7 b9 s8 ^
  10. |                 STC15W204S                   |5 V, _. M7 w( y6 g3 [; s( C6 q  }
  11. |3 (LED)                         (TXD) 6|
    7 o/ \: ]. w2 f" `$ {
  12. |                                                   |
    % X* K# T+ S% z  ~1 u3 d
  13. |4 (GND)                         (RXD) 5|
    3 A! c  G- i- B4 [7 t- v
  14. --------------------------
    ! P0 |* L7 E1 t% d# N) k, E
  15. / A  S# O6 O7 |5 U2 @
  16. LED ---|<|---[===]--- VCC
    * q# y- [+ F9 y
  17.            Red          3306 T5 m3 O( K. H/ L8 q

  18. 9 x, {' t1 B( y9 k( G4 f
  19. Fosc = 6MHz9 q7 u  r# k/ Z& k* }# W
  20. */: y& P0 B9 y9 f( X: w# |+ A

  21. 9 D/ e# }5 Q$ x) E- G0 G1 a2 ^( N
  22. : j4 \. N! W& f/ a3 r
  23. // 矩形波输出脚) T( m% U# S1 n/ h0 }) N- N( _: S
  24. sbit OUT = P5^4;
    ; i2 }4 o) z$ v
  25. // 低压指示灯引脚) a: F7 r  l% |7 q9 n* ^6 p$ h
  26. sbit LED = P5^5;
    2 }. R4 c. t* C$ n
  27. - Z9 L! u' O& S6 l9 ?) |; w
  28. // 停机标志位, U5 K) ]2 Q! q: r' K: X2 ]
  29. bit isReadyToHalt = 0;
    3 w! z( b% i3 a7 @3 j% s& ~- `
  30. ! H% d* V( h9 Z
  31. // 矩形波次数累计
    # ^8 Q! }4 t8 K( h: x5 l
  32. static volatile unsigned char count = 0;  ^# Q8 n: R- ~% B5 U& [

  33. $ q0 j2 q6 C4 ^8 u! G
  34. - B) e$ X9 `# _
  35. static void GPIO_Init(){' h, T/ s6 A" j# Y# h4 G8 h0 Q  M2 g
  36.         // P3口设置为准双向,默认靠内部弱上拉输出高电平" @% X; R! Q' K
  37.         P3M0 = 0;
    9 [; u; ^4 o3 L8 N3 ^/ N; g0 q
  38.         P3M1 = 0;
    8 a9 m: F% p' x$ E
  39.         P3 = 0xFF;7 r' f' h- U* R( \5 B, ]5 @
  40.         // P5口设置为准双向,默认靠内部弱上拉输出高电平3 h$ X1 `1 A' H2 o8 |6 u- J
  41.         P5M0 = 0;
    1 p) {( j4 G: I0 h/ y% E4 Z' `
  42.         P5M1 = 0;2 b7 K# x- W% m
  43.         P5 = 0xFF;
    " y. {# r" C/ `0 B
  44. }1 \. j4 d. C* [% _

  45. ) R* X  p8 R( D$ u2 o1 G- \3 g
  46. static void Timer0_Init(){
    # p+ H) T  U7 l) V$ ]
  47.         // 16毫秒@6.000MHz2 ?/ \% ^! o2 P9 K0 c# O
  48.         AUXR &= 0x7F;        // 定时器时钟12T模式
    ( \; b; y; M( t3 v1 Z/ i
  49.         TMOD &= 0xF0;        // 设置定时器模式$ [; J& m" @/ x, u
  50.         TL0 = 0xC0;                // 设置定时初值/ k- j6 y2 ^3 y: L. m
  51.         TH0 = 0xE0;                // 设置定时初值
    & ]0 K/ Y$ D# G% z. g5 p: t1 d0 _
  52.         TF0 = 0;                // 清除TF0标志
    ) ^  f6 \4 e, v5 H2 `
  53.         TR0 = 1;                // 定时器0开始计时0 @' W, {. i  u0 |4 Y4 W$ E
  54. }
    2 w" d1 u6 K  {1 K

  55. # k9 p# m( u, X; _/ q
  56. static void Interrupt_Init(){, m' p; @( @& \1 }% d* x- B
  57.         // INT0中断触发类型为下降沿触发/ v. U1 d9 e" g3 b$ |3 Y( _( g- }' i& f
  58.         IT0 = 1;
    7 ]& ^3 _/ t& C% z8 s; l
  59.         // 允许INT0中断
    & }: q5 N5 Y" h* W8 J& |
  60.         EX0 = 1;
    % P- N3 ]8 H- l
  61.         // INT1中断触发类型为下降沿触发
    & x8 v0 x) `4 c1 G4 S; `
  62.         IT1 = 1;
    & a& u# f* g- O1 J
  63.         // 允许INT1中断4 W" e  V7 ~9 G' u% J
  64.         EX1 = 1;% b' |" m2 r) [
  65.         // 允许定时器0中断
    " R) i$ _+ \3 I; p. L8 @+ j
  66.         ET0 = 1;+ e$ R0 y* b0 W1 @7 @
  67.         // 允许全局中断, a4 ^) p) i% l: p
  68.         EA = 1;
    % X7 t' l. M5 v3 l
  69. }7 W9 H5 s8 N. q3 z" e' G3 }

  70. # D# L+ K8 W) m8 S
  71. static void INT0_Isr() interrupt 0{
    , G3 ~6 ~6 |2 k' U* D1 O7 o4 b
  72.         // 矩形波次数累计归零
    $ g9 N2 B  X3 t
  73.         count = 0;
    " F' ?# ~6 ?# g1 w( X
  74.         // 重开定时器0中断
    8 |/ I2 i6 F7 E
  75.         ET0 = 1;# @- B$ u5 M/ a( H" J. e% A
  76. }  G) v" f& v5 a" S3 O( `* Y3 r& x

  77. 4 T9 w0 H* T+ a# E' V
  78. static void Timer0_Isr() interrupt 1{
    ! F( k  @* r7 E, v- q
  79.         // 输出矩形波
    1 ^; I/ O7 r, @/ \
  80.         OUT = ~OUT;% }: k9 z9 I( e& M2 e) K
  81.         // 累计矩形波次数
    8 l3 L1 E2 B; o- O) g1 H
  82.         count++;
    5 F7 Z/ L- V( t1 T  F4 D" Z
  83.         // 超过250个矩形波,准备停机
    0 a2 [' u  ~: O% _7 ]& f; T: p
  84.         if(count > 250){
      z. x* w) H( e6 ]$ ~& U3 E! C
  85.                 count = 0;
    3 Q. k' y% W6 v% C
  86.                 isReadyToHalt = 1;
    6 K) G9 g: a* y. c1 M( v
  87.         }
    0 w8 n5 S. X- Z0 K$ `4 M0 ]- ~, [3 I
  88. }3 N  H- J6 k( F( ~9 G
  89. % i- a) Q$ t; T1 ?. x1 L- Y
  90. static void INT1_Isr() interrupt 2{6 J2 e( B1 u2 }/ `3 l- C2 S
  91.         // 矩形波次数累计归零$ H$ x" U2 I+ Y6 C1 [. J
  92.         count = 0;% E: [4 ?* \1 j1 \3 D
  93.         // 重开定时器0中断  c+ ?$ K1 h' O7 h2 c: C9 n
  94.         ET0 = 1;
    + K- b' J1 Y; {# J
  95. }" F. C' X& V# ^# Y4 m
  96. . R* t6 n% G; C2 Z

  97. ; t8 `( U* u' O, j8 S; H
  98. void main(){0 J: {0 i: n) f* K0 p
  99.         // 初始化P3和P5口9 r# j+ x0 j7 v1 a" Q: q
  100.         GPIO_Init();' a  S8 l5 S5 h
  101.         // 初始化定时器0
    7 i4 A) X% y4 L+ ^) J8 F5 K/ v) Z
  102.         Timer0_Init();
    0 P- d- A- u4 ?
  103.         // 初始化中断. b0 c3 l- t/ A! T
  104.         Interrupt_Init();& o) |6 s; R9 U. N; c
  105.         8 t/ A+ _2 W, e6 p: [/ @
  106.         while(1){
    ! x& b# g. v+ }1 C' H0 Z
  107.                 // 检测电量* }) T( V/ `4 l
  108.                 if(PCON & (1 << 5)){
    1 M% v7 V& ]3 q* F+ Z. D
  109.                         // 如果电量低,低压指示灯亮
    " Q8 V/ J6 K0 ]! K! o
  110.                         LED = 0;6 U; X2 V3 k. M) B" n8 ~: Y5 E
  111.                         // 清电量检测硬件标志位
    & D! N: w" Y0 V9 u  `7 o2 j
  112.                         PCON &= ~(1 << 5);
    - o5 a& D- ~! l+ G' O  {5 a
  113.                 }else{
    ! s. p3 h0 y4 n( K$ N! q) v
  114.                         // 电量正常,低压指示灯灭) q/ m& {: ]+ A' ?# M
  115.                         LED = 1;
    6 a2 k; ?5 `& i
  116.                 }
    " B$ k  R+ w/ l2 Z) Y
  117. + D" H% z- O) D0 N
  118.                 // 检测到停机标志
    0 P# U2 x, z6 s  @
  119.                 if(isReadyToHalt == 1){
    2 D. G( q9 o* [: m( b
  120.                         // 暂时关闭定时器0中断% T; i; W- F+ l5 A
  121.                         ET0 = 0;
    ' p; j# }1 `# s" J4 i# Z( ?# l) M
  122.                         // 停机之前先把矩形波输出脚置低电平,以方便INT0和INT1唤醒CPU
    0 l( l& o+ K3 a9 w4 w' B
  123.                         OUT = 0;
    $ A! q" Z4 b: U; T& }
  124.                         // 停机之前先把低压指示灯灭掉,以省电# ]: G6 q" {- B2 p' C- x7 r& C
  125.                         LED = 1;+ y# w6 A, D  x' i& B
  126.                         // 进入停机模式
    9 m/ p2 B& G8 |1 X
  127.                         PCON |= 0x02;" ^' q5 G) R9 ^" V: Y3 i
  128.                         _nop_();( `1 K% Q  N4 ]7 X
  129.                         _nop_();
    ' a" S, Q0 o& p2 `. N( Q8 Q
  130.                         _nop_();1 u# R! m; ?+ L
  131.                         _nop_();
    % V' z: b7 [5 ~5 \3 i0 R' t
  132.                         // 唤醒,清标志位
    . F/ c3 e- a- W8 H0 B8 Y  Q7 e
  133.                         isReadyToHalt = 0;/ ]; N/ t/ T- u2 H" ]3 W
  134.                         // 重开定时器0中断
    5 u" d; E% n- i, m! A$ q  ]" a
  135.                         ET0 = 1;$ l3 j& z- K/ w# I- ?( c: Y
  136.                 }  f/ t5 u% v  G0 U/ ^- i
  137.         }- X0 M1 ~7 K0 M( V
  138. }' r  ~3 f% M6 j0 U0 }( R6 t
复制代码

( Y  h$ H& H5 x. l( b, B硬件参数配置:: h2 V% E* j  O$ }7 Y! _- m4 b
% ^6 u$ @% X( @: b5 R; E
5 @( }8 f; h8 J8 D
接收端:
9 d8 i2 `' _" j3 n+ h5 \
  1. #include <INTRINS.H>
    ( v1 N1 Y; u8 c
  2. #include "STC15W.h"! |4 ?9 l) B/ x6 h4 `0 g1 o# P* t
  3.   L; d+ `/ [. f8 w/ Q, N- y9 P

  4. 2 r0 c* Q6 J' C& r) k- i
  5. /*
    ' y4 ^; |. f+ P% {/ g: y
  6. 6 s) s9 i0 d% d0 K8 j
  7. *---------------------------*+ U$ c# B* G1 l: |
  8. |1 (GPIO2)         \__/  (GPIO1)16|
    : k2 S/ Z9 m" \, J$ C3 B' D: c
  9. |                                                        |
    , ~2 e: v' {  @" L
  10. |2 (GPIO3)                   (GPIO0)15|6 ]( b# N! {# v5 }+ P* Y6 ~
  11. |                                                        |3 z, _8 p7 w" L/ k
  12. |3 (GPIO4)                                  14|
    5 e4 a! `' _: A) C6 J  P( U
  13. |                                                        |$ o- v+ r+ j. q1 G, P0 I' H
  14. |4 (GPIO5)                        (DATA)13|% m9 `$ @* O# Y* H' z: t, q
  15. |                  STC15W204S                |
    $ p% i5 l* U$ c! E6 n0 r( [
  16. |5 (GPIO6)                   (LATCH)12|
    " _' L/ ?3 R' @+ X" R% I! D, ~5 x# p
  17. |                                                        |5 k3 o. Z, s) E; d3 b. Q
  18. |6 (VCC)                         (CLK)11|4 u9 f  y2 Z6 u, L/ x5 W
  19. |                                                          |& w" X# {  J) f! X% z. x
  20. |7 (GPIO7)                         (TXD)10|3 W8 w: c* A4 @/ f0 c2 ]5 u
  21. |                                                        |
    9 t' M1 Y6 ]- d/ ?* z
  22. |8 (GND)                         (RXD) 9|4 }( s7 r( M5 J/ O* e1 k  N
  23. *---------------------------*
    ! G" m4 N3 \3 y2 ^
  24. Fosc = 12MHz
    ) }; f' ?) |0 c) L$ u% e

  25. ; K3 \+ Y" m: f3 l! d
  26. P1.0 -> 上
    - X; O/ c/ ^4 Y% u& G# j3 g6 t
  27. P1.1 -> 左) J9 b7 L6 \; L' y8 a
  28. P1.2 -> 下
    * u% R$ J$ o# }; W. T$ t
  29. P1.3 -> 右* N/ R% S* M1 J/ y5 p3 W! P; r3 m" w
  30. P1.4 -> SEL
    & [$ t( A. q2 r3 W' w# \0 X
  31. P1.5 -> STA
    ; P' L- w5 ]# g- D5 S
  32. P5.4 -> B; e6 F7 p) G& _$ z4 A0 {
  33. P5.5 -> A! |2 }& \7 f% L2 N

  34. 3 |" o  n' t) b) T% T# O5 [/ _
  35. */5 q7 |: z2 {5 w$ i' H

  36. 7 v8 k* _+ P# B  J1 x3 \$ s' R% n

  37. * q8 w4 V6 K  h. M& Y8 P
  38. sbit CLK        = P3^2;
    ; l8 E7 m: l1 f& N0 g
  39. sbit LATCH        = P3^3;8 w4 `* J/ A& t5 y' }
  40. sbit DATA        = P3^6;3 F  \6 `+ z6 a5 _

  41. $ s/ W. @5 ^8 e& k! b2 ^4 i
  42. bit isReady = 0;
    $ K% C! ]+ c6 ^% X( q
  43. static unsigned char key = 0;' A* _4 s$ G" A  q' i  y& P
  44. static unsigned char buf = 0;        // 双缓冲。这个缓冲区保存从P1和P5组合而来的键值
    , K1 c0 `7 t! Y. i
  45. static unsigned char bufReady = 0;        // 双缓冲。这个缓冲区保存上面那个缓冲区的备份
    - P4 K: F! R( u. ]1 l$ V+ {$ [
  46. static const unsigned char data mask[] = {0x80, 0x40, 0x10, 0x20, 0x01, 0x04, 0x02, 0x08};        // A B SELECT START UP DOWN LEFT RIGHT。为提升速度,这个表放到RAM中1 {6 k2 V, l5 f8 r8 h9 }
  47. static unsigned char idx = 0;
    3 q6 j, [! o7 {1 ?

  48. ) O; p6 T8 O  \/ [% P7 B4 ~
  49. ( Q" C% W/ \2 \/ ?" h) [
  50. static void GPIO_Init(){3 Y# Q  K8 l) P
  51.         // P1口和P5口用于接收并行信号,全部初始化为准双向,依靠内部弱上拉输出高电平
    7 `- E$ i  h7 Y. J6 p) D* J5 V
  52.         P1M0 = 0;
    & T9 c7 u% I2 N/ F9 _, w3 u
  53.         P1M1 = 0;
    + v* ~9 e; U& [
  54.         P1= 0xFF;
    2 d" m0 e- P, |5 E2 A/ Y
  55.         P5M0 = 0;8 I4 v7 m, s, W/ G* p! h
  56.         P5M1 = 0;2 e1 ?$ k+ Y  w4 W: F1 O" X
  57.         P5= 0xFF;
    : S7 [  h, Y8 E" F) i
  58.         // P3口初始化为准双向
    3 o0 F9 }+ J3 V& q2 T
  59.         P3M0 = 0;
    2 ~/ h" o+ p8 Z6 F4 ?) ~
  60.         P3M1 = 0;+ J5 C) b3 u5 z( H
  61.         P3 = 0xFF;
    & ^( o' |3 L. a" w" t
  62. }4 U8 r* |1 s6 Y$ r

  63. ( G/ z' \1 }. C
  64. static void Interrupt_Init(){" n4 z5 D" @! s: g' i. ]
  65.         // INT0中断(CLK)触发类型为上升沿+下降沿
    1 O3 @7 ^9 u1 ]; k+ ~8 Z# q
  66.         IT0 = 0;
    6 S9 h0 N2 n: h: Z* u  c  w3 _) J8 ^
  67.         // 允许INT0中断
    1 c3 u/ @- {$ a- F
  68.         EX0 = 1;$ Z7 W9 n. [) i2 Q
  69.         // INT1中断(LATCH)触发类型为上升沿+下降沿
    $ j" p1 l+ m; ^
  70.         IT1 = 0;
    0 |6 B% d4 z* C' B! O! H
  71.         // 允许INT1中断
    6 x4 S( k, h- ?. M+ @6 u
  72.         EX1 = 1;9 ?. Y! \& R8 G4 U
  73.         // 开启全局中断* l' W8 f$ i" m6 o
  74.         EA = 1;
    " a: e. Z: n- Q4 f  F, D7 w3 l
  75. }
    6 U; L. i% B7 H# [0 n; ~% l( l

  76. . E5 `2 y' ^5 X/ `3 o+ q' Q
  77. static void INT0_Isr() interrupt 0{) q$ f* i1 C( D, Y8 g+ ]' m
  78.         // 只有已经成功锁存才允许CLK移位+ E% p# `" ^( {- X% t2 b8 `1 K
  79.         if(isReady == 0)
    ' {) E* X% n  p9 i% f$ u% [
  80.                 return;
    # N8 X3 O0 r' ]3 F0 B
  81.         // 读当前引脚电平,如果是低电平则说明是下降沿,此时直接忽略该中断
    0 w& M7 J, R/ g8 G
  82.         if(CLK == 0)0 I& L/ f, N: X4 H
  83.                 return;
    ) ?# _  o7 H; @( `1 R. T/ j, T
  84.         // CLK上升沿到来的时候,取锁存值的下一位输出' C2 ?. Y# m% t9 t
  85.         idx++;
    4 O& a  @7 s% A, c- K' s
  86.         DATA = key & mask[idx];* ^7 b* f" c: R" d: T
  87.         // 如果已经完成7次移位,则一轮读取完成
    1 S! Z' Y; X' _' _7 c3 A+ j
  88.         if(idx >= 7)5 W$ o$ w. U& g  B4 P+ F
  89.                 isReady = 0;) h$ ?) E0 u0 ^" A4 }/ K6 r
  90. }3 G0 D% [( B% x; B* e: C9 m

  91. / j. ]% h2 c/ D$ k0 Z
  92. static void INT1_Isr() interrupt 2{7 k$ w& I) Q% D" g
  93.         // 读当前引脚电平,如果是低电平则说明是下降沿,此时直接忽略该中断
    , g( F) w/ y' o6 e) n5 F$ v  Q
  94.         if(LATCH == 0)4 J) Q0 t$ W- u
  95.                 return;; K! a3 g6 X7 C& c
  96.         // 当LATCH上升沿到来的时候,锁存所有按键状态,同时把键值A输出到DATA# A7 j0 f3 f# D% y" y6 c3 A1 |
  97.         key = bufReady;" |) i$ v" {( U/ s. ~: d3 n
  98.         DATA = key & 0x80;//mask[0];        // 为了加速运算,直接取表中的值而不是读表6 D3 o3 \) Z( Q) c
  99.         idx = 0;# m3 y9 o2 h$ c: j  Z
  100.         // 允许CLK进行移位' ^0 W" K8 z4 D. _2 b* \2 X
  101.         isReady = 1;" o- u! j& W- ]* [" W
  102. }/ j( T; L1 Y+ Z  E% A
  103. % C, G6 G8 F  D7 a
  104. void main(){
    2 a/ x% J$ q6 \  K, ?) z
  105.         GPIO_Init();
    ( C+ d+ H* R, a3 ]% j2 g4 D8 I
  106.         Interrupt_Init();
    3 D& h8 w5 h, A! t& x- }
  107.         2 [6 \# M, H6 Z! @
  108.         while(1){
    % v" V, |( o  k9 ?# J
  109.                 //PCON |= 0x01;        // 进入省电模式, m1 J% j1 T* s4 L: a& e# k
  110.                 //_nop_();
    3 n6 k' n& R  e+ y8 S. K
  111.                 //_nop_();
    * m. E/ J) X5 u: x+ ^' }* o) K3 n
  112.                 //_nop_();
    3 S' W# Y. x$ Y" \
  113.                 //_nop_();
    , m6 Q( y- s- v5 I( {% D
  114.                 buf = ~((P1 & 0x3F) | ((P5 << 2) & 0xC0));
    5 t4 G- U1 }) D7 X% n
  115.                 bufReady = buf;! O# S  ?* v$ y& h+ Y0 Q% ?
  116.         }
    7 L2 A3 ?. L# j/ j" [0 v
  117. }
    ( m: a8 M+ a& d6 W6 V  Z
复制代码
5 ^! l9 V' I9 q+ l# E; m+ z
硬件参数配置无特殊要求,晶振频率选择12M即可。
3 k: e$ F8 g$ ^2 L* w: S; a
9 g: Y/ P/ Z- J这是编译好的固件。

本帖子中包含更多资源

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

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' U" v* e0 a1 N6 k/ p
不错的设计,想问一下楼主,FC的15针公头怎么解决?普通的公头太短了,插不进去FC的扩展接口。 ...
( }7 a$ J7 q/ J  l
坛友的改造方案
回复

使用道具 举报

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

使用道具 举报

发表于 2019-5-25 12:07:18 | 显示全部楼层
精彩,楼主动手强,也写得很详细。
  J7 d0 T% J9 j- J* T) T+ C6 o4 c' p2.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
$ S$ E; q' V+ a. ~& N精彩,楼主动手强,也写得很详细。
* P( ?  E0 e8 M2.4G方案是目前无线的最低延迟吗?

( ~4 i* J# q8 S" [我没用过其他无线手柄,所以实在不知道我自己做的这个手柄到底是不是最低延迟。
& f2 i! z5 R% a: U$ V* V9 V不过根据网上的说法,延迟高低主要是由通信协议的复杂程度,以及数据传输速率决定的。这个模块虽然是2.4G无线模块,但由于协议很简单,所以延迟比较低。
& H1 R! |& P/ k' W: x: Y# _) L4 A我用这个手柄玩一些ACT游戏,比如超级马里奥、忍者龙剑传、热血系列,完全感觉不到延迟,和游戏机自带的手柄没有任何区别。唯一的区别就是这个手柄是用火花山寨手柄改造的,外壳是垃圾回收塑料,粗糙+脆弱,导电橡胶弹性不佳,手感不是一般的差。# ?! F8 w, q$ u8 f) e  I
我手里还有十几张板子,等我有空了我再做一套,到时候买一个好一点的手柄改造。
回复

使用道具 举报

 楼主| 发表于 2019-5-29 16:56:14 | 显示全部楼层
ppad 发表于 2019-5-28 17:27
7 V# ], N- F0 k- {! w" H给技术帝赞一个,有半成品发布吗,自己焊接改造就可以,编程实在不会啊 ...

6 x" {3 U* G# S/ F; t" e! V& K/ {很可惜,我手里没有多余的单片机了,LDO也找不到了,锂电池以及充电模块更是没有了。反正就是该用到的元件基本都没了,所以没法发布半成品。
  s; t# X2 M3 ~. l两个板子倒是有十几张剩余。, `7 t4 T2 L$ l4 C/ @$ ]
你要是有USB转TTL串口板,完全可以自己买这两种单片机,然后我给你编译好的固件,你自己用串口板下载到单片机里面就行了。两个2.4G无线模块也得通过串口板用AT命令设置参数,不过好在我在设计电路的时候就已经预留好了串口,可以直接在线下载和在线设置参数。总的来说并不麻烦。
回复

使用道具 举报

 楼主| 发表于 2019-5-29 17:00:34 | 显示全部楼层
孙大师 发表于 2019-5-28 18:55
$ A) I2 ^7 J$ F! l" q非常好,楼主是技术帝,到目前我都还没开发fc的无线套件,等空了,开发一套套件,等玩家自己组装。 ...
( d0 P5 K3 b- p; J
能得到孙大师的赞誉,不胜荣幸!
7 z3 F& m9 b8 X) Z' ~% h不如开发一个多功能手柄,比如用SFC手柄改造,L/R键配合其他组合键可以用来切换2P~4P、调节连发速度、软重启等各种功能。接收端插到15PIN扩展口。
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-4-20 13:11 , Processed in 0.059667 second(s), 14 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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