首页 > 技术文章 > 小白入门教程 | 小梦老师带你学蓝牙,四种常用模式一文通晓

luat 2021-09-02 11:35 原文

图片

大家好啊,我是梦程~合宙Cat.1模块1.3主线固件支持双模蓝牙,今天就简单说一下蓝牙应该如何使用。

本教程以Air820开发板为例,讲解BLE的广播和从机功能。

我们将从经典蓝牙、Beacon、Broadcast、Slave四种模式进行具体讲解,在大多数的使用环境下,基本离不开这四种模式。

经典蓝牙示例


1.1 蓝牙功能系统信息

首先了解一下蓝牙功能里面的一些系统消息服务,我们要使用这些服务进行逻辑编排。
图片

1.2 经典蓝牙函数

图片图片

1.3 经典蓝牙示例代码
--- 模块功能:经典蓝牙示例
-- @author Darren Cheng
-- @module bluetooth.bt
-- @license MIT
-- @copyright openLuat-
- @release 2021.08.24
-- @注意 需要使用core(Luat_VXXXX_RDA8910_BT_FLOAT)版本
module(..., package.seeall)
require "audio"

local vol = 50
local musicstatus = 1
local keyMap = {{},{},{},{},{},{},{},{},{},{}}

keyMap[0] = {}
keyMap[255] = {}
keyMap[2][0] = "ENTER"
keyMap[2][1] = "DOWN"
keyMap[1][0] = "UP"
keyMap[1][1] = "ESC"
keyMap[255][255] = "PWK"



local function keyMsg(msg)   
      if keyMap[msg.key_matrix_row][msg.key_matrix_col] == "PWK" and msg.pressed then

        btcore.setavrcpsongs(musicstatus)     

   if musicstatus == 0 then

            musicstatus = 1
        elseif musicstatus == 1 then
            musicstatus = 0
        end
        log.info("bt", "musicstatus",musicstatus)    end
    if msg.pressed then
        if keyMap[msg.key_matrix_row][msg.key_matrix_col] == "ENTER" then
            btcore.setavrcpsongs(3)        

           log.info("bt","下一曲")   
     elseif keyMap[msg.key_matrix_row][msg.key_matrix_col] == "ESC" then

            btcore.setavrcpsongs(2)     

           log.info("bt","上一曲")    
    elseif keyMap[msg.key_matrix_row][msg.key_matrix_col] == "UP" then

            vol = vol + 10
            if vol > 127 then
                vol = 127
            end
            btcore.setavrcpvol(vol)        

           log.info("bt","加音量", vol)   
     elseif keyMap[msg.key_matrix_row][msg.key_matrix_col] == "DOWN" then

            vol = vol - 10
            if vol < 0 then
                vol = 0
            end
            btcore.setavrcpvol(vol)   

           log.info("bt","减音量", vol)   
     end

  end

end

rtos.on(rtos.MSG_KEYPAD,keyMsg)

rtos.init_module(rtos.MOD_KEYPAD,0,0x7F,0x7F)



local function init()

    log.info("bt", "init")
    rtos.on(rtos.MSG_BLUETOOTH, function(msg)
        if msg.event == btcore.MSG_OPEN_CNF then
            sys.publish("BT_OPEN", msg.result) --蓝牙打开成功
        elseif msg.event == btcore.MSG_BT_HFP_CONNECT_IND then
        sys.publish("BT_HFP_CONNECT_IND", msg.result) --hfp连接成功
	elseif msg.event == btcore.MSG_BT_HFP_DISCONNECT_IND then
            log.info("bt", "bt hfp disconnect") --hfp断开连接
        elseif msg.event == btcore.MSG_BT_HFP_CALLSETUP_OUTGOING then
            log.info("bt", "bt call outgoing") --建立呼出电话
        elseif msg.event == btcore.MSG_BT_HFP_CALLSETUP_INCOMING then
            log.info("bt", "bt call incoming") --呼叫传入    
            sys.publish("BT_CALLSETUP_INCOMING", msg.result)   
    elseif msg.event == btcore.MSG_BT_HFP_RING_INDICATION then

            log.info("bt", "bt ring indication") --呼叫传入铃声
        elseif msg.event == btcore.MSG_BT_AVRCP_CONNECT_IND then          sys.publish("BT_AVRCP_CONNECT_IND", msg.result) --avrcp连接成功
		elseif msg.event == btcore.MSG_BT_AVRCP_DISCONNECT_IND then
            log.info("bt", "bt avrcp disconnect") --avrcp断开连接
        end
    end)

end



sys.taskInit(function()

    sys.wait(5000)    -- audio.setChannel(1) -- 可调用此api切换播放通道,默认spk
    init()  -- 初始化

    log.info("bt", "poweron")
    btcore.open(2)  --打开经典蓝牙
    sys.waitUntil("BT_OPEN", 5000) --等待蓝牙打开成功

    log.info("bt", "设置蓝牙参数")
    btcore.setname("Cat1BT")-- 设置广播名称
    btcore.setvisibility(0x11)-- 设置蓝牙可见性
    log.info("bt", "蓝牙可见性",btcore.getvisibility())    
    local _, result = sys.waitUntil("BT_AVRCP_CONNECT_IND") --等待连接成功
    if result ~= 0 then
        return
    end
    log.info("bt", "连接成功")  

  while true do

        vol = btcore.getavrcpvol()        if vol == -1 then
            log.info("bt", "获取音量失败", vol)        elseif vol == -2  then
            log.info("bt", "设备不支持获取音量", vol)   

     else

            log.info("bt", "设备音量", vol)  

      end

        sys.wait(1000)  

  end

end)

代码效果解释:

  • 模块成功开机后会初始化蓝牙并广播名称为“Cat1BT”的蓝牙设备

  • 使用手机连接名为“Cat1BT”的设备

  • 按POWER键控制音乐播放与暂停

  • 按DOWN键减小音量,单位为10

  • 按UPWARD键增大音量,单位为10

  • 按ENTER键切换下一首音乐

  • 按ESC键切换上一首音乐

  • 部分手机可能不支持音量调节和获取

源码下载链接:

https://gitee.com/openLuat/X-MagicBox-820/blob/master/demo/bt-learn/bt.lua
 
 

BLE-Beacon示例


Beacon:一种特殊的广播,多用于蓝牙定位环境。

系统信息及函数说明详见:
https://doc.openluat.com/article/3495#BLEBeacon_393

2.1 BLE-Beacon示例代码
--- 模块功能:蓝牙功能测试
-- @author openLuat
-- @module bluetooth.beacon
-- @license MIT
-- @copyright openLuat
-- @release 2020.09.27
-- @注意 需要使用core(Luat_VXXXX_RDA8910_BT_FLOAT)版本module(..., package.seeall)



local function init() 

       log.info("bt", "init")         

       rtos.on(rtos.MSG_BLUETOOTH, function(msg)
      

        if msg.event == btcore.MSG_OPEN_CNF then               sys.publish("BT_OPEN", msg.result) --蓝牙打开成功   

      end


    end)

end



sys.taskInit(function()
  

      sys.wait(5000) 

      init() -- 初始化 

  

      log.info("bt", "poweron")      

      btcore.open(0) --打开蓝牙从模式
   

      sys.waitUntil("BT_OPEN", 5000) --等待蓝牙打开成功

  



      log.info("bt", "设置蓝牙参数")       

 btcore.setadvparam(0x80,0xa0,0,0,0x01,0) 

--广播参数设置 (最小广播间隔,最大广播间隔,广播类型,广播本地地址类型,广播channel map,广播过滤策略,定向地址类型,定向地址)
    btcore.setbeacondata("AB8190D5D11E4941ACC442F30510B4AB",10107,50179) --beacon设置  (uuid,major,minor)
    
  



 btcore.advertising(1)-- 打开广播

end)




源码下载链接:

https://gitee.com/openLuat/X-MagicBox-820/blob/master/demo/bt-learn/beacon.lua
 

2.2 抓包分析

这是通过抓包获取的Beacon数据包:

-----------------------------------------------+-------------------- - - -

|     Packet sniffer frame header               |

+-------+-------------+-------------------------+-------+----------------- - - -

|channel| Packet nbr. | Time stamp              | Length|  Packet data

+-------+-------------+-------------------------+-------+----------------- - - -

| 0x25  | 03 00 00 00 | 9D B0 E3 07 00 00 00 00 | 26 00 | 00 24 A2 65 44 C6 C2 C8 02 01 1A 1A FF 4C 00 02 15 AB 81 90 D5 D1 1E 49 41 AC C4 42 F3 05 10 B4 AB 27 7B C4 03 C5 

+-------+-------------+-------------------------+-------+----------------- - - -

请添加图片描述
这里我们可以获取的信息有:Channel就是为0x25,转换成十进制就是37通道AdvA就是模块的MAC地址AdvData为抓取的信息,这是封装用户数据生成的,在代码中则为UUID的数据,即:AB 81 90 D5 D1 1E 49 41 AC C4 42 F3 05 10 B4 AB


这里没有分析仪也可以使用手机app查看,推荐软件为nRF Connect。
图片图片
 
 

BLE-Broadcast示例


系统信息及函数说明详见:

https://doc.openluat.com/article/3495#BLEBroadcast_582

3.1 BLE广播示例代码
-- 模块功能:BLE广播示例
-- @author Darren Cheng
-- @module bluetooth.slave
-- @license MIT
-- @copyright openLuat
-- @release 2021.08.24
-- @注意 需要使用core(Luat_VXXXX_RDA8910_BT_FLOAT)版本
module(..., package.seeall)

local function init()

    log.info("bt", "init")
    rtos.on(rtos.MSG_BLUETOOTH, function(msg)
        if msg.event == btcore.MSG_OPEN_CNF then
            sys.publish("BT_OPEN", msg.result) --蓝牙打开成功
        end
    end)
end


sys.taskInit(function()

    sys.wait(5000)

    init() --初始化
    log.info("bt", "开蓝牙")
    btcore.open(0)  --打开蓝牙从模式
    sys.waitUntil("BT_OPEN", 5000)  --等待蓝牙打开成功

    log.info("bt", "设置蓝牙参数")
    btcore.setname("Cat1BT") -- 设置广播名称

    ------------ 设置蓝牙广播数据(LTV格式) --------------
    advData = "64617272656e"
    advType = "08"
    advLenth = string.format("%02x",(advData:len()/2)+1)
    btcore.setadvdata(string.fromHex(advLenth .. advType .. advData))    ------------ 设置蓝牙响应包数据(LTV格式) --------------
    rspData = "6368656e67"
    rspType = "08"
    rspLenth = string.format("%02x",(rspData:len()/2)+1)
    btcore.setscanrspdata(string.fromHex(rspLenth .. rspType .. rspData))

    btcore.setadvparam(0x80,0xa0,0,0,0x07,0)    --广播参数设置 (最小广播间隔,最大广播间隔,广播类型,广播本地地址类型,广播channel map,广播过滤策略,定向地址类型,定向地址)
    btcore.advertising(1)   -- 打开广播
end)

源码下载链接:

https://gitee.com/openLuat/X-MagicBox-820/blob/master/demo/bt-learn/broadcast.lua

3.2 现象展示及分析

请添加图片描述

通过抓取数据包得知:
设备会广播设置好的数据64617272656e
当主机端发出scan请求时,设备端会回复响应包内容6368656e67
注意:
蓝牙广播数据和响应包数据务必要符合LTV格式
完成所有设置之后,再去调用打开广播的API
 
 

BLE-Slave示例


系统信息及函数说明详见:

https://doc.openluat.com/article/3495#BLESlave_810

4.1 BLE-Slave示例代码
-- @module bluetooth.slave
-- @license MIT
-- @copyright openLuat
-- @release 2021.08.24
-- @注意 需要使用core(Luat_VXXXX_RDA8910_BT_FLOAT)版本
module(..., package.seeall)



local useUserService = true -- 用户自定义服务,true启用,false禁用

local function init()

    log.info("bt", "init")
    rtos.on(rtos.MSG_BLUETOOTH, function(msg)
        if msg.event == btcore.MSG_OPEN_CNF then
            sys.publish("BT_OPEN", msg.result) --蓝牙打开成功
        elseif msg.event == btcore.MSG_BLE_CONNECT_IND then
            sys.publish("BT_CONNECT_IND", {["handle"] = msg.handle, ["result"] = msg.result}) --蓝牙连接成功
		elseif msg.event == btcore.MSG_BLE_DISCONNECT_IND then
            log.info("bt", "ble disconnect") --蓝牙断开连接
        elseif msg.event == btcore.MSG_BLE_DATA_IND then
            sys.publish("BT_DATA_IND", {["result"] = msg.result})--接收到的数据内容
        end
    end)

end



sys.taskInit(function()

    sys.wait(5000)
    init() --初始化

    log.info("bt", "poweron")
    btcore.open(0) --打开蓝牙从模式
    sys.waitUntil("BT_OPEN", 5000) --等待蓝牙打开成功

    log.info("bt", "设置蓝牙参数")
    btcore.setname("Cat1BT")-- 设置广播名称
	btcore.setadvparam(0x80,0xa0,0,0,0x07,0) --广播参数设置 (最小广播间隔,最大广播间隔,广播类型,广播本地地址类型,广播channel map,广播过滤策略,定向地址类型,定向地址)
    
    if useUserService then
        log.info("bt", "useUserService")
        btcore.addservice(0xff88)     -- 添加服务uuid
        btcore.addcharacteristic(0xffe1,0x08,0x002)  --添加特征 可写
        -- btcore.addcharacteristic(0xffe1,0x08+0x04,0x002)  --添加特征 可写 特征属性可以写多个,用+连接
        btcore.addcharacteristic(0xffe2,0x10,0x001)  --添加特征 通知
        btcore.adddescriptor(0x2902,0x0001)      --添加描述
        btcore.addcharacteristic(0xffe3,0x02,0x001)  --添加特征 可读
    end

    btcore.advertising(1)-- 打开广播
    _, bt_connect = sys.waitUntil("BT_CONNECT_IND")    if bt_connect.result ~= 0 then
        return false
    end
    --链接成功
    log.info("bt","connect_handle",bt_connect.handle) -- 连接句柄
    while true do
        _, bt_recv = sys.waitUntil("BT_DATA_IND") -- 等待接收到数据
        local data = ""
        local len = 0
        local uuid = ""
        while true do
            local recvuuid, recvdata, recvlen = btcore.recv(3)            

           if recvlen == 0 then

                break
            end
            uuid = recvuuid       

           len = len + recvlen

            data = data .. recvdata        end
        if len ~= 0 then
            log.info("bt","recv_data:", data)            log.info("bt","recv_data_len", len)            log.info("bt","recv_uuid:", string.toHex(uuid))            if data == "close" then
                btcore.disconnect()--主动断开连接
            end
            if useUserService then
                btcore.send(data, 0xffe2, bt_connect.handle)    -- 发送数据(数据 对应特征uuid 连接句柄)
            end
            btcore.send(data, 0xfee2, bt_connect.handle)    -- 发送数据(数据 对应特征uuid 连接句柄)
        end
    end

end)


源码下载链接:

https://gitee.com/openLuat/X-MagicBox-820/blob/master/demo/bt-learn/slave2.lua

4.2 代码效果展示:

用户需根据需求设置useUserService,true为启用用户添加服务,false为禁用用户添加服务,使用默认服务。

1)用户不添加服务的情况下,会提供几个默认服务,若用户自行添加服务,则默认服务会被删除。

图片图片

2)用户添加自定义服务

图片图片

用户可使用0xFFE1的UUID向模块发送数据,发送的数据会回显到0xFFE2,用户可通过订阅0xFFE2获取数据。

注意:

  • 添加服务时不要与已有服务的UUID重复

  • 添加特征时,特征属性和特征权限要按照规定的格式

  • 特征属性和权限可使用多个,使用+连接

  • 用户完成所有添加操作之后,再去调用打开广播API

今天的内容就分享到这里了,建议大家阅读本文的API相关知识,已经根据官方文档做了部分翻译和注释,也提到了一些注意点。根据我编写的一些小demo去学习和实践,甚至可以说,改一改demo就是你自己的作品,期待大家可以使用蓝牙去做一些更有意思的项目。

- 相关开发资料链接 -

Air820UG开发板资料

https://gitee.com/openLuat/X-MagicBox-820/

LuatOS-Air开发资料

https://gitee.com/openLuat/Luat_Lua_Air724U

LuatOS-SoC仓库

https://gitee.com/openLuat/LuatOS

LuatOS开发指南/入门教程

https://doc.openluat.com/wiki/3?wiki_page_id=606

上海合宙通信模块 - 合宙Luat,让万物互联更简单

推荐阅读