最近有一个库存系统,需要在电子秤上能够称完重发到系统上,于是来了个带着安卓屏的电子秤,让我看看怎么处理,我的天哪,3k工资都给我干上物联网了,人有点麻了,还不如当保安...

        老大哥跟我说这个数据是串口发送的,得先搞到称返回的数据,于是开始看uniapp上的插件,有没有,还是老样子,先找免费的,有个非常棒的还免费,作者真是我义父了,给作者磕一个,usb-serial - DCloud 插件市场,然后导入完插件打个包拷贝到称上,有了,不过有点不对劲,因为称的文档上写的是什么ttyS1的,这个插件给我返回的都是usbxxx啊,我试着点了点,弹出没有串口数据。人麻了,于是找插件,又找了几个插件,都没这个好使,关键是点了半天也没有东西,烦死了烦死了烦死了烦死了烦死了烦死了烦死了烦死了烦死了烦死了烦死了烦死了烦死了烦死了烦死了烦死了烦死了烦死了烦死了烦死了烦死了烦死了,期间还想,要不要自己把java代码封装成原生的,一想到一个臭前端不会java一个月3k还得会这么多就有点烦。下班回家打游戏去了。

        打游戏的时候想到一件事,就是插件市场的插件,有的叫usb串口,有的是安卓串口,这些有什么区别吗,于是搜了一下,感觉有点思路了,又去插件市场看看,嘿,还有一个串口插件,也是这个作者写的,作者真是我义父了,rs232-serial - DCloud 插件市场,兄弟们给我义父点点赞打打赏,我一个月臭3k的比要饭的挣的少就不参与了。回到正题,早上懒得再写测试代码了,直接拿这个插件的实例项目打包,还真出数据了,打开监听后走到称上,也能出东西。数据不过要处理一下,这就是后话了。

        usb的串口和这个什么ttys系列还真是有区别,称这样的东西大概率就是ttys这样的,记得用第二个插件,不仅如此,串口号,HEX ASCII、什么数据位波特率要如实写,写的错的,就不一定接收的到了,还有一件事,这个插件的示例项目是vue3的,我直接抄完导入到vue2里面点不动,想试试的话可以直接拿这个插件示例项目打包,然后再试试打包的app能不能有数据,最后,用这个插件成功的记得给我义父点个赞赏,不要钱是人家大气,兄弟们挣的比我多的请我义父喝瑞幸不过分吧

        下面是我用的该插件写的调用电子秤的代码,注意,先对一下是不是基础的参数等东西一样,根据实际情况修改,关于具体参数值,厂家应该会有实际的文档。我写的里面有些无用代码,看情况删改即可

<template>
	<view class="container" id="content2PDF">

	</view>
	<!-- 分割线 -->
	<view class="divider"></view>
	<!-- 下部分:称重区域 -->
	<view class="weight-section">
		<view class="weight-display">
			<template>
				<view class="flex-row">
					<text class="unit">当前已记录重量:{{ recordWeightList.join(',') }} </text>
					<text class="unit">合计重量{{ totalWeight }}kg</text>
				</view>

				<view class="flex-row">
					<text class="weight-tit">实际重量</text>
					<text class="current-weight">{{ Weight_real }}</text>
					<text class="unit">kg</text>
				</view>

				<view class="weight-controls card-t2">
					<text class="nvue-btn graybtn" @tap="outPackageFn">去皮</text>
					<text class="nvue-btn graybtn" @tap="resetWeightFn">清零</text>
				</view>
			</template>

		</view>
	</view>

	</view>
</template>

<script>
	import {
		RS232Serial,
		checkHasIntegration
	} from '@/uni_modules/shmily-rs232-serial';
	let serialPort;
	
	export default {
		components: {
		},
		computed: {
			totalWeight() {
				// 1. 将数字转换为整数运算(避免浮点数精度问题)
				const toIntegerCents = num => Math.round(num * 100); // 元转分

				// 2. 计算记录列表的总分(以分为单位)
				const listTotalCents = this.recordWeightList.reduce((acc, cur) => {
					const num = Number(cur);
					return isNaN(num) ? acc : acc + toIntegerCents(num);
				}, 0);

				// 3. 加上当前重量的分值
				const current = Number(this.Weight_real) || 0;
				const totalCents = listTotalCents + toIntegerCents(current);

				// 4. 转换回元并保留两位小数(消除小数误差)
				return (totalCents / 100).toFixed(2);
			},
		},
		onLaunch: function() {

		},
		created() {

			serialPort = new RS232Serial();
			if (checkHasIntegration()) {
				// this.portList = this.resolveData(serialPort.getDeviceList());
			} else {
				uni.showToast({
					title: '需要在自定义基座中运行',
					duration: 4000,
					icon: "error",
				});
			}

		},

		data() {
			return {
				recordWeightList: [],
				// 串口获取的当前数据
				serialOptions: {
					port: '/dev/ttyS1',
					baudRate: '9600',
					dataBits: '8',
					stopBits: '1',
					parity: 0,
					flowCon: 0
				},

				Weight_real: null,
				Weight_code: null,
				Weight_code222: null,
			};
		},
		onLoad(e) {},
		onShow(e) {

		},
		mounted() {
			this.handleOpen()
		},
		methods: {
			// ----------------------------------------
			showToast(text) {
				uni.showToast({
					title: text,
					icon: 'none',
				});
			},

			// 打开与电子秤的数据连接
			handleOpen() {

				if (!checkHasIntegration()) {
					this.showToast('需要在自定义基座中运行');
					return;
				}
				serialPort.subscribe('HEX', data => {
					this.handleAddDaa('rx', data);
				});
				if (!this.serialOptions.port) {
					this.showToast('请选择串口号');
					return;
				}
				const options = {
					port: this.serialOptions.port,
					baudRate: parseInt(this.serialOptions.baudRate),
					dataBits: parseInt(this.serialOptions.dataBits),
					stopBits: parseInt(this.serialOptions.stopBits),
					parity: parseInt(this.serialOptions.parity),
					flowCon: parseInt(this.serialOptions.flowCon)
				};
				const success = serialPort.open(options);

				if (success) {
					this.isOpen = true;
					// 防止superuser、magisk等软件跳转后看不到提示
					setTimeout(() => {
						this.showToast('连接电子秤成功');
					}, 1000);
				} else {
					this.showToast('连接电子秤失败');
				}
			},
			// 用于去皮
			outPackageFn() {
				serialPort.sendHex('3C 54 41 52 40 3E');

			},
			// 置零数据
			resetWeightFn() {
				serialPort.sendText('<ZER@>');
			},
			// 转化获取当前称重信息
			analysis(hexString) {
				// 将十六进制字符串转换为字节数组
				const bytes = [];
				for (let i = 0; i < hexString.length; i += 2) {
					const byte = parseInt(hexString.substr(i, 2), 16);
					bytes.push(byte);
				}

				// 1. 判断是否9位数以内
				if (bytes.length > 9) return "数据错误-1";

				// 2. 判断第0位和第1位是否为开始符 0x0A, 0x0D
				if (bytes[0] !== 0x0A || bytes[1] !== 0x0D) return "数据错误-2";

				// 3. 判断第2位是否为空格 0x20 或负号 0x2D
				if (bytes[2] === 0x2D) return "重量数值是负数!";
				if (bytes[2] !== 0x20) return "数据错误-3";

				// 4. 检查数字部分是否有 0xFF(超重或负数)
				const numStart = 3;
				const numEnd = bytes.length - 1;
				for (let i = numStart; i <= numEnd; i++) {
					if (bytes[i] === 0xFF) return "超重或负数";
				}

				// 重量计算
				let mWeight = 0;
				const len = bytes.length;

				if (len === 8) {
					mWeight += (bytes[3] - 48) * 10000; // 万位
					mWeight += (bytes[4] - 48) * 1000; // 千位
					mWeight += (bytes[5] - 48) * 100; // 百位
					mWeight += (bytes[6] - 48) * 10; // 十位
					mWeight += (bytes[7] - 48) * 1; // 个位
				} else if (len === 9) {
					mWeight += (bytes[3] - 48) * 100000; // 十万位
					mWeight += (bytes[4] - 48) * 10000; // 万位
					mWeight += (bytes[5] - 48) * 1000; // 千位
					mWeight += (bytes[6] - 48) * 100; // 百位
					mWeight += (bytes[7] - 48) * 10; // 十位
					mWeight += (bytes[8] - 48) * 1; // 个位
				} else {
					return "数据错误-5";
				}

				// 转换为千克并格式化为三位小数
				return (mWeight * 0.001).toFixed(3) + "kg";
			},



			handleAddDaa(type, text) {
				if (text.trim()) {
					if (type === 'rx') {
						// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
						// this.testval1=text.trim().replace(/\n/g, "")
						// this.testval3=text
						this.Weight_code222 = text
						this.weight_code = text.trim().replace(/\n/g, "")

						// if(this.open_translateFN){
						// this.Weight_real=this.analysis(text.trim().replace(/\n/g, ""))
						this.Weight_real = this.analysis(text.trim().replace(/\n/g, "")).replace("kg", "")
						// }
						// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

					} else {
						// this.history.unshift({
						//   time: this.getTime(),
						//   prefix: 'Tx: ==>',
						//   text: text.trim().replace(/\n/g, "")
						// });
					}
				}
			},

		},

	};
</script>



<style scoped>
	/* ===== 通用样式 ===== */
	.container {
		flex: 1;
		flex-direction: column;
		padding: 5px 20px;
		background-color: #f8f8f8;
	}

	.weight-section {
		flex: 1;
		flex-direction: row;
		background-color: #ffffff;
		border-radius: 8px;
		overflow: hidden;
		display: flex;
		flex-direction: row;
		justify-content: space-between;
		overflow: auto !important;
		/* 覆盖原始样式 */
		overflow: hidden !important;
	}

	/* ===== 广告区域样式 ===== */
	.sssAD,
	.sssAD222 {
		width: 240px;
		height: 160px;
		background-color: rgba(248, 248, 248, 1.0);
	}

	/* ===== 商品信息区域 ===== */
	.product-section {
		padding: 0 15px;
		background-color: #ffffff;
		border-radius: 8px;
	}

	.info-row {
		flex-direction: row;
		padding: 10px 0;
		border-bottom-width: 1px;
		border-bottom-color: #eeeeee;
	}

	.label {
		width: 80px;
		color: #666666;
		font-size: 15px;
	}

	.value {
		flex: 1;
		color: #333333;
		font-size: 16px;
		font-weight: 500;
	}

	.divider {
		height: 10px;
	}

	/* ===== 图片区域 ===== */
	.gallery-container {
		background-color: rgba(255, 255, 255, 0.1);
		border-radius: 10px;
		padding: 15px;
		margin-top: 15px;
	}

	.scroll-container {
		flex-direction: row;
	}

	.item {
		width: 160px;
		background-color: rgba(255, 255, 255, 0.08);
		border-radius: 8px;
		overflow: hidden;
		border-width: 1px;
		border-color: rgba(255, 255, 255, 0.15);
	}

	.image-container {
		flex-direction: column;
		gap: 10px;
		padding: 10px;
	}

	.image-item {
		flex-direction: column;
		gap: 6px;
	}

	.image {
		width: 140px;
		height: 80px;
		border-radius: 6px;
		justify-content: center;
		align-items: center;
		background-color: #3a1c71;
		color: white;
		font-weight: bold;
		font-size: 14px;
	}

	.weight {
		text-align: center;
		font-size: 14px;
		font-weight: 600;
		color: #ffd166;
		background-color: rgba(0, 0, 0, 0.3);
		padding: 4px;
		border-radius: 4px;
		margin: 0 7px 7px;
	}

	/* ===== 称重区域 ===== */
	.photo-area {
		width: 240px;
		height: 320px;
		background-color: #ebfff8;
		display: flex;
		flex-direction: column;
		justify-content: start;
		margin-top: 100px;
		padding-top: 80px;
	}

	.camera {
		width: 100%;
		height: 100%;
	}

	.weight-display {
		width: 100%;
		flex-direction: column;
		justify-content: center;
		align-items: center;
		padding: 15px;
	}

	.flex-row {
		display: flex;
		align-items: center;
		text-align: center;
		justify-content: center;
		margin: 0 auto;
	}

	.weight-tit {
		font-size: 40px;
		color: #007AFF;
		margin-top: 20px;
	}

	.current-weight {
		font-size: 60px;
		font-weight: bold;
		color: #007AFF;
		margin: 0 15px;
	}

	.unit {
		font-size: 18px;
		color: #999999;
	}

	.weight-controls {
		display: flex;
		flex-direction: row;
		justify-content: space-between;
		align-items: center;
		justify-content: center;
		text-align: center;
		margin: 0 auto;
		margin-top: 30px;
		gap: 10px;
	}

	.card-t1 {
		width: 320px;
		margin: 30px auto;
	}

	.card-t2 {
		width: 280px;

	}

	/* ===== 按钮样式 ===== */
	.btn {
		min-width: 90px;
		height: 40px;
		line-height: 40px;
		font-size: 16px;
		border-radius: 6px;
		background-color: #007AFF;
		color: white;
		text-align: center;
	}

	.confirm-btn {
		color: white;
	}

	.hafehide-btn {
		background-color: transparent;
		border-width: 1px;
		border-color: #cccccc;
		color: #999999;
	}

	.nvue-btn {
		min-width: 90px;
		height: 40px;
		line-height: 40px;
		font-size: 16px;
		border-radius: 6px;
		background-color: #007AFF;
		text-align: center;
		margin: 0 10px;
		color: white;
		font-size: 16px;
		transition: all 0.1s linear;
	}

	.nvue-btn:active {
		background-color: rgba(0, 122, 255, 0.8);
		transform: scale(0.98);
	}

	.graybtn {
		margin-top: -8px;
		display: block;
		background-color: white;
		border: 1px solid gray;
		color: gray;
		width: 80px !important;
		height: 30px !important;
		padding: 0 !important;
		line-height: 30px !important;
		box-sizing: border-box;
		font-size: 14px;
		/* 可选,调整字体大小 */
	}


	/* ===== 图片滚动容器 ===== */
	.pic-container {
		display: flex;
		flex-direction: row;
		white-space: nowrap;
		overflow-x: auto;
		padding: 12px;
		background-color: #f7f7f7;
		width: 100%;
	}

	/* ===== 图片列表项 ===== */
	.list-item {
		display: inline-flex;
		flex-direction: column;
		align-items: center;
		margin-right: 20px;
		vertical-align: top;
		width: auto;
		width: 110px;
	}

	.pic-photo {
		width: 85px;

		height: 60px;
		margin-bottom: 8px;
		background-color: #e0e0e0;
		border-radius: 4px;
	}

	.pic-weight {
		font-size: 18px;
		font-weight: bold;
		color: #333;
		margin-top: 4px;
	}

	/* ===== 滚动条隐藏 ===== */
	::-webkit-scrollbar {
		display: none;
	}
</style>

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐