zoukankan      html  css  js  c++  java
  • 微信小程序连接低功率蓝牙控制单片机上硬件设备

    1.软件部分介绍

      微信小程序是一种新的应用,用户不需要下载应用只用通过扫二维码或者打开链接就能使用,使用完后不需要卸载,直接关闭就行了。微信在2017年初推出微信小程序开发环境。任何企业,媒体,个人都可以注册开发。是一种全新的 开发模式。微信也因此受到许多程序员的一致好评,尤其是微信小程序的云开发,提供大量数据处理接口,让初学者也可以很快入手。不需要后端数据库的支持,自己一个人就可以开发前端和后台。

    微信小程序为蓝牙模块提供了18个API。其中低功率蓝牙9个,传统蓝牙9个。本次设计使用了其中的9个接口:

    (1) openBluetoothAdapter,这个API用来初始化蓝牙适配器;

    (2) startBluetoothDevicesDiscovery,开始搜索蓝牙设备;

    (3) onBluetoothDeviceFound,判断搜索到的蓝牙设备的信号强度;

    (4) createBLEConnection,连接搜索到的蓝牙设备;

    (5) stopBluetoothDevicesDiscovery,关闭搜索蓝牙设备;

    (6) getBLEDeviceServices,获取蓝牙的deviceId;

    (7) getBLEDeviceCharacteristics,获取蓝牙设备服务的所有特征值;

    (8) notycharacteristicsId,启用低功耗蓝牙特征值的notify功能;

    (9) writeBLECharacteristicValue,通过微信小程序向蓝牙模块发送命令。

     js源代码

    Page({
        /**
         * 页面的初始数据
         */
        data: {
            connect: false,
            send_hex: false,
            send_string: true,
            send_string_val: 'Hex',
            recv_string: true,
            recv_string_val: 'Hex',
            recv_value: '',
            send_number: 0,
            recv_number: 0,
            recv_hex: true,
            wendu: 30,
            yanwu: 60
        },
        /*** 生命周期函数--监听页面加载 */
        onLoad: function (options) {
            wx.stopBluetoothDevicesDiscovery({
                success: function (res) {
                    console.log('停止搜索设备', res)
                }
            })
            console.log(options);
            this.setData({
                deviceId: options.id,
                deviceName: options.name
            });
            console.log('设备的ID', this.data.deviceId);
        },
        /*** 生命周期函数--监听页面显示 */
        onShow: function () {
            wx.stopBluetoothDevicesDiscovery({
                success: function (res) {
                    console.log('停止搜索设备', res)
                }
            })
            var that = this;
            /* 连接中动画 */
            wx.showLoading({
                title: '连接中...',
            });
            /* 开始连接蓝牙设备 */
            wx.createBLEConnection({
                deviceId: that.data.deviceId,
                success: function (res) {
                    console.log('连接成功', res);
                    wx.hideLoading();
                    /* 获取设备的服务UUID */
                    wx.getBLEDeviceServices({
                        deviceId: that.data.deviceId,
                        success: function (service) {
                            that.setData({
                                serviceId: "0000FFE0-0000-1000-8000-00805F9B34FB" //确定需要的服务UUID
                            });
                            console.log('需要的服务UUID', that.data.serviceId)
                            that.Characteristics(); //调用获取特征值函数
                        },
                    });
                    that.setData({
                        connect: true
                    })
                },
            })
        },
        Characteristics: function () {
            var that = this;
            var device_characteristics = [];
            var characteristics_uuid = {};
            wx.getBLEDeviceCharacteristics({
                deviceId: that.data.deviceId,
                serviceId: that.data.serviceId,
                success: function (res) {
                    var characteristics = res.characteristics; //获取到所有特征值
                    var characteristics_length = characteristics.length; //获取到特征值数组的长度
                    console.log('获取到特征值', characteristics);
                    console.log('获取到特征值数组长度', characteristics_length);
                    that.setData({
                        notycharacteristicsId: "0000FFE1-0000-1000-8000-00805F9B34FB", //需确定要的使能UUID
                        characteristicsId: "0000FFE1-0000-1000-8000-00805F9B34FB" //暂时确定的写入UUID
                    });
    
                    console.log('使能characteristicsId', that.data.notycharacteristicsId);
                    console.log('写入characteristicsId', that.data.characteristicsId);
                    that.notycharacteristicsId(); //使能事件
                },
            })
        },
        /* 使能函数 */
        notycharacteristicsId: function () {
            var that = this;
            var recv_value_ascii = "";
            var string_value = "";
            var recve_value = "";
            wx.notifyBLECharacteristicValueChange({
                deviceId: that.data.deviceId,
                serviceId: that.data.serviceId,
                characteristicId: that.data.notycharacteristicsId,
                state: true,
                success: function (res) {
                    console.log('使能成功', res);
                    /* 设备返回值 */
                    wx.onBLECharacteristicValueChange(function (res) {
                        var length_hex = [];
                        var turn_back = "";
                        var result = res.value;
                        var hex = that.buf2hex(result);
                        console.log('返回的值', hex);
                        if (that.data.recv_string == true) {
                            /* 成功接收到的值的展示 */
                            that.setData({
                                recv_value: that.data.recv_value + hex
                            });
                            /* 接收成功的值的字节 */
                            var recv_number_1 = that.data.recv_number + hex.length / 2;
                            var recv_number = Math.round(recv_number_1);
                            that.setData({
                                recv_number: recv_number
                            });
                        } else {
                            console.log('设备返回来的值', hex);
                            var f_hex = hex;
                            var length_soy = f_hex.length / 2;
                            var length = Math.round(length_soy);
                            for (var i = 0; i < length; i++) {
                                var hex_spalit = f_hex.slice(0, 2);
                                length_hex.push(hex_spalit);
                                f_hex = f_hex.substring(2);
                            }
                            console.log('length_hex', length_hex);
                            for (var j = 0; j < length_hex.length; j++) {
    
                                var integar = length_hex[j]; //十六进制
                                recve_value = parseInt(integar, 16); //十进制
                                console.log('recve_value', recve_value);
    
                                turn_back = turn_back + String.fromCharCode(recve_value);
                                console.log('turn_back', turn_back);
                            }
    
                            console.log('最终转回来的值', turn_back)
                            var recv_number_1 = that.data.recv_number + turn_back.length;
                            var recv_number = Math.round(recv_number_1);
                            that.setData({
                                recv_number: recv_number,
                                recv_value: that.data.recv_value + turn_back
                            })
                        }
                    });
                },
                fail: function (res) {
                    console.log('使能失败', res);
                }
            })
        },
        /* 断开连接 */
        DisConnectTap: function () {
            var that = this;
            wx.closeBLEConnection({
                deviceId: that.data.deviceId,
                success: function (res) {
                    console.log('断开设备连接', res);
                    wx.reLaunch({
                        url: '../index/index',
                    })
                }
            });
        },
        /*** 生命周期函数--监听页面卸载  */
        onUnload: function () {
            var that = this;
            wx.closeBLEConnection({
                deviceId: that.data.deviceId,
                success: function (res) {
                    console.log('断开设备连接', res);
                }
            });
        },
        /* 清除Recv Bytes */
        CleanNumberRecv: function () {
            this.setData({
                recv_number: 0
            })
        },
        /* ArrayBuffer类型数据转为16进制字符串 */
        buf2hex: function (buffer) { // buffer is an ArrayBuffer
            var hexArr = Array.prototype.map.call(
                new Uint8Array(buffer),
                function (bit) {
                    return ('00' + bit.toString(16)).slice(-2)
                }
            )
            return hexArr.join('');
        },
        switch1Change: function (e) {
            var that = this;
            let buffer = new ArrayBuffer(1)
            let dataView = new DataView(buffer)
            if (e.detail.value) {
                dataView.setUint8(0, 0)
            } else {
                dataView.setUint8(0, 1)
            }
    
            wx.writeBLECharacteristicValue({
                deviceId: that.data.deviceId,
                serviceId: that.data.serviceId,
                characteristicId: that.data.characteristicsId,
                value: buffer,
                success: function (res) {
                    console.log('数据发送成功', res);
                    console.log(buffer);
                },
                fail: function (res) {
                    console.log('调用失败', res);
                    /* 调用失败时,再次调用 */
                    wx.writeBLECharacteristicValue({
                        deviceId: that.data.deviceId,
                        serviceId: that.data.serviceId,
                        characteristicId: that.data.characteristicsId,
                        value: buffer,
                        success: function (res) {
                            console.log('第2次数据发送成功', res);
                        }
                    })
                }
            })
        },
        switch1Change1: function (e) {
            var that = this;
            let buffer = new ArrayBuffer(1)
            let dataView = new DataView(buffer)
            if (e.detail.value) {
                dataView.setUint8(0, 2)
            } else {
                dataView.setUint8(0, 3)
            }
            wx.writeBLECharacteristicValue({
                deviceId: that.data.deviceId,
                serviceId: that.data.serviceId,
                characteristicId: that.data.characteristicsId,
                value: buffer,
                success: function (res) {
                    console.log('数据发送成功', res);
                    console.log(buffer);
                },
                fail: function (res) {
                    console.log('调用失败', res);
                    /* 调用失败时,再次调用 */
                    wx.writeBLECharacteristicValue({
                        deviceId: that.data.deviceId,
                        serviceId: that.data.serviceId,
                        characteristicId: that.data.characteristicsId,
                        value: buffer,
                        success: function (res) {
                            console.log('第2次数据发送成功', res);
                        }
                    })
                }
            })
        },
        add: function (e) {
            var id = e.target.id;
            if (this.data[id] > 98) {
                wx.showToast({
                    title: '已超过最大数值',
                    icon: 'loading',
                    duration: 2000
                })
                return;
            }
            this.setData({
          [id]: +this.data[id] + 1
            });
            this.numbers(id)
        },
        lessen: function (e) {
            var id = e.target.id;
            if (this.data[id] < 1) {
                wx.showToast({
                    title: '已小于最小数值',
                    icon: 'loading',
                    duration: 2000
                })
                return;
            }
            this.setData({
           [id]: +this.data[id] - 1
            });
            this.numbers(id)
        },
        changeVal: function (e) {
            var id = e.target.id;
            if (e.detail.value < 1 || e.detail.value > 100) {
                wx.showToast({
                    title: '请输入有效数值',
                    icon: 'loading',
                    duration: 2000
                })
                return;
            }
            this.setData({
          [id]: e.detail.value
            });
            this.numbers(id)
        },
        numbers: function (id) {
            var that = this;
            var number = '9';
            let buffer = new ArrayBuffer(1)
            let dataView = new DataView(buffer)
            console.log(id)
            if (id == 'wendu') {
                number = '8' + that.data[id];
                dataView.setUint8(0, 8)
            } else {
                number = number + that.data[id];
                dataView.setUint8(0, number)
            }
            wx.writeBLECharacteristicValue({
                deviceId: that.data.deviceId,
                serviceId: that.data.serviceId,
                characteristicId: that.data.characteristicsId,
                value: buffer,
                success: function (res) {
                    console.log('数据发送成功', res);
                    console.log(buffer);
                }
            })
        }
    })
    wxss源代码
    .connect_box {
        width: 100%;
        height: 30px;
        line-height: 30px;
        font-size: 32rpx;
        color: #666;
        font-family: "Microsoft YaHei";
    }
    .connect_device_name{
        float: left;
        padding-left: 10px;
        color: #39beff;
    }
    
    .connect_state {
        float: right;
        padding-right: 10px;
        text-decoration: underline;
        color: #39beff;
    }
    
    .fan{
      width: 2rem;
      height: 2rem;
      vertical-align: middle;
      margin-left: 2.25rem;
      margin-right: 0.25rem;
    }
    .water{
      width: 2.5rem;
      height: 2rem;
      vertical-align: middle;
      margin-left: 2rem;
    }
    .name{
      display: inline-block;
      width: 22%;
      margin-left: 1.5rem;
      font-size: 0.9rem;
    }
    .key{
      float: right;
      margin-right: 2rem;
      margin-top: 0.2rem;
    }
    .detail_box{
      padding: 1.5rem 0;
      border-bottom: 1px solid #ccc;
    }
    
    .num {
      display: inline-block;
      width: 45%;
      text-align: right;
      vertical-align: middle;
    }
    
    .num input {
      display: inline-block;
      width: 2rem;
      text-align: center;
      border: 1px solid #f2f2f2;
      border-left: none;
      border-right: none;
      color: #a2a2a2;
    }
    
    .num text {
      display: inline-block;
      width: 1.4rem;
      height: 1.4rem;
      line-height: 1.4rem;
      text-align: center;
      border: 1px solid #f2f2f2;
      vertical-align: top;
      color: #dcdcdc;
    }
    .wendu{
      width:1.9rem;
      height:2rem;
      vertical-align:middle;
      margin-left:2.3rem;
      margin-right:.3rem;
    }
    wxml源代码
    <view class="connect_box">
        <text class='connect_device_name'>{{deviceName}}</text>
        <text wx:if="{{connect}}" class="connect_state" catchtap="DisConnectTap">已连接</text>
        <text wx:else class="connect_state">未连接</text>
    </view>
    <view >
      <view class="detail_box">
       <image src='../../images/airFan.png' class="fan"></image>
       <view class='name'>风扇</view>
       <switch bindchange="switch1Change" class='key' />
      </view>
        <view class="detail_box">
        <image src='../../images/waterPump.png' class="water"></image>
        <view class='name'>水泵</view>
        <switch  bindchange="switch1Change1" class='key' />
      </view>
      <view class="detail_box">
        <image src='../../images/temperature.png' class="wendu"></image>
        <view class='name'>温度阀值</view>
        <view class='num'>
          <text style='border-radius: 3px 0 0 3px;' id='wendu' bindtap='lessen'>-</text>
          <input type='number' value='{{wendu}}' name='piece' id='wendu' bindblur="changeVal" />
          <text style='border-radius: 0 3px 3px 0;' id='wendu' bindtap='add'>+</text>
        </view>
      </view>
      <view class="detail_box">
        <image src='../../images/smog.png' class="water"></image>
        <view class='name'>烟雾阀值</view>
        <view class='num'>
          <text style='border-radius: 3px 0 0 3px;' id='yanwu' bindtap='lessen'>-</text>
          <input type='number' value='{{yanwu}}' name='piece' id='yanwu' bindblur="changeVal" />
          <text style='border-radius: 0 3px 3px 0;' id='yanwu' bindtap='add'>+</text>
        </view>
      </view>
     
    </view>

     微信小程序展示页面

            

      微信小程序不能在电脑上模拟,智能用手机操作,我们需要用手机打开我们的微信小程序。首先如果手机蓝牙没有打开回提醒打开蓝牙重新加载。如果手机蓝牙打开了就会去搜索附近的蓝牙模块,搜索到自己的低功率蓝牙,点击就可以连接到自己的蓝牙。我们就到了控制页面。
      我们可以通过微信小程序风扇和水泵。点击开关时会调用writeBLECharacteristicValue接口通过蓝牙模块给单片机发送指令,控制单片机上的风扇和水泵等硬件设备。

    2.硬件设备介绍

      硬件部分主要介绍单片机、低功率蓝牙、风扇和水泵。单片机用什么型号的都行,都能与蓝牙模块正常通信,收发数据。低功率蓝牙主要优点是功率低,寿命长,价格便宜。多用于硬件连接上位机软件。风扇和水泵是外接设备,由单片机控制。

    1.单片机
      单片机的型号是stc89c52rc,STC89C52RC是STC公司生产的一种低功耗、高性能CMOS8位微控制器,具有8K字节系统可编程Flash存储器。STC89C52使用经典的MCS-51内核,但是做了很多的改进使得芯片具有传统的方法51单片机不具备的功能。在单芯片上,拥有灵巧的8 位CPU 和在系统可编程Flash,使得STC89C52为众多嵌入式控制应用系统提供高灵活、超有效的解决方案。
    2.蓝牙模块
      我用的是蓝牙型号是HC-06,给HC-06上电之后,HC-06的指示灯会不停地闪烁,这个时候就标志着进入AT模式了,配置的时候,HC-06的Rx和Tx 接到 51单片机的 Rx和 Tx,一般是P3.0,和P3.1,正常工作时,HC-06的Rx和Tx 接到 51单片机的 Tx和 Rx,8位数据位,1位结束位,无奇偶校验。一般HC-06模块的默认名称就是hc-06,默认配对密码是1234或0000。我们如果连接微信小程序,我们要把密码取消,这样微信小程序才能直接来连接。
    3.风扇和水泵  
      风扇和水泵是直接供电就可以使用,我们只需要一个继电器就可以控制这两个设备,我选择了P3.5,P3.4这两个引脚来控制,高电平驱动,低电平关闭,这两个外接设备主要是测试数据有没有接受成功。

    单片机程序主程序

    void ctrl(unsigned char a)    //单字节数据接收
    {                            //注意:若单片机TXD(P3.1)无上拉能力,必须在P3.1端接上拉电阻。本次测试需要接上拉电阻
        TI=0;    
        SBUF=a;
        while(TI==0);
        TI=0;
        Mode=1;
        if(SBUF==0){
            LED_yanwu=0;
            baojing=0;
            fs=0;
            led1=0;
            led2=0;
          }else if(SBUF==1){
            LED_yanwu=1;
            baojing=1;
            fs=1;
            Mode=0;
          }else if(SBUF==2){
            baojing=0;
            LED_wendu=0;
            fs1=0;
          }else if(SBUF==3){
            baojing=1;
            LED_wendu=1;
            fs1=1;
            led1=0;
            led2=0;
            Mode=0;
          }
    } 
    void main()
    {
        check_wendu();
        check_wendu();
        Init1602();
        ES=0;                                  //关中断
        SCON = 0x50;                        // REN=1允许串行接受状态,串口工作模式1,
                                              //10位UART(1位起始位,8位数据位,1位停止位,无奇偶校验),波特率可变
        TMOD = 0x20;                        // 定时器1工作于方式2,8位自动重载模式, 用于产生波特率
        TH1=TL1=0xFD;                       // 波特率9600 (本次测试采用晶振为11.0592)
        PCON &= 0x7f;                       // 波特率不倍增
        TR1 = 1;                              //定时器1开始工作,产生波特率                
        TI=0;                                  //接收标志位置0
        RI=0;
    
        ES=1;
        while(1)
        {
            temp=ADC0809();
            check_wendu();
            Key();
            if(RI==1)                     // 是否有数据到来
            {
              RI = 0;
              ctrl(SBUF);
            }       
            Display_1602(yushe_wendu,yushe_yanwu,c,temp); //c温度值,temp烟雾值
            if(Mode==0)
            {
                if(temp>=yushe_yanwu)
                {
                    LED_yanwu=0;
                    baojing=0;
                    fs=0;
                }
                else
                {
                    LED_yanwu=1;
                }
                if(c>800){
                    c = 0;
                }
                if(c>=(yushe_wendu*10))
                {
                    baojing=0;
                    LED_wendu=0;
                    fs1=0;
                }
                else
                {
                    LED_wendu=1;
                }
                if((temp<yushe_yanwu)&&(c<(yushe_wendu*10)))
                {
                    baojing=1;
                    fs=1;
                    fs1=1;
                }
            }  
        }
    }

    硬件实物图

           

      数据采集显示正常,微信小程序可以正常控制单片机的水泵和风扇,通信正常无异常。硬件部分我就简单的拿出来说了一下,所涉及到的知识肯定比我展示到的多,软件部分主要是对低功率蓝牙的搜索,连接,发送数据比较麻烦。

        视频链接:http://v.youku.com/v_show/id_XNDE1ODI1NzI2NA==.html?x&sharefrom=android&sharekey=f051256eda08cc3764d9d6d7a5d231788

  • 相关阅读:
    Adobe产品在Lion上的已知问题
    SAP HANA能否推动实时应用?
    如果Android与Chrome合体?
    基于MINA构建简单高性能的NIO应用MINA架构
    Drupal 测试邮件发送
    jQuery doTimeout插件: 比setTimeout实用
    Raven – 社会化浏览器
    LSO/Flash Cookie
    CSS3动画效果animate.css
    seaJs的模块定义、模块加载及模块依赖关系
  • 原文地址:https://www.cnblogs.com/liuzhou1/p/10772905.html
Copyright © 2011-2022 走看看