unity 使用藍牙通訊(PC版,非安卓)

BlueTooth in pc with unity

最近接到的需求是在unity里面開發藍牙功能,其實一開始我并不慌,因為據我所知,unity有豐富的插件可以使用,但是問題隨之而來
1.unity里面無法直接與藍牙通訊(后來找到了開啟runtime一類的東西,但是我找了半天也沒找到在哪里可以打開)
2.引入dll通過dll與藍牙通訊,包括去微軟的官網下載c++編譯,但是編譯過程中種種問題.而我對于c++這一套也不精通.也是放棄了
3.github上找到一個封裝好的BLE的一個 這是網址 但是在我的測試中發現 會有搜不到我的藍牙設備的問題.并且即使連上了,發出的消息也沒有回應.所以也是放棄了

于是只能通過一個比較笨的辦法,將藍牙通訊在winform中或者是wpf中,然后將unity程序放在winform或者是wpf的容器中,二者通過udp協議連接傳輸數據.最后的效果如下:

運行界面

那么如果是這種辦法,那就變得簡單的多了.winform開發不在話下.unity也是我熟悉的.其中winform支持原生開發,也就是說不用下載任何dll與插件,用到的只是windows.winmd,而這個windows系統是自帶的.

將winmd類型文件引入后,編寫開發工具類:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.Advertisement;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Devices.Enumeration;
using Windows.Foundation;
using Windows.Networking;
using Windows.Networking.Proximity;
using Windows.Networking.Sockets;
using Windows.Security.Cryptography;
using Windows.Storage.Streams;namespace Bluetooth
{internal class BleCore{private Boolean asyncLock = false;/// <summary>/// 搜索藍牙設備對象/// </summary>private BluetoothLEAdvertisementWatcher watcher;/// <summary>/// 當前連接的藍牙設備/// </summary>public BluetoothLEDevice CurrentDevice { get; set; }/// <summary>/// 特性通知類型通知啟用/// </summary>private const GattClientCharacteristicConfigurationDescriptorValue CHARACTERISTIC_NOTIFICATION_TYPE = GattClientCharacteristicConfigurationDescriptorValue.Notify;/// <summary>/// 存儲檢測到的設備/// </summary>private List<BluetoothLEDevice> DeviceList = new List<BluetoothLEDevice>();/// <summary>/// 搜索藍牙設備委托/// </summary>public delegate void DeviceScanEvent(BluetoothLEDevice bluetoothLEDevice);/// <summary>/// 搜索藍牙事件/// </summary>public event DeviceScanEvent DeviceScan;/// <summary>/// 提示信息委托/// </summary>public delegate void MessAgeLogEvent(MsgType type, string message, byte[] data = null);/// <summary>/// 提示信息事件/// </summary>public event MessAgeLogEvent MessAgeLog;/// <summary>/// 接收通知委托/// </summary>public delegate void ReceiveNotificationEvent(GattCharacteristic sender, byte[] data);/// <summary>/// 接收通知事件/// </summary>public event ReceiveNotificationEvent ReceiveNotification;/// <summary>/// 獲取服務委托/// </summary>public delegate void DeviceFindServiceEvent(DeviceService deviceService);/// <summary>/// 獲取服務事件/// </summary>public event DeviceFindServiceEvent DeviceFindService;/// <summary>/// 藍牙狀態委托/// </summary>public delegate void DeviceConnectionStatusEvent(BluetoothConnectionStatus status);/// <summary>/// 藍牙狀態事件/// </summary>public event DeviceConnectionStatusEvent DeviceConnectionStatus;/// <summary>/// 當前連接的藍牙Mac/// </summary>private string CurrentDeviceMAC { get; set; }public BleCore(){}/// <summary>/// 搜索藍牙設備/// </summary>public void StartBleDeviceWatcher(){watcher = new BluetoothLEAdvertisementWatcher();watcher.ScanningMode = BluetoothLEScanningMode.Active;//只有在接收到數值大于等于 -80 的情況下才激活監視器watcher.SignalStrengthFilter.InRangeThresholdInDBm = -80;// 如果數值低于 -90(用戶離開),則停止監測watcher.SignalStrengthFilter.OutOfRangeThresholdInDBm = -90;// 注冊回調函數,以便在我們看到廣播時觸發(執行)相關操作watcher.Received += OnAdvertisementReceived;// 等待 5 秒鐘以確保設備確實超出范圍watcher.SignalStrengthFilter.OutOfRangeTimeout = TimeSpan.FromMilliseconds(5000);watcher.SignalStrengthFilter.SamplingInterval = TimeSpan.FromMilliseconds(2000);// starting watching for advertisementsthis.DeviceList.Clear();watcher.Start();string msg = "開始搜索藍牙設備...";this.MessAgeLog(MsgType.NotifyTxt, msg);}/// <summary>/// 停止搜索藍牙/// </summary>public void StopBleDeviceWatcher(){this.watcher.Stop();}private void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs eventArgs){//this.MessAgeChanged(MsgType.NotifyTxt, "發現設備FR_NAME:"+ eventArgs.Advertisement.LocalName + "BT_ADDR: " + eventArgs.BluetoothAddress);BluetoothLEDevice.FromBluetoothAddressAsync(eventArgs.BluetoothAddress).Completed = (asyncInfo, asyncStatus) =>{if (asyncStatus == AsyncStatus.Completed){if (asyncInfo.GetResults() != null){BluetoothLEDevice currentDevice = asyncInfo.GetResults();Boolean contain = false;foreach (BluetoothLEDevice device in DeviceList)//過濾重復的設備{if (device.BluetoothAddress == currentDevice.BluetoothAddress){contain = true;}}if (!contain){byte[] _Bytes1 = BitConverter.GetBytes(currentDevice.BluetoothAddress);Array.Reverse(_Bytes1);this.DeviceList.Add(currentDevice);string str;if (currentDevice.DeviceInformation.Name != ""){str = "發現設備:" + currentDevice.DeviceInformation.Name + " - MAC: \r\n" +BitConverter.ToString(_Bytes1, 2, 6).Replace('-', ':').ToUpper() + " - ID: /r/n" + currentDevice.DeviceInformation.Id;}//舍棄沒有名字的設備(匿名設備)else{//    str = "發現設備:" + BitConverter.ToString(_Bytes1, 2, 6).Replace('-', ':').ToUpper();return;}this.MessAgeLog(MsgType.NotifyTxt, str);this.DeviceScan(currentDevice);}}}};}/// <summary>/// 匹配/// </summary>/// <param name="Device"></param>public void StartMatching(BluetoothLEDevice Device){this.CurrentDevice?.Dispose();this.CurrentDevice = Device;Connect();FindService();}/// <summary>/// 獲取藍牙服務/// </summary>public async void FindService(){this.MessAgeLog(MsgType.NotifyTxt, "開始獲取服務列表");this.CurrentDevice.GetGattServicesAsync().Completed = async (asyncInfo, asyncStatus) =>{if (asyncStatus == AsyncStatus.Completed){var services = asyncInfo.GetResults().Services;//this.MessAgeChanged(MsgType.NotifyTxt, "GattServices size=" + services.Count);foreach (GattDeviceService ser in services){FindCharacteristic(ser);}}};}/// <summary>/// 獲取特性/// </summary>public async void FindCharacteristic(GattDeviceService gattDeviceService){IAsyncOperation<GattCharacteristicsResult> result = gattDeviceService.GetCharacteristicsAsync();result.Completed = async (asyncInfo, asyncStatus) =>{if (asyncStatus == AsyncStatus.Completed){var characters = asyncInfo.GetResults().Characteristics;List<GattCharacteristic> characteristics = new List<GattCharacteristic>();foreach (GattCharacteristic characteristic in characters){characteristics.Add(characteristic);this.MessAgeLog(MsgType.NotifyTxt, "服務UUID:" + gattDeviceService.Uuid.ToString() + " --- 特征UUID:" + characteristic.Uuid.ToString());}DeviceService deviceService = new DeviceService();deviceService.gattDeviceService = gattDeviceService;deviceService.gattCharacteristic = characteristics;this.DeviceFindService(deviceService);}};}/// <summary>/// 獲取操作/// </summary>/// <returns></returns>public async Task SetNotify(GattCharacteristic gattCharacteristic){GattCharacteristic CurrentNotifyCharacteristic;if ((gattCharacteristic.CharacteristicProperties & GattCharacteristicProperties.Notify) != 0){CurrentNotifyCharacteristic = gattCharacteristic;CurrentNotifyCharacteristic.ProtectionLevel = GattProtectionLevel.Plain;CurrentNotifyCharacteristic.ValueChanged += Characteristic_ValueChanged;await this.EnableNotifications(CurrentNotifyCharacteristic);}}/// <summary>/// 連接藍牙/// </summary>/// <returns></returns>private async Task Connect(){byte[] _Bytes1 = BitConverter.GetBytes(this.CurrentDevice.BluetoothAddress);Array.Reverse(_Bytes1);this.CurrentDeviceMAC = BitConverter.ToString(_Bytes1, 2, 6).Replace('-', ':').ToLower();string msg = "正在連接設備:" + this.CurrentDeviceMAC.ToUpper() + " ...";this.MessAgeLog(MsgType.NotifyTxt, msg);this.CurrentDevice.ConnectionStatusChanged += this.CurrentDevice_ConnectionStatusChanged;}/// <summary>/// 搜索到的藍牙設備/// </summary>/// <returns></returns>private async Task Matching(string Id){try{BluetoothLEDevice.FromIdAsync(Id).Completed = async (asyncInfo, asyncStatus) =>{if (asyncStatus == AsyncStatus.Completed){BluetoothLEDevice bleDevice = asyncInfo.GetResults();this.DeviceList.Add(bleDevice);this.DeviceScan(bleDevice);this.CurrentDevice = bleDevice;FindService();}};}catch (Exception e){string msg = "沒有發現設備" + e.ToString();this.MessAgeLog(MsgType.NotifyTxt, msg);this.StartBleDeviceWatcher();}}/// <summary>/// 主動斷開連接/// </summary>/// <returns></returns>public void Dispose(){CurrentDeviceMAC = null;CurrentDevice?.Dispose();CurrentDevice = null;MessAgeLog(MsgType.NotifyTxt, "主動斷開連接");}private void CurrentDevice_ConnectionStatusChanged(BluetoothLEDevice sender, object args){this.DeviceConnectionStatus(sender.ConnectionStatus);if (sender.ConnectionStatus == BluetoothConnectionStatus.Disconnected && CurrentDeviceMAC != null){string msg = "設備已斷開,自動重連...";MessAgeLog(MsgType.NotifyTxt, msg);if (!asyncLock){asyncLock = true;this.CurrentDevice.Dispose();this.CurrentDevice = null;SelectDeviceFromIdAsync(CurrentDeviceMAC);}}else{string msg = "設備已連接!";MessAgeLog(MsgType.NotifyTxt, msg);}}/// <summary>/// 按MAC地址直接組裝設備ID查找設備/// </summary>public async Task SelectDeviceFromIdAsync(string MAC){CurrentDeviceMAC = MAC;CurrentDevice = null;BluetoothAdapter.GetDefaultAsync().Completed = async (asyncInfo, asyncStatus) =>{if (asyncStatus == AsyncStatus.Completed){BluetoothAdapter mBluetoothAdapter = asyncInfo.GetResults();byte[] _Bytes1 = BitConverter.GetBytes(mBluetoothAdapter.BluetoothAddress);//ulong轉換為byte數組Array.Reverse(_Bytes1);string macAddress = BitConverter.ToString(_Bytes1, 2, 6).Replace('-', ':').ToLower();string Id = "BluetoothLE#BluetoothLE" + macAddress + "-" + MAC;await Matching(Id);}};}/// <summary>/// 設置特征對象為接收通知對象/// </summary>/// <param name="characteristic"></param>/// <returns></returns>public async Task EnableNotifications(GattCharacteristic characteristic){if (CurrentDevice.ConnectionStatus != BluetoothConnectionStatus.Connected){this.MessAgeLog(MsgType.NotifyTxt, "藍牙未連接!");return;}characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(CHARACTERISTIC_NOTIFICATION_TYPE).Completed = async (asyncInfo, asyncStatus) =>{Console.WriteLine("asyncStatus:" + asyncStatus);if (asyncStatus == AsyncStatus.Completed){GattCommunicationStatus status = asyncInfo.GetResults();asyncLock = false;string msg = "Notify(" + characteristic.Uuid.ToString() + "):" + status;this.MessAgeLog(MsgType.NotifyTxt, msg);}else{Console.WriteLine(asyncInfo.ErrorCode.ToString());}};}/// <summary>/// 接受到藍牙數據/// </summary>private void Characteristic_ValueChanged(GattCharacteristic characteristic, GattValueChangedEventArgs args){byte[] data;CryptographicBuffer.CopyToByteArray(args.CharacteristicValue, out data);string str = System.Text.Encoding.UTF8.GetString(data);this.ReceiveNotification(characteristic, data);this.MessAgeLog(MsgType.BleData, "收到數據(" + characteristic.Uuid.ToString() + "):" + str);}/// <summary>/// 發送數據接口/// </summary>/// <returns></returns>public async Task Write(GattCharacteristic writeCharacteristic, byte[] data){if (writeCharacteristic != null){string str = "發送數據(" + writeCharacteristic.Uuid.ToString() + "):" + BitConverter.ToString(data);this.MessAgeLog(MsgType.BleData, str, data);IAsyncOperation<GattCommunicationStatus> async = writeCharacteristic.WriteValueAsync(CryptographicBuffer.CreateFromByteArray(data), GattWriteOption.WriteWithResponse);async.Completed = async (asyncInfo, asyncStatus) =>{if (asyncStatus == AsyncStatus.Completed){this.MessAgeLog(MsgType.BleData, "數據發送成功!");}else{this.MessAgeLog(MsgType.BleData, "數據發送失敗:" + asyncInfo.ErrorCode.ToString());}};}}}public enum MsgType{NotifyTxt,BleData,BleDevice}public class DeviceService{public GattDeviceService gattDeviceService;public List<GattCharacteristic> gattCharacteristic;}
}

然后對于頁面的按鈕進行賦值,并將unity開發的exe放在合適的位置,其中通訊部分只需要簡單的通訊即可,不需要考慮什么分包問題.因為本機通訊很穩定.
winform部分的udp:

using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;namespace VincentUDP
{public class UdpServer{private UdpClient udpClient;private IPEndPoint remoteEndPoint;public void Init(){int port = 8888; // 選擇一個端口udpClient = new UdpClient();remoteEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), port); // 目標IP和端口}public void Send(byte[] message){// byte[] data = Encoding.UTF8.GetBytes(message);udpClient.Send(message, message.Length, remoteEndPoint);}public void Close(){udpClient.Close();}}
}

unity接收部分:

using System;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using UnityEngine;public class RecvUDPMsg : MonoBehaviour
{private UdpClient udpClient;//消息隊列private Queue queue = new Queue();private void Start(){// 初始化UDP客戶端udpClient = new UdpClient(8888); // 監聽的端口StartReceiving();}private void StartReceiving(){udpClient.BeginReceive(ReceiveCallback, null);}private void ReceiveCallback(IAsyncResult ar){IPEndPoint remoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);byte[] receivedBytes = udpClient.EndReceive(ar, ref remoteIpEndPoint);// string receivedText = Encoding.UTF8.GetString(receivedBytes);//Debug.Log("Received: " + receivedText);queue.Enqueue(receivedBytes);// 繼續監聽StartReceiving();}private void OnDestroy(){// 關閉UDP客戶端udpClient.Close();}
}

那么最后的運行如下:
最終效果
最后附上下載地址: 點擊這里
PS:如果下載不了(非csdn會員)請私信我.

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/80659.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/80659.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/80659.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

MySQL中的意向鎖 + next-key鎖 + 間隙鎖

引言 在數據庫并發控制中&#xff0c;鎖機制是保障數據一致性和隔離性的核心手段。MySQL中意向鎖、間隙鎖以及next-key鎖等復雜鎖類型&#xff0c;旨在協調表級鎖與行級鎖之間的關系&#xff0c;防止數據的臟讀、不可重復讀和幻讀現象&#xff0c;尤其是在可重復讀隔離級別下發…

機器學習 數據集

數據集 1. scikit-learn工具介紹1.1 scikit-learn安裝1.2 Scikit-learn包含的內容 2 數據集2.1 sklearn玩具數據集介紹2.2 sklearn現實世界數據集介紹2.3 sklearn加載玩具數據集示例1&#xff1a;鳶尾花數據示例2&#xff1a;分析糖尿病數據集 2.4 sklearn獲取現實世界數據集示…

Linux-c語言串口程序

c語言串口程序 // C library headers #include <stdio.h> #include <string.h>// Linux headers #include <fcntl.h> // Contains file controls like O_RDWR #include <errno.h> // Error integer and strerror() function #include <termios.h&g…

TCP IP

TCP/IP 通信協議&#xff0c;不是單一協議&#xff0c;是一組協議的集合 TCP IP UDP 1.建立鏈接 三次握手 第一步&#xff1a;客戶端發送一個FIN報文&#xff0c;SEQX,等待服務器回應 第二步&#xff1a;服務器端受到&#xff0c;發送ackx1,seqy, 等待客戶端回應 第三步&am…

用uniapp在微信小程序實現畫板(電子簽名)功能,使用canvas實現功能

效果&#xff1a; 功能&#xff1a;實現重簽 退出 保存 等功能 解決的問題: 電子簽名畫布抖動問題解 注意&#xff1a; 保存的時候上傳到自己的服務器地址&#xff0c;后端返回圖片地址 代碼&#xff1a; <template><view><view class"signature&qu…

機器學習經典算法:用決策樹原理優化新能源汽車續航能力

?? “用決策樹重構新能源車能量大腦!算法推導+代碼實戰全解,續航暴增15%” 決策樹算法就像我們生活中做決策的 “流程指南”,通過層層判斷得出最終結論。比如你去超市買水果,站在琳瑯滿目的貨架前,就不自覺地用上了決策樹思維。首先,你可能會想 “今天想吃酸的還是甜的…

【Unity中的數學】—— 四元數

一、四元數的定義&#x1f60e; 四元數是一種高階復數&#xff0c;是一個四維空間的概念&#xff0c;相對于復數的二維空間。它可以表示為 q s i x j y k z q s ix jy kz qsixjykz&#xff0c;其中 s s s、 x x x、 y y y、 z z z 都是實數&#xff0c;并且滿足 i …

macOS 15.4.1 Chrome不能訪問本地網絡

前言 最近使用macmini m4&#xff0c;自帶macOS15系統&#xff0c;對于開發者簡直是一言難盡&#xff0c;Chrome瀏覽器的本地網絡有bug&#xff0c;可以訪問本機&#xff0c;但是不能訪問路由器上的其他機器&#xff0c;路由器提供的頁面也不能訪問&#xff0c;如下是折騰解決…

瀏覽器刷新結束頁面事件,調結束事件的接口(vue)

瀏覽器刷新的時候&#xff0c;正在進行中的事件結束掉&#xff0c;在刷新瀏覽器的時候做一些操作。 如果是調接口&#xff0c;就不能使用axios封裝的接口&#xff0c;需要使用原生的fetch。 找到公共的文件App.vue 使用window.addEventListener(‘beforeunload’, function (e…

TCP/IP 模型每層的封裝格式

TCP/IP 模型是一個四層網絡架構&#xff0c;每一層在數據傳輸時都會對數據進行封裝&#xff0c;添加相應的頭部&#xff08;和尾部&#xff09;信息。以下是各層的封裝格式及關鍵字段說明&#xff1a; 1. 應用層&#xff08;Application Layer&#xff09; 封裝格式&#xff1a…

【行業深度解析】什么是馬甲包?

在 Android 應用分發和增長運營的實踐中&#xff0c;“馬甲包” 是一個常被提及的策略術語。特別是在 Google Play 平臺上&#xff0c;許多開發者或運營團隊出于營銷、風險分攤或生態布局等原因&#xff0c;會選擇通過發布“馬甲包”來實現多元化的業務拓展。 然而&#xff0c…

谷歌與微軟的AI戰爭:搜索、云服務與生態布局

谷歌與微軟的AI戰爭&#xff1a;搜索、云服務與生態布局 系統化學習人工智能網站&#xff08;收藏&#xff09;&#xff1a;https://www.captainbed.cn/flu 文章目錄 谷歌與微軟的AI戰爭&#xff1a;搜索、云服務與生態布局摘要引言技術路線對比1. AI基礎設施&#xff1a;算力…

uniapp自定義導航欄搭配插槽

<uni-nav-bar dark :fixed"true" shadow background-color"#007AFF" left-icon"left" left-text"返回" clickLeft"back"><view class"nav-bar-title">{{ navBarTitle }}</view><block v-slo…

無人機飛控算法開發實戰:從零到一構建企業級飛控系統

簡介 無人機飛控算法是實現穩定飛行和精確控制的核心技術,涉及飛行動力學建模、傳感器數據處理、狀態估計和控制策略等多個環節。本實戰指南將系統講解四旋翼無人機飛控算法的開發流程,包括飛行動力學模型建立、傳感器校準與數據融合、主流控制算法實現(PID、ADRC、EKF)以…

p2p虛擬服務器

ZeroTier Central ? 推薦工具&#xff1a;ZeroTier&#xff08;免費、穩定、跨平臺&#xff09; ZeroTier 可以幫你把多臺設備&#xff08;無論是否跨網&#xff09;加入一個虛擬局域網&#xff0c;彼此間可以像在同一個 LAN 中通信&#xff0c;UDP 視頻、文件傳輸、SSH 等都…

MySQL數據庫遷移SQL語句指南

MySQL數據庫遷移SQL語句指南 一、基礎遷移方法 1. 使用mysqldump進行全量遷移 -- 導出源數據庫&#xff08;在命令行執行&#xff09; mysqldump -u [源用戶名] -p[源密碼] --single-transaction --routines --triggers --events --master-data2 [數據庫名] > migration…

畫立方體軟件開發筆記 js three 投影 參數建模 旋轉相機 @tarikjabiri/dxf導出dxf

gitee&#xff1a; njsgcs/njsgcs_3d mainwindow.js:4 Uncaught SyntaxError: The requested module /3dviewport.js does not provide an export named default一定要default嗎 2025-05-10 14-27-58 專門寫了個代碼畫立方體 import{ scene,camera,renderer} from ./3dviewp…

【工具】HandBrake使用指南:功能詳解與視頻轉碼

HandBrake使用指南&#xff1a;功能詳解與視頻轉碼 一、前言 高清視頻在當下日益普及&#xff0c;從影視制作到個人拍攝&#xff0c;從社交媒體發布到遠程教育&#xff0c;如何高效地壓縮、轉換和管理視頻文件的體積與清晰度&#xff0c;成為內容創作者與技術開發者的核心任務…

Docker容器網絡架構深度解析與技術實踐指南——基于Linux內核特性的企業級容器網絡實現

第1章 容器網絡基礎架構 1 Linux網絡命名空間實現原理 1.1內核級隔離機制深度解析 1.1.1進程隔離的底層實現 通過clone()系統調用創建新進程時&#xff0c;設置CLONE_NEWNET標志位將觸發內核執行以下操作&#xff1a; 內核源碼示例&#xff08;linux-6.8.0/kernel/fork.c&a…

SAP 交貨單行項目含稅金額計算報cx_sy_zerodivide處理

業務背景&#xff1a;SAP交貨單只有數量&#xff0c;沒有金額&#xff0c;所以開發報表從訂單的價格按數量計算交貨單的金額。 用戶反饋近期報表出現異常&#xff1a; ****2012/12/12 清風雅雨 規格變更 Chg 修改開始 ** 修改原因:由于余數為0時&#xff0c;可能會報錯溢出。…