- 2024-11-04
-
回复了主题帖:
【NUCLEO-WB09KE】开箱及开发环境测试
lijinlei 发表于 2024-11-3 15:28
我的怎么都识别不到设备,连接开发板之后端口根本没变化
板子上有个跳线,设置到boot loader状态,我上面有图
- 2024-10-29
-
发表了主题帖:
【NUCLEO-WB09KE】BLE应用架构与分析
1、测试介绍
(1)测试前说明
为了了解ST BLE设备的编程架构,开始对ST提供的应用进行测试。最开始时使用“BLE_Peripheral_Lite”应用进行研究,结果该应用出现了配对失败的问题,随即放弃了该应用转而使用BLE_p2pServer应用进行测试。所以下面的测试为该应用的分析和测试。
(2)测试需要的硬件
PC主机:系统为windows 10版本
USB蓝牙适配器:版本为5.4,建议使用勉驱的产品,需要驱动的产品又可能出现兼容问题。
NUCLEO-WB09KE开发板:主要芯片为STM32WB09KE芯片,为低功耗产品ARM m0+内核
(3)测试需要的软件
Bluetooth LE Eplorer:该软件为微软提供的测试产品,虽然功能一般但是较为实用。可以从微软的应用商店免费获得。
BLE_p2pServer: STM32WB0 的演示程序。使用STM32CubeMX复制
ComAssistant串口助手:可以从EE下载,软件为本人编写
2、测试过程
(1)下载安装Bluetooth LE Eplorer软件
软件比较简洁,只要启动就可以使用了
(2)烧写BLE_p2pServer到开发板
注意:需要将开发板的跳线设置到Boot Loader状态。
打开keil软件编译程序,如果可以连接开发板则进行烧写
烧写到开发板后,重新上电,上电后
打开串口连接测试串口波特率:115200,N,8,1
按压B3停止系统指示灯不停闪烁,按压B1开始系统连接状态
(3)连接配对
将开发板的跳线设置到USER FLASH状态
进行配对,可以发现设备的PIN码一致,如果:多次配对需要在windows设备管理中删除设备。
配对成功后
进行操作,向设备写入0101打开LED1 ,写入0100关闭LED1
写入命令
3、程序结构分析
设备功能参数,设备包含三组“Service”
服务号:UUID
SERVICE1
UUID:00001801-0000-1000-8000-00805f9b34fb
SERVICE2
UUID:00001800-0000-1000-8000-00805f9b34fb
SERVICE3
UUID:0000fe40-cc7a-482a-984a-7f2ed5b3e58f
#define P2P_SERVER_UUID 0x8f,0xe5,0xb3,0xd5,0x2e,0x7f,0x4a,0x98,0x2a,0x48,0x7a,0xcc,0x40,0xfe,0x00,0x00
#define LED_C_UUID 0x19,0xed,0x82,0xae,0xed,0x21,0x4c,0x9d,0x41,0x45,0x22,0x8e,0x41,0xfe,0x00,0x00
#define SWITCH_C_UUID 0x19,0xed,0x82,0xae,0xed,0x21,0x4c,0x9d,0x41,0x45,0x22,0x8e,0x42,0xfe,0x00,0x00
这个与程序定义的一致。
/* USER CODE BEGIN Header */
/**
******************************************************************************
* [url=home.php?mod=space&uid=1307177]@File[/url] p2p_server_app.c
* [url=home.php?mod=space&uid=1315547]@author[/url] MCD Application Team
* [url=home.php?mod=space&uid=159083]@brief[/url] p2p_server_app application definition.
******************************************************************************
* [url=home.php?mod=space&uid=1020061]@attention[/url] *
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "app_common.h"
#include "app_ble.h"
#include "ble.h"
#include "p2p_server_app.h"
#include "p2p_server.h"
#include "stm32_seq.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
typedef struct{
uint8_t Device_Led_Selection;
uint8_t Led1;
}P2P_LedCharValue_t;
typedef struct{
uint8_t Device_Button_Selection;
uint8_t ButtonStatus;
}P2P_ButtonCharValue_t;
/* USER CODE END PTD */
typedef enum
{
Switch_c_NOTIFICATION_OFF,
Switch_c_NOTIFICATION_ON,
/* USER CODE BEGIN Service1_APP_SendInformation_t */
/* USER CODE END Service1_APP_SendInformation_t */
P2P_SERVER_APP_SENDINFORMATION_LAST
} P2P_SERVER_APP_SendInformation_t;
typedef struct
{
P2P_SERVER_APP_SendInformation_t Switch_c_Notification_Status;
/* USER CODE BEGIN Service1_APP_Context_t */
P2P_LedCharValue_t LedControl;
P2P_ButtonCharValue_t ButtonControl;
/* USER CODE END Service1_APP_Context_t */
uint16_t ConnectionHandle;
} P2P_SERVER_APP_Context_t;
/* Private defines -----------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* External variables --------------------------------------------------------*/
/* USER CODE BEGIN EV */
/* USER CODE END EV */
/* Private macros ------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
static P2P_SERVER_APP_Context_t P2P_SERVER_APP_Context;
uint8_t a_P2P_SERVER_UpdateCharData[247];
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
static void P2P_SERVER_Switch_c_SendNotification(void);
/* USER CODE BEGIN PFP */
static void P2P_SERVER_APP_LED_BUTTON_context_Init(void);
/* USER CODE END PFP */
/* Functions Definition ------------------------------------------------------*/
void P2P_SERVER_Notification(P2P_SERVER_NotificationEvt_t *p_Notification)
{
/* USER CODE BEGIN Service1_Notification_1 */
/* USER CODE END Service1_Notification_1 */
switch(p_Notification->EvtOpcode)
{
/* USER CODE BEGIN Service1_Notification_Service1_EvtOpcode */
/* USER CODE END Service1_Notification_Service1_EvtOpcode */
case P2P_SERVER_LED_C_READ_EVT:
/* USER CODE BEGIN Service1Char1_READ_EVT */
/* USER CODE END Service1Char1_READ_EVT */
break;
case P2P_SERVER_LED_C_WRITE_NO_RESP_EVT:
/* USER CODE BEGIN Service1Char1_WRITE_NO_RESP_EVT */
if(p_Notification->DataTransfered.p_Payload[1] == 0x01)
{
BSP_LED_On(LED_BLUE);
APP_DBG_MSG("-- P2P APPLICATION SERVER : LED1 ON\n");
P2P_SERVER_APP_Context.LedControl.Led1 = 0x01; /* LED1 ON */
}
if(p_Notification->DataTransfered.p_Payload[1] == 0x00)
{
BSP_LED_Off(LED_BLUE);
APP_DBG_MSG("-- P2P APPLICATION SERVER : LED1 OFF\n");
P2P_SERVER_APP_Context.LedControl.Led1 = 0x00; /* LED1 OFF */
}
/* USER CODE END Service1Char1_WRITE_NO_RESP_EVT */
break;
case P2P_SERVER_SWITCH_C_NOTIFY_ENABLED_EVT:
/* USER CODE BEGIN Service1Char2_NOTIFY_ENABLED_EVT */
P2P_SERVER_APP_Context.Switch_c_Notification_Status = Switch_c_NOTIFICATION_ON;
APP_DBG_MSG("-- P2P APPLICATION SERVER : NOTIFICATION ENABLED\n");
APP_DBG_MSG(" \n\r");
/* USER CODE END Service1Char2_NOTIFY_ENABLED_EVT */
break;
case P2P_SERVER_SWITCH_C_NOTIFY_DISABLED_EVT:
/* USER CODE BEGIN Service1Char2_NOTIFY_DISABLED_EVT */
P2P_SERVER_APP_Context.Switch_c_Notification_Status = Switch_c_NOTIFICATION_OFF;
APP_DBG_MSG("-- P2P APPLICATION SERVER : NOTIFICATION DISABLED\n");
APP_DBG_MSG(" \n\r");
/* USER CODE END Service1Char2_NOTIFY_DISABLED_EVT */
break;
default:
/* USER CODE BEGIN Service1_Notification_default */
/* USER CODE END Service1_Notification_default */
break;
}
/* USER CODE BEGIN Service1_Notification_2 */
/* USER CODE END Service1_Notification_2 */
return;
}
void P2P_SERVER_APP_EvtRx(P2P_SERVER_APP_ConnHandleNotEvt_t *p_Notification)
{
/* USER CODE BEGIN Service1_APP_EvtRx_1 */
/* USER CODE END Service1_APP_EvtRx_1 */
switch(p_Notification->EvtOpcode)
{
/* USER CODE BEGIN Service1_APP_EvtRx_Service1_EvtOpcode */
/* USER CODE END Service1_APP_EvtRx_Service1_EvtOpcode */
case P2P_SERVER_CONN_HANDLE_EVT :
P2P_SERVER_APP_Context.ConnectionHandle = p_Notification->ConnectionHandle;
/* USER CODE BEGIN Service1_APP_CENTR_CONN_HANDLE_EVT */
/* USER CODE END Service1_APP_CENTR_CONN_HANDLE_EVT */
break;
case P2P_SERVER_DISCON_HANDLE_EVT :
P2P_SERVER_APP_Context.ConnectionHandle = 0xFFFF;
/* USER CODE BEGIN Service1_APP_DISCON_HANDLE_EVT */
P2P_SERVER_APP_LED_BUTTON_context_Init();
/* USER CODE END Service1_APP_DISCON_HANDLE_EVT */
break;
default:
/* USER CODE BEGIN Service1_APP_EvtRx_default */
/* USER CODE END Service1_APP_EvtRx_default */
break;
}
/* USER CODE BEGIN Service1_APP_EvtRx_2 */
/* USER CODE END Service1_APP_EvtRx_2 */
return;
}
void P2P_SERVER_APP_Init(void)
{
P2P_SERVER_APP_Context.ConnectionHandle = 0xFFFF;
P2P_SERVER_Init();
/* USER CODE BEGIN Service1_APP_Init */
UTIL_SEQ_RegTask( 1U << CFG_TASK_SEND_NOTIF_ID, UTIL_SEQ_RFU, P2P_SERVER_Switch_c_SendNotification);
/**
* Initialize LedButton Service
*/
P2P_SERVER_APP_Context.Switch_c_Notification_Status= Switch_c_NOTIFICATION_OFF;
P2P_SERVER_APP_LED_BUTTON_context_Init();
/* USER CODE END Service1_APP_Init */
return;
}
/* USER CODE BEGIN FD */
void P2P_SERVER_APP_LED_BUTTON_context_Init(void)
{
BSP_LED_Off(LED_BLUE);
P2P_SERVER_APP_Context.LedControl.Device_Led_Selection=0x01; /* Device1 */
P2P_SERVER_APP_Context.LedControl.Led1=0x00; /* led OFF */
P2P_SERVER_APP_Context.ButtonControl.Device_Button_Selection=0x01;/* Device1 */
P2P_SERVER_APP_Context.ButtonControl.ButtonStatus=0x00;
return;
}
/* USER CODE END FD */
/*************************************************************
*
* LOCAL FUNCTIONS
*
*************************************************************/
__USED void P2P_SERVER_Switch_c_SendNotification(void) /* Property Notification */
{
P2P_SERVER_APP_SendInformation_t notification_on_off = Switch_c_NOTIFICATION_OFF;
P2P_SERVER_Data_t p2p_server_notification_data;
p2p_server_notification_data.p_Payload = (uint8_t*)a_P2P_SERVER_UpdateCharData;
p2p_server_notification_data.Length = 0;
/* USER CODE BEGIN Service1Char2_NS_1*/
if(P2P_SERVER_APP_Context.ButtonControl.ButtonStatus == 0x00)
{
P2P_SERVER_APP_Context.ButtonControl.ButtonStatus = 0x01;
}
else
{
P2P_SERVER_APP_Context.ButtonControl.ButtonStatus = 0x00;
}
a_P2P_SERVER_UpdateCharData[0] = 0x01; /* Device Led selection */
a_P2P_SERVER_UpdateCharData[1] = P2P_SERVER_APP_Context.ButtonControl.ButtonStatus;
/* Update notification data length */
p2p_server_notification_data.Length = (p2p_server_notification_data.Length) + 2;
if(P2P_SERVER_APP_Context.Switch_c_Notification_Status == Switch_c_NOTIFICATION_ON)
{
APP_DBG_MSG("-- P2P APPLICATION SERVER : INFORM CLIENT BUTTON 1 PUSHED\n");
notification_on_off = Switch_c_NOTIFICATION_ON;
}
else
{
APP_DBG_MSG("-- P2P APPLICATION SERVER : CAN'T INFORM CLIENT - NOTIFICATION DISABLED\n");
}
/* USER CODE END Service1Char2_NS_1*/
if (notification_on_off != Switch_c_NOTIFICATION_OFF && P2P_SERVER_APP_Context.ConnectionHandle != 0xFFFF)
{
P2P_SERVER_NotifyValue(P2P_SERVER_SWITCH_C, &p2p_server_notification_data, P2P_SERVER_APP_Context.ConnectionHandle);
}
/* USER CODE BEGIN Service1Char2_NS_Last*/
/* USER CODE END Service1Char2_NS_Last*/
return;
}
/* USER CODE BEGIN FD_LOCAL_FUNCTIONS*/
/* USER CODE END FD_LOCAL_FUNCTIONS*/
程序摘抄与p2p_serverApp.c文件。
/* Private function prototypes -----------------------------------------------*/
static void P2P_SERVER_Switch_c_SendNotification(void);
/* USER CODE BEGIN PFP */
static void P2P_SERVER_APP_LED_BUTTON_context_Init(void);
程序中有关键的回调函数:P2P_SERVER_Switch_c_SendNotification,这个函数在收到消息后被调用。
事件的执行如下:
case P2P_SERVER_LED_C_WRITE_NO_RESP_EVT:
/* USER CODE BEGIN Service1Char1_WRITE_NO_RESP_EVT */
if(p_Notification->DataTransfered.p_Payload[1] == 0x01)
{
BSP_LED_On(LED_BLUE);
APP_DBG_MSG("-- P2P APPLICATION SERVER : LED1 ON\n");
P2P_SERVER_APP_Context.LedControl.Led1 = 0x01; /* LED1 ON */
}
if(p_Notification->DataTransfered.p_Payload[1] == 0x00)
{
BSP_LED_Off(LED_BLUE);
APP_DBG_MSG("-- P2P APPLICATION SERVER : LED1 OFF\n");
P2P_SERVER_APP_Context.LedControl.Led1 = 0x00; /* LED1 OFF */
}
/* USER CODE END Service1Char1_WRITE_NO_RESP_EVT */
break;
这里含有一个开关控制:P2P_SERVER_SWITCH_C_NOTIFY_ENABLED_EVT可以扩展该函数。
- 2024-10-28
-
回复了主题帖:
测评入围名单: 英飞凌PSOC™ 4100S Max Pioneer套件
计划确认,可以按时完成测评。感谢英飞凌和EE
- 2024-10-26
-
回复了主题帖:
#反激大作战#来聊一聊,在设计反激电源的时候,你觉得最重要的是什么?
变压器最难的是基础知识,多数都是经验格式,但是又不告诉你这参数如何确定。先确定什么后确定什么。
例如:
(1)开关频率和开关损耗什么关系
(2)线径和肌肤效应什么关系(频率一定的情况下)
(3)变压器的电感如何确定等。
(4)气隙的距离和匝数关系等
- 2024-10-23
-
发表了主题帖:
光耦模拟电位器原理
1、如图:两个光耦模拟电位器的电路。
2、该电路使用两个光耦模拟电位器,PWM的脉宽通过上下两个光耦调节“电位器”的输出的电位。
这个电路通过RC滤波来控制电位器的输出电压,这个和简易的DAC非常相似。
我的问题是这个电路的功耗如何计算。是不是可以等效为电阻分压电路?
- 2024-10-22
-
回复了主题帖:
请问,这个有两个MOS管控制的12V电压的工作过程怎么分析?
就是EN-2端的电压不能直接开启Q3的G端电压,使用Q4作为中间转换一下。常见到的方案是Q4为三极管,这里用了MOS管
-
回复了主题帖:
【NUCLEO-WB09KE】蓝牙通信与OTA升级
wangerxian 发表于 2024-10-22 09:07
通过手机可以给它OTA升级吗。
可以,使用ST的工具软件或高版本的web页面都可以。这个比较方便
- 2024-10-19
-
回复了主题帖:
【NUCLEO-WB09KE】蓝牙通信与OTA升级
感觉OTA应用的安全性有待提高
- 2024-10-18
-
发表了主题帖:
【NUCLEO-WB09KE】蓝牙通信与OTA升级
本帖最后由 bigbat 于 2024-10-19 15:12 编辑
1、测试介绍
目前我们使用的升级都可以使用OTA进行升级,ST公司也可以使用蓝牙通讯进行OTA升级程序。本次测试将对OTA进行测试。测试的硬件除了NUCLEO-WB09KE开发板外,还需要准备手机硬件或PC主机。手机只可以用作OTA升级服务器,而PC机除了可以使用做OTA升级服务器外也可以用作开发使用。既然是OTA那么就应该使用方便才行。所以ST公司将提供了web方式的OTA服务程序。
按照ST公司的方案,只需要下载STM32WBA-Web-Bluetooth-App-Interfaces程序到本地,然后根据需要修改成公司的OTA页面。
但是这里有个BUG,我的应用在安装后,一直停在了”npm warn deprecated svgo@1.3.2: This SVGO version is no longer supported. Upgrade to v2.x.x.“就不再动了。
npm install
所以只能使用https://applible.github.io/Web_Bluetooth_App_WBA/
页面链接和配对和升级服务器。
2、NUCLEO-WB09KE开发板OTA存根服务器
开发板必须使用OTA服务的程序才可以。ST公司提供了BLE_ApplicationInstallManager、BLE_p2pServer_ota、BLE_HeartRate_ota三个程序带有OTA服务。
使用开发工具烧写到开发板
3、OTA服务建立程序
(1)建立配对
(2)配对成功
(3)升级设置
(4)进入OTA升级服务
(5)上传OTA程序,BLE_p2pServer_ota.bin程序
(6)升级程序成功后
(7)完后,程序就具有OTA功能的BLE_p2pServer_ota的程序
(8)连接配对后可以使用该页面测试
(9)测试程序
4、测试照片
Ligth ON 灯打开
Ligth OFF 灯关闭
5、总结
OTA程序的服务只要有OTA就可以使用OTA服务。
- 2024-10-17
-
回复了主题帖:
【入围名单】Follow me第二季第3期,与得捷一起解锁开发板超能力!
个人信息已更改,由于mail.tom.com的邮箱服务公司停止服务,邮箱已经更改。申请更改个人信息
- 2024-10-13
-
加入了学习《DigiKey 应用说:蓝牙5.4 新特性解读及实例演示》,观看 蓝牙5.4 新特性解读及实例演示
- 2024-10-12
-
回复了主题帖:
【NUCLEO-WB09KE】蓝牙通信的稳定性与BEACON服务
dvacos 发表于 2024-10-11 16:43
Beacon 就是广播,不能连接代码专门设置的不给连接。
Beacon 协议可以包含指令的,例如:发出指令使得设备锁定等动作,只是需要设备服务端配合
- 2024-10-11
-
回复了主题帖:
【NUCLEO-WB09KE】PC机与蓝牙设备通讯与web编程
dvacos 发表于 2024-10-11 16:42
你这个是谷歌的web ble的demo改的吧(询问,没恶意)?
这些demo没有服务器是不是不能在手机上运行,要 ...
手机上的需要看操作系统的版本,其实是浏览器的内核,我的程序也可以运行在web服务器当中。客户端本地不需要安装任何支持库
-
回复了主题帖:
【NUCLEO-WB09KE】PC机与蓝牙设备通讯与web编程
dvacos 发表于 2024-10-11 16:42
你这个是谷歌的web ble的demo改的吧(询问,没恶意)?
这些demo没有服务器是不是不能在手机上运行,要 ...
是web标准的BLE API,不需要额外的设置。最新的浏览器都支持。可以参考文章中的相关连接
-
发表了主题帖:
【NUCLEO-WB09KE】蓝牙通信的稳定性与BEACON服务
1、测试介绍
无线信标服务是一种物件定位跟踪服务,BLE Beacon服务可以用来监视我们身边的一些智能设备是否离开我们的距离。如:佩戴Beacon服务设备的儿童在该设备远离我们的距离足够远时,设备向我们发出“告警”,提示我们应该注意这一情况。本次测试将使用NUCLEO-WB09KE开发板模拟Beacon设备。
2、测试过程
(1)通过STM32Cube下载测试程序BLE_Beacon测试例程
(2)使用keil编译例程,烧写到开发板
(3)下载一个Beacon服务应用
Beacon服务软件比较多,我选择了BrigthBeacon软件。
(4)打开软件进行设置
注意:一定要给设备赋予蓝牙使用权限
打开后可以发现会从当前搜索到一些可以接收的Beacon设备,这些设备不需要预先和手机配对
(5)将开发板设备添加到软件当中。
需要添加的设备UUID为:00010203-0405-0607-0809-0a0b0c0d0e0f
这个UUID是从Readme.html文件中获得的。
开发板设备的UUID被登记后,就可以使用软件查看该设备的详细信息了。
(6)测试开发板的功能
因为开发板不能移动,所以我就将手机拿到远离开发板的地方进行测试。可能是我的USB BLE适配器太好了的缘故,我(我家在三楼,为板楼结构)将设备直到拿到一楼才发现设备信号丢失。
查找设备详细信息
回到二楼发现信号
设备信息
重新出现。
3、测试过程总结
测试中发现周围很多的Beacon设备,不知道开发板如何接收Beacon的信号。
对于Beacon服务和BLE设备关系是怎样定义的,本测试中的Beacon设备无法与主设备(PC或手机)都无法配对。后续我将继续深入的学习该协议。
-
回复了主题帖:
【NUCLEO-WB09KE】PC机与蓝牙设备通讯与web编程
最近正在学习node.js,发现js可以开发的内容大大超出了传统web的范畴,可以覆盖大部分的桌面APP。包括BLE API和摄像头等等外设。
- 2024-10-10
-
发表了主题帖:
【NUCLEO-WB09KE】PC机与蓝牙设备通讯与web编程
1、测试介绍
本测试 使用开发板模拟心率仪,用来验证连接性、BLE、BLE 协议、BLE 配对、BLE 配置文件等项目。其中的程序可以作为BLE的编程框架来使用。测试使用NUCLEO-WB09KE作为BLE“服务端”,客户端使用web页面的javascript程序作为“客户端”。本测试最开始使用移动客户端作为测试工具,最近我在学习scratch编程时,发现现在的node.js也可以支持BLE的API,并且可以很好的使用web浏览器作为客户端向web网站发送测试数据,于是就改用javascript作为客户端了。
2、客户端介绍
客户端的源码是我从https://github.com/WebBluetoothCG/demos项目下载的。心率仪作为BLE的标准设备。通讯和数据格式已经被固定格式化了。只要提供规定的API函数就可以使用任何的客户端程序和设备链接。
首先是定义一个index.html文件作为页面
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Heart Rate Sensor Demo</title>
<meta name="description" content="Monitor a heart rate sensor with a Web Bluetooth app.">
<link rel="icon" sizes="192x192" href="../favicon.png">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="container">
<div id="statusText">GET ❤</div>
<canvas id="waves"></canvas>
</div>
<script src="/heartRateSensor.js"></script>
<script src="/app.js"></script>
</body>
</html>
程序主要分为app.js,本程序主要是用来在画布“canvas”上面显示数据和界面交互。画布的id="waves"。
var canvas = document.querySelector('canvas');
var statusText = document.querySelector('#statusText');
statusText.addEventListener('click', function() {
statusText.textContent = 'Breathe...';
heartRates = [];
heartRateSensor.connect()
.then(() => heartRateSensor.startNotificationsHeartRateMeasurement().then(handleHeartRateMeasurement))
.catch(error => {
statusText.textContent = error;
});
});
function handleHeartRateMeasurement(heartRateMeasurement) {
heartRateMeasurement.addEventListener('characteristicvaluechanged', event => {
var heartRateMeasurement = heartRateSensor.parseHeartRate(event.target.value);
statusText.innerHTML = heartRateMeasurement.heartRate + ' ❤';
heartRates.push(heartRateMeasurement.heartRate);
drawWaves();
});
}
var heartRates = [];
var mode = 'bar';
canvas.addEventListener('click', event => {
mode = mode === 'bar' ? 'line' : 'bar';
drawWaves();
});
function drawWaves() {
requestAnimationFrame(() => {
canvas.width = parseInt(getComputedStyle(canvas).width.slice(0, -2)) * devicePixelRatio;
canvas.height = parseInt(getComputedStyle(canvas).height.slice(0, -2)) * devicePixelRatio;
var context = canvas.getContext('2d');
var margin = 2;
var max = Math.max(0, Math.round(canvas.width / 11));
var offset = Math.max(0, heartRates.length - max);
context.clearRect(0, 0, canvas.width, canvas.height);
context.strokeStyle = '#00796B';
if (mode === 'bar') {
for (var i = 0; i < Math.max(heartRates.length, max); i++) {
var barHeight = Math.round(heartRates[i + offset ] * canvas.height / 200);
context.rect(11 * i + margin, canvas.height - barHeight, margin, Math.max(0, barHeight - margin));
context.stroke();
}
} else if (mode === 'line') {
context.beginPath();
context.lineWidth = 6;
context.lineJoin = 'round';
context.shadowBlur = '1';
context.shadowColor = '#333';
context.shadowOffsetY = '1';
for (var i = 0; i < Math.max(heartRates.length, max); i++) {
var lineHeight = Math.round(heartRates[i + offset ] * canvas.height / 200);
if (i === 0) {
context.moveTo(11 * i, canvas.height - lineHeight);
} else {
context.lineTo(11 * i, canvas.height - lineHeight);
}
context.stroke();
}
}
});
}
window.onresize = drawWaves;
document.addEventListener("visibilitychange", () => {
if (!document.hidden) {
drawWaves();
}
});
heartRateSensor.js文件,js使用BLE通过API从设备中调测试数据。设备BLE被定义在navigator.bluetooth.requestDevice中,函数将返回一个设备class,成功后装配该对象。
(function() {
'use strict';
class HeartRateSensor {
constructor() {
this.device = null;
this.server = null;
this._characteristics = new Map();
}
connect() {
return navigator.bluetooth.requestDevice({filters:[{services:[ 'heart_rate' ]}]})
.then(device => {
this.device = device;
return device.gatt.connect();
})
.then(server => {
this.server = server;
return server.getPrimaryService('heart_rate');
})
.then(service => {
return this._cacheCharacteristic(service, 'heart_rate_measurement');
})
}
/* Heart Rate Service */
startNotificationsHeartRateMeasurement() {
return this._startNotifications('heart_rate_measurement');
}
stopNotificationsHeartRateMeasurement() {
return this._stopNotifications('heart_rate_measurement');
}
parseHeartRate(value) {
// In Chrome 50+, a DataView is returned instead of an ArrayBuffer.
value = value.buffer ? value : new DataView(value);
let flags = value.getUint8(0);
let rate16Bits = flags & 0x1;
let result = {};
let index = 1;
if (rate16Bits) {
result.heartRate = value.getUint16(index, /*littleEndian=*/true);
index += 2;
} else {
result.heartRate = value.getUint8(index);
index += 1;
}
let contactDetected = flags & 0x2;
let contactSensorPresent = flags & 0x4;
if (contactSensorPresent) {
result.contactDetected = !!contactDetected;
}
let energyPresent = flags & 0x8;
if (energyPresent) {
result.energyExpended = value.getUint16(index, /*littleEndian=*/true);
index += 2;
}
let rrIntervalPresent = flags & 0x10;
if (rrIntervalPresent) {
let rrIntervals = [];
for (; index + 1 < value.byteLength; index += 2) {
rrIntervals.push(value.getUint16(index, /*littleEndian=*/true));
}
result.rrIntervals = rrIntervals;
}
return result;
}
/* Utils */
_cacheCharacteristic(service, characteristicUuid) {
return service.getCharacteristic(characteristicUuid)
.then(characteristic => {
this._characteristics.set(characteristicUuid, characteristic);
});
}
_readCharacteristicValue(characteristicUuid) {
let characteristic = this._characteristics.get(characteristicUuid);
return characteristic.readValue()
.then(value => {
// In Chrome 50+, a DataView is returned instead of an ArrayBuffer.
value = value.buffer ? value : new DataView(value);
return value;
});
}
_writeCharacteristicValue(characteristicUuid, value) {
let characteristic = this._characteristics.get(characteristicUuid);
return characteristic.writeValue(value);
}
_startNotifications(characteristicUuid) {
let characteristic = this._characteristics.get(characteristicUuid);
// Returns characteristic to set up characteristicvaluechanged event
// handlers in the resolved promise.
return characteristic.startNotifications()
.then(() => characteristic);
}
_stopNotifications(characteristicUuid) {
let characteristic = this._characteristics.get(characteristicUuid);
// Returns characteristic to remove characteristicvaluechanged event
// handlers in the resolved promise.
return characteristic.stopNotifications()
.then(() => characteristic);
}
}
window.heartRateSensor = new HeartRateSensor();
})();
当收到数据后调用相关的事件函数。BLE的API请参考:https://developer.mozilla.org/en-US/docs/Web/API/BluetoothDevice
3、测试过程
(1)首先使用STM32Cub下载BLE_HeartRate程序到本地磁盘。
(2)使用编译工具烧写到开发板。
我使用的是keil工具烧写到开发板。烧写完成后,开发板就可以模拟心率仪了。
(3)使用PC机连接和配对心率仪HR_5C
这里需要注意使用比较高的BLE适配器,最初我使用的是4.0的适配器,只能连接但是会出现问题。这里不知道是我的适配器的问题还是什么问题。我换成BLE 5.4的适配器就没有出现问题了。我的BLE 4.0是需要驱动的。是不是和这个有关系就不知道了,所以还请知道的朋友科普。
(4)配对连接设备
如果不配对就会连接失败
这个API会记录上次的配对设备,如果连接不上可以将设备重新上电和运行程序。
(5)配对连接后就可以从页面上显示数据了
4、总结
蓝牙设备有很多的属性文件。如果想开发BLE设备需要仔细的研究GATT官方。ST官方的协议栈编程的框架学习曲线较为陡直。目前我也是入门,在后期的测试中我会分享一些心得。
- 2024-09-16
-
回复了主题帖:
【NUCLEO-WB09KE】开箱及开发环境测试
不知道为什么链接配对成功,但是windows中没有出现串口设备。我的windows是win10,蓝牙是4.0模块。是不是需要5.4的模块呀
- 2024-09-15
-
发表了主题帖:
【NUCLEO-WB09KE】开箱及开发环境测试
1、开发板介绍
NUCLEO-WB09KE,其中核心MCU STM32WB09KE为超低功耗Arm Cortex-M0+ MCU,运行频率64 MHz,具有512 KB Flash存储器、64 KB RAM,支持Bluetooth LE 5.4。这个与ST公司推出的STM32WB的其它系列采用的是基于以64 MHz运行的Arm® Cortex®‐M4内核,该系列从结构上推断STM32WB0XX应该功耗要更低。 Bluetooth®低功耗5.4的传输距离更长,速度快的特点。我拿到手的ST NUCLEO-WB09KE开发板是由两块组成的。下层的是ST-Link调试和按键、LED开发板。上层是蓝牙核心开发板。
2、开发环境搭建
开发环境搭建的测试只测试出了keil的环境。STM32CubeProgrammer的环境一直没有成功,我为此还下载了最新版本的环境。VSCode+OpenOCD的环境因为没有STM32WB0XX芯片的支持有没有成功。期待ST能够尽快的完善该款芯片的支持。
(1)首先下载或升级STM32CubeMX的最新版本。从首页安装添加STM32WB0的支持包。
最新版本是默认支持的。低版本可能无法安装该支持包,因此需要新版STM32Cube
安装完成后安装keil的支持。
(2)STM32WB0的芯片在keil的官方无法直接获得支持包。需要手工安装该开发包。
从C:\Users\[username]\STM32Cube\Repository\STM32Cube_FW_WB0_V1.0.0\Utilities\PC_Softwarem目录可以获得keil和IAR的支持包。
(3)手工安装该支持包到keil环境。
解压zip文件
单机文件或从keil包管理其中手工安装
(4)从STM32Cube中导入STM32WB0的BLE_SerialPort_Server 例程。
(5)烧录程序到开发板
完成后就可以测试。
3、测试过程
烧录前需要将开发板的启动模式使用跳线设置为Bootloader模式,否则无法烧写程序。
上电后如果再次烧写程序,需要按开发板的RESET按钮!!!
(2)windows PC的蓝牙中可以添加SPortS_5C的设备。
(3)链接配对完成
至此环境搭建成功
- 2024-09-13
-
回复了主题帖:
反激电源新手看过来,开源项目准备好了,是时候动手了~
很好,谢谢楼主总结