ADC采集部分请参见:https://forum.eepw.com.cn/thread/388424/1
一、首先在原来ADC采集的基础上规范下数据格式
1、定义一个16字节的数组
uint8_t four_ADC_UpdateCharData[16];
上报数据一次报16字节,而不是之前分4次每次上传4个字节
第一个4字节 | 第二个4字节 | 第三个4字节 | 第四个4字节 |
模拟参考电压 | GPIO PA7输入电压采集 | 内部参考电压1.2v | 片内温度传感器 |
2、重新编写了数据格式化函数
void formatSendData(uint32_t x,uint8_t pos) { uint8_t i; a_ADC_UpdateCharData[0] = (x >> 24) & 0xFF; // 最高有效字节 a_ADC_UpdateCharData[1] = (x >> 16) & 0xFF; a_ADC_UpdateCharData[2] = (x >> 8) & 0xFF; a_ADC_UpdateCharData[3] = x & 0xFF; // 最低有效字节 for(i=0;i<4;i++) { four_ADC_UpdateCharData[pos*4+i]=a_ADC_UpdateCharData[i]; } }
3、调用formatSendData函数,最后全部数据写入16字节数组
//Notification formatSendData(uhADCxConvertedData_VrefAnalog_mVolt,0);//模拟参考电压 formatSendData(uhADCxConvertedData_VoltageGPIO_mVolt,1);//GPIO PA7输入电压采集 formatSendData(uhADCxConvertedData_VrefInt_mVolt,2);//内部参考电压1.2v formatSendData(hADCxConvertedData_Temperature_DegreeCelsius,3);//片内温度传感器 update_ADC_data_to_char(four_ADC_UpdateCharData);
4、update_ADC_data_to_char
/* USER CODE BEGIN FD_LOCAL_FUNCTIONS*/ void update_ADC_data_to_char(uint8_t *updateData) { tBleStatus result = BLE_STATUS_INVALID_PARAMS; SERVICE1_Data_t msg_conf; msg_conf.p_Payload=updateData; msg_conf.Length=16;//sizeof(updateData); result = SERVICE1_UpdateValue(SERVICE1_ADCCHAR, &msg_conf); if( result != BLE_STATUS_SUCCESS ) { LOG_INFO_APP("Sending of Report Map Failed error 0x%X\n", result); } } /* USER CODE END FD_LOCAL_FUNCTIONS*/
数据准备完毕可以开始微信小程序的编写。
二、小程序
小程序涉及json、html、css、js的编写,如果熟悉前端很容易上手。
关于BLE小程序编写,建议参考:
1、微信官方的:https://developers.weixin.qq.com/miniprogram/dev/framework/device/ble.html
2、https://esp-document.icce.top/%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%BC%80%E5%8F%91/18%E3%80%81%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%A2%9E%E5%8A%A0%E8%93%9D%E7%89%99%E9%80%9A%E4%BF%A1%E5%8A%9F%E8%83%BD.html
1、将涉及BLE的部分做成一个组件方便调用
如下bluetooth-comp部分,这部分如何建立请参考前面2个参考连接。
index.js内容:
// components/bluetooth-comp/index.js function inArray(arr, key, val) { for (let i = 0; i < arr.length; i++) { if (arr[i][key] === val) { return i; } } return -1; } // 将字符串转为 ArrayBuffer function str2ab(str) { let buf = new ArrayBuffer(str.length); let bufView = new Uint8Array(buf); for (var i = 0, strLen = str.length; i < strLen; i++) { bufView[i] = str.charCodeAt(i); } return buf; } function intToArrayBuffer(int) { // 将整数转换为十六进制字符串 let hexStr = int.toString(16); // 计算需要的字节数,如果十六进制字符串长度为奇数,需要补0以确保字节对齐 let byteLength = (hexStr.length + (hexStr.length % 2 === 0 ? 0 : 2)) / 2; // 创建一个与计算出的字节长度相同的新的ArrayBuffer对象 let buffer = new ArrayBuffer(byteLength); let dataView = new DataView(buffer); // 将十六进制字符串中的每个字节转换为无符号8位整数,并写入到ArrayBuffer中 for (let i = 0; i < hexStr.length; i += 2) { let byte = parseInt(hexStr.substr(i, 2), 16); // 将每两个字符转换为一个字节的整数 dataView.setUint8(i / 2, byte); // 将整数写入ArrayBuffer的适当位置(注意这里假设了整数是按大端序排列的) } return buffer; // 返回生成的ArrayBuffer对象 } Component({ behaviors: ['wx://component-export'], /** * 组件的属性列表 */ properties: { }, /** * 组件的初始数据 */ // bluetooth-comp/index.js data: { devices: [], connected: false, chs: [], }, /** * 组件的方法列表 */ // bluetooth-comp/index.js methods: { triggerParentFunction(value) { console.log("发送自定义事件"); this.triggerEvent('customEvent', { message: value }); }, /* 初始化蓝牙模块 */ openBluetoothAdapter() { // 先关闭蓝牙模块再开启 防止断开后点连接连接不上 this.closeBluetoothAdapter(); wx.openBluetoothAdapter({ success: response => { console.log("初始化蓝牙模块成功:openBluetoothAdapter", response); this.startBluetoothDevicesDiscovery(); }, fail: err => { if (err.errCode === 10001) { /* 监听蓝牙适配器状态变化事件 */ wx.onBluetoothAdapterStateChange(res => { console.log("监听蓝牙适配器状态变化事件:onBluetoothAdapterStateChange", res); res.available && this.startBluetoothDevicesDiscovery(); }); } }, }); }, /* 获取本机蓝牙适配器状态 */ getBluetoothAdapterState() { wx.getBluetoothAdapterState({ success: res => { console.log("getBluetoothAdapterState", res); if (res.discovering) { // 是否正在搜索设备 this.onBluetoothDeviceFound(); } else if (res.available) { // 蓝牙适配器是否可用 this.startBluetoothDevicesDiscovery(); } }, }); }, /* 开始搜寻附近的蓝牙外围设备 */ startBluetoothDevicesDiscovery() { // 开始扫描参数 if (this._discoveryStarted) return; this._discoveryStarted = true; wx.startBluetoothDevicesDiscovery({ allowDuplicatesKey: true, success: response => { console.log("开始搜寻附近的蓝牙外围设备:startBluetoothDevicesDiscovery", response); this.onBluetoothDeviceFound(); }, fail: err => { console.log("搜索设备失败", err); wx.showToast({ title: "搜索设备失败", icon: "none" }); }, }); }, /* 停止搜寻附近的蓝牙外围设备。*/ stopBluetoothDevicesDiscovery() { console.log("停止搜寻附近的蓝牙外围设备"); wx.stopBluetoothDevicesDiscovery(); }, /* 监听搜索到新设备的事件 */ onBluetoothDeviceFound() { wx.onBluetoothDeviceFound(res => { res.devices.forEach(device => { if (!device.name && !device.localName) { return; } const foundDevices = this.data.devices; const idx = inArray(foundDevices, "deviceId", device.deviceId); const data = {}; if (idx === -1) { data[`devices[${foundDevices.length}]`] = device; } else { data[`devices[${idx}]`] = device; } this.setData(data); }); }); }, /* 连接蓝牙低功耗设备。*/ createBLEConnection(e) { const ds = e.currentTarget.dataset; const deviceId = ds.deviceId; const name = ds.name; wx.createBLEConnection({ deviceId, success: () => { this.setData({ connected: true, name, deviceId }); wx.showToast({ title: "连接蓝牙设备成功", icon: "none" }); this.getBLEDeviceServices(deviceId); }, fail: e => { console.log("连接失败", e.errMsg); wx.showToast({ title: "连接失败,错误信息: " + e.errMsg, icon: "none" }); }, }); // 停止搜寻蓝牙设备 this.stopBluetoothDevicesDiscovery(); }, /* 断开与蓝牙低功耗设备的连接。 */ closeBLEConnection() { console.log("断开与蓝牙低功耗设备的连接"); wx.showToast({ title: "已断开和蓝牙设备的连接", icon: "none" }); wx.closeBLEConnection({ deviceId: this.data.deviceId }); this.setData({ connected: false, chs: [], canWrite: false }); }, /* 获取蓝牙低功耗设备所有服务 (service) */ getBLEDeviceServices(deviceId) { wx.getBLEDeviceServices({ deviceId, success: res => { for (let i = 0; i < res.services.length; i++) { if (res.services[i].isPrimary) { this.getBLEDeviceCharacteristics(deviceId, res.services[i].uuid); return; } } }, }); }, /* 获取蓝牙低功耗设备某个服务中所有特征 (characteristic)。 */ getBLEDeviceCharacteristics(deviceId, serviceId) { wx.getBLEDeviceCharacteristics({ deviceId, serviceId, success: res => { console.log("获取蓝牙低功耗设备某个服务中所有特征:getBLEDeviceCharacteristics"); for (let i = 0; i < res.characteristics.length; i++) { let item = res.characteristics[i]; if (item.properties.read) { wx.readBLECharacteristicValue({ deviceId, serviceId, characteristicId: item.uuid }); } if (item.properties.write) { this.setData({ canWrite: true }); this._deviceId = deviceId; this._serviceId = serviceId; this._characteristicId = item.uuid; // this.writeBLECharacteristicValue(); } if (item.properties.notify || item.properties.indicate) { wx.notifyBLECharacteristicValueChange({ deviceId, serviceId, characteristicId: item.uuid, state: true, success(res) { console.log("notifyBLECharacteristicValueChange success", res); }, }); } } }, fail(res) { console.error("getBLEDeviceCharacteristics", res); }, }); // 操作之前先监听,保证第一时间获取数据 wx.onBLECharacteristicValueChange(characteristic => { // TODO 收到的信息为ArrayBuffer类型,可根据自己的需要转换 可发送给父组件用来回显 console.log("收到原始的数据", characteristic, characteristic.value, characteristic.characteristicId); if (characteristic.characteristicId == "00000002-0000-1000-8000-00805F9B34FB") { console.log("特征值正确"); this.triggerParentFunction(characteristic.value); } // 测试向设备发送数据 // this.writeBLECharacteristicValue(JSON.stringify({"FAN":"OFF"})) }); }, /* 向蓝牙低功耗设备特征值中写入二进制数据 */ writeBLECharacteristicValue(jsonStr) { let arrayBufferValue = str2ab(jsonStr); console.log("发送数据给蓝牙", "原始字符串", jsonStr, "转换arrayBuffer", arrayBufferValue); wx.writeBLECharacteristicValue({ deviceId: this._deviceId, serviceId: this._serviceId, // 微信文档上是错误的 characteristicId: this._characteristicId, value: arrayBufferValue, // 只能发送arrayBuffer类型数据 success(res) { console.log("消息发送成功", res.errMsg); wx.showToast({ title: "消息发送成功", icon: "none" }); }, fail(e) { i console.log("发送消息失败", e); i wx.showToast({ title: "发送消息失败,错误信息: " + e.errMsg, icon: "none" }); }, }); }, /* 向蓝牙低功耗设备特征值中写入十进制数据 */ writeBLECharacteristicValue1(i) { let arrayBufferValue = intToArrayBuffer(i); console.log("发送数据给蓝牙", "原始字符串", i, "转换arrayBuffer", arrayBufferValue); wx.writeBLECharacteristicValue({ deviceId: this._deviceId, serviceId: this._serviceId, // 微信文档上是错误的 characteristicId: this._characteristicId, value: arrayBufferValue, // 只能发送arrayBuffer类型数据 success(res) { console.log("消息发送成功", res.errMsg); wx.showToast({ title: "消息发送成功", icon: "none" }); }, fail(e) { console.log("发送消息失败", e); wx.showToast({ title: "发送消息失败,错误信息: " + e.errMsg, icon: "none" }); }, }); }, closeBluetoothAdapter() { console.log("关闭蓝牙模块"); wx.closeBluetoothAdapter(); this._discoveryStarted = false; }, } }) |
其中,下面代码负责对收到的notify数据进行处理:
1、所有的notify数据都在前面的代码中,被手机订阅
2、所以手机可以收到所有ble设备的notfiy,通过判断characteristicId,看是否是期待的ADC数据
3、如果是,调用triggerParentFunction函数,向上级模块发送事件及数据,提醒上级处理。
// 操作之前先监听,保证第一时间获取数据 wx.onBLECharacteristicValueChange(characteristic => { // TODO 收到的信息为ArrayBuffer类型,可根据自己的需要转换 可发送给父组件用来回显 console.log("收到原始的数据", characteristic, characteristic.value, characteristic.characteristicId); if (characteristic.characteristicId == "00000002-0000-1000-8000-00805F9B34FB") { console.log("特征值正确"); this.triggerParentFunction(characteristic.value); } });
triggerParentFunction调用自定义事件函数:
triggerParentFunction(value) { console.log("发送自定义事件"); this.triggerEvent('customEvent', { message: value }); },
2、新建一个自己的page
STM32WBA55CG.wxml文件内容如下,这部分语法类似于HTML,定义一个页面
<!--pages/WBA55/STM32WBA55CG.wxml--> <view class="volt-view vn1"><text class="volt-name ">模拟参考:</text><text class="volt-text ">{{VrefAnalogvolt}}V</text></view> <view class="volt-view vn2"><text class="volt-name ">输入电压:</text><text class="volt-text ">{{VoltageGPIO}}V</text></view> <view class="volt-view vn3"><text class="volt-name ">内部参考:</text><text class="volt-text ">{{refvolt}}V</text></view> <view class="volt-view vn4"><text class="volt-name ">芯片温度:</text><text class="volt-text ">{{Temperature_DegreeCelsius}}°C</text></view> <view><bluetoothcomp id="bluetoothid" bind:customEvent="handleCustomEvent"></bluetoothcomp></view>
STM32WBA55CG.wxss文件内容如下,这部分是样式,类似于CSS
/* pages/WBA55/STM32WBA55CG.wxss */ .volt-view{ height: 156rpx; display: block; box-sizing: border-box; margin-top: 10rpx; } .volt-name{ font-size:32pt; color:azure; padding-left:20rpx;}.vn1{ background-color:blue; }.vn2{ background-color:green; }.vn3{ background-color: rgb(250, 29, 0);} .vn4{ background-color:indigo;} .volt-text{ padding-left: 20rpx; font-size:32pt; color:azure; font-family:sans-serif; }
STM32WBA55CG.json如下,说明包括前面自定义的BLE组件
{ "usingComponents": { "bluetoothcomp":"/components/bluetooth-comp/index" }}
STM32WBA55CG.js是控制部分:
// pages/WBA55/STM32WBA55CG.js Page({ /** * 页面的初始数据 */ data: { message:[], VrefAnalogvolt:0.000, VoltageGPIO:0.000, refvolt:0.000, Temperature_DegfreeCelsius:0, }, /** * 生命周期函数--监听页面加载 */ onLoad(options) { }, /** * 生命周期函数--监听页面初次渲染完成 */ onReady() { }, /** * 生命周期函数--监听页面显示 */ onShow() { }, /** * 生命周期函数--监听页面隐藏 */ onHide() { }, /** * 生命周期函数--监听页面卸载 */ onUnload() { }, /** * 页面相关事件处理函数--监听用户下拉动作 */ onPullDownRefresh() { }, /** * 页面上拉触底事件的处理函数 */ onReachBottom() { }, /** * 用户点击右上角分享 */ onShareAppMessage() { }, handleCustomEvent(e) { console.log("收到自定义事件"); console.log(e.detail.message); // 输出 "Hello from child" // 可以在这里调用父级的其它函数 // this.data.message=e.detail.message; let dataView = new DataView(e.detail.message); console.log(dataView.getInt32(0, false)); console.log(dataView.getInt32(4, false)); console.log(dataView.getInt32(8, false)); console.log(dataView.getInt32(12, false)); this.setData({VrefAnalogvolt:dataView.getInt32(0, false)/1000}); this.setData({VoltageGPIO:dataView.getInt32(4, false)/1000}); this.setData({VrefInt:dataView.getInt32(8, false)/1000}); this.setData({Temperature_DegreeCelsius:dataView.getInt32(12, false)}); }})
handleCustomEvent(e) 是接收到自定义的BLE组件的消息事件的处理函数。
e.detail.message为蓝牙NOTIFY的16字节数据,
使用dataView.getInt32将数据解析为4个数字,
用this.setData更新成员变量,界面随之自动更新。
三、运行效果
模拟参考和温度数据是对的,中间两个数据处理部分可能还要调一调: