嘿,各位蓝牙玩家、开发大神们~ 今天来聊个超实用的技能:在 Quecpython 平台上用 SPP 模式玩转蓝牙!不管你是想做无线串口通信,还是搞设备间数据互传,这篇指南都能让你秒变 “蓝牙达人”,小白也能轻松上手~

先搞懂:蓝牙 SPP 到底是个啥?

其实呀,SPP(Serial Port Profile,串口协议)就是经典蓝牙(Bluetooth BR/EDR)里的 “无线串口”!它能让两个设备像接了根无形的数据线一样,通过蓝牙模拟传统的 RS232 串口通信。简单说:有线串口能做的,它用蓝牙无线也能做,是不是很神奇?

SPP 能玩出哪些花样?

这可太多了!日常开发和生活中到处都能见到它的身影:

👉 蓝牙串口模块:比如咱们熟悉的 HC-05、HC-06、JDY-08,插上单片机就能用 SPP 无线传数据,告别杂乱的电线~
 👉 车载诊断:汽车 OBD2 读码器就是靠 SPP 和手机连接,实时读取车速、油耗这些数据,修车师傅的好帮手!
 👉 蓝牙打印机:超市小票、快递标签打印机,用 SPP 无线接收打印指令,摆在哪里都方便~
 👉 工业设备:工厂里的 PLC、单片机,不用布线就能通过 SPP 传数据,维护起来超省心!
 👉 日常小场景:比如蓝牙耳机(音频数据传输)、设备间传图片 / 文件,甚至自定义设备界面的 logo,都能靠它实现~

而且哦,SPP 支持最高 3M 速率传输,速度杠杠的!

哪些模组能玩 SPP?

Quecpython 平台下,这些 4G 模组都支持蓝牙 SPP,手里有的小伙伴可以直接开工:
 EC200U、EC600U、EG912U、EG915ULA_AB、EG915UEU_AB
 (没有的也别慌,先马住攻略,以后说不定就用上啦~)

划重点:Quecpython 开发 SPP 有多简单?

最爽的是,在 Quecpython 平台上玩蓝牙 SPP,根本不用啃复杂的底层协议栈!就像搭积木一样,调用几个简单的接口,分分钟搞定连接、传数据~ 是不是超省心?

手把手教你:蓝牙 SPP 初始化 + 通信全流程

下面咱们一步步来,从初始化到收发数据,跟着做就能搞定~

第一步:准备工作 —— 初始化蓝牙

首先得让蓝牙 “醒过来”,还得给它配个 “消息通知员”(回调函数),蓝牙有啥动静(比如连上了、收到数据了)都会通过它告诉你~

核心接口:bt.init(user_cb)

● 作用:初始化蓝牙,注册回调函数

● 回调函数(user_cb):蓝牙事件的 “消息中心”,比如 “蓝牙启动了”“收到数据了” 都会在这里通知你~

第二步:认识蓝牙的 “小动作”——

 事件 ID

蓝牙工作时会有各种 “状态通知”,咱们得知道这些通知代表啥,比如:

● BT_START_STATUS_IND(0):蓝牙启动了

● BT_SPP_CONNECT_IND(61):SPP 连接成功啦

● BT_SPP_RECV_DATA_IND(14):收到数据啦

● BT_SPP_DISCONNECT_IND(62):连接断开了

这些就像蓝牙的 “表情”,看懂了就能知道它在干嘛~

第三步:代码示例 —— 从启动到传数据全流程

咱们直接上代码,每一步都给你标清楚,小白也能看懂~

    # 导入蓝牙模块,用于蓝牙相关操作
    import bt
    # 导入时间模块,用于延时等时间操作
    import utime
    # 导入多线程模块,用于创建事件处理线程
    import _thread
    # 从队列模块导入Queue,用于存储蓝牙事件消息
    from queue import Queue
    # 定义蓝牙设备名称,其他设备可通过该名称搜索到本设备
    BT_NAME = 'QuecPython-SPP'
    # 定义蓝牙事件字典,键为事件描述,值为事件ID,用于识别不同蓝牙事件
    BT_EVENT = {
        'BT_START_STATUS_IND': 0,         # 蓝牙/ble启动状态通知
        'BT_STOP_STATUS_IND': 1,          # 蓝牙/ble停止状态通知
        'BT_SPP_INQUIRY_IND': 6,          # 蓝牙SPP查询到设备通知
        'BT_SPP_INQUIRY_END_IND': 7,      # 蓝牙SPP查询结束通知
        'BT_SPP_RECV_DATA_IND': 14,       # 蓝牙SPP接收数据通知
        'BT_SPP_CONNECT_IND': 61,         # 蓝牙SPP连接状态通知
        'BT_SPP_DISCONNECT_IND': 62,      # 蓝牙SPP断开连接通知
    }
    # 目标设备信息字典,存储要连接的设备名称和蓝牙地址
    DST_DEVICE_INFO = {
        'dev_name':'iQOO Neo7 SE',# 要连接的目标设备蓝牙名称
        'bt_addr': None  # 目标设备蓝牙地址,初始为None,搜索到后赋值
    }
    # 蓝牙运行状态标记:0-未运行,1-运行中
    BT_IS_RUN = 0
    # 创建消息队列,最大容量30,用于缓存蓝牙回调函数传来的事件消息
    msg_queue = Queue(30)
    # 蓝牙回调函数:当蓝牙有事件发生时,系统会调用该函数
    # 参数args:事件相关参数,包含事件ID、状态等信息
    def bt_callback(args):
        global msg_queue
        # 将事件参数放入消息队列,供事件处理线程处理
        msg_queue.put(args)
    # 打开/usr/test.txt文件,模式为a+(追加+可读),用于存储接收的蓝牙数据
    f=open('usr/test.txt','a+')
    # 蓝牙事件处理线程函数:循环从消息队列获取事件并处理
    def bt_event_proc_task():
        # 声明使用全局变量
        global msg_queue
        global BT_IS_RUN
        global DST_DEVICE_INFO
        while True:
            print('wait msg...')
            # 从消息队列获取消息,若无消息则阻塞等待
            msg = msg_queue.get()
            # 解析事件ID(第一个参数为事件ID)
            event_id = msg[0]
            # 解析状态(第二个参数为状态:0-成功,非0-失败)
            status = msg[1]
            # 处理蓝牙启动状态通知事件
            if event_id == BT_EVENT['BT_START_STATUS_IND']:
                print('event: BT_START_STATUS_IND')
                # 若启动成功
                if status == 0:
                    print('BT start successfully.')
                    # 更新蓝牙运行状态为运行中
                    BT_IS_RUN = 1
                    print('Set BT name to {}'.format(BT_NAME))
                    # 设置蓝牙设备名称
                    retval = bt.setLocalName(0, BT_NAME)
                    if retval != -1:
                        print('BT name set successfully.')
                    else:
                        print('BT name set failed.')
                        # 若设置名称失败,停止蓝牙
                        bt.stop()
                        continue
                    # 设置蓝牙可见模式(3表示可见)
                    retval = bt.setVisibleMode(3)
                    if retval == 0:
                        # 获取当前可见模式并验证
                        mode = bt.getVisibleMode()
                        if mode == 3:
                            print('BT visible mode set successfully.')
                        else:
                            print('BT visible mode set failed.')
                            bt.stop()
                            continue
                    else:
                        print('BT visible mode set failed.')
                        bt.stop()
                        continue
                    # 以下为查询设备相关代码(默认注释,取消注释可启用)
                    # retval = bt.startInquiry(15)
                    # if retval != 0:
                    #     print('Inquiry error.')
                    #     bt.stop()
                    #     continue
                # 若启动失败
                else:
                    print('BT start failed.')
                    bt.stop()
                    continue
            # 处理蓝牙停止状态通知事件
            elif event_id == BT_EVENT['BT_STOP_STATUS_IND']:
                print('event: BT_STOP_STATUS_IND')
                if status == 0:
                    # 更新蓝牙运行状态为未运行
                    BT_IS_RUN = 0
                    print('BT stop successfully.')
                else:
                    print('BT stop failed.')
                # 以下为释放SPP和蓝牙资源的代码(默认注释)
                # retval = bt.sppRelease()
                # if retval == 0:
                #     print('SPP release successfully.')
                # else:
                #     print('SPP release failed.')
                # retval = bt.release()
                # if retval == 0:
                #     print('BT release successfully.')
                # else:
                #     print('BT release failed.')
                # break
                # 延时5秒后重新启动蓝牙
                utime.sleep(5)
                bt.start()
                bt.setVisibleMode(3)
            # 处理SPP查询到设备通知事件
            elif event_id == BT_EVENT['BT_SPP_INQUIRY_IND']:
                print('event: BT_SPP_INQUIRY_IND')
                if status == 0:
                    # 解析信号强度(第三个参数为rssi)
                    rssi = msg[2]
                    # 解析设备名称(第五个参数为设备名称)
                    name = msg[4]
                    # 解析设备地址(第六个参数为设备地址)
                    addr = msg[5]
                    # 格式化MAC地址(转换为xx:xx:xx:xx:xx:xx格式)
                    mac = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[5], addr[4], addr[3], addr[2], addr[1], addr[0])
                    print('name: {}, addr: {}, rssi: {}'.format(name, mac, rssi))
                    # 若查询到目标设备
                    if name == DST_DEVICE_INFO['dev_name']:
                        print('The target device is found, device name {}'.format(name))
                        # 记录目标设备地址
                        DST_DEVICE_INFO['bt_addr'] = addr
                        # 取消查询(已找到目标设备)
                        retval = bt.cancelInquiry()
                        if retval != 0:
                            print('cancel inquiry failed.')
                            continue
                else:
                    print('BT inquiry failed.')
                    bt.stop()
                    continue
            # 处理SPP接收数据通知事件
            elif event_id == BT_EVENT['BT_SPP_RECV_DATA_IND']:
                # print('event: BT_SPP_RECV_DATA_IND')
                # 若接收数据成功
                if status == 0:
                    # 解析接收的数据(第四个参数为数据)
                    data = msg[3]
                    # 将数据写入文件
                    f.write(data)
                    print('recvbytes data: {}'.format(data))
                    # 以下为发送响应数据的代码(默认注释,取消注释可启用)
                    # send_data = 'I have received the data you sent.'
                    # print('send data: {}'.format(send_data))
                    # retval = bt.sppSend(send_data)
                    if retval != 0:
                        print('send data faied.')
                else:
                    print('Recv data failed.')
                    bt.stop()
                    continue
            # 处理SPP连接通知事件
            elif event_id == BT_EVENT['BT_SPP_CONNECT_IND']:
                print('event: BT_SPP_CONNECT_IND')
                # 若连接成功
                if status == 0:
                    # 解析连接状态(第三个参数为连接状态)
                    conn_sta = msg[2]
                    # 解析设备地址(第四个参数为设备地址)
                    addr = msg[3]
                    # 格式化MAC地址
                    mac = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[5], addr[4], addr[3], addr[2], addr[1], addr[0])
                    print('SPP connect successful, conn_sta = {}, addr {}'.format(conn_sta, mac))
                else:
                    print('Connect failed.')
                    bt.stop()
                    continue
            # 处理SPP断开连接通知事件
            elif event_id == BT_EVENT['BT_SPP_DISCONNECT_IND']:
                print('event: BT_SPP_DISCONNECT_IND')
                # 解析连接状态(第三个参数为连接状态)
                conn_sta = msg[2]
                # 解析设备地址(第四个参数为设备地址)
                addr = msg[3]
                # 格式化MAC地址
                mac = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[5], addr[4], addr[3], addr[2], addr[1], addr[0])
                print('SPP disconnect successful, conn_sta = {}, addr {}'.format(conn_sta, mac))
                # 关闭文件
                f.close()
                bt.stop()
                continue
    # 主函数:初始化并启动蓝牙SPP
    def main():
        global BT_IS_RUN
        # 启动蓝牙事件处理线程
        _thread.start_new_thread(bt_event_proc_task, ())
        # 初始化蓝牙(注册回调函数)
        retval = bt.init(bt_callback)
        if retval == 0:
            print('BT init successful.')
        else:
            print('BT init failed.')
            return -1
        # 初始化SPP
        retval = bt.sppInit()
        if retval == 0:
            print('SPP init successful.')
        else:
            print('SPP init failed.')
            return -1
        # 启动蓝牙
        retval = bt.start()
        if retval == 0:
            print('BT start successful.')
        else:
            print('BT start failed.')
            # 若启动失败,释放SPP资源
            retval = bt.sppRelease()
            if retval == 0:
                print('SPP release successful.')
            else:
                print('SPP release failed.')
            return -1
        # 循环监测蓝牙运行状态
        count = 0
        while True:
            utime.sleep(1)
            count += 1
            # 获取当前时间
            cur_time = utime.localtime()
            # 格式化时间戳(时:分:秒)
            timestamp = "{:02d}:{:02d}:{:02d}".format(cur_time[3], cur_time[4], cur_time[5])
            # 每5秒打印一次运行状态
            if count % 5 == 0:
                if BT_IS_RUN == 1:
                    print('[{}] BT SPP is running, count = {}......'.format(timestamp, count))
                    print('')
                else:
                    print('BT SPP has stopped running, ready to exit.')
                    break
    # 若脚本作为主程序运行,则执行main函数
    if __name__ == '__main__':
    main()

    第四步:手机配合测试 —— 秒变

     “蓝牙数据中转站”

    代码跑起来后,咱们用手机配合测试一下:

    1、手机下载 “blue-spp” 软件(专门玩 SPP 的工具)

    2、打开手机蓝牙,搜索到咱们设置的蓝牙名(比如 “QuecPython-SPP”)

    3、连接成功后,在手机上输入点文字,模组就能收到啦~反过来模组也能发数据给手机

    亲测有效,数据嗖嗖传,比插线方便多了!

    图片

    图片

    图片

    总结一下:SPP 模式超实用,上手超简单!

    今天的蓝牙 SPP 小课堂就到这里~ 简单说:

    ● SPP 是经典蓝牙的 “无线串口”,能模拟有线通信,传数据超方便

    ● 支持 EC200U、EC600U 等多款模组,手头有的赶紧试

    ● Quecpython 平台调用接口就行,不用啃底层,小白也能玩

    更多推荐