微信小程序App实现小车方向控制

2024-08-31 21:20

本文主要是介绍微信小程序App实现小车方向控制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

概述

1 系统框架结构

1.1 结构介绍

 1.2 硬件模块介绍

1.2.1 蓝牙模块介绍

1.2 .2 模块功能介绍

2 功能实现

2.1 微信小程序APP

2.2 下位机功能

3 功能测试

3.1 小程序UI测试

3.2 小车方向控制


微信小程序和蓝牙模块控制小车运行状态

概述

本文主要介绍使用微信小程序和蓝牙模块设计一个智能小程控制系统,笔者介绍了系统的实现框架结构,还介绍了微信小程序的代码结构和源代码。下位机部分树妖包括:小车方向控制代码,微信小程序与下位机的通信方法。

1 系统框架结构

1.1 结构介绍

1) 使用STM32F103 Timer8 产生4路PWM信号,用于控制电机的转向和调速

2) TIMER7和IO EXIT interrupt 控制光电编码器,用于计算当前电机的转速

3) STM32F103 UART-3接口和蓝牙模块通信

 1.2 硬件模块介绍

1.2.1 蓝牙模块介绍

       HC-08蓝牙串口通信模块是新一代的基于Bluetooth Specification V4.0 BLE 蓝牙协议的数传模块。无线工作频段为 2.4GHz ISM,调制方式是 GFSK。模块最大发射功率为4dBm,接收灵敏度-93dBm,空旷环境下和 手机可以实现 80 米超远距离通信。

        其和MCU之间通过串口通信,软件设计也简单便捷,且不需要考虑蓝牙协议栈问题,非常适合做速成产品。

蓝牙模块与MCU之间连接图:

1.2 .2 模块功能介绍

1)测试传感器

工作原理:

当模块中的槽无遮挡时,接收管导通,DQ输出为低电平

当槽被遮挡时,DQ输出为高电平。

2)码盘

该码盘一周总共有20个孔,则其将一个圆分为20个等分,在测速的时候。只需记录其在1s时间内走过孔的个数,然后通过轮胎的周长与孔等分的关系,就能计算出速度。

 3)轮胎参数

根据参数可得,轮胎的直径为:6.8cm

2 功能实现

2.1 微信小程序APP

1) UI设计

通过4个按钮控制小车的运动方向

2)代码实现:

 在 detail.wxml 文件中实现如下UI代码

<view class="connect_box"><text class='connect_device_name'>{{deviceName}}</text><text wx:if="{{connected}}" class="connect_state" catchtap="DisConnectTap">已连接</text><text wx:else class="connect_state" catchtap="DisConnectTap" >未连接</text>
</view><view class="block-content"><view class="block-item column"><view class="item-row slider-box"><view class="item-title" ><image class="item-title-icon" src="/images/light_s.png" />温度(℃)</view><view class="input-unit"></view><view class="item-title" style="position: relative;  left: 30rpx; "><image class="item-title-icon" src="/images/light_s.png" />湿度(%)</view><view class="input-unit"></view></view><view class="item-row"><view class="input-value"><input type="digit" value="{{temphtValue}}" disabled="false"/></view><view class="input-value" style="position: relative;  left: -40rpx; "><input type="digit" value="{{humidityValue}}" disabled="false"/></view></view></view> <view class="block-item column"><view class="item-row slider-box"><view class="item-title"><image class="item-title-icon" src="/images/light_s.png" />光照(lux)</view><view class="input-unit"></view><view class="item-title" style="position: relative;  left: 60rpx; "><image class="item-title-icon" src="/images/light_s.png" />SR测距(cm)</view><view class="input-unit"></view></view><view class="item-row"><view class="input-value" ><input type="digit" value="{{luxValue}}" disabled="false"/></view><view class="input-value" style="position: relative;  left: -40rpx; "><input type="digit" value="{{srValue}}" disabled="false"/></view></view></view> <view class="block-item column" style="width: 750rpx; height: 507rpx; display: flex; box-sizing: border-box; left: 0rpx; top: 0rpx; position: relative"><button type="primary" bindtap="run_up" plain="true" style="position: relative; left: 3rpx; top: 5rpx; width: 183rpx; height: 357rpx; display: block; box-sizing: border-box">前进</button><button type="primary" bindtap="run_down" plain="true" style="position: relative; left: 0rpx; top: 263rpx; width: 188rpx; height: 326rpx; display: block; box-sizing: border-box">后退</button><button type="primary" bindtap="run_left" plain="true" style="position: relative; left: -247rpx; top: 3rpx; width: 183rpx; height: 361rpx; display: block; box-sizing: border-box">左转</button><button type="primary" bindtap="run_right" plain="true" style="position: relative; left: 256rpx; top: -82rpx; width: 183rpx; height: 343rpx; display: block; box-sizing: border-box">右转</button><button type="primary" bindtap="run_stop" plain="true" style="position: relative; left: 5rpx; top: -173rpx; width: 179rpx; height: 361rpx; display: block; box-sizing: border-box">停止</button></view> 
</view>

逻辑功能实现:

const utils = require('utils.js')
const ble = require('bluetooth.js')
Page({/*** 页面的初始数据*/data: {pageload: false,connected: 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,try_cnt:0,rece_string:'',deviceArray: []},/*** 生命周期函数--监听页面加载*/onLoad: function (options) {var that = this; console.log(options);this.setData({pageload:true,connected: false,deviceId: options.id,try_cnt:0,deviceName: options.name});console.log("detail:  onLoad");wx.stopBluetoothDevicesDiscovery({success: function (res) {console.log('停止搜索设备', res)}})that.closeBLEConnection(that.data.deviceId);that.createBLEConnection(that.data.deviceId, that.data.deviceName); }, onHide () {var that = this;// Do something when hide.// 断开连接console.log("detail:  onHide");},onShow:function(){      // var that = this; // connect bluetooth// that.closeBLEConnection(that.data.deviceId);// that.createBLEConnection(that.data.deviceId, that.data.deviceName); },onUnload() {var that = this;this.setData({pageload:true,connected: false,try_cnt:0,});console.log("page:  onUnload  ");that.offBLEMonitor();that.closeBLEConnection(that.data.deviceId);that.closeBluetoothAdapter();wx.showToast({title: '断开蓝牙',icon: 'success',duration: 2000})  },DisConnectTap:function(){var that = this;that.setData({pageload:true,connected: false,try_cnt:0,});ble.openBluetoothAdapter(that.data.deviceId, that.data.deviceName);that.createBLEConnection(that.data.deviceId, that.data.deviceName); },RecvCleanTap: function () {this.setData({recv_value: '',recv_number: 0});},  /*** 创建连接* @param {*} deviceId * @param {*} name */createBLEConnection(deviceId, name) {wx.createBLEConnection({deviceId,  success: (res) => {console.log('createBLEConnection - success: ', res)this.getBLEDeviceServices(deviceId)              },fail: (res) => {console.error('createBLEConnection - fail: ', res)if(res.errCode == 10006 ){this.createBLEConnection(deviceId, name)}else{ble.openBluetoothAdapter(deviceId, name)this.createBLEConnection(deviceId, name)}this.setData({connected: false,})               } })},getBLEDeviceServices(deviceId) {var that = this;wx.getBLEDeviceServices({deviceId,success: (res) => {console.log('getBLEDeviceServices - success: ', res)for (let i = 0; i < res.services.length; i++) {var ergodic_UUID =res.services[i].uuid;      //取出服务里面的UUIDvar UUID_slice = ergodic_UUID.slice(4, 8);   //截取4到8位console.log('getBLEDeviceServices, service ID =  ', res.services[i].uuid);if ( res.services[i].isPrimary && (UUID_slice == "FFE0") ) {that.setData({serviceId: res.services[i].uuid,});break;}}wx.getConnectedBluetoothDevices({services: res.services,success: (res) => {                         console.log("getConnectedBluetoothDevices - success:  " +  res)},fail: (res) => {console.error('getConnectedBluetoothDevices - fail: ', res)ble.openBluetoothAdapter(deviceId, that.data.deviceName)}                    })that.getBLEDeviceCharacteristics(deviceId, that.data.serviceId);},fail: (res) => {console.error('getBLEDeviceServices - fail: ', res)// try it againble.openBluetoothAdapter(deviceId, that.data.deviceName)that.monitor_connected();} });},getBLEDeviceCharacteristics(deviceId, serviceId) {var that = this;let falg = false;wx.getBLEDeviceCharacteristics({deviceId,serviceId,success: (res) => {that.setData({connected: true,})                console.log('getBLEDeviceCharacteristics success', res.characteristics)for (let i = 0; i < res.characteristics.length; i++) {let item = res.characteristics[i]console.log('getBLEDeviceCharacteristics, Characteristics ID =  ', item.uuid)// 该特征值:可读if (item.properties.read) {wx.readBLECharacteristicValue({deviceId,serviceId,characteristicId: item.uuid,})}// 该特征值:可写if (item.properties.write) {this.setData({canWrite: true})this._deviceId = deviceIdthis._serviceId = serviceIdthis._characteristicId = item.uuidthis.writeValue()}if (item.properties.notify || item.properties.indicate) {that.setData({characteristicId: item.uuid});falg = true;break;}}if( falg ){console.debug('getBLEDeviceCharacteristics - deviceId : ', deviceId)console.debug('getBLEDeviceCharacteristics - serviceId : ', serviceId)console.debug('getBLEDeviceCharacteristics - characteristicId: ', that.data.characteristicId)// read device character value that.readBLECharacteristicValue(deviceId, serviceId, that.data.characteristicId)   that.notifyBLECharacteristicValueChange(deviceId, serviceId, that.data.characteristicId) }},fail: (res) => {console.error('getBLEDeviceCharacteristics -- fail: ', res)this.setData({connected: false,})if (res.errCode === 10006){that.offBLEMonitor();that.createBLEConnection(deviceId, that.data.deviceName); }}})},readBLECharacteristicValue(deviceId,serviceId, characteristicId ){wx.readBLECharacteristicValue({// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接deviceId,// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取serviceId,// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取characteristicId,success (res) {console.log('readBLECharacteristicValue:', res.errCode)}})},notifyBLECharacteristicValueChange(deviceId,serviceId, characteristicId ){var that = this;wx.notifyBLECharacteristicValueChange({state: true,    // enable notifydeviceId,serviceId,characteristicId,success: (res) => {console.info('notifyBLECharacteristicValueChange success: ', res.errMsg)// read data here // 操作之前先监听,保证第一时间获取数据wx.onBLECharacteristicValueChange(function(res) {that.data.connected = true; console.info('onBLECharacteristicValueChange', res);console.info(`characteristic ${res.characteristicId} has changed, now is ${res.value}`);var result = res.value;var hex = utils.buf2hex(result);var _hex_ss =  utils.hex2string(hex);console.info("hex: " + hex);console.info("string: " + _hex_ss);that.data.rece_string += _hex_ss;var recv_number_1 = that.data.recv_number + _hex_ss.length / 2;var recv_number = Math.round(recv_number_1);if( that.data.rece_string.includes("log:") && that.data.rece_string.includes(":end")){that.setData({recv_number: recv_number,recv_value: that.data.recv_value + that.data.rece_string,});console.info("string: " + that.data.rece_string);let buff =  that.data.rece_string.split(':')console.log(buff)that.data.rece_string = ''let valueList = buff[1].split(',')that.data.recv_value = "";that.data.recv_number = 0;console.log(valueList)if(valueList.length == 4 ){that.setData({temphtValue: valueList[0],humidityValue: valueList[1],luxValue: valueList[2],srValue: valueList[3],});} }     that.monitor_connected();})                                 },fail: (res) => {console.error('notifyBLECharacteristicValueChange fail: ', res)that.monitor_connected();}})    },monitor_connected_action(){var that = this;let deviceId = that.data.deviceId;wx.onBLEConnectionStateChange(function(res) {// 该方法回调中可以用于处理连接意外断开等异常情况console.log( "onBLEConnectionStateChange ----- " +  `device ${res.deviceId} state has changed, connected: ${res.connected}`)if( res.deviceId == deviceId && res.connected == false ){    wx.closeBLEConnection({deviceId,success: (res) => {console.debug('detail: closeBLEConnection success', res);  that.offBLEMonitor();that.createBLEConnection(deviceId, that.data.deviceName); },fail: (res) => {                     console.error('detail: closeBLEConnection fail', res);  if (res.errCode === 10006) {that.offBLEMonitor();that.createBLEConnection(deviceId, that.data.deviceName); }}})that.setData({try_cnt: that.data.try_cnt + 1,})}else{that.data.try_cnt  = 0;}})   },monitor_connected(){var that = this;setTimeout(that.monitor_connected_action, 200);},writeValue( val ) {// 向蓝牙设备发送一个0x00的16进制数据let buffer = new ArrayBuffer(1);let dataView = new DataView(buffer);dataView.setUint8(0, val);console.debug('getBLEDeviceCharacteristics - deviceId : ', this._deviceId)console.debug('getBLEDeviceCharacteristics - serviceId : ', this._serviceId)console.debug('getBLEDeviceCharacteristics - characteristicId: ', this._characteristicId)wx.writeBLECharacteristicValue({deviceId: this._deviceId,serviceId: this._serviceId,characteristicId: this._characteristicId,value: buffer,success: (res) => {console.debug('writeBLECharacteristicValue success', res);  },fail: (res) => {console.error(' writeBLECharacteristicValue fail', res);  this.setData({connected: false,}) }})},closeBluetoothAdapter() {wx.closeBluetoothAdapter({           success (res) {console.log(res)}        })this.setData({connected: false,}),         this._discoveryStarted = false},closeBLEConnection( deviceId ) {wx.closeBLEConnection({deviceId,success: (res) => {console.debug('detail: closeBLEConnection success', res);  },fail: (res) => {console.error('detail: closeBLEConnection fail', res);  }})this.setData({connected: false,canWrite: false,})},run_up:function(){var that = this;var val = 0x01 ;that.writeValue( val );}, run_down:function(){var that = this;var val = 0x02;      that.writeValue( val );   },run_left:function(){var that = this;var val = 0x03;      that.writeValue( val );   },run_right:function(){var that = this;var val = 0x04;      that.writeValue( val );},run_stop:function(){var that = this;var val = 0x05;that.writeValue( val );},whiteLightValueSliderChange:function(e){var that = this;// 向蓝牙设备发送一个0x00的16进制数据var val = Math.random() * 255 | 0; that.writeValue( val );   },offBLEMonitor(){this.setData({connected: false,}), wx.offBLEPeripheralConnectionStateChanged();wx.offBLEConnectionStateChange();wx.offBLECharacteristicValueChange();wx.offBLEMTUChange();}
})

2.2 下位机功能

代码第29行: 从UART读取一个byte

代码第30行:判断buff接收到的字符串是否越界

代码第38行:设置蓝牙控制命令

#include "bluetooth.h"#define PROT_FRAME_LEN       16Stru_BlueCmd stru_BlueCmd;static uint8_t recv_buf[PROT_FRAME_LEN];
static uint8_t rev_cnt = 0;void bluetoothCmd_DataRecvByte(uint8_t data )
{recv_buf[rev_cnt++] =  data;if( rev_cnt >= PROT_FRAME_LEN)rev_cnt = 0;// bluetooth commandrev_cnt = 0;stru_BlueCmd.recStatus +=1;if( stru_BlueCmd.recStatus > PROT_FRAME_LEN )stru_BlueCmd.recStatus = 0;stru_BlueCmd.mcmd = recv_buf[0];}

串口回调函数:

在void UART_RxCpltCallback(UART_HandleTypeDef *huart)函数调用该函数

 

小车运动方向控制函数:

方向控制枚举定义


 电机转动控制函数:

void motor_ctrlAct( uint8_t type, uint16_t speed  )
{switch( type ){case IDLE:break;case STOP_RUN:HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_1);HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_2);HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_3);HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_4);break;case RIGHT_RUN:HAL_TIM_SetPWM_Pulse( speed*FACTOR, TIM_CHANNEL_2);HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_1);HAL_TIM_SetPWM_Pulse( speed, TIM_CHANNEL_3);HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_4);break;case LEFT_RUN:HAL_TIM_SetPWM_Pulse( speed*FACTOR, TIM_CHANNEL_1);HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_2);HAL_TIM_SetPWM_Pulse( speed, TIM_CHANNEL_4);HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_3);break;case UP_RUN:HAL_TIM_SetPWM_Pulse( speed, TIM_CHANNEL_1);HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_2);HAL_TIM_SetPWM_Pulse( speed, TIM_CHANNEL_3);HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_4);break;case DOWN_RUN:HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_1);HAL_TIM_SetPWM_Pulse( speed, TIM_CHANNEL_2);HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_3);HAL_TIM_SetPWM_Pulse( speed, TIM_CHANNEL_4);break;}
}

蓝牙模块控制电机转动功能:

3 功能测试

3.1 小程序UI测试

 1) 手机扫描蓝牙模块信息

手机App上打开小程序,其会自动扫描蓝牙模块的信息

蓝牙模块连接成功,小程序会跳转到主控UI页面

 

 同时,在调试接口上打印出连接成功的信息:

3.2 小车方向控制

通过小程序上的如下四个按钮控制小车的运行方向

 

 系统硬件

调试状态:

 

这篇关于微信小程序App实现小车方向控制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/1125026

相关文章

IDEA如何实现远程断点调试jar包

《IDEA如何实现远程断点调试jar包》:本文主要介绍IDEA如何实现远程断点调试jar包的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录问题步骤总结问题以jar包的形式运行Spring Boot项目时报错,但是在IDEA开发环境javascript下编译

Python实现自动化Word文档样式复制与内容生成

《Python实现自动化Word文档样式复制与内容生成》在办公自动化领域,高效处理Word文档的样式和内容复制是一个常见需求,本文将展示如何利用Python的python-docx库实现... 目录一、为什么需要自动化 Word 文档处理二、核心功能实现:样式与表格的深度复制1. 表格复制(含样式与内容)2

python获取cmd环境变量值的实现代码

《python获取cmd环境变量值的实现代码》:本文主要介绍在Python中获取命令行(cmd)环境变量的值,可以使用标准库中的os模块,需要的朋友可以参考下... 前言全局说明在执行py过程中,总要使用到系统环境变量一、说明1.1 环境:Windows 11 家庭版 24H2 26100.4061

如何搭建并配置HTTPD文件服务及访问权限控制

《如何搭建并配置HTTPD文件服务及访问权限控制》:本文主要介绍如何搭建并配置HTTPD文件服务及访问权限控制的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、安装HTTPD服务二、HTTPD服务目录结构三、配置修改四、服务启动五、基于用户访问权限控制六、

Python中bisect_left 函数实现高效插入与有序列表管理

《Python中bisect_left函数实现高效插入与有序列表管理》Python的bisect_left函数通过二分查找高效定位有序列表插入位置,与bisect_right的区别在于处理重复元素时... 目录一、bisect_left 基本介绍1.1 函数定义1.2 核心功能二、bisect_left 与

VSCode设置python SDK路径的实现步骤

《VSCode设置pythonSDK路径的实现步骤》本文主要介绍了VSCode设置pythonSDK路径的实现步骤,包括命令面板切换、settings.json配置、环境变量及虚拟环境处理,具有一定... 目录一、通过命令面板快速切换(推荐方法)二、通过 settings.json 配置(项目级/全局)三、

pandas实现数据concat拼接的示例代码

《pandas实现数据concat拼接的示例代码》pandas.concat用于合并DataFrame或Series,本文主要介绍了pandas实现数据concat拼接的示例代码,具有一定的参考价值,... 目录语法示例:使用pandas.concat合并数据默认的concat:参数axis=0,join=

Python程序打包exe,单文件和多文件方式

《Python程序打包exe,单文件和多文件方式》:本文主要介绍Python程序打包exe,单文件和多文件方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录python 脚本打成exe文件安装Pyinstaller准备一个ico图标打包方式一(适用于文件较少的程

java中BigDecimal里面的subtract函数介绍及实现方法

《java中BigDecimal里面的subtract函数介绍及实现方法》在Java中实现减法操作需要根据数据类型选择不同方法,主要分为数值型减法和字符串减法两种场景,本文给大家介绍java中BigD... 目录Java中BigDecimal里面的subtract函数的意思?一、数值型减法(高精度计算)1.

C#代码实现解析WTGPS和BD数据

《C#代码实现解析WTGPS和BD数据》在现代的导航与定位应用中,准确解析GPS和北斗(BD)等卫星定位数据至关重要,本文将使用C#语言实现解析WTGPS和BD数据,需要的可以了解下... 目录一、代码结构概览1. 核心解析方法2. 位置信息解析3. 经纬度转换方法4. 日期和时间戳解析5. 辅助方法二、L