CodexPadFrameDecoder Arduino 库 1.0.0
载入中...
搜索中...
未找到
ble_uno_or_nl_16_module.ino
浏览该文件的文档.
1/**
2 * @~Chinese
3 * @file basic_polling/ble_uno_or_nl_16_module/ble_uno_or_nl_16_module.ino
4 * @example basic_polling/ble_uno_or_nl_16_module/ble_uno_or_nl_16_module.ino
5 * @brief 演示通过基本轮询方式定期打印 CodexPad 所有按钮状态与摇杆值。
6 * @details 本示例先通过 AT 指令连接到指定的 CodexPad 设备(根据蓝牙设备地址),然后进入轮询循环。
7 * 每隔 30 毫秒,它会打印所有按钮的当前状态(按下/弹起)以及两个摇杆的原始模拟值(0‑255)。
8 * 它展示了 `button_state()` 用于离散按钮查询和 `axis_value()` 用于连续摇杆读取的基本用法。
9 * @note 本示例使用简单的定时机制(`millis()`)以固定间隔打印,适用于状态监控或日志记录。
10 * 对于实时控制应用,请确保尽可能频繁地调用 `Update()` 且无阻塞延时。
11 * @see CodexPadFrameDecoder::button_state
12 * @see CodexPadFrameDecoder::axis_value
13 * @see CodexPadFrameDecoder::Update
14 */
15/**
16 * @~English
17 * @file basic_polling/ble_uno_or_nl_16_module/ble_uno_or_nl_16_module.ino
18 * @example basic_polling/ble_uno_or_nl_16_module/ble_uno_or_nl_16_module.ino
19 * @brief The demonstration regularly prints the status of all buttons and joystick values in CodexPad using a basic polling method.
20 * @details This example first sends AT commands to connect to a designated CodexPad (by Bluetooth Device Address), then enters a simple polling loop.
21 * Every 30 milliseconds, it prints the current state of all buttons (pressed/released) and the raw analog values (0‑255) of both joysticks.
22 * It showcases the fundamental usage of `button_state()` for discrete button queries and `axis_value()` for continuous joystick readings.
23 * @note This example uses a simple timing mechanism (`millis()`) to print at a fixed interval, which is suitable for monitoring or logging.
24 * For real‑time control, ensure `Update()` is called as frequently as possible without blocking delays.
25 * @see CodexPadFrameDecoder::button_state
26 * @see CodexPadFrameDecoder::axis_value
27 * @see CodexPadFrameDecoder::Update
28 */
29
30#include <SoftwareSerial.h>
31
33
34namespace {
35// 调试串口引脚定义。
36// 将外部串口工具连接到这些引脚以查看调试输出。
37// Debug serial port pin definitions.
38// Connect external serial port tools to these pins to view debug output.
39constexpr uint8_t kDebugSerialRxPin = 6; // 调试输出接收引脚 | RX pin for debug output
40constexpr uint8_t kDebugSerialTxPin = 5; // 调试输出发送引脚 | TX pin for debug output
41
42// 替换为你的 CodexPad 的 Bluetooth device address。
43// Replace with your CodexPad device's Bluetooth device address.
44const String kBluetoothDeviceAddress = "0C:3D:5E:9D:80:99";
45
46// 与蓝牙模块通信的串口波特率(请查阅模块数据手册,替换为模块对应的波特率)。
47// The serial port baud rate for communication with the Bluetooth module (please refer to the module data manual, replace with the corresponding baud
48// rate for the module).
49constexpr uint32_t kBluetoothModuleSerialBaudRate = 115200;
50
51// 此处解码器传入的串口实例,与 Connect() 中传入的为同一个串口实例。
52// The serial instance passed in by the decoder here is the same as the one passed in Connect().
53CodexPadFrameDecoder g_codex_pad_frame_decoder(Serial);
54
55// 用于调试输出的软串口。
56// A soft serial port used for debugging output.
57SoftwareSerial g_debug_serial(kDebugSerialRxPin, kDebugSerialTxPin);
58
59/**
60 * @~Chinese
61 * @brief 向蓝牙模块发送 AT 指令以建立 BLE 连接。
62 * @details 依次发送固定的 AT 指令序列(AT+DISCON, AT+RESET, AT+ECHO=1, AT+ROLE=0, AT+CON=<地址>),
63 * 配置并连接到目标设备。
64 * @param[in] bluetooth_stream 连接蓝牙模块的 Stream 对象。
65 * 注意:此对象必须与传入 CodexPadFrameDecoder 的 Stream 是同一个实例(如 Serial),
66 * 因为解码器正是从这同一个串口读取手柄发来的数据。
67 * @param[in] bluetooth_device_address 目标设备的 MAC 地址,格式为 "XX:XX:XX:XX:XX:XX"。
68 */
69/**
70 * @~English
71 * @brief Send AT commands to the Bluetooth module to establish a BLE connection.
72 * @details Sends a fixed sequence of AT commands (AT+DISCON, AT+RESET, AT+ECHO=1, AT+ROLE=0, AT+CON=<address>)
73 * to configure and connect to the target device.
74 * @param[in] bluetooth_stream Stream connected to the Bluetooth module.
75 * Note: This must be the same Stream instance that is passed to the CodexPadFrameDecoder
76 * (e.g., Serial), as the decoder reads incoming data from this same serial port.
77 * @param[in] bluetooth_device_address MAC address of the target device in format "XX:XX:XX:XX:XX:XX".
78 */
79void Connect(Stream &bluetooth_stream, const String &bluetooth_device_address) {
80 if (bluetooth_device_address.length() != 17 || bluetooth_device_address[2] != ':' || bluetooth_device_address[5] != ':' ||
81 bluetooth_device_address[8] != ':' || bluetooth_device_address[11] != ':' || bluetooth_device_address[14] != ':') {
82 g_debug_serial.println("Error: Invalid MAC address format. Expected: XX:XX:XX:XX:XX:XX");
83 while (true);
84 }
85
86 g_debug_serial.print("Start to connect ");
87 g_debug_serial.println(kBluetoothDeviceAddress);
88
89 // 断开任何已存在的蓝牙连接,确保进入清洁状态。
90 // Disconnect any existing BLE connection to ensure a clean state.
91 bluetooth_stream.println("AT+DISCON");
92 delay(100);
93
94 // 软件复位蓝牙芯片,清除所有配对和配置数据。
95 // Software reset BLE chip, clear all pairing and configuration data.
96 bluetooth_stream.println("AT+RESET");
97 delay(100);
98
99 // 打开AT信息显示。
100 // Open AT information display.
101 bluetooth_stream.println("AT+ECHO=1");
102 delay(100);
103
104 // 设置模块为主机模式,使其能够主动连接从机蓝牙。
105 // Set the module to host mode so that it can actively connect to the BLE of the slave device.
106 bluetooth_stream.println("AT+ROLE=0");
107 delay(100);
108
109 // 使用指定的MAC地址发起与从机蓝牙连接。
110 // Initiate BLE connection with the slave using the specified MAC address.
111 bluetooth_stream.print("AT+CON=");
112 bluetooth_stream.println(bluetooth_device_address);
113 delay(100);
114
115 g_debug_serial.println("Connected");
116}
117
118} // namespace
119
120void setup() {
121 g_debug_serial.begin(115200);
122
123 Serial.begin(kBluetoothModuleSerialBaudRate);
124
125 Connect(Serial, kBluetoothDeviceAddress);
126}
127
128void loop() {
129 // 重要:Update()方法必须在循环中尽可能频繁地调用,不能添加延时。
130 // 该方法负责处理所有接收到的蓝牙数据包,延时会导致数据丢失和响应延迟。
131 // 对于实时控制应用,必须保持高频率调用以确保及时响应手柄输入。
132 // Important: Update() method must be called as frequently as possible in the loop, no delays should be added.
133 // This method processes all received Bluetooth packets, delays will cause data loss and response lag.
134 // For real-time control applications, high-frequency calls are essential to ensure prompt response to gamepad input.
135 g_codex_pad_frame_decoder.Update();
136
137 static uint32_t s_print_time = 0;
138 if (s_print_time == 0 || s_print_time + 30 < millis()) {
139 s_print_time = millis();
140
141 g_debug_serial.print("Up:");
142 g_debug_serial.print(g_codex_pad_frame_decoder.button_state(CodexPadFrameDecoder::Button::kUp));
143 g_debug_serial.print(", ");
144 g_debug_serial.print("Down:");
145 g_debug_serial.print(g_codex_pad_frame_decoder.button_state(CodexPadFrameDecoder::Button::kDown));
146 g_debug_serial.print(",");
147 g_debug_serial.print("Left:");
148 g_debug_serial.print(g_codex_pad_frame_decoder.button_state(CodexPadFrameDecoder::Button::kLeft));
149 g_debug_serial.print(", ");
150 g_debug_serial.print("Right:");
151 g_debug_serial.print(g_codex_pad_frame_decoder.button_state(CodexPadFrameDecoder::Button::kRight));
152 g_debug_serial.print(", ");
153 g_debug_serial.print("Square(X):");
154 g_debug_serial.print(g_codex_pad_frame_decoder.button_state(CodexPadFrameDecoder::Button::kSquareX));
155 g_debug_serial.print(", ");
156 g_debug_serial.print("Triangle(Y):");
157 g_debug_serial.print(g_codex_pad_frame_decoder.button_state(CodexPadFrameDecoder::Button::kTriangleY));
158 g_debug_serial.print(", ");
159 g_debug_serial.print("Cross(A):");
160 g_debug_serial.print(g_codex_pad_frame_decoder.button_state(CodexPadFrameDecoder::Button::kCrossA));
161 g_debug_serial.print(", ");
162 g_debug_serial.print("Circle(B):");
163 g_debug_serial.print(g_codex_pad_frame_decoder.button_state(CodexPadFrameDecoder::Button::kCircleB));
164 g_debug_serial.print(", ");
165 g_debug_serial.print("L1:");
166 g_debug_serial.print(g_codex_pad_frame_decoder.button_state(CodexPadFrameDecoder::Button::kL1));
167 g_debug_serial.print(", ");
168 g_debug_serial.print("L2:");
169 g_debug_serial.print(g_codex_pad_frame_decoder.button_state(CodexPadFrameDecoder::Button::kL2));
170 g_debug_serial.print(", ");
171 g_debug_serial.print("L3:");
172 g_debug_serial.print(g_codex_pad_frame_decoder.button_state(CodexPadFrameDecoder::Button::kL3));
173 g_debug_serial.print(", ");
174 g_debug_serial.print("R1:");
175 g_debug_serial.print(g_codex_pad_frame_decoder.button_state(CodexPadFrameDecoder::Button::kR1));
176 g_debug_serial.print(", ");
177 g_debug_serial.print("R2:");
178 g_debug_serial.print(g_codex_pad_frame_decoder.button_state(CodexPadFrameDecoder::Button::kR2));
179 g_debug_serial.print(", ");
180 g_debug_serial.print("R3:");
181 g_debug_serial.print(g_codex_pad_frame_decoder.button_state(CodexPadFrameDecoder::Button::kR3));
182 g_debug_serial.print(", ");
183 g_debug_serial.print("Select:");
184 g_debug_serial.print(g_codex_pad_frame_decoder.button_state(CodexPadFrameDecoder::Button::kSelect));
185 g_debug_serial.print(", ");
186 g_debug_serial.print("Start:");
187 g_debug_serial.print(g_codex_pad_frame_decoder.button_state(CodexPadFrameDecoder::Button::kStart));
188 g_debug_serial.print(", ");
189 g_debug_serial.print("Home:");
190 g_debug_serial.print(g_codex_pad_frame_decoder.button_state(CodexPadFrameDecoder::Button::kHome));
191 g_debug_serial.print(", ");
192
193 // 获取摇杆轴数据,axis_value()返回0~255的数值。
194 // 中间位置约为128,数值范围表示摇杆的偏移程度。
195 // Get joystick axis data, axis_value() returns value from 0 to 255.
196 // Center position is around 128, values represent stick deflection.
197 g_debug_serial.print("L(X:");
198 g_debug_serial.print(g_codex_pad_frame_decoder.axis_value(CodexPadFrameDecoder::Axis::kLeftStickX));
199 g_debug_serial.print(", Y:");
200 g_debug_serial.print(g_codex_pad_frame_decoder.axis_value(CodexPadFrameDecoder::Axis::kLeftStickY));
201 g_debug_serial.print("), R(X:");
202 g_debug_serial.print(g_codex_pad_frame_decoder.axis_value(CodexPadFrameDecoder::Axis::kRightStickX));
203 g_debug_serial.print(", Y:");
204 g_debug_serial.print(g_codex_pad_frame_decoder.axis_value(CodexPadFrameDecoder::Axis::kRightStickY));
205 g_debug_serial.println(")");
206 }
207}
CodexPad 手柄数据帧解码主类。