大家好, 我是james, 是一名hacker, 我一直在努力修炼现代魔法.
* 项目介绍
第三季第1期funpack活动的开发板是来自Silicon Labs(以下简称silabs)的XG24-EK2703A(以下简称XG24). Silabs是位于美国德州奥斯汀的半导体公司, 该公司于纳斯达克股票市场上市, 代码为SLAB. Silabs是安全和智能无线技术的引领者之一, 主营物联网业务.
本期Funpack活动中, 我使用该板卡实现了一个蓝牙温度计, 完成了任务1, 即"使用芯片内部的温度检测外设,测量温度并通过蓝牙发送至上位机,在上位机中以“绘图”的形式对温度数据进行可视化".
开发过程中, 首先和同学在交流群中相互切磋学习, 相互帮助, 感到充实和意义; 其次开发过程中解决了一些和本期板卡相关代码的CircuitPython问题, 提交给了adafruit并获得通过, 获得了一些成就感; 最后Silabs友好的开发环境和方便的开发工具, 令人印象深刻, 活动完成后, 我对蓝牙的一些核心概念的设计思想有了更深入的认识.
* 实现功能
使用芯片内部的温度检测外设,测量温度并通过基于低功耗蓝牙的HoGP(HID over GATT Profile)协议发送至上位机,在上位机中使用Excel进行"绘图", 对温度数据可视化。
* 设计思路
Silabs提供了很多官方例程能够轻松实现HoGP. 本期使用的EFR32系列MCU(EFR32MG24B210F1536IM48)无线SoC芯片已经内置了温度传感器, 实现蓝牙温度计没有设计难点, 目标非常清晰. 当然本期实现的蓝牙温度计属于原型, 仅仅用来熟悉板卡和Silabs的器件, 为将来应用积累一些经验. 在此基础上, 为了增加趣味性, 上位机绘图使用了Excel, 通信协议是HID所以能够方便的模拟键盘鼠标操作, 也就是能够模拟人类操作电脑的方式. 整个开发过程还是很有趣的.
最初, 面对一个陌生的板卡, 避免陷入细节的泥沼, 我使用了CircuitPython. Silicon Labs的工程师已经将CircuitPython移植到了这块板卡. 所以入门没有什么难度, 参考活动群里面同学们的探索, 能够实现NUS(Nordic UART Service)传输数据到蓝牙辅助设备, 也就是上位机.
上述两个方面的探索让我慢慢熟悉了板卡的使用, 接下来, 我就开始探索如何将HoGP相关的例程和CircuitPython结合起来. 参考同学们的实践, 我进行了比较长时间的尝试, 然后逐渐发现, 特征描述符并没有生效, 查看bleio的代码, 发现相关代码不完善的地方, 稍微调整之后, 问题解决. 将HoGP相关官方例程和CircuitPython进行结合, 完善CircuitPython的bleio相关的代码, 让后续的工作变得轻而易举, 最终实现了最初定的设计目标.
图1 HoGP通信建立流程(cited from TI's documents)
蓝牙协议为了达到低功耗, 支持的外设计算能力受限, 种类多种多样, 但是最重要的是, wifi和bluetooth分别由wifi alliance和bluetooth SIG推动, 所以虽然wifi和bluetooth都是基于2.4G/5G ISM频段, 并不兼容, 模型也不一样. 蓝牙最常见的就是替代了USB之类需要物理连线的人机交互设备, 而wifi替代了网线. 有重叠, 但是应用各不相同. 虽然大家可能普遍认为蓝牙不能支持长距离数据传输, 10米左右是其常见的工作举例, 但是BLE其实最大的传输距离可以达到1000M(bluetooth 5.0)
蓝牙协议是复杂的, 而且包含了多个相互交叠的模型, 同时使用蓝牙技术也是简单的, 因为不必了解所有的细节, 比如对GATT协议的使用, 主要理解其是一个订阅发布模型即可. 芯片厂商提供的文档为理解这一模型提供很很多帮助. 通过查看Silabs, TI, Nordic免费提供的相关文档, 逐步了解并掌握了GATT协议模型.
图2 蓝牙低功耗协议栈(cited from docs of Bluetooth SIG)
选择一个好点儿的库可以节约很多需要自行编码的情况需要的额外时间. CircuitPython内置的bleio就是很好的库. 虽然在一些情况下需要完善, 但是清晰的设计, 开箱即用, 能够快速让开发者理解其中的要义.
* 环境搭建
如果计划使用官方的sistudio, 环境搭建过程就是安装sistudio的过程, 在线安装sistudio真是痛苦的过程, 很容易因为网络质量问题失败, 但是想直接尝试官方例程, 就必须安装sistudio, 我在这上面也浪费了很多时间, 还好有同学们的提醒和提前踩坑, 最后也参考做的比较好的同学热心提供的离线安装方法.
如果使用CircuitPython, 安装过程会简单很多, 但是这种方法适合原来就有一些MPy/CPy的开发经验的开发者, 不然所需要的时间不会比直接使用sistudio少.
* 机械结构
由于这回是读取传感器并传输数据, 不需要使用执行器, 不需要改造板卡, 所以没有机械结构方面的工作.
* 软件实现
基于CircuitPython的实现非常简单, 下面列代码.
"""
temperature meter with ble hogt communication and excel plotting.
author: james
"""
# import board
import sys
import time
from ada_hid.keyboard import Keyboard, Keycode
from ada_hid.keyboard_layout_us import KeyboardLayoutUS
import ada_ble
from ada_ble.advertising import Advertisement
from ada_ble.advertising.standard import ProvideServicesAdvertisement
from ada_ble.services.standard.hid import HIDService
from ada_ble.services.standard import BatteryService
from ada_ble.services.standard.device_info import DeviceInfoService
from ada_ble.services.standard import GenericAccess
from uctypes import BF_POS, BF_LEN, UINT32, BFUINT32, BFUINT16, struct
from time import sleep
EMU_BASE = 0x50004000
EMU_LAYOUT = {
"EMU_TEMP": (0x88, {
"TEMP": 2 << BF_POS | 9 << BF_LEN | BFUINT32,
"TEMPLSB": 0 << BF_POS | 2 << BF_LEN | BFUINT32
})
}
def read_temperature():
emu = struct(EMU_BASE, EMU_LAYOUT)
return emu.EMU_TEMP.TEMP + emu.EMU_TEMP.TEMPLSB * 0.25 - 273.15
DEFAULT_HID_DESCRIPTOR = (
b"\x05\x01" # Usage Page (Generic Desktop Ctrls)
b"\x09\x06" # Usage (Keyboard)
b"\xA1\x01" # Collection (Application)
b"\x85\x01" # Report ID (1)
b"\x05\x07" # Usage Page (Kbrd/Keypad)
b"\x19\xE0" # Usage Minimum (\xE0)
b"\x29\xE7" # Usage Maximum (\xE7)
b"\x15\x00" # Logical Minimum (0)
b"\x25\x01" # Logical Maximum (1)
b"\x75\x01" # Report Size (1)
b"\x95\x08" # Report Count (8)
b"\x81\x02" # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
b"\x95\x01" # Report Count (8)
b"\x75\x08" # Report Size (1)
b"\x81\x01" # Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
b"\x95\x03" # Report Count (3)
b"\x75\x01" # Report Size (1)
b"\x05\x08" # Usage Page (LEDs)
b"\x19\x01" # Usage Minimum (Num Lock)
b"\x29\x05" # Usage Maximum (Kana)
b"\x91\x02" # Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
b"\x95\x01" # Report Count (1)
b"\x75\x05" # Report Size (5)
b"\x91\x01" # Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
b"\x95\x06" # Report Count (6)
b"\x75\x08" # Report Size (8)
b"\x15\x00" # Logical Minimum (0)
b"\x26\xFF\x00" # Logical Maximum (255)
b"\x05\x07" # Usage Page (Kbrd/Keypad)
b"\x19\x00" # Usage Minimum (0x00)
b"\x2A\xFF\x00" # Usage Maximum (0xFF)
b"\x81\x00" # Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
b"\xC0" # End Collection
)
hid = HIDService(DEFAULT_HID_DESCRIPTOR)
#battery = BatteryService()
#battery.level = 100
#genericAccess = GenericAccess()
#genericAccess.appearance = 961
# device_info = DeviceInfoService(
# software_revision=ada_ble.__version__,
# hardware_revision= "v1",
# manufacturer="Adafruit Industries"
# )
advertisement = ProvideServicesAdvertisement(hid)
# advertisement.appearance = 961
scan_response = Advertisement()
ble = ada_ble.BLERadio()
if ble.connected:
for c in ble.connections:
c.disconnect()
print("advertising")
ble.start_advertising(advertisement, scan_response)
print(hid.devices)
k = Keyboard(hid.devices)
kl = KeyboardLayoutUS(k)
def say(n):
kl.write("{:.2f}\n".format(n))
line = 1
while True:
while not ble.connected:
pass
print("Start typing:")
while ble.connected:
say(read_temperature())
if line == 10:
while line >= 1:
k.send(Keycode.UP_ARROW)
time.sleep(0.1)
line = line - 1
line = line + 1
time.sleep(1)
ble.start_advertising(advertisement, scan_response)
图3 代码流程图
* 硬件实现
本期没有设计拓展板, 没有连接外部传感器, 所以无需硬件实现.
* 功能展示
见视频
* 常见问题
- 安装Simplicity Studio
如上文所述, 安装Silab的IDE会遇到网络的问题, 即便是很好的网络质量, 也会由于SiStudio的一些更新机制, 导致下载安装失败, 这时候可以使用HonestQiao同学整理的离线安装步骤: https://gitee.com/honestqiao/efr32x-g24-explorer-kit-study-on-circuitpython
- adafruit_hid使用问题
如果遇到在CPY导入包的时候遇到报错, 可以将错误的py文件上传到板卡的flash然后进行修改, py的修改很方便, 因为不用重新编译, 也有异常抛出, 直接修改有问题的地方即可.
* 心得体会
1. 一定有简单的方法学习和应用复杂的技术, 但是如果想要成为专家, 那么一定需要大量全方面的学习才行.
2. 技术可以复杂, 但是不能难学难用, 这点蓝牙做到了. 虽然蓝牙技术从1994年诞生以来, 一直在丰富内容, 甚至发生BLE和传统蓝牙分道扬镳几乎成了全新的技术, 但是其完善的生态和丰富的参考资料让开发变得更容易.
* 参考文献
SiLabs, TI, Noridcsemi提供的免费的BLE学习资料都很有参考价值.
- https://www.silabs.com/support/training/getting-started-with-bluetooth/bluetooth-le-fundamentals
- https://www.ti.com/technologies/wired-wireless-connectivity/bluetooth-low-energy/overview.html
- https://www.nordicsemi.com/Products/Wireless/Bluetooth-Low-Energy
* Code&Future
最后,感谢硬禾学堂和得捷电子,让我接触到了SiLabs的EFR32系列蓝牙开发板,让我能在业余时间参与更多有趣项目的学习,也感谢群的小伙伴提供很多种实现题目功能的思路,感谢大家一路的折腾与陪伴,谢谢!