基于ESP32的藍牙小手柄 | 附Arduino原始碼
在B站看到了UP主皇工小毒仔的的視頻感覺很有意思,可以拿來打原神,于是把他復現了出來由于UP主并沒有開源代碼,于是我把我的代碼和UP主開源的網址一并發出供參考
皇工小毒仔的Git庫
我的Git庫
演示視頻
我的代碼是基于UP主的板子進行除錯的,有很多資料在UP主的庫里面都有提及
代碼部分
我把代碼分為了兩部分 一部分為連接電腦實作藍牙手柄按鍵的功能 另一部分UP主使用搖桿控制小車移動的功能(UP主用的是MPU6050但我買回的來MPU6050有些問題我就放棄了你們也可以嘗試一下) 你們也可以將兩個代碼合到一起通過按鍵切換 不過我沒寫 因為按鍵真的不夠用啊= =
藍牙鍵盤手柄
我想試著用這個手柄來打原神,但這樣就需要esp32同時模擬滑鼠和鍵盤,當我嘗試這樣做的時候我發現這兩個不能同時使用,所幸的是藍牙鍵盤庫和藍牙滑鼠庫的作者Github庫里的lssues區有個大佬將這兩個庫整合起來了,這個組合庫和單獨的庫我都會放進我的Git庫里面

下面我們來看代碼,此處用到的簡單定時器我也會放進我的Git庫里面的
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);//初始化波特率為115200
Keyboard.begin();// 藍牙鍵盤初始化
Mouse.begin();//藍牙滑鼠初始化
Serial.println("Starting BLE Keyboard&Mouse!");//串口列印資訊
pinMode(33, INPUT_PULLUP); //設定搖桿SW為上拉輸入模式
pinMode(34, INPUT);//搖桿34,35腳設定為輸入模式
pinMode(35, INPUT);
//此處配置按鍵為輸出模式并設為高電平
pinMode(14, OUTPUT);
digitalWrite(14, HIGH);
pinMode(25, OUTPUT);
digitalWrite(25, HIGH);
pinMode(26, OUTPUT);
digitalWrite(26, HIGH);
pinMode(27, OUTPUT);
digitalWrite(27, HIGH);
pinMode(4, OUTPUT);
digitalWrite(4, HIGH);
pinMode(19, OUTPUT);
digitalWrite(19, HIGH);
timer.setInterval(0.001L, Simple_timer_1);//設定一個簡單定時器1 1L=一毫秒
Serial.println("Init OK!");
}
setup里面打開藍牙鍵盤和滑鼠,初始化簡單定時器并打開它,因為我用的是整合庫,所以我并沒有像單獨使用鍵盤和滑鼠一樣去初始化名字電量這些,如果你想改請使用BleComboKeyboard函式,因為他的組合庫是以鍵盤形式來鏈接藍牙的,但也可以操作滑鼠,因為我修改的是.h檔案里的默認值,所以我就沒有添加這個函式
void Simple_timer_1() {
//簡單定時器1
//讀取按鍵和搖桿IO口的電平
KeyUp = digitalRead(25);
KeyDown = digitalRead(27);
KeyLeft = digitalRead(14);
KeyRight = digitalRead(26);
Key_Front_Left = digitalRead(4);
Key_Front_Right = digitalRead(19);
JoyX = analogRead(35);
JoyY = analogRead(34);
JoySW = digitalRead(33);
}
簡單定時器里面就一直讀取引腳電平,直接放到loop里面從而不使用定時器也行,但我更喜歡loop里面更少的代碼
void joy() {
//搖桿函式 進入函式執行搖桿的一系列操作 此處可以自由發揮
//判斷搖桿y軸狀態 JoyY這里定義>3500表示正推 <350表示反推
if (JoyY > 3500)
{
Mouse.move(0, -1);//Mouse.move函式控制滑鼠移動
Serial.println("joyUp");
}
else if (JoyY < 350)
{
Mouse.move(0, 1);
Serial.println("joyDown");
}
//判斷搖桿x軸狀態 JoyX這里定義>3500表示正推 <350表示反推
if (JoyX > 3500)
{
Mouse.move(-1, 0);
Serial.println("joyLeft");
}
else if (JoyX < 350)
{
Mouse.move(1, 0);
Serial.println("joyRight");
}
//判斷搖桿按鈕狀態 當按鈕被按下,讀取值為0
if (JoySW == 0) {
Genshin = 1;//切換為原神模式0w0
while (JoySW == 0) {
JoySW = digitalRead(33);
}
Serial.println("joyPress");
}
}
joy是搖桿函式此處的3500和350是通過讀取引腳的AD值得到的,每種型號的開發板讀取到的值貌似不一樣,我只試了UNO和ESP32,UNO就一直穩定在400多,當正推時會達到600多,所以就可以設定大于600時為正推,發推都為0,但esp32并不一樣,當你沒任何操作時它會穩定在2000左右,正推時可以達到4000多,于是我設定為大于3500為正推,小于350為反推
按鍵函式就不放了,大家伙都會
void loop() {
// put your main code here, to run repeatedly:
timer.run();//運行簡單定時器
if (Keyboard.isConnected()) {
//通過 Keyboard.isConnected() 來判斷ESP32是否與電腦連接成功,如果沒有連接,寫在這里面的程式是不會執行的,只有在電腦與ESP32配對連接之后,里面的程式才會執行,
// codes here...
if (Genshin == 0) {
joy();
key();
}
else if (Genshin == 1) {
joy_Genshin();
key_Genshin();
}
}
}
我就喜歡這樣的loop函式,很簡潔,Genshin是我寫的原神模式
搖桿遙控小車部分
這里我又準備了一塊esp32開發板,和小車進行連接,這兩塊esp32通過wifi模塊和ESP-NOW協議進行資料通信 這里放一下ESP-NOW協議的官網 可以去看一下
ESP-NOW
#include "WiFi.h"
void setup(){
Serial.begin(115200);
WiFi.mode(WIFI_MODE_STA);
Serial.print("MAC地址為:");
Serial.println(WiFi.macAddress());
}
void loop(){
}
通過這串代碼獲取接收板的MAC地址 使發送板能與之通信

以下代碼是發送板代碼
記錄下你的MAC地址將其填到uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};里面
// 此處為接收的ESP32的MAC地址
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
// 發送資料的結構示例
// 必須匹配接收器結構
typedef struct struct_message {
int control;
int pwm;
} struct_message;
// 創建一個名為myData的struct_message的資料結構
struct_message myData;
// 當資料發送時回呼
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
Serial.print("\r\nLast Packet Send Status:\t");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
void setup() {
Serial.begin(115200);
// 將設備設定為Wi-Fi站
WiFi.mode(WIFI_STA);
// 初始化 ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
// 一旦ESPNow成功初始化,我們將注冊Send CB來獲取發送報文的狀態
esp_now_register_send_cb(OnDataSent);
// Register peer
esp_now_peer_info_t peerInfo;
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;
// Add peer
if (esp_now_add_peer(&peerInfo) != ESP_OK) {
Serial.println("Failed to add peer");
return;
}
myData.control = 0;//0:stop 1:run 2:back 3:left 4:right
myData.pwm = 75;
pinMode(33, INPUT_PULLUP); //設定搖桿SW為上拉輸入模式
pinMode(34, INPUT);//搖桿34,35腳設定為輸入模式
pinMode(35, INPUT);
pinMode(25, OUTPUT);
digitalWrite(25, HIGH);
pinMode(27, OUTPUT);
digitalWrite(27, HIGH);
}
初始化里面很多設定函式 在官方網站里面都有講 我們會用就行
以下代碼是接受板代碼
//此處簡單定時器的作用為PWM控制小車移速
void Simple_timer_1() {
pwm = pwm + 1;
if (pwm == 255) {
digitalWrite(ENA1, HIGH);
digitalWrite(ENA2, HIGH);
pwm = 0;
}
if (pwm == myData.pwm) {
digitalWrite(ENA1, LOW);
digitalWrite(ENA2, LOW);
}
}
這里的myData.pwm是發送板發送來的資料 來進行控速
// 當接收到資料時執行的回呼函式 當接受到資料時才會運行以下函式
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
memcpy(&myData, incomingData, sizeof(myData));
if (myData.control == 0) {
car_stop();
Serial.println("stop");
} else if (myData.control == 1) {
car_run();
Serial.println("run");
} else if (myData.control == 2) {
car_back();
Serial.println("back");
} else if (myData.control == 3) {
car_left();
Serial.println("left");
} else if (myData.control == 4) {
car_right();
Serial.println("right");
}
}
這里就是通過發送板發送來的myData.control的值來判斷小車的運動
到此為止你就擁有了一個基本智能的手柄 自己拿來娛樂還是很不錯的 我再夸一句皇工小毒仔的PCB畫的真的很好 很細 我感覺很不錯很Nice 開出來是這個樣子的 不是很大 大約巴掌大小

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/400352.html
標籤:其他
