双轴摇杆模块接Arduino:SW按键加X/Y读数与方向判定

2026-11-16 07:21:56 13阅读

家里翻出一个游戏手柄拆下来的双轴摇杆模块,就是那种几块钱一个、五个引脚的小板子,KY-023 这类。很多新手看它引脚多就不敢碰,其实它是入门 Arduino 模拟量输入最划算的器件之一:两个电位器加一个按键,就能把"手往哪边掰"变成单片机能读的数字。这次我把 arduinogetstarted.com 上的摇杆教程完整理了一遍,把新手会卡的地方都标出来,照着做一遍基本十分钟就能在串口监视器里看到数据跑起来。

双轴摇杆模块接Arduino

先说这模块能干什么。最直接的用法是给遥控小车当方向输入:X 轴管左右转向,Y 轴管前进后退,中间那个按下当喇叭或者模式切换。再进阶一点,两个轴还能映射成角度去控云台上的两个舵机。学会读它,等于打开了模拟量输入这扇门。

五个引脚各管什么

摇杆模块一共五个引脚,见下面的引脚图。GND 接地,+5V 接电源(有的板子丝印是 VCC,一个意思),剩下三个是输出:VRX 输出水平位置的模拟值,VRY 输出垂直位置的模拟值,SW 是里面那个按压按键的输出。

摇杆模块引脚图

关键点是 VRX 和 VRY 这两个。摇杆内部是两个互相垂直安装的电位器,掰动摇杆就是在同时转两个电位器。Arduino 用 analogRead 读模拟引脚,得到 0 到 1023 的数值——摇杆在中间松手不动时,读数大约在 500 上下;推到最左边 VRX 趋近 0,推到最右边趋近 1023,Y 轴同理。

SW 按键要注意:它本身是常开的,模块上一般不带上拉电阻,所以要把 SW 引脚设成 INPUT_PULLUP 模式,或者外接上拉电阻。这样不按时读 HIGH,按下读 LOW。新手最常见的坑就是这里——没上拉,引脚悬空,读出来的值乱跳,还以为模块坏了。

接线:五根杜邦线搞定

接线很简单,照下面的接线图来:GND 对 GND,+5V 对 5V,VRX 接 A1,VRY 接 A0,SW 接 D2。模拟脚随便挑 A0 到 A5 都行,代码里改一下宏定义就好;SW 接 D2 是因为后面代码用数字脚读它。

摇杆与Arduino Uno接线图

如果是长期跑的项目,或者要装进小车壳子里,杜邦线容易松。官方教程里推荐了 Screw Shield V2 这种螺丝端子扩展板,直接叠在 Arduino 上,每个引脚变成一个螺丝接线柱,线拧进去就跑不掉了。下面的图就是用了螺丝端子板之后的接法,看着乱但每根都拧得很牢。

使用螺丝端子扩展板的摇杆接线

第一步:先把 X/Y 读数跑起来

别急着写方向判定,第一步永远是"把原始读数打到串口看"。下面这段代码从教程原文逐字符搬过来,就是不停地读 A1 和 A0,然后打印。代码里的 VRX_PIN 定义成 A1、VRY_PIN 定义成 A0,和你接的线要一一对应,接反了只是 X 和 Y 互换,不算错,但方向判定时会把你绕晕。

/*
 * Created by ArduinoGetStarted.com
 *
 * This example code is in the public domain
 *
 * Tutorial page: https://arduinogetstarted.com/tutorials/arduino-joystick
 */

#define VRX_PIN  A1 // Arduino pin connected to VRX pin
#define VRY_PIN  A0 // Arduino pin connected to VRY pin

int xValue = 0; // To store value of the X axis
int yValue = 0; // To store value of the Y axis

void setup() {
  Serial.begin(9600) ;
}

void loop() {
  // read analog X and Y analog values
  xValue = analogRead(VRX_PIN);
  yValue = analogRead(VRY_PIN);

  // print data to Serial Monitor on Arduino IDE
  Serial.print("x = ");
  Serial.print(xValue);
  Serial.print(", y = ");
  Serial.println(yValue);
  delay(200);
}

烧录后打开串口监视器(波特率 9600),把摇杆推到极限画圈。记住官方教程给的一个小窍门:X 读到 0 的那个位置就是"左",对面就是"右";Y 读到 0 的位置是"上",对面是"下"。不同厂家的模块中位值和方向可能不一样,所以这一步是在给你的模块"定方向",别跳过。

第二步:把 SW 按键也读上

按键部分官方用了 ezButton 库,这个库自带消抖,还能省掉手动上拉的很多细节。装库就在 Arduino IDE 左侧库管理器里搜 ezButton,作者是 ArduinoGetStarted.com,装上就行。按键接在 D2。

照例说明一下:原代码里头文件写的是尖括号引用,我们平台会把尖括号吃掉,所以下面贴成了等价的双引号写法,在 Arduino IDE 里编译效果一样。代码其余部分逐字符未动。

/*
 * Created by ArduinoGetStarted.com
 *
 * This example code is in the public domain
 *
 * Tutorial page: https://arduinogetstarted.com/tutorials/arduino-joystick
 */

#include "ezButton.h"

#define VRX_PIN  A1 // Arduino pin connected to VRX pin
#define VRY_PIN  A0 // Arduino pin connected to VRY pin
#define SW_PIN   2  // Arduino pin connected to SW  pin

ezButton button(SW_PIN);

int xValue = 0; // To store value of the X axis
int yValue = 0; // To store value of the Y axis
int bValue = 0; // To store value of the button

void setup() {
  Serial.begin(9600) ;
  button.setDebounceTime(50); // set debounce time to 50 milliseconds
}

void loop() {
  button.loop(); // MUST call the loop() function first

  // read analog X and Y analog values
  xValue = analogRead(VRX_PIN);
  yValue = analogRead(VRY_PIN);

  // Read the button value
  bValue = button.getState();

  if (button.isPressed()) {
    Serial.println("The button is pressed");
    // TODO do something here
  }

  if (button.isReleased()) {
    Serial.println("The button is released");
    // TODO do something here
  }

  // print data to Serial Monitor on Arduino IDE
  Serial.print("x = ");
  Serial.print(xValue);
  Serial.print(", y = ");
  Serial.print(yValue);
  Serial.print(" : button = ");
  Serial.println(bValue);
}

有个细节值得划重点:loop 里必须先调 button.loop(),再读状态。我看过好几个新手卡在这里——把 button.loop() 忘了或者放在最后,结果 isPressed 永远不触发。消抖时间设的 50 毫秒,按起来手感正常;如果你的模块按键特别灵或者特别肉,可以微调这个值。

第三步:从读数变成方向命令

有了原始读数,下一步是把它变成"命令"。教程的思路是设阈值:X 小于 400 判为左,大于 800 判为右;Y 同理。四个方向用四个位标志(0x01、0x02、0x04、0x08),这样摇杆斜推时可以同时带上两个方向,比如左上。中间区域 400 到 800 之间算死区,手轻碰不会误触发。

/*
 * Created by ArduinoGetStarted.com
 *
 * This example code is in the public domain
 *
 * Tutorial page: https://arduinogetstarted.com/tutorials/arduino-joystick
 */

#define VRX_PIN  A1 // Arduino pin connected to VRX pin
#define VRY_PIN  A0 // Arduino pin connected to VRY pin

#define LEFT_THRESHOLD  400
#define RIGHT_THRESHOLD 800
#define UP_THRESHOLD    400
#define DOWN_THRESHOLD  800

#define COMMAND_NO     0x00
#define COMMAND_LEFT   0x01
#define COMMAND_RIGHT  0x02
#define COMMAND_UP     0x04
#define COMMAND_DOWN   0x08

int xValue = 0 ; // To store value of the X axis
int yValue = 0 ; // To store value of the Y axis
int command = COMMAND_NO;

void setup() {
  Serial.begin(9600) ;
}

void loop() {
  // read analog X and Y analog values
  xValue = analogRead(VRX_PIN);
  yValue = analogRead(VRY_PIN);

  // converts the analog value to commands
  // reset commands
  command = COMMAND_NO;

  // check left/right commands
  if (xValue < LEFT_THRESHOLD)
    command = command | COMMAND_LEFT;
  else if (xValue > RIGHT_THRESHOLD)
    command = command | COMMAND_RIGHT;

  // check up/down commands
  if (yValue < UP_THRESHOLD)
    command = command | COMMAND_UP;
  else if (yValue > DOWN_THRESHOLD)
    command = command | COMMAND_DOWN;

  // NOTE: AT A TIME, THERE MAY BE NO COMMAND, ONE COMMAND OR TWO COMMANDS

  // print command to serial and process command
  if (command & COMMAND_LEFT) {
    Serial.println("COMMAND LEFT");
    // TODO: add your task here
  }

  if (command & COMMAND_RIGHT) {
    Serial.println("COMMAND RIGHT");
    // TODO: add your task here
  }

  if (command & COMMAND_UP) {
    Serial.println("COMMAND UP");
    // TODO: add your task here
  }

  if (command & COMMAND_DOWN) {
    Serial.println("COMMAND DOWN");
    // TODO: add your task here
  }
}

烧进去之后推摇杆,串口里就该出现 SEND: LEFT 这类字样了。代码注释里官方也提醒了:每个摇杆的电阻不一样,阈值要按你手上这只微调。如果你的模块中位明显不是 500 左右,比如是 480 或者 520,就照着实测值把上下阈值整体平移一下。

往遥控小车上搬的思路

拿到 LEFT/RIGHT/UP/DOWN 命令之后,控小车就只是"命令到动作"的翻译题。常见做法是:接收端用一块 Arduino 加电机驱动模块(L298N、TB6612 这类都行),发射端把命令字符从串口或者蓝牙模块发过去。UP 时两个电机同向正转,DOWN 反转,LEFT/RIGHT 让左右轮差速。斜推时 command 是两个位标志的组合,正好对应"边走边拐"。

如果想做得细腻一点,不用阈值开关,而是把 0 到 1023 的读数用 map() 映射到 PWM 占空比,推得越多跑得越快,手感跟真遥控器一样。再往上一个层级,是把两个轴映射成两个舵机的角度,官方那篇 Joystick controls Servo Motor 就是这么做的,做云台正好用得上。

最后提醒几个新手常踩的点:一是中位不归零,松手后读数停在 490 或 530 都正常,别追求正好 512;二是 A0/A1 接反导致左右上下颠倒,改宏定义比改线快;三是 SW 别忘了上拉;四是主循环里别放长 delay,delay 太长会吃掉按键事件, ezButton 的 loop 调用频率跟不上就会漏按。把这几处避开,摇杆这块基本一次点亮。


作者:隔壁老王的教程
链接:https://www.aiddithome.com/p/1ff18711aab256.html
本作版权归作者所有,未经允许请勿转载。若存在违规行为,您可以点击 “举报”。


登录 后发表评论
4条评论
只看不说话
1楼 · 22分钟前

map()映射PWM那招做遥控车确实爽,推多少跑多少,比纯开关阈值手感好一个档次

刷视频进来围观
2楼 · 22分钟前

螺丝端子扩展板这个建议不错,我小车上的杜邦线跑两圈就接触不良,早该换

触底反弹的Tony
3楼 · 22分钟前

这篇把『先读数再定方向』的顺序讲得很对。我第一次玩摇杆就是跳过了画圈标方向那步,直接写判断,结果左右上下全反了,调了一晚上才反应过来是模块中位和官方示例不一样。另外 ezButton 那个 loop 必须先调的坑确实存在,我漏过,按键就是不触发,最后翻文档才看到那句 MUST call。

锡点
4楼 · 22分钟前

A0 A1接反这个太真实了,我也是宏定义改的,比拔线快多了