0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

用M61系列模块做一个手机蓝牙自拍杆?

AIoT行业洞察 来源:AIoT行业洞察 作者:AIoT行业洞察 2024-10-25 13:49 次阅读

以下作品由安信可社区用户

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

wKgZoWcbMU2AGaqUAAA5Vcvzij0641.jpg

项目目录结构

-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 呢,看下面消息体信息就会理解。

wKgaoWcbMU6Ac81QAAAgI97LFq8725.jpg

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

wKgZoWcbMU-ANesyAABezQqBXgM676.jpg

wKgaoWcbMU-Ad3SaAACNOlqQJvc229.jpg

两种方式,我们一般用下接的方式。

第一个图:注意点。当按键按下,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(); }

以上就完成了自拍杆的全部功能了。

wKgZoWcbMVCAbh7NAAAIfKTsQnc894.jpg

这个就是发现的自拍杆设备蓝牙名称与外观。

其他

这里有个有意思的地方就是可以改变蓝牙的外观图标。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

    文章

    5742

    浏览量

    169466
  • 蓝牙技术
    +关注

    关注

    44

    文章

    338

    浏览量

    52810
  • WIFI
    +关注

    关注

    81

    文章

    5274

    浏览量

    202966
收藏 人收藏

    评论

    相关推荐

    自拍撬动蓝牙世界的神经

    在这里我们不详细讨论蓝牙芯片的那些事情,只是从很小很不起眼的自拍中发现了了不起的现象,那就是:
    发表于 04-18 17:26 2029次阅读

    M61模组做一个红外空调遥控器

    管的亮灭来承载编码信息,对应的空调设备上有接收管,它接收到发射管的光信号来解析协议获取数据,然后对空调进行对应指令的控制 例如:将温度设置为 16° 冷风 风速 1 级 既然要控制灯的亮灭,那么就只需要
    的头像 发表于 08-23 08:58 997次阅读
    <b class='flag-5'>用</b> <b class='flag-5'>M61</b>模组<b class='flag-5'>做一个</b>红外空调遥控器

    自拍不再困难 Stikbox手机壳变身自拍

    【路之遥电子网】无论你多么支持自拍,你都难以抵抗这件酷炫的集合自拍手机壳和支架为体的
    发表于 12-21 15:05

    低功耗蓝牙自拍芯片:st17h29 正反回连功能

    ,任何特殊应用拍照器类产品。[/tr]注:带正反回连功能,首次连接,自拍开机,在手机设置/蓝牙/打开搜索蓝牙设备/点击连接。首次连接成功,
    发表于 06-02 16:14

    灵动微电子 | MM32W无线MCU系列产品应用笔记 —— 蓝牙自拍方案

    蓝牙产品的应用方案,基于MM32W系列开发的蓝牙自拍
    发表于 01-13 19:17

    基于蓝牙技术的自拍设计

    的场景、方便人们的生活。硬件资源:本方案基于MM32 BLE_Test Board进行测试验证,蓝牙自拍应用在硬件上只需要功能按键即可
    发表于 11-26 06:48

    基于嵌入式芯片的自拍神器自拍

    相当于是只有按键的蓝牙键盘,这个按键对应手机上的音量增大键(位于
    发表于 10-27 17:07

    使用 MSPM0 MCU 设计单轴和三轴自拍

    驱动或三电机以产生反向移动,用于抵消手机屏幕的振动并在拍摄照片或视频时使手机稳定。为了在云台或自拍
    发表于 04-12 14:02

    【沁恒 CH32V208 开发板免费试用】改进的蓝牙自拍

    拍照功能,而蓝牙自拍就是利用了这特性,将自拍的遥控器以
    发表于 04-29 22:48

    TCL 飞利浦超级SMT M61机芯电路图

    TCL SMT M61彩电电路图TCL SMT M61彩色电视机电路图,TCL SMT M61彩电图纸,TCL SMT M61原理图。
    发表于 05-06 14:40 35次下载
    TCL 飞利浦超级SMT <b class='flag-5'>M61</b>机芯电路图

    无线MCU系列蓝牙自拍应用方案的详细介绍

    的场景、方便人们的生活。 硬件资源: 本方案基于MM32 BLE_Test Board进行测试验证,蓝牙自拍应用在硬件上只需要功能按键
    发表于 01-20 14:40 2227次阅读

    灵动微MM32W无线MCU系列蓝牙自拍应用方案

    的场景、方便人们的生活。硬件资源:本方案基于MM32 BLE_Test Board进行测试验证,蓝牙自拍应用在硬件上只需要功能按键即可
    发表于 11-18 17:36 11次下载
    灵动微MM32W无线MCU<b class='flag-5'>系列</b><b class='flag-5'>蓝牙</b><b class='flag-5'>自拍</b><b class='flag-5'>杆</b>应用方案

    MM32W无线MCU系列产品应用笔记 —— 蓝牙自拍方案

    在前面章中我们已经详细介绍了我们基于MM32W系列开发的智能灯控方案,在本章节我们将介绍款大家生活中很常见的
    发表于 02-09 12:08 5次下载
    MM32W无线MCU<b class='flag-5'>系列</b>产品应用笔记 —— <b class='flag-5'>蓝牙</b><b class='flag-5'>自拍</b><b class='flag-5'>杆</b>方案

    Ai-M61-32S开发板能玩出多少拓展板?

    时间过的真快,眨眼间楼主玩M61这个模组已经有一个多月了,学习的同时结交了很多不讲武德志同道合的朋友,从最开始刚接触的点灯到慢慢尝试上手用M61驱动各种电子模块,深感还要学习很多。
    的头像 发表于 11-13 10:29 403次阅读
    <b class='flag-5'>用</b>Ai-<b class='flag-5'>M61</b>-32S开发板能玩出多少拓展板?

    DIY案例:Ai-M61-32S做一个多功能书桌灯

    这个书桌灯可以通过Ai-M61-32S联网实时显示时间,通过dht11温湿度模块显示温湿度,同时具备抽拉式手机支架,可以将手机放在上面,同时可以通过
    的头像 发表于 01-25 15:05 521次阅读
    DIY案例:<b class='flag-5'>用</b>Ai-<b class='flag-5'>M61</b>-32S<b class='flag-5'>做一个</b>多功能书桌灯