本帖最后由 sujingliang 于 2024-11-24 19:15 编辑
M61模块的核心BL618确实支持传统蓝牙功能,然而,由于博流官方(BL618芯片制造商)尚未正式发布针对这一功能的SDK,开发者在使用M61进行传统蓝牙开发时面临诸多挑战。GitHub上虽然可以找到博流官方的SDK,但其中关于传统蓝牙的代码非常有限,且基于Zephyr蓝牙栈的官方代码缺乏具体的例程,这无疑增加了开发的难度。
一、论坛里有大佬实现了BTstack port,参见:
使用BTstack测试M61
https://bbs.ai-thinker.com/forum.php?mod=viewthread&tid=44962&fromuid=14007
(出处: 物联网开发者社区-安信可论坛)
也就是说可以用BTstack开源协议栈来开发M61模块传统蓝牙功能。
二、本文想实现的蓝牙歌词播放功能可参见:
看到有蓝牙歌词播放器在卖,感觉很神奇,用ESP32实现一下
https://bbs.21ic.com/icview-3414880-1-1.html?fromuser=sujingliang
(出处: 21ic电子技术开发论坛)
为了达到目标,需要完成以下工作:
1、驱动一个屏幕,可以是LED、LCD,这个决定最终的显示效果。
2、需要一个GBK汉字字模库,用来获取显示汉字。
3、需要一个UTF转GBK的函数,因为AVRCP是UTF-8格式的,需要转换成GBK格式才能通过GBK汉字字模库获取字模。
4、读懂A2DP例程,加入适当的功能。(btstack编程)
三、关于LCD驱动和字库驱动,不是本重点,请参见:
【外设移植】+LCD_ST7735+M61开发板+GB2312字库
https://bbs.ai-thinker.com/forum.php?mod=viewthread&tid=44421&fromuid=14007
(出处: 物联网开发者社区-安信可论坛)
四、关于UTF转GBK的函数
UTF汉字不能直接转换为GBK,需要先将UTF转换为unicode,再将unicode通过查表法转换为GBK。
这部分不用自己实现,网上有现成的。https://gitee.com/zhangkt1995/my ... /utf8_gb2312_switch
五、btstack编程
可参考前面大佬提供的btstack_test工程:
- git clone https://github.com/bouffalolab/bouffalo_sdk.git
- cd ./bouffalo_sdk/examples
- git clone https://github.com/O2C14/btstack_test.git
- cd ./btstack_test
- rm -rf ./btstack
- git clone https://github.com/bluekitchen/btstack.git -b v1.6.1
复制代码 在CMakeLists.txt中设置使用a2dp_sink_demo.c这个例子
- set(EXAMPLE "a2dp_sink_demo")
复制代码 a2dp_sink_demo.c中在 case AVRCP_SUBEVENT_NOW_PLAYING_TITLE_INFO:增加如下内容
- case AVRCP_SUBEVENT_NOW_PLAYING_TITLE_INFO:
- if (avrcp_subevent_now_playing_title_info_get_value_len(packet) > 0){
- memcpy(avrcp_subevent_value, avrcp_subevent_now_playing_title_info_get_value(packet), avrcp_subevent_now_playing_title_info_get_value_len(packet));
- printf("AVRCP Controller: Title %s\n", avrcp_subevent_value);
-
- memset(gb2312Data,'\0',sizeof(gb2312Data));
- size_t gb2312DataLen = utf8_to_gb2312((uint8_t *)avrcp_subevent_value, strlen(avrcp_subevent_value), (uint8_t *)gb2312Data, sizeof(gb2312Data));
-
-
- if(gb2312DataLen>0){
- if(gb2312DataLen<256)gb2312Data[gb2312DataLen]='\0';
- gb2312Data[64]='\0';
- printf("%s,len:%d\r\n",gb2312Data,strlen(gb2312Data));
- GUI_Write16CnCharMatrix(10,10,gb2312Data,LCD_COLOR_RGB565(255,255,255),LCD_COLOR_RGB565(255,0,0));
- }
-
- }
- break;
复制代码 大概意思就在AVRCP收到TITLE事件后,获取title(歌词)信息avrcp_subevent_value;通过utf8_to_gb2312将utf8格式转为GB2312格式;然后在LCD上显示出来。
AVRCP_SUBEVENT_NOTIFICATION_TRACK_CHANGED中增加对avrcp_controller_get_now_playing_info的调用,就是在TRACK发生改变时调用获取playing_info函数,进而触发AVRCP_SUBEVENT_NOW_PLAYING_TITLE_INFO。
- case AVRCP_SUBEVENT_NOTIFICATION_TRACK_CHANGED:
- printf("AVRCP Controller: Track changed\n");
- //Track changed
- avrcp_controller_get_now_playing_info(a2dp_sink_demo_avrcp_connection.avrcp_cid);
- break;
复制代码
六、使用
1、手机打开蓝牙,和M61配对连接,然后可以断开连接
2、在手机蓝牙断开连接的情况下,
通过串口工具发出btstack c命令使M61发送AVRCP连接命令,缺省会触发订阅AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED
avrcp_controller_enable_notification(a2dp_sink_demo_avrcp_connection.avrcp_cid, AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED);
这时手机和M61会自动连接上。
3、打开手机上的音乐播放软件
手机上的歌词变化,LCD上也会相应变化:
七、总结
1、使用了BTstack下的a2dp_sink_demo例程,这个例程好像是mcu这边连接手机发送A2DP、AVRCP连接和订阅才能获取歌词信息,而通过手机连接MCU就不能。尝试改成手机端主动连接实现相同功能,但没有成功,还是对btstack了解太少。而且从MCU端连接需要提供手机蓝牙的MAC地址,这个比较头晕了,打个比方:想用蓝牙耳机连接手机听歌需要先知道手机蓝牙MAC,这完全不具有操作性。
2、类似下面的报错时不时就发生,然后程序就挂了,非常不稳定。
exception_entry
mcause=38000007
mepc:a0004732
mtval:00000000
Store/AMO access fault
3、不是每个手机都可以建立AVRCP连接,手头2个手机,1个可以,1个不行。
4、归根到底利用AVRCP协议获取歌词信息,实现的方案还是存在不少问题。主要是因为接触传统蓝牙时间比较短,而且蓝牙协议栈还是太复杂,好多东西都不懂。没有好办法,慢慢看吧,说不定哪天就看懂了。
|