CodexPadFrameDecoder Arduino 库 1.0.0
载入中...
搜索中...
未找到
ble_uno_or_nl_16_module.ino
浏览该文件的文档.
1/**
2 * @~Chinese
3 * @file inputs_detection/ble_uno_or_nl_16_module/ble_uno_or_nl_16_module.ino
4 * @example inputs_detection/ble_uno_or_nl_16_module/ble_uno_or_nl_16_module.ino
5 * @brief 演示如何检测已连接的 CodexPad 设备的实时按钮状态与摇杆移动。
6 * @details 本示例先通过 AT 指令与指定的 CodexPad 设备建立蓝牙连接,然后持续监控所有用户输入。
7 * 它展示了三种不同的按钮状态检测: **按下** (瞬间按下)、 **释放** (瞬间释放)和 **持续按住** 。
8 * 同时,它监控模拟摇杆轴,当检测到超过设定阈值的显著变化时打印其值,从而过滤微小抖动。
9 * @note 必须在主循环中尽可能频繁地调用 `Update()` 方法,且不得添加延时,以确保实时响应性并防止数据包丢失。
10 * @see CodexPadFrameDecoder::Update
11 * @see CodexPadFrameDecoder::pressed
12 * @see CodexPadFrameDecoder::released
13 * @see CodexPadFrameDecoder::holding
14 * @see CodexPadFrameDecoder::HasAxisValueChanged
15 * @see CodexPadFrameDecoder::axis_value
16 */
17/**
18 * @~English
19 * @file inputs_detection/ble_uno_or_nl_16_module/ble_uno_or_nl_16_module.ino
20 * @example inputs_detection/ble_uno_or_nl_16_module/ble_uno_or_nl_16_module.ino
21 * @brief Demonstrate how to detect real-time button status and joystick movement of connected CodexPad devices.
22 * @details This example first sends AT commands to establish a BLE connection to a CodexPad device (by Bluetooth Device Address), then continuously
23 * monitors all user inputs. It showcases the detection of three distinct button states: **pressed** (momentary press), **released** (momentary
24 * release), and **holding** (sustained press). It also monitors the analog joystick axes and prints their values when a significant change beyond a
25 * set threshold is detected, filtering out minor jitter.
26 * @note The `Update()` method must be called as frequently as possible within the main loop without delays to ensure real‑time
27 * responsiveness and prevent data packet loss.
28 * @see CodexPadFrameDecoder::Update
29 * @see CodexPadFrameDecoder::pressed
30 * @see CodexPadFrameDecoder::released
31 * @see CodexPadFrameDecoder::holding
32 * @see CodexPadFrameDecoder::HasAxisValueChanged
33 * @see CodexPadFrameDecoder::axis_value
34 */
35
36#include <SoftwareSerial.h>
37
39
40namespace {
41// 调试串口引脚定义。
42// 将外部串口工具连接到这些引脚以查看调试输出。
43// Debug serial port pin definitions.
44// Connect external serial port tools to these pins to view debug output.
45constexpr uint8_t kDebugSerialRxPin = 6; // 调试输出接收引脚 | RX pin for debug output
46constexpr uint8_t kDebugSerialTxPin = 5; // 调试输出发送引脚 | TX pin for debug output
47
48// 摇杆轴变化检测的阈值。当前值与上一帧值的绝对差值达到此值(或到达边界0/255)时才被视为有效变化,用于过滤微小抖动。
49// Threshold for joystick axis change detection. Only when the absolute difference between the current and previous axis value reaches this value
50// (or the value hits boundaries 0/255) will it be reported as a significant change.
51constexpr uint8_t kAxisThreshold = 2;
52
53// 替换为你的 CodexPad 的 Bluetooth device address。
54// Replace with your CodexPad device's Bluetooth device address.
55const String kBluetoothDeviceAddress = "0C:3D:5E:9D:80:99";
56
57// 与蓝牙模块通信的串口波特率(请查阅模块数据手册,替换为模块对应的波特率)。
58// The serial port baud rate for communication with the Bluetooth module (please refer to the module data manual, replace with the corresponding baud
59// rate for the module).
60constexpr uint32_t kBluetoothModuleSerialBaudRate = 115200;
61
79
80// 用于调试输出的软串口。
81// A soft serial port used for debugging output.
82SoftwareSerial g_debug_serial(kDebugSerialRxPin, kDebugSerialTxPin);
83
84// 此处解码器传入的串口实例,与 Connect() 中传入的为同一个串口实例。
85// The serial instance passed in by the decoder here is the same as the one passed in Connect().
86CodexPadFrameDecoder g_codex_pad_frame_decoder(Serial);
87
88/**
89 * 将按钮枚举值转换为可读的字符串。
90 * Convert a Button enumeration value to a human-readable string.
91 */
92const String ButtonToString(CodexPadFrameDecoder::Button button) {
93 switch (button) {
95 return "Up"; // 上按钮 | UP button
96 }
98 return "Down"; // 下按钮 | DOWN button
99 }
101 return "Left"; // 左按钮 | LEFT button
102 }
104 return "Right"; // 右按钮 | RIGHT button
105 }
107 return "Square(X)"; // 方形 或者 X 按钮 | SQUARE or X button
108 }
110 return "Triangle(Y)"; // 三角 或者 Y 按钮 | TRIANGLE or Y button
111 }
113 return "Cross(A)"; // 叉形 或者 A 按钮 | CROSS or A button
114 }
116 return "Circle(B)"; // 圆形 或者 B 按钮 | CIRCLE or B button
117 }
119 return "L1"; // L1按钮 | L1 button
120 }
122 return "L2"; // L2按钮 | L2 button
123 }
125 return "L3"; // L3按钮 | L3 button
126 }
128 return "R1"; // R1按钮 | R1 button
129 }
131 return "R2"; // R2按钮 | R2 button
132 }
134 return "R3"; // R3按钮 | R3 button
135 }
137 return "Select"; // 选择按钮 | SELECT button
138 }
140 return "Start"; // 开始按钮 | START button
141 }
143 return "Home"; // 首页按钮 | HOME button
144 }
145 default: {
146 return {}; // 未知按钮返回空字符串 | Unknown button returns empty string
147 }
148 }
149}
150
151/**
152 * @~Chinese
153 * @brief 向蓝牙模块发送 AT 指令以建立 BLE 连接。
154 * @details 依次发送固定的 AT 指令序列(AT+DISCON, AT+RESET, AT+ECHO=1, AT+ROLE=0, AT+CON=<地址>),
155 * 配置并连接到目标设备。
156 * @param[in] bluetooth_stream 连接蓝牙模块的 Stream 对象。
157 * 注意:此对象必须与传入 CodexPadFrameDecoder 的 Stream 是同一个实例(如 Serial),
158 * 因为解码器正是从这同一个串口读取手柄发来的数据。
159 * @param[in] bluetooth_device_address 目标设备的 MAC 地址,格式为 "XX:XX:XX:XX:XX:XX"。
160 */
161/**
162 * @~English
163 * @brief Send AT commands to the Bluetooth module to establish a BLE connection.
164 * @details Sends a fixed sequence of AT commands (AT+DISCON, AT+RESET, AT+ECHO=1, AT+ROLE=0, AT+CON=<address>)
165 * to configure and connect to the target device.
166 * @param[in] bluetooth_stream Stream connected to the Bluetooth module.
167 * Note: This must be the same Stream instance that is passed to the CodexPadFrameDecoder
168 * (e.g., Serial), as the decoder reads incoming data from this same serial port.
169 * @param[in] bluetooth_device_address MAC address of the target device in format "XX:XX:XX:XX:XX:XX".
170 */
171void Connect(Stream &bluetooth_stream, const String &bluetooth_device_address) {
172 if (bluetooth_device_address.length() != 17 || bluetooth_device_address[2] != ':' || bluetooth_device_address[5] != ':' ||
173 bluetooth_device_address[8] != ':' || bluetooth_device_address[11] != ':' || bluetooth_device_address[14] != ':') {
174 g_debug_serial.println("Error: Invalid MAC address format. Expected: XX:XX:XX:XX:XX:XX");
175 while (true);
176 }
177
178 g_debug_serial.print("Start to connect ");
179 g_debug_serial.println(kBluetoothDeviceAddress);
180
181 // 断开任何已存在的蓝牙连接,确保进入清洁状态。
182 // Disconnect any existing BLE connection to ensure a clean state.
183 bluetooth_stream.println("AT+DISCON");
184 delay(100);
185
186 // 软件复位蓝牙芯片,清除所有配对和配置数据。
187 // Software reset BLE chip, clear all pairing and configuration data.
188 bluetooth_stream.println("AT+RESET");
189 delay(100);
190
191 // 打开AT信息显示。
192 // Open AT information display.
193 bluetooth_stream.println("AT+ECHO=1");
194 delay(100);
195
196 // 设置模块为主机模式,使其能够主动连接从机蓝牙。
197 // Set the module to host mode so that it can actively connect to the BLE of the slave device.
198 bluetooth_stream.println("AT+ROLE=0");
199 delay(100);
200
201 // 使用指定的MAC地址发起与从机蓝牙连接。
202 // Initiate BLE connection with the slave using the specified MAC address.
203 bluetooth_stream.print("AT+CON=");
204 bluetooth_stream.println(bluetooth_device_address);
205 delay(100);
206
207 g_debug_serial.println("Connected");
208}
209} // namespace
210
211void setup() {
212 g_debug_serial.begin(115200);
213
214 Serial.begin(kBluetoothModuleSerialBaudRate);
215
216 Connect(Serial, kBluetoothDeviceAddress);
217}
218
219void loop() {
220 // 重要:Update()方法必须在循环中尽可能频繁地调用,不能添加延时。
221 // 该方法负责处理所有接收到的蓝牙数据包,延时会导致数据丢失和响应延迟。
222 // 对于实时控制应用,必须保持高频率调用以确保及时响应手柄输入。
223 // Important: Update() method must be called as frequently as possible in the loop, no delays should be added.
224 // This method processes all received Bluetooth packets, delays will cause data loss and response lag.
225 // For real-time control applications, high-frequency calls are essential to ensure prompt response to gamepad input.
226 g_codex_pad_frame_decoder.Update();
227
228 for (auto button : kAllButtons) {
229 // 检测按钮是否刚刚按下(从弹起变为按下)。
230 // Check if button was just pressed (transition from released to pressed).
231 if (g_codex_pad_frame_decoder.pressed(button)) {
232 g_debug_serial.print("Button ");
233 g_debug_serial.print(ButtonToString(button));
234 g_debug_serial.println(": pressed");
235 }
236
237 // 检测按钮是否刚刚释放(从按下变为弹起)。
238 // Check if button was just released (transition from pressed to released).
239 else if (g_codex_pad_frame_decoder.released(button)) {
240 g_debug_serial.print("Button ");
241 g_debug_serial.print(ButtonToString(button));
242 g_debug_serial.println(": released");
243 }
244
245 // 检测按钮是否持续按下状态。
246 // Check if button is holding.
247 else if (g_codex_pad_frame_decoder.holding(button)) {
248 g_debug_serial.print("Button ");
249 g_debug_serial.print(ButtonToString(button));
250 g_debug_serial.println(": holding");
251 }
252 }
253
254 // 检测左右两个摇杆的X轴或Y轴是否有显著变化。
255 // Check if left and right sticks X or Y axes have significant changes.
256 if (g_codex_pad_frame_decoder.HasAxisValueChanged(CodexPadFrameDecoder::Axis::kLeftStickX, kAxisThreshold) ||
257 g_codex_pad_frame_decoder.HasAxisValueChanged(CodexPadFrameDecoder::Axis::kLeftStickY, kAxisThreshold) ||
258 g_codex_pad_frame_decoder.HasAxisValueChanged(CodexPadFrameDecoder::Axis::kRightStickX, kAxisThreshold) ||
259 g_codex_pad_frame_decoder.HasAxisValueChanged(CodexPadFrameDecoder::Axis::kRightStickY, kAxisThreshold)) {
260 // 打印摇杆轴的当前值(0-255)。
261 // Print current joystick axis values (0-255).
262 g_debug_serial.print("L(X:");
263 g_debug_serial.print(
264 g_codex_pad_frame_decoder.axis_value(CodexPadFrameDecoder::Axis::kLeftStickX)); // 左摇杆X轴当前值 | Left stick X axis current value
265 g_debug_serial.print(", Y:");
266 g_debug_serial.print(
267 g_codex_pad_frame_decoder.axis_value(CodexPadFrameDecoder::Axis::kLeftStickY)); // 左摇杆Y轴当前值 | Left stick Y axis current value
268 g_debug_serial.print("), R(X:");
269 g_debug_serial.print(
270 g_codex_pad_frame_decoder.axis_value(CodexPadFrameDecoder::Axis::kRightStickX)); // 右摇杆X轴当前值 | Right stick X axis current value
271 g_debug_serial.print(", Y:");
272 g_debug_serial.print(
273 g_codex_pad_frame_decoder.axis_value(CodexPadFrameDecoder::Axis::kRightStickY)); // 右摇杆Y轴当前值 | Right stick Y axis current value
274 g_debug_serial.println(")");
275 }
276}
CodexPad 手柄数据帧解码主类。
Button
手柄按键掩码枚举。