以下作品由安信可社區用戶
lazy制作
閑話
開始其實想做藍牙鍵盤的,后來順便把自拍桿功能也實現了。
雖然市面上有很多這樣的產品,但是作為 DIY 愛好者的快樂不就是折騰嗎。折騰使我快樂。
比如,剛到手的 AiPi-KVM 被我用 12V 點亮的故事
【我和小安派】故(shi)事(gu)AiPi-KVM 短暫的一生后續
后來買了一堆零件,還想著用烙鐵焊上結果焊盤都干掉了。
HID簡介
The Human Interface Device (HID) ,即人機交互設備。定義了藍牙在人機接口設備中的協議、特征和使用規程。典型的應用包括藍牙鼠標、藍牙鍵盤、藍牙游戲手柄等。該協議改編自 USB HID Protocol。
手機藍牙的 HID 是指人機接口設備。
HID 是藍牙技術中的一種協議,用于描述設備與人之間的交互接口。下面是詳細的解釋:
HID 基本含義:HID 是英文“Human Interface Devices”的縮寫,中文可以翻譯為“人機接口設備”。在藍牙技術中,HID 被廣泛應用在各種設備之間,尤其是手機與外設之間。比如,我們常常用手機的藍牙連接鼠標、鍵盤等外部設備,這時就會用到 HID 協議。
工作原理:當手機通過藍牙與另一個設備建立連接時,如果另一設備支持 HID 協議,那么手機就可以識別并與之通信。這種通信允許用戶通過這些外設設備進行更直觀、便捷的操作。比如,使用藍牙連接的鍵盤輸入文字,或者使用鼠標移動屏幕上的光標。
手機中的應用場景:在日常生活中,手機藍牙的 HID 功能經常被用于連接各種外部設備,如耳機、音箱、游戲手柄等。這使得手機的功能得到了擴展,提高了用戶的使用體驗。通過 HID 協議,這些設備可以與手機快速建立連接,并進行數據傳輸和控制。
總的來說,手機藍牙的 HID 是指人機接口設備協議,它使得手機能夠識別并與各種外部設備進行通信,提高了用戶的使用體驗和便捷性。
詳細學習參考可以下資料:
【USB 系列】自定義 USB HID 設備(bzhou830)
【小安派試玩】基于 HID 協議的 USB 鍵盤測試(iiv
(二十)零基礎開發小安派-Eyes-S1【番外篇】——BLE 基礎通訊
用 btstack 開發一個簡單的藍牙自拍桿
【低功耗藍牙】⑤ HID 協議
USB HID 報告描述符教程 - 知乎
HID 自拍原理
其實想要實現藍牙自拍功能其實比較簡單,目前市面上的手機大多都可以通過按“音量-”按鍵進行拍照。知道了這個實現起來就比較簡單了。只要我們能夠模擬點擊“音量-”按鍵就可以實現遙控拍照功能。
既然知道了拍照原理下一步我們就要開始想辦法通過 HID 實現這個功能。
前置條件
自拍桿 HID 報告描述【使用的話把# 替換換成 //】
# Report ID 1: Advanced buttons
0x05, 0x0C, # Usage Page (Consumer)
0x09, 0x01, # Usage (Consumer Control)
0xA1, 0x01, # Collection (Application)
0x85, 0x01, # Report Id (1)
0x15, 0x00, # Logical minimum (0)
0x25, 0x01, # Logical maximum (1)
0x75, 0x01, # Report Size (1)
0x95, 0x01, # Report Count (1)
0x09, 0xCD, # Usage (Play/Pause)
0x81, 0x06, # Input (Data,Value,Relative,Bit Field)
0x0A, 0x83, 0x01, # Usage (AL Consumer Control Configuration)
0x81, 0x06, # Input (Data,Value,Relative,Bit Field)
0x09, 0xB5, # Usage (Scan Next Track)
0x81, 0x06, # Input (Data,Value,Relative,Bit Field)
0x09, 0xB6, # Usage (Scan Previous Track)
0x81, 0x06, # Input (Data,Value,Relative,Bit Field)
0x09, 0xEA, # Usage (Volume Down)
0x81, 0x06, # Input (Data,Value,Relative,Bit Field)
0x09, 0xE9, # Usage (Volume Up)
0x81, 0x06, # Input (Data,Value,Relative,Bit Field)
0x0A, 0x25, 0x02, # Usage (AC Forward)
0x81, 0x06, # Input (Data,Value,Relative,Bit Field)
0x0A, 0x24, 0x02, # Usage (AC Back)
0x81, 0x06, # Input (Data,Value,Relative,Bit Field)
0xC0 # End Collection
作者:我是鵬老師 https://www.bilibili.com/read/cv15067064/
有了它我們就可以模擬手機按鍵了。
具體實現
這里藍牙部分主要參考官方的教程里面的藍牙功能
【完全開源】智能桌面助手——AiPi-DSL_Dashboard
https://bbs.ai-thinker.com/forum.php?mod=viewthread&tid=42026&fromuid=16612
資料獲取
AiPi-DSL_Dashboard 資料包地址:https://docs.ai-thinker.com/dsl
AiPi-DSL_Dashboard 資料包地址(Github): https://github.com/Ai-Thinker-Open/AiPi-Open-Kits/tree/master/AiPi-DSL_Dashboard
項目目錄結構
-BLE_HID 負責藍牙
-main 程序主入口
-wifi MQTT 接入準備
程序
main
int main(void) { …… // 保留藍牙相關任務 xTaskCreate(ble_hid_task, (char*)"ble_hid_task", 1024, NULL, 10, NULL); vTaskStartScheduler(); …… }
ble_hid_dev.c藍牙任務管理
/** * @brief HID 任務 * @param arg */ void ble_hid_task(void* arg) { // 主要是通知【lvgl】UI更新藍牙狀態的由于沒有屏幕暫時注釋以下兩行代碼 // ble_queue = xQueueCreate(1, 512); // xTaskCreate(queue_receive_ble_task, "queue_ble_task", 1024, arg, 7, NULL); vTaskDelay(200/portTICK_RATE_MS); hid_key_num_t kb_num; btblecontroller_em_config(); ble_init(); bas_init(); dis_init(0x01, 0x07AF, 0x707, 0x2A50); hog_kb_init(); ble_kb_start(); ble_hid_queue = xQueueCreate(1, 4); while (1) { xQueueReceive(ble_hid_queue, &kb_num, portMAX_DELAY); ble_hid_dev_send(kb_num); } }
ble_hid_dev.h文件中添加
typedef enum { HID_KEY_NUMBLE_NONE = 0, HID_KEY_NUMBLE_SELFIE_STICK,// 自拍桿 …… }
kb.h文件中添加
typedef enum { KEY_NUMBLE_SELFIE_STICK = 0X10, // 拍照 …… } int send_selfie_stick_value(struct bt_conn* conn, uint8_t* keyboard_cmd); // 拍照指令
修改kb.c
增加
static uint8_t report_selfie_stick_map[] = { // Report ID 1: Advanced buttons 0x05, 0x0C, // Usage Page (Consumer) 0x09, 0x01, // Usage (Consumer Control) 0xA1, 0x01, // Collection (Application) 0x85, 0x01, // Report Id (1) 0x15, 0x00, // Logical minimum (0) 0x25, 0x01, // Logical maximum (1) 0x75, 0x01, // Report Size (1) 0x95, 0x01, // Report Count (1) 0x09, 0xCD, // Usage (Play/Pause) 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) 0x0A, 0x83, 0x01, // Usage (AL Consumer Control Configuration) 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) 0x09, 0xB5, // Usage (Scan Next Track) 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) 0x09, 0xB6, // Usage (Scan Previous Track) 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) 0x09, 0xEA, // Usage (Volume Down) 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) 0x09, 0xE9, // Usage (Volume Up) 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) 0x0A, 0x25, 0x02, // Usage (AC Forward) 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) 0x0A, 0x24, 0x02, // Usage (AC Back) 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) 0xC0 // End Collection //通用按鍵 // 0x05, 0x0C, // Usage Page (Consumer) // 0x09, 0x01, // Usage (Consumer Control) // 0xA1, 0x01, // Collection (Application) // 0x85, 0x03, // Report ID (3) // 0x15, 0x00, // Logical Minimum (0) // 0x25, 0x01, // Logical Maximum (1) // 0x75, 0x01, // Report Size (1) // 0x95, 0x0B, // Report Count (11) // 0x0A, 0x23, 0x02, // Usage (AC Home) // 0x0A, 0x21, 0x02, // Usage (AC Search) // 0x0A, 0xB1, 0x01, // Usage (AL Screen Saver) // 0x09, 0xB8, // Usage (Eject) // 0x09, 0xB6, // Usage (Scan Previous Track) // 0x09, 0xCD, // Usage (Play/Pause) // 0x09, 0xB5, // Usage (Scan Next Track) // 0x09, 0xE2, // Usage (Mute) // 0x09, 0xEA, // Usage (Volume Decrement) // 0x09, 0xE9, // Usage (Volume Increment) // 0x09, 0x30, // Usage (Power) // 0x0A, 0xAE, 0x01, // Usage (AL Keyboard Layout) // 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) // 0x95, 0x01, // Report Count (1) // 0x75, 0x0D, // Report Size (13) // 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) // 0xC0, // End Collection };
經過測試以上兩套報告描述都可以拍照,內容稍有不同。
修改
static ssize_t read_report_map(struct bt_conn* conn, const struct bt_gatt_attr* attr, void* buf, uint16_t len, uint16_t offset) { printf("read_report_map:%d rn", len); // report_selfie_stick_map 這個是自拍桿報告描述 return bt_gatt_attr_read(conn, attr, buf, len, offset, report_selfie_stick_map, sizeof(report_selfie_stick_map)); }
增加
int send_selfie_stick_value(struct bt_conn* conn, uint8_t* keyboard_cmd) { struct bt_gatt_attr* attr; attr = &attrs[BT_CHAR_BLE_HID_REPORT_ATTR_VAL_INDEX]; return bt_gatt_notify(conn, attr, keyboard_cmd, 1); }
ble_hid_dev_send 方法中添加
switch (key_num) { case HID_KEY_NUMBLE_SELFIE_STICK: { key_vaule[0] = KEY_NUMBLE_SELFIE_STICK; // 0x10 // 按下音量鍵- send_selfie_stick_value(ble_conn_handle, key_vaule); vTaskDelay(100/portTICK_RATE_MS); key_vaule[0] = 0x00; // 釋放音量鍵- send_selfie_stick_value(ble_conn_handle, key_vaule); LOG_I("HID SEND: 0x10"); } break; …… }
拍照發送的指令為什么是 0x10 呢,看下面消息體信息就會理解。
0x10 表示音量-
現在消息發送搞定了,那要怎么將消息發出去,如何觸發呢
按鈕
目前最簡單的就是增加按鈕了那么如何增加按鈕呢
可以參考,以下兩張圖摘自
32 單片機基礎:GPIO 輸入
版權聲明:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接:https://blog.csdn.net/weixin_64484421/article/details/136200996
————————————————
原文鏈接:https://blog.csdn.net/weixin_64484421/article/details/136200996
兩種方式,我們一般用下接的方式。
第一個圖:注意點。當按鍵按下,PA0 接地,被置為低電平, 但是一旦按鍵松手,PA0 懸空,引腳電壓不確定。所以無論怎么讀引腳也不知道知否被按下,所以為了解決這個問題,所以必須要求 PA0 是上拉輸入的模式,這樣引腳懸空的話,就會被置為高電平,這樣我們我們就可以讀取 PA0 的電壓就知道按鍵是否被按下。
但是第二個圖就不會出現問題,按下時,被置為低電平,松手,由于上拉電阻的作用,被置為高電平。這樣引腳就不會出現浮空狀態。所以此時 PA0 可以配置浮空輸入和上拉輸入。上拉輸入,兩個電阻共同作用,這樣高電平就會更加穩定一些,
第三個圖同樣注意要使用下拉輸入模式。
這里沒有上下拉,直接使用的 Ai-M61-32SU 內部的上拉
struct bflb_device_s* btn_gpio; // 初始化gpio int btn_clicked = 0; // 按鈕檢測任務 static void btn_event(void* args){ while (1) { int status = bflb_gpio_read(btn_gpio, GPIO_PIN_14); // 檢測gpio14是否為低電平,默認上拉高電平 if(status == 0){ // 消除抖動 vTaskDelay(15/portTICK_RATE_MS); 再判斷一次 if(status == 0){ // 防止多次觸發 if(btn_clicked){ continue;; } LOG_I("點擊"); btn_clicked = 1; hid_key_num_t hid_key_num = HID_KEY_NUMBLE_SELFIE_STICK; // 發送音量-按鍵進行拍照 xQueueSend(ble_hid_queue, &hid_key_num, portMAX_DELAY); } }else{ btn_clicked = 0; } } } int main(void) { board_init(); // gpio初始化 btn_gpio = bflb_device_get_by_name("gpio"); // 默認上拉 bflb_gpio_init(btn_gpio, GPIO_PIN_14, GPIO_INPUT| GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_1); …… // 創建按鈕檢測任務 xTaskCreate(btn_event, "btn_event", 1024, NULL, 1, NULL); …… vTaskStartScheduler(); }
以上就完成了自拍桿的全部功能了。
這個就是發現的自拍桿設備藍牙名稱與外觀。
其他
這里有個有意思的地方就是可以改變藍牙的外觀圖標。HID 服務的 UUID 是 0x1812,鼠鍵的外觀是 0x03C0,鍵盤的外觀是 0x03C1,鼠標的外觀是 0x03C2,游戲手柄的外觀是 0x03C3。
想要改變藍牙設備外觀
修改 kb.h 第 10 行
#define BLE_APPEARANCE_HID_KEYBOARD 0x03C3
編譯并燒錄完成后,搜索藍牙就可以看到效果了。
源碼在文章評論區自取。目前只實現了功能,外觀上還沒設計比較丑陋暫時就不上圖了。可持續關注原貼:【DIY電子作品】Ai-M61-32SU 手機藍牙自拍桿https://bbs.ai-thinker.com/foru
審核編輯 黃宇
-
藍牙
+關注
關注
114文章
5809瀏覽量
170188 -
藍牙技術
+關注
關注
45文章
341瀏覽量
52904 -
WIFI
+關注
關注
81文章
5296瀏覽量
203571
發布評論請先 登錄
相關推薦
評論