内容提要:2023年6月14日,树莓派官方发布了对树莓派Pico W无线开发板(简称Pico W)MicroPython蓝牙功能的支持。本文首先介绍Pico W接口信号及蓝牙通信协议,然后通过Pico W接口信号扩展连接一只LED和一个按键,并给出Pico W蓝牙通信MicroPython编程示例。
 一、Pico W接口信号
 1. Pico W开发板介绍
 Pico W是树莓派基金会于2022年6月底推出的搭载无线通信芯片的树莓派Pico开发板,主要技术规格如下:
 •工作电压:1.8~5.5V;
 •MCU:MCU采用树莓派基金会自研的型号为RP2040的芯片(该芯片于2021年1月随树莓派Pico开发板发布),芯片內部集成了32位双核ARM Cortex-M0+,运行时钟133MHz;
 •SRAM大小:264KB;
 •Flash存储器容量:2MB(QSPI接口);
 •GPIO接口引脚:26个,包括3个模拟输入引脚、16个PWM通道;
 •串行通信接口:2个UART、2个SPI控制器和2个I2C控制器;
 •USB接口:内置USB 1.1控制器和PHY,支持主控端(host)和设备端(device);
 •片内温度传感器:RP2040内置一个片内温度传感器(可用来测量RP2040芯片的温度,以便进行温度补偿或保护),可以通过ADC4读取片内温度传感器的值并转换为摄氏或华氏温度;
 •WiFi无线通信功能:2.4GHz 802.11n
 •Bluetooth 5.2蓝牙通信功能:2023年2月支持C程序蓝牙开发,2023年6月支持支持MicroPython蓝牙开发;
 Pico W搭载英飞凌公司的AIROC CYW43439无线通信芯片,具备2.4GHz WiFi 4(802.11n,支持WPA3)和Bluetooth 5.2(可使用官方2023年2月推出的SDK 1.5编写C蓝牙程序,或使用官方2023年6月以后推出的支持Pico W蓝牙通信功能的MicroPython固件和MicroPython蓝牙库开发MicroPython蓝牙程序),带板载天线。
 2.Pico W接口信号
 Pico W的外观尺寸和接口信号引脚也跟Pico开发板一样,两侧各有20個接口信号引脚(如图1所示),这些引脚采用邮票孔设计,以方便下游厂商以表面粘着方式将Pico W开发板焊接到产品的主板中。
 Pico W接口信号引脚说明如下:
 •VSYS:2V~5V电源输入引脚。
 •VBUS:从Micro USB接口获得的5V电源输出,可供电给需要5V电源的电子元件。
 •3V3:3.3V电源,与Pico W的工作电压相同。
 •3V3_EN:使能或禁止电源;使能或禁止Pico W以及3V3引脚的电源输出。
 •RUN/RESET:启用或停用Pico∕重置,输入低电平将使Pico W停止运行。
 •GP0-GP28:GPIO(通用输入/输出)引脚,板载LED与WL_GPIO0相连。
 •ADC0 ~ ADC2:具备模拟输入功能的GPIO引脚,可当作模拟输入或数字输入/输出引脚。
 •ADC_VREF:模数转换器(ADC)的参考电压输入。
 •GND:模数转换器的接地引脚,与ADC_VREF引脚配合使用。
 
 图1
 特别说明的是,Pico W板载(On-board)LED引脚与Pico板载LED引脚接GPIO25不同,在MicroPython中,Pico W板载LED引脚就叫做‘LED’或者‘WL_GPIO0’(均为字符串类型),下面两行典型的MicroPython语句都表示建立控制Pico W板载LED对象:
 led = Pin(‘LED’, Pin.OUT)
 或
 led = Pin(‘WL_GPIO0’, Pin.OUT)
 二、低功耗蓝牙(BLE)简介
 低功耗蓝牙(Bluetooth Low Energy, 简称BLE)是蓝牙无线通信技术的一种改进变体,其显著特点是省电。 与经典蓝牙不同的是,BLE 在不收发数据时可以保持在休眠状态。 BLE非常适合于使用电池供电的设备,如可穿戴式设备、安全监控设备等。
 1.BLE通信拓扑结构
 BLE通信拓扑结构如下:
 (1)点对点(Point-to-Point):网络中两个结点(设备)之间的通信;服务器-客户机通信。
 (2)Mesh网络:使用Mesh网络,多个结点可以相互通信。
 (3)广播模式(Broadcast Mode):服务器通过网络广播可供许多设备读取的数据。
 2.BLE设备状态机
 BLE设备状态机定义了设备通信时的某些状态:
 (1)待机状态(Standby state):设备既不发送也不接收数据,开机上电就是该状态。
 (2)初始化状态(Initiating state):用于对其他设备发起连接。
 (3)广播状态(Advertising state):发送广播数据包,告诉其他设备一些信息,以方便其他设备查找自己或连接自己。当然,并非所有广播设备都是可连接或可扫描的。
 (4)连接状态(Connection state):与其他设备连接。
 (5)扫描状态(Scanning state):扫描正在进行广播的设备。
 (6)同步广播状态(Isochronous broadcasting state):广播同步数据包。
 (7)同步状态(Synchronization state):用于周期性广播的数据同步。
 BLE设备状态机如图2所示。
 
 图2
 从图2可知,一个BLE设备进入连接(Connection)状态时,之前的状态要么是广播(Advertising)状态, 要么是初始化(Initiating)状态。从Initiating到Connection状态的BLE设备就变成BLE主设备。从Advertising到Connection状态的BLE设备就变成BLE从设备。BLE从设备最初处于广播状态,当它接受来自BLE主设备的连接请求时,它就转换到连接状态。
 这里将Pico W作为BLE从设备,并通过低功耗蓝牙与 Android 设备(Android智能手机)建立点对点通信。
 三、Pico W扩展LED和按键硬件接口电路
 本文实践需要的硬件材料如下:
 (1)Pico W×1;
 (2)Micro-USB数据线×1;
 (3)面包板×1;
 (4) 470Ω电阻×1;
 (5)LED发光二极管×1;
 (6)轻触按键×1;
 (7)跳线×4。
 Pico W扩展一只小功率LED和一个按键的硬件接口电路原理图如图3(a)所示,面包板按线实物图如图3(b)所示。
 
 图3
 四、Pico W蓝牙通信MicroPython编程
 1.Pico W MicroPython固件下载与安装
 首先,在Pico W上安装支持 WiFi 和BLE的Pico W MicroPython UF2 固件文件。我们可从树莓派官网https://www.raspberrypi.com/documentation/microcontrollers/micropython.html或MicroPython官网https://micropython.org/download/RPI_PICO_W/下载支持 WiFi 和BLE最新版本的Pico W MicroPython UF2文件,这里下载MicroPython固件文件名为“RPI_PICO_W-20240105-v1.22.1.uf2”,将其安装到Pico W中(具体安装方法可参见上面的树莓派官网或博主以前在CSDN发布的树莓派Pico/Pico W系列相关博文)。
 2. Pico W BLE MicroPython模块
 我们需要在Pico W中保存两个 MicroPython 模块,以便实现低功耗蓝牙通信功能。
 这里从网站https://datasheets.raspberrypi.com/picow/connecting-to-the-internet-with-pico-w.pdf下载文件名为“connecting-to-the-internet-with-pico-w.pdf”的PDF电子书。
 Pico W第1个BLE MicroPython模块见PDF电子书的Page 34-36,模块1命名为“ble_advertising.py”文件,这里使用Thonny IDE MicroPython开发环境将Page 34-36的代码粘贴(需去掉行号)并存储到Pico W中(Thonny使用方法可参考博主以前在CSDN发布的树莓派Pico/Pico W系列相关博文)。
 模块1程序清单如下:
# Filename: ble_advertising.py
# Helpers for generating BLE advertising payloads.from micropython import const
import struct
import bluetooth# Advertising payloads are repeated packets of the following form:
#   1 byte data length (N + 1)
#   1 byte type (see constants below)
#   N bytes type-specific data_ADV_TYPE_FLAGS = const(0x01)
_ADV_TYPE_NAME = const(0x09)
_ADV_TYPE_UUID16_COMPLETE = const(0x3)
_ADV_TYPE_UUID32_COMPLETE = const(0x5)
_ADV_TYPE_UUID128_COMPLETE = const(0x7)
_ADV_TYPE_UUID16_MORE = const(0x2)
_ADV_TYPE_UUID32_MORE = const(0x4)
_ADV_TYPE_UUID128_MORE = const(0x6)
_ADV_TYPE_APPEARANCE = const(0x19)# Generate a payload to be passed to gap_advertise(adv_data=...).
def advertising_payload(limited_disc=False, br_edr=False, name=None, services=None, appearance=0):payload = bytearray()def _append(adv_type, value):nonlocal payloadpayload += struct.pack("BB", len(value) + 1, adv_type) + value_append(_ADV_TYPE_FLAGS,