sujingliang 发表于 2024-9-27 15:11

【NUCLEO-WB09KE评测】5、微信小程序BLE调节LD3亮度

<p><span style="font-size:18px;">目标</span></p>

<p>&nbsp; &nbsp; &nbsp; &nbsp; 开发微信小程序建立蓝牙主机访问WB09KE蓝牙从机,发送调节参数PWM调整LD3(PB2)亮度</p>

<p>&nbsp;</p>

<p><span style="font-size:16px;"><strong>一、WB09KE端</strong></span></p>

<p>1、关于PWM调节LED亮度,请参见:<a href="https://bbs.eeworld.com.cn/thread-1294722-1-1.html" target="_blank">https://bbs.eeworld.com.cn/thread-1294722-1-1.html</a></p>

<p>2、</p>

<div></div>

<p>只建了一个GATT服务和特征值,并且特征值是可以写入,1个BYTE</p>

<p>&nbsp;</p>

<p>3、BLE调节LD3亮度</p>

<p>接收到LED_SERVICE_LED_TOGGLE_WRITE_EVT后,通过*p_Notification-&gt;DataTransfered.p_Payload获得写入特征值,并将此值给PWM调节占空比。</p>

<pre>
<code class="language-cpp">    case LED_SERVICE_LED_TOGGLE_WRITE_EVT:
      /* USER CODE BEGIN Service1Char1_WRITE_EVT */
                TIM_SetTIM2Compare3(*p_Notification-&gt;DataTransfered.p_Payload);
                APP_DBG_MSG("LED_SERVICE_LED_TOGGLE_WRITE_EVT\r\n");
      /* USER CODE END Service1Char1_WRITE_EVT */
      break;</code></pre>

<pre>
<code class="language-cpp">//设置 TIM 通道 3 的占空比
//compare:比较值
void TIM_SetTIM2Compare3(uint32_t compare)
{
        //TIM2-&gt;CCR3=compare;
        __HAL_TIM_SET_COMPARE(&amp;htim2, TIM_CHANNEL_3, compare); // compare为新的占空比值

}</code></pre>

<p><span style="font-size:16px;"><strong>二、微信小程序端</strong></span></p>

<p>1、将涉及BLE的功能建立了一个自定义组件</p>

<div style="text-align: center;"></div>

<div>index.js</div>

<div>&nbsp;</div>

<div>主要的思路是1、扫描蓝牙;2、连接自建蓝牙从机,连接成功后所有连接参数将可以直接用到下一步;3、通过writeBLECharacteristicValue1()发送0-255的数字。</div>

<div>
<pre>
<code class="language-javascript">// components/bluetooth-comp/index.js

function inArray(arr, key, val) {
for (let i = 0; i &lt; arr.length; i++) {
    if (arr === 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 &lt; strLen; i++) {
    bufView = 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 &lt; 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: {
/* 初始化蓝牙模块 */
openBluetoothAdapter() {
    // 先关闭蓝牙模块再开启 防止断开后点连接连接不上
    this.closeBluetoothAdapter();

    wx.openBluetoothAdapter({
      success: response =&gt; {
      console.log("初始化蓝牙模块成功:openBluetoothAdapter", response);
      this.startBluetoothDevicesDiscovery();
      },
      fail: err =&gt; {
      if (err.errCode === 10001) {
          /* 监听蓝牙适配器状态变化事件 */
          wx.onBluetoothAdapterStateChange(res =&gt; {
            console.log("监听蓝牙适配器状态变化事件:onBluetoothAdapterStateChange", res);
            res.available &amp;&amp; this.startBluetoothDevicesDiscovery();
          });
      }
      },
    });
},
/* 获取本机蓝牙适配器状态 */
getBluetoothAdapterState() {
    wx.getBluetoothAdapterState({
      success: res =&gt; {
      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 =&gt; {
      console.log("开始搜寻附近的蓝牙外围设备:startBluetoothDevicesDiscovery", response);
      this.onBluetoothDeviceFound();
      },
      fail: err =&gt; {
      console.log("搜索设备失败", err);
      wx.showToast({ title: "搜索设备失败", icon: "none" });
      },
    });
},
/* 停止搜寻附近的蓝牙外围设备。*/
stopBluetoothDevicesDiscovery() {
    console.log("停止搜寻附近的蓝牙外围设备");
    wx.stopBluetoothDevicesDiscovery();
},
/* 监听搜索到新设备的事件 */
onBluetoothDeviceFound() {
    wx.onBluetoothDeviceFound(res =&gt; {
      res.devices.forEach(device =&gt; {
      if (!device.name &amp;&amp; !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: () =&gt; {
      this.setData({ connected: true, name, deviceId });
      wx.showToast({ title: "连接蓝牙设备成功", icon: "none" });
      this.getBLEDeviceServices(deviceId);
      },
      fail: e =&gt; {
      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 =&gt; {
      for (let i = 0; i &lt; res.services.length; i++) {
          if (res.services.isPrimary) {
            this.getBLEDeviceCharacteristics(deviceId, res.services.uuid);
            return;
          }
      }
      },
    });
},
/* 获取蓝牙低功耗设备某个服务中所有特征 (characteristic)。 */
getBLEDeviceCharacteristics(deviceId, serviceId) {
    wx.getBLEDeviceCharacteristics({
      deviceId,
      serviceId,
      success: res =&gt; {
      console.log("获取蓝牙低功耗设备某个服务中所有特征:getBLEDeviceCharacteristics");

      for (let i = 0; i &lt; res.characteristics.length; i++) {
          let item = res.characteristics;
          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 =&gt; {
      // TODO 收到的信息为ArrayBuffer类型,可根据自己的需要转换 可发送给父组件用来回显
      console.log("收到原始的数据", characteristic, 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;
},
}
})</code></pre>

<p>index.json:</p>

<pre>
<code class="language-javascript">{
"component": true,
"usingComponents": {}

}</code></pre>

<p>index.wxml</p>

<pre>
<code class="language-javascript">createBLEConnection&lt;!-- bluetooth-comp/index.wxml --&gt;
&lt;view style="margin: 26rpx"&gt;
&lt;button wx:if="{{!connected}}" bindtap="openBluetoothAdapter"&gt;开始扫描&lt;/button&gt;
&lt;button wx:else bindtap="closeBLEConnection"&gt;断开连接 - {{name}}&lt;/button&gt;

&lt;view class="devices_summary"&gt;已发现 {{devices.length}} 个外围设备:&lt;/view&gt;
&lt;view
    wx:for="{{devices}}"
    wx:key="index"
    data-device-id="{{item.deviceId}}"
    data-name="{{item.name || item.localName}}"
    bindtap="createBLEConnection"
    class="device_item"
    hover-class="device_item_hover"&gt;
    &lt;view style="font-size: 16px; color: #333"&gt;{{item.name}}&lt;/view&gt;
    &lt;view style="font-size: 10px"&gt;信号强度: {{item.RSSI}}dBm&lt;/view&gt;
    &lt;view style="font-size: 10px"&gt;UUID: {{item.deviceId}}&lt;/view&gt;
    &lt;view style="font-size: 10px"&gt;localName: {{item.localName}}&lt;/view&gt;
&lt;/view&gt;
&lt;/view&gt;</code></pre>

<p>index.wxss:</p>

<pre>
<code class="language-javascript">/* bluetooth-comp/index.wxss */
.devices_summary {
/* margin-top: 30px; */
padding: 10px;
font-size: 16px;
}

.device_item {
border-bottom: 1px solid #eee;
padding: 10px;
color: #666;
}
.device_item_hover {
background-color: rgba(0, 0, 0, 0.1);
}</code></pre>

<p>2、主程序</p>

<p>*.json中引入组件</p>

<pre>
<code class="language-javascript">{
"usingComponents": {

    "bluetoothcomp":"/components/bluetooth-comp/index"
}
}</code></pre>

<p>*.wxml外观</p>

<pre>
<code class="language-javascript">&lt;!--pages/wifi.wxml--&gt;
&lt;!--
&lt;view style="position: inherit; width: 100%; background: #d3d3d3; height: auto; left: 0rpx; top: inherit"&gt;
&lt;icon type="success" size="40" style="position: relative; left: 31rpx; top: 6rpx"&gt;&lt;/icon&gt;
&lt;text style="position: relative; left: 85rpx; top: -14rpx"&gt;蓝牙&lt;/text&gt;
&lt;switch style="position: relative; left: 449rpx; top: -19rpx" checked="{{isBlueTooth}}" bindchange="openDialogBluetooth" /&gt;
&lt;/view&gt;
--&gt;
&lt;!--bind:close="onCloseBlueTooth"--&gt;
&lt;view&gt;
&lt;bluetoothcomp id="bluetoothid"&gt;&lt;/bluetoothcomp&gt;
&lt;/view&gt;

&lt;view&gt;
&lt;slider bindchange="slider1change" min="0" max="255" show-value="true" left-icon="cancel" right-icon="success_no_circle"/&gt;

&lt;text style="position: relative; left: 303rpx; top: 20rpx" &gt;{{slidervalue}}&lt;/text&gt;
&lt;/view&gt;
&lt;image style="position: relative; left: 47rpx; top: 354rpx" src="/images/wb09.jpg"/&gt;


</code></pre>

<p>*.js控制部分</p>

<pre>
<code class="language-javascript">// pages/wifi.js
Page({

/**
   * 页面的初始数据
   */
data: {
    isBlueTooth:false,
    bluetoothDialog:false,
    slidervalue:0,
   

},


/**
   * 生命周期函数--监听页面加载
   */
onLoad(options) {

},

/**
   * 生命周期函数--监听页面初次渲染完成
   */
onReady() {
    this.bluetoothcomp = this.selectComponent("#bluetoothid");
},

/**
   * 生命周期函数--监听页面显示
   */
onShow() {

},

/**
   * 生命周期函数--监听页面隐藏
   */
onHide() {

},

/**
   * 生命周期函数--监听页面卸载
   */
onUnload() {

},

/**
   * 页面相关事件处理函数--监听用户下拉动作
   */
onPullDownRefresh() {

},

/**
   * 页面上拉触底事件的处理函数
   */
onReachBottom() {

},

/**
   * 用户点击右上角分享
   */
onShareAppMessage() {

},

bluetoothChange(){


},

openDialogBluetooth(){
    this.setData({bluetoothDialog:true});
},
onCloseBlueTooth(){
    this.setData({bluetoothDialog:false});
},

slider1change: function(e) {
    // e.detail.value 包含了当前slider的value值
    this.setData({slidervalue:e.detail.value});

    console.log('Slider value changed to:', this.data.slidervalue);
    // 在这里你可以对获取到的value值进行进一步的处理或更新数据模型中的值
    this.bluetoothcomp.writeBLECharacteristicValue1(this.data.slidervalue);
},

})</code></pre>

<p>&nbsp;</p>
</div>

<p>&nbsp;</p>

<p><strong>三、效果</strong></p>

<p>1、小程序外观</p>

<div style="text-align: center;"></div>

<div>2、运行演示</div>

<div>&nbsp;</div>

<p>ca8e053f2eefc519e5e0671fe042701a<br />
&nbsp;</p>

秦天qintian0303 发表于 2024-9-28 13:44

<p>微信小程序可以直接蓝牙连接吗?不是通过wifi吗?&nbsp;</p>

何剑波 发表于 2024-9-29 17:45

秦天qintian0303 发表于 2024-9-28 13:44
微信小程序可以直接蓝牙连接吗?不是通过wifi吗?&nbsp;

<p>好像是可以的,我这边的一个客户就是通过这个方式去连接蓝牙终端的</p>

慕容雪花 发表于 2024-9-30 13:04

<p>牛的老哥,小程序666</p>

lugl4313820 发表于 2024-11-2 21:57

大佬,可以分享一下您的小程源码吗?

sujingliang 发表于 2024-11-5 14:18

lugl4313820 发表于 2024-11-2 21:57
大佬,可以分享一下您的小程源码吗?

<p>建议参考微信官方的资料,很详细:</p>

<p>https://developers.weixin.qq.com/miniprogram/dev/framework/device/ble.html</p>

<p>&nbsp;</p>

<p>有些UP主在bilibili上也有视频说明。</p>

<p>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</p>
页: [1]
查看完整版本: 【NUCLEO-WB09KE评测】5、微信小程序BLE调节LD3亮度