聚豐項目 > 基于AB32VG1的藍牙通信小程序
藍訊驕龍 AB32VG1 是中科藍訊在 2020 RT-Thread 開發者大會上首度面向通用市場發布的其自主 RISC-V 內核 32 位 MCU 芯片,具有豐富的軟硬件資源和低成本優勢,微信小程序作為微信公眾號和app不足之處的補充,能夠提供更好的用戶體驗,多元性的曝光,在餐飲行業,服務行業,電子商務行業等領域有顯著的用戶流量。本設計意在為AB32開發板提供更多的應用方向。
尋游記
分享尋游記
團隊成員
尋游記 嵌入式軟件
RT-Thread使用情況概述:
整個方案涉及的技術有:rtt模塊化任務代碼設計,BLE-GATT,微信小程序軟件開發(wxml+wxss+js);
內核部分:使用了線程、信號量、定時器 、PWM
設備驅動:
GPIO/PWM/BLE 等
PC端將程序燒錄到MCU,通過downloader調用ble命令開始開發板藍牙廣播,使其處于可被發現狀態;小程序端打開藍牙搜索,找到開發板,獲取Notify/read/write信息;
這里著重說一下BLE-GATT。
現在低功耗藍牙(BLE)連接都是建立在 GATT (Generic Attribute Profile) 協議之上。GATT 是一個在藍牙連接之上的發送和接收很短的數據段的通用規范,這些很短的數據段被稱為屬性(Attribute)。
詳細介紹 GATT 之前,需要了解 GAP(Generic Access Profile),它在用來控制設備連接和廣播。GAP 使你的設備被其他設備可見,并決定了你的設備是否可以或者怎樣與合同設備進行交互。例如 Beacon 設備就只是向外廣播,不支持連接,小米手環就等設備就可以與中心設備連接。
GAP 給設備定義了若干角色,其中主要的兩個是:外圍設備(Peripheral)和中心設備(Central)。
外圍設備:這一般是簡單的低功耗設備,用來提供數據,并連接到一個更加相對強大的中心設備。這里指我們的開發板。
中心設備:中心設備相對比較強大,用來連接其他外圍設備。這里指手機端。
GAP 的廣播工作流程如下圖所示
GATT通信的雙方是C/S關系。外設作為GATT服務端(Server),它維持了ATT的查找表以及service和characteristic的定義。中心設備是GATT客戶端(Client),他向Server發起請求。需要注意的是,所有的通信事件,都是由客戶端(也叫主設備,Master)發起,并且接收服務端(也叫從設備,Slava)的響應。而GATT事務是建立在嵌套的Profiles,Services和Characteristics之上的,如下如所示:
Profile :
Profile并不是實際存在于BLE外設上的,它只是一個被Bluetooth SIG或者外設設計者預先定義的Service的集合。例如我們的例程心率Profile(Heart Rate Profile)就是結合了Heart Rate Service和Device Information Sercvice。所有官方通過GATT Profile的列表可以從這里找到。
這里給出官網的列表Assigned Numbers。
Service:
Service是把數據分成一個個的獨立邏輯項,它包含一個或者多個Characteristic。每個Service有一個UUID唯一標識。UUID有16bit的,或者128bit的。16bit的UUID是官方通過認證的,需要花錢購買,128bit是自定義的,這個就可以自己隨便設置。
官方通過了一些標準Service,完整列表在這里。以Heart Rate Service為例,可以看到它的官方通過16bitUUID是0x180D,包含3個Characteristic:Heart Rate Measurement,Body Sensor Location和Heart Control Point,并且定義了只有一個第一個必須的,它是可選實現的。
Characteristic :
Characteristic 在GATT事務中的最低界別的是Characteristic,Characteristic是最小的邏輯數據單元,當然它可能包含一個組關聯的數據,例如加速度計的X/Y/Z三軸值。與Service類似,每個Characteristic用16bit或者128bit的UUID唯一標識。你可以免費使用Bluetooth SIG官方定義的標準Characteristic,使用官方定義的,可以確保BLE的軟件和硬件能相互理解。當然,你可以自定義Characteristic,這樣的話,就只有你自己的軟件和外設能夠相互理解。
舉個例子,Heart Rate Measurement Characteristic,這是上面提到的Heart Rate Service必需實現的Characteristic,它的UUID是0x2A37。它的數據結構是,開始8bit定義心率數據格式(是UINT8還是UINT16?),接下來就是對應格式的實際心率數據。
實際上,和BLE外設打交道,主要是通過Characteristic。你可以從Characteristic讀取數據,也可以往Characteristic寫數據。這樣就實現了雙向的通信。所以你可以自己實現一個類似串口(UART)的service,這個Service中包含兩個Characteristic,一個被配置只讀的通道(RX),另一個配置為只寫的通道(TX)。
軟件部分設計邏輯還是十分明確的;
開發板:打開ble,開始廣播等待被發現。建立通信后,按照主機端的請求發送相應數據;
小程序:打開藍牙適配器,搜索周圍藍牙,獲取搜索過程中所搜索到的設備信息,連接想要連接的設備,獲取服務、特征值,進行數據交互;
貼上代碼:
在進行完基本初始化之后,進行對BLE的設置:
//設置回調函數
ble_hs_cfg.sync_cb = blehr_on_sync;
//初始化定時器
ble_npl_callout_init(&blehr_tx_timer, nimble_port_get_dflt_eventq(),
blehr_tx_hrate, NULL);
ble_npl_callout_init(&my_notify_tx_timer,nimble_port_get_dflt_eventq(),
my_notify_tx,NULL);
//初始化gatt服務
rc = gatt_svr_init();
assert(rc == 0);
//設備默認名字
//這里可以更改設備名字
rc = ble_svc_gap_device_name_set(device_name);
我在DEVICE_INFO Service里添加了String(0x2A3D)和0X5A5D 的自定義characteristic;
屬性分別為READ和NOTIFY
{
/*Characteristic:Model number string */
.uuid=BLE_UUID16_DECLARE(GATT_STRING_UUID),
.access_cb=gatt_svr_chr_access_device_info,
.flags=BLE_GATT_CHR_F_READ,
},
{
/*Characteristic:Model number string */
.uuid=BLE_UUID16_DECLARE(GATT_RIGHT_UUID),
.access_cb=gatt_svr_chr_access_device_info,
.val_handle = &my_notify_handle,
.flags=BLE_GATT_CHR_F_NOTIFY,
},
給2A3D的value為:"ab32vg1";
在blehr中寫了(0x5A5D)notify的實現;
代碼如下:
//my notify--
static void my_notify_stop(void)
{
ble_npl_callout_stop(&my_notify_tx_timer);
}
//重置
static void my_notify_reset(void)
{
int rc;
rc = ble_npl_callout_reset(&my_notify_tx_timer, RT_TICK_PER_SECOND);
assert(rc == 0);
}
static void my_notify_tx(struct ble_npl_event* ev2)
{
static char my_notify_hrm[2];
int rc;
struct os_mbuf *om;
if (!notify_state) {
my_notify_stop();
XXX = 15;
return;
}
my_notify_hrm[0] = 0x02; /* contact of a sensor *///傳感器的聯系
my_notify_hrm[1] = XXX; /* storing dummy data *///儲存虛擬數據
/* Simulation of heart beats *///模擬心跳
XXX++;
if (XXX == 50) {
XXX = 90;
}
om = ble_hs_mbuf_from_flat(my_notify_hrm, sizeof(my_notify_hrm));
rc = ble_gattc_notify_custom(my_notify_conn_handle, my_notify_handle, om);
assert(rc == 0);
my_notify_reset();
}
在blehr的gap事件函數中設置notify事件:
case BLE_GAP_EVENT_SUBSCRIBE:
//對等方訂閱狀態的狀態更改1?2:3
MODLOG_DFLT(INFO, "subscribe event; cur_notify=%d\n value handle; "
,"val_handle2=%d\n",
event->subscribe.cur_notify, my_notify_handle);
if (event->subscribe.attr_handle !=0) {
if (event->subscribe.attr_handle==my_notify_handle)
{
notify_state = event->subscribe.cur_notify;
my_notify_conn_handle = event->subscribe.conn_handle;
my_notify_reset();
}
} else if (event->subscribe.attr_handle != (&my_notify_handle)) {
notify_state = event->subscribe.cur_notify;
notify_conn_handle = 0;
my_notify_conn_handle=0;
my_notify_stop();
}
break;
最后進行定時器的初始化:
ble_npl_callout_init(&my_notify_tx_timer,nimble_port_get_dflt_eventq(),my_notify_tx,NULL);
現在進行測試:
開發板程序運行正常!
現在展示小程序的代碼:
wxml:
<view class="content">
<text>\ntext>
<view class="p2" bindtap="getBluetoothDevices">
<text style="margin-left:36px">可用設備text>
view>
<block wx:if="{{show_available_devices_switch === 0}}">
<block wx:for="{{devices}}">
<view>
<text style="margin-left:36px" class="p3" id="{{item.deviceId}}" data-device-name="{{item.name}}" bindtap="connectTO">{{item.name}}text>
view>
block>
block>
<block wx:if="{{connected_device_switch === 0}}">
<view>
<text class="p3" style="margin-left:36px">{{device_name}} 已連接text>
view>
block>
<text>\n\n\ntext>
<view>
<text class="p2" style="margin-left:36px">接收字符串 text>
view>
<view>
<text class="p3" style="margin-left:36px">{{cur_string}}《-text>
view>
<text>\ntext>
<view>
<text class="p2" style="margin-left:36px">接收訂閱text>
view>
<view>
<text class="p3" style="margin-left:36px">{{cur_notify}}《-text>
view>
<text>\ntext>
wxss:
page {
color: #333;
}
.devices_summary {
margin-top: 30px;
padding: 10px;
font-size: 16px;
}
.device_list {
height: 300px;
margin: 50px 5px;
margin-top: 0;
border: 1px solid #EEE;
border-radius: 5px;
width: auto;
}
.device_item {
border-bottom: 1px solid #EEE;
padding: 10px;
color: #666;
}
.device_item_hover {
background-color: rgba(0, 0, 0, .1);
}
.connected_info {
position: fixed;
bottom: 0;
width: 100%;
background-color: #F0F0F0;
padding: 10px;
padding-bottom: 20px;
margin-bottom: env(safe-area-inset-bottom);
font-size: 14px;
min-height: 100px;
box-shadow: 0px 0px 3px 0px;
}
.connected_info .operation {
position: absolute;
display: inline-block;
right: 30px;
}
.p1 {
position: relative;
left: 36px;
}
.p2 {
font-size: 1.3em;
font-weight: 500;
font-family: 'Times New Roman', Times, serif;
}
.p3 {
font-weight: 400;
color: rgb(171, 171, 171);
}
.p4 {
position: relative;
right: 36px;
}
.p5 {
font-family: SimSun;
}
js后端:
// 初始化藍牙適配器
this.initBluetoothAdapter();
// 本機藍牙適配器狀態
this.getBluetoothAdapterState();
// 開始搜索外圍設備
this.startBluetoothDevicesDiscovery();
/* 獲取在藍牙模塊生效期間所有已發現的藍牙設備。包括已經和本機處于連接狀態的設備。*/
getBluetoothDevices: function() {
var that = this;
wx.getBluetoothDevices({
success: function(res) {
console.log('搜到的藍牙設備數目:' + res.devices.length);
console.log(res.devices);
that.setData({
devices: res.devices,
/* 顯示可用設備開關 */
show_available_devices_switch: 0,
});
},
}
...
具體代碼在我的評論區
(6.94 MB)下載
尋游記: 這里是代碼:https://gitee.com/YYYYYao/ab32-vg1-ble.git
回復