文章的目的为了记录使用Arkts 进行Harmony app 开发学习的经历。本职为嵌入式软件开发,公司安排开发app,临时学习,完成app的开发。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。

 相关链接:

开源 Arkts 鸿蒙应用 开发(一)工程文件分析-CSDN博客

开源 Arkts 鸿蒙应用 开发(二)封装库.har制作和应用-CSDN博客

开源 Arkts 鸿蒙应用 开发(三)Arkts的介绍-CSDN博客

开源 Arkts 鸿蒙应用 开发(四)布局和常用控件-CSDN博客

开源 Arkts 鸿蒙应用 开发(五)控件组成和复杂控件-CSDN博客

开源 Arkts 鸿蒙应用 开发(六)数据持久--文件和首选项存储-CSDN博客

开源 Arkts 鸿蒙应用 开发(七)数据持久--sqlite关系数据库-CSDN博客

开源 Arkts 鸿蒙应用 开发(八)多媒体--相册和相机-CSDN博客

开源 Arkts 鸿蒙应用 开发(九)通讯--tcp客户端-CSDN博客

开源 Arkts 鸿蒙应用 开发(十)通讯--Http-CSDN博客

开源 Arkts 鸿蒙应用 开发(十一)证书和包名修改-CSDN博客

开源 Arkts 鸿蒙应用 开发(十二)传感器的使用-CSDN博客

开源 Arkts 鸿蒙应用 开发(十三)音频--MP3播放_arkts avplayer播放音频 mp3-CSDN博客

开源 Arkts 鸿蒙应用 开发(十四)线程--任务池(taskpool)-CSDN博客

开源 Arkts 鸿蒙应用 开发(十五)自定义绘图控件--仪表盘-CSDN博客

开源 Arkts 鸿蒙应用 开发(十六)自定义绘图控件--波形图-CSDN博客

开源 Arkts 鸿蒙应用 开发(十七)通讯--http多文件下载-CSDN博客

开源 Arkts 鸿蒙应用 开发(十八)通讯--Ble低功耗蓝牙服务器-CSDN博客

 推荐链接:

开源 java android app 开发(一)开发环境的搭建-CSDN博客

开源 java android app 开发(二)工程文件结构-CSDN博客

开源 java android app 开发(三)GUI界面布局和常用组件-CSDN博客

开源 java android app 开发(四)GUI界面重要组件-CSDN博客

开源 java android app 开发(五)文件和数据库存储-CSDN博客

开源 java android app 开发(六)多媒体使用-CSDN博客

开源 java android app 开发(七)通讯之Tcp和Http-CSDN博客

开源 java android app 开发(八)通讯之Mqtt和Ble-CSDN博客

开源 java android app 开发(九)后台之线程和服务-CSDN博客

开源 java android app 开发(十)广播机制-CSDN博客

开源 java android app 开发(十一)调试、发布-CSDN博客

开源 java android app 开发(十二)封库.aar-CSDN博客

推荐链接:

开源C# .net mvc 开发(一)WEB搭建_c#部署web程序-CSDN博客

开源 C# .net mvc 开发(二)网站快速搭建_c#网站开发-CSDN博客

开源 C# .net mvc 开发(三)WEB内外网访问(VS发布、IIS配置网站、花生壳外网穿刺访问)_c# mvc 域名下不可訪問內網,內網下可以訪問域名-CSDN博客

开源 C# .net mvc 开发(四)工程结构、页面提交以及显示_c#工程结构-CSDN博客

开源 C# .net mvc 开发(五)常用代码快速开发_c# mvc开发-CSDN博客

本章内容主要演示了蓝牙广播调试应用,主要功能是通过BLE广播发送包含设备ID的心率数据。

1.工程结构

2.源码解析

3.演示效果

4.工程下载网址

一、工程结构:

BluetoothServer.ets - 主界面和业务逻辑

AdvertiseBluetoothViewModel.ets - 蓝牙广播和GATT服务管理

AdvData.ets - 广播数据构造

辅助工具类:ArrayBufferUtils, MathUtils, Logger
 

二、源码解析

2.1  BluetoothServer.ets主界面组件,主要功能:提供UI界面让用户输入ID,管理广播状态,处理权限请求,协调视图模型操作。

函数说明:

toggleAdvertiser() - 切换广播状态

toggleHeartRate() - 开始/停止心率模拟

stringCheck() - 验证用户输入的ID格式

import { abilityAccessCtrl, common, Permissions } from '@kit.AbilityKit';
import { promptAction } from '@kit.ArkUI';
import { util } from '@kit.ArkTS';
import { BusinessError } from '@kit.BasicServicesKit';
import { Logger } from '../utils/Logger';
import advertiseBluetoothViewModel from '../viewmodel/AdvertiseBluetoothViewModel';
import MathUtils from '../utils/MathUtils';
// ble.tsconst MIN_HEART_RATE = 40;
const MAX_HEART_RATE = 200;const PERMISSION_LIST: Array<Permissions> = ['ohos.permission.ACCESS_BLUETOOTH'
];function reqPermissionFromUser(permissions: Array<Permissions>, context: common.UIAbilityContext): void {const atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();atManager.requestPermissionsFromUser(context, permissions).then((data) => {Logger.info(`data:${JSON.stringify(data)}`);}).catch((err: BusinessError) => {Logger.error(`requestPermissionsFromUser fail: err = ${JSON.stringify(err)}`);})
}@Entry
@Component
export struct BluetoothServer {@StorageLink('deviceId') @Watch('onDeviceIdChange') deviceId: string = '';@StorageLink('bluetoothEnable') @Watch('onBluetoothEnableChange') bluetoothEnable: boolean = false;@State startAdvertiserState: boolean = false;@State localName: string = '';@State heartRate: number = -1;private mIntervalId: number = -1;@State myid: string = '' // IDprivate idArray: Uint8Array = new Uint8Array([0x00, 0x00, 0x00,0x0]);onDeviceIdChange(): void {Logger.info(`onDeviceIdChange: deviced = ${this.deviceId}`);}onBluetoothEnableChange(): void {if (this.bluetoothEnable) {this.toggleAdvertiser();} else {advertiseBluetoothViewModel.stopAdvertiser();this.toggleHeartRate(false);this.startAdvertiserState = false;promptAction.showToast({message: $r('app.string.bluetooth_off_Stop_heart_rate_broadcast'),duration: 2000});}}stringToBytes(val: string): number {let that = new util.TextEncoder('utf-8');let result = that.encodeInto(val);return result?.length ?? 0;}toggleAdvertiser(): void {if (this.startAdvertiserState) {advertiseBluetoothViewModel.stopAdvertiser();this.toggleHeartRate(false);this.startAdvertiserState = false;promptAction.showToast({message: $r('app.string.ble_heart_rate_broadcast_is_disabled'),duration: 2000});} else {let BLEName: string = advertiseBluetoothViewModel.getLocalName();if (this.stringToBytes(BLEName) > 22) {promptAction.showToast({message: $r('app.string.change_bluetooth_name'),duration: 2000});return;}let ret = advertiseBluetoothViewModel.startAdvertiser(this.idArray);if (ret) {this.localName = BLEName;this.toggleHeartRate(true);this.startAdvertiserState = true;promptAction.showToast({message: $r('app.string.the_ble_heart_rate_broadcast_has_been_enabled'),duration: 2000});}}}toggleHeartRate(open: boolean): void {clearInterval(this.mIntervalId);if (open) {this.mIntervalId = setInterval(() => {this.heartRate = MathUtils.getRandomInt(MIN_HEART_RATE, MAX_HEART_RATE);if (this.deviceId) {advertiseBluetoothViewModel.notifyCharacteristicChanged(this.deviceId, this.heartRate);}}, 1000)}}aboutToAppear(): void {const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;reqPermissionFromUser(PERMISSION_LIST, context);}aboutToDisappear(): void {advertiseBluetoothViewModel.stopAdvertiser();}stringCheck():boolean {// 验证myidif (this.myid.length != 8) {promptAction.showToast({message: '请重新输入,ID为1个字节',duration: 2000});return false;}return true;}build() {Column() {Text('BLE广播调试').fontSize(24).fontWeight(FontWeight.Bold).margin({ top: 20, bottom: 30 })TextInput({ placeholder: 'ID' ,text:'12345678'}).width('90%').height(40).margin({ bottom: 10 }).onChange((value: string) => {this.myid = value})// 按钮行Row() {Button('发送').width('45%').height(50).fontSize(18).onClick(() => {if(!this.stringCheck()) {return;}for (let i = 0; i < 8; i += 2) {let byteStr = this.myid.substr(i, 2); // 截取两位this.idArray[i / 2] = parseInt(byteStr, 16); // 按十六进制解析}this.toggleAdvertiser()// 发送按钮点击事件console.log('发送按钮被点击')})Button('停止').width('45%').height(50).fontSize(18).margin({ left: '10%' }).onClick(() => {this.toggleAdvertiser()// 停止按钮点击事件console.log('停止按钮被点击')})}.width('90%').justifyContent(FlexAlign.SpaceBetween)}.width('100%').height('100%').padding(16).backgroundColor('#F5F5F5')}
}

2.2  AdvertiseBluetoothViewModel.ets组件实现:蓝牙状态管理,广播的启动和停止,GATT服务管理,连接状态监控

简单函数说明:

startAdvertiser() - 配置并启动BLE广播

stopAdvertiser() - 停止广播

notifyCharacteristicChanged() - 通知客户端特征值变化

/*** 最佳实践:低功耗蓝牙开发实践*/
// [Start access1]
import { access, ble, connection, constant } from '@kit.ConnectivityKit';
// [End access1]
import { promptAction } from '@kit.ArkUI';
import ArrayBufferUtils from '../utils/ArrayBufferUtils';
import { Logger } from '../utils/Logger';
import { BusinessError } from '@kit.BasicServicesKit';
import advData from '../viewmodel/AdvData';const uiContext: UIContext | undefined = AppStorage.get('uiContext');interface CharacteristicModel {serviceUuid: string,characteristicUuid: string,characteristicValue: ArrayBufferLike,descriptors: Array<ble.BLEDescriptor>
}interface NotifyCharacteristicModel {serviceUuid: string,characteristicUuid: string,characteristicValue: ArrayBufferLike,confirm: boolean
}export class AdvertiseBluetoothViewModel {private mGattServer: ble.GattServer | undefined;private advHandle: number = 0xFF; // 初始的无效值private stateChangeFunc = (data: access.BluetoothState): void => {if (data === access.BluetoothState.STATE_ON) {AppStorage.setOrCreate('bluetoothEnable', true);} else if (data === access.BluetoothState.STATE_OFF) {AppStorage.setOrCreate('bluetoothEnable', false);}}private connectionStateChangeFunc = (data: ble.BLEConnectionChangeState): void => {if (data) {if (data.state === constant.ProfileConnectionState.STATE_CONNECTED) {let deviceId = data.deviceId;AppStorage.setOrCreate('deviceId', deviceId);} else if (data.state === constant.ProfileConnectionState.STATE_DISCONNECTED) {AppStorage.setOrCreate('deviceId', '');}}}isBluetoothEnabled(): boolean {const state: access.BluetoothState = access.getState();Logger.info(`isBluetoothEnabled: state = ${state}`);if (state === access.BluetoothState.STATE_ON || state === access.BluetoothState.STATE_TURNING_ON) {return true;}return false;}enableBluetooth() {try {this.onBTStateChange();access.enableBluetooth();} catch (err) {Logger.error(`enableBluetooth: err = ${JSON.stringify(err)}`);}}disableBluetooth() {try {this.offBTStateChange();access.disableBluetooth();} catch (err) {Logger.error(`disableBluetooth: err = ${JSON.stringify(err)}`);}}getLocalName(): string {let localName = '';try {localName = connection.getLocalName();} catch (err) {Logger.error(`getLocalName: err = ${JSON.stringify(err)}`);}return localName;}// [Start tooth1]startAdvertiser(PhoneId: Uint8Array): boolean {if (!this.isBluetoothEnabled()) {this.enableBluetooth();uiContext?.getPromptAction().showToast({message: $r('app.string.bluetooth_enabled_please_wait'),duration: 2000})return false;}/*// Create a GattServer instancethis.mGattServer = ble.createGattServer();// [StartExclude tooth1]let descriptors: Array<ble.BLEDescriptor> = [];const arrayBuffer = ArrayBufferUtils.byteArray2ArrayBuffer([11]);const descriptor: ble.BLEDescriptor = {serviceUuid: '0000180D-0000-1000-8000-00805F9B34FB',characteristicUuid: '00002A37-0000-1000-8000-00805F9B34FB',descriptorUuid: '00002902-0000-1000-8000-00805F9B34FB',descriptorValue: arrayBuffer}descriptors[0] = descriptor;let characteristics: Array<ble.BLECharacteristic> = [];const arrayBufferC = ArrayBufferUtils.byteArray2ArrayBuffer([1]);let characteristic: ble.BLECharacteristic = {serviceUuid: '0000180D-0000-1000-8000-00805F9B34FB',characteristicUuid: '00002A37-0000-1000-8000-00805F9B34FB',characteristicValue: arrayBufferC,descriptors: descriptors}characteristics[0] = characteristic;// [EndExclude tooth1]// Define the heart rate beating serviceconst service: ble.GattService = {serviceUuid: '0000180D-0000-1000-8000-00805F9B34FB',isPrimary: true,characteristics: characteristics,includeServices: []}try {// Add a servicethis.mGattServer.addService(service);} catch (err) {Logger.error(`addService: err = ${JSON.stringify(err)}`);}*/try {// The status of the subscription connection servicethis.onConnectStateChange();// [StartExclude tooth1]let setting: ble.AdvertiseSetting = {interval: 160,txPower: 1,connectable: false}/*let advData: ble.AdvertiseData = {serviceUuids: ['0000180D-0000-1000-8000-00805F9B34FB'],manufactureData: [],serviceData: [],includeDeviceName: true}*/let recv = advData.CreateData(PhoneId);let manufactureValueBuffer: Uint8Array = new Uint8Array([0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0]);//比协议多1个字节的,设置不可连接后,长度不够for (let i = 0; i < manufactureValueBuffer.length-1; i++) {manufactureValueBuffer[i+1] = recv[i];}let manufactureDataUnit: ble.ManufactureData = {manufactureId: 0x0006,manufactureValue: manufactureValueBuffer.buffer};let advPacket: ble.AdvertiseData = {serviceUuids: [],manufactureData: [manufactureDataUnit],serviceData: [],includeDeviceName: false // 表示是否携带设备名,可选参数。注意:带上设备名时,容易导致广播报文长度超出31个字节,使得广播启动失败};let advResponse: ble.AdvertiseData = {serviceUuids: ['0000180D-0000-1000-8000-00805F9B34FB'],manufactureData: [],serviceData: []}// [EndExclude tooth1]ble.startAdvertising(setting, advPacket, advResponse);return true;} catch (err) {Logger.error(`startAdvertiser: err = ${JSON.stringify(err)}`);}return false}// [End tooth1]stopAdvertiser() {ble.stopAdvertising();/*if (this.mGattServer){try {this.offConnectStateChange();ble.stopAdvertising();this.disableBluetooth();} catch (err) {Logger.error(`stopAdvertiser: err = ${JSON.stringify(err)}`);}}* */}// [Start not_char]notifyCharacteristicChanged(deviceId: string, heartRate: number) {if (!deviceId) {return;}if (this.mGattServer) {try {let descriptors: Array<ble.BLEDescriptor> = [];let arrayBuffer = ArrayBufferUtils.byteArray2ArrayBuffer([11]);let descriptor: ble.BLEDescriptor = {serviceUuid: '0000180D-0000-1000-8000-00805F9B34FB',characteristicUuid: '00002A37-0000-1000-8000-00805F9B34FB',descriptorUuid: '00002902-0000-1000-8000-00805F9B34FB',descriptorValue: arrayBuffer}descriptors[0] = descriptor;let arrayBufferC = ArrayBufferUtils.byteArray2ArrayBuffer([0x00, heartRate]);let characteristic: CharacteristicModel = {serviceUuid: '0000180D-0000-1000-8000-00805F9B34FB',characteristicUuid: '00002A37-0000-1000-8000-00805F9B34FB',characteristicValue: arrayBufferC,descriptors: descriptors}let notifyCharacteristic: NotifyCharacteristicModel = {serviceUuid: '0000180D-0000-1000-8000-00805F9B34FB',characteristicUuid: '00002A37-0000-1000-8000-00805F9B34FB',characteristicValue: characteristic.characteristicValue,confirm: false}this.mGattServer.notifyCharacteristicChanged(deviceId, notifyCharacteristic, (err: BusinessError) => {if (err) {Logger.error(`notifyCharacteristicChanged callback failed: err = ${JSON.stringify(err)}`);} else {Logger.info('notifyCharacteristicChanged callback success')}})} catch (err) {Logger.error(`notifyCharacteristicChanged: err = ${JSON.stringify(err)}`);}}}// [End not_char]// [Start on_bts]private onBTStateChange() {try {access.on('stateChange', (data: access.BluetoothState) => {if (data === access.BluetoothState.STATE_ON) {AppStorage.setOrCreate('bluetoothEnable', true);} else if (data === access.BluetoothState.STATE_OFF) {AppStorage.setOrCreate('bluetoothEnable', false);}})} catch (err) {Logger.error(`onBTSateChange: err = ${JSON.stringify(err)}`);}}// [End on_bts]private offBTStateChange() {try {access.off('stateChange');} catch (err) {Logger.error(`offBTSateChange: err = ${JSON.stringify(err)}`);}}// [Start change_State]private onConnectStateChange() {if (!this.mGattServer) {return;}try {this.mGattServer.on('connectionStateChange', (data: ble.BLEConnectionChangeState) => {if (data) {if (data.state === constant.ProfileConnectionState.STATE_CONNECTED) {let deviceId = data.deviceId;AppStorage.setOrCreate('deviceId', deviceId);} else if (data.state === constant.ProfileConnectionState.STATE_DISCONNECTED) {AppStorage.setOrCreate('deviceId', '');this.stopAdvertiser();}}})} catch (err) {Logger.error(`connectInner: err = ${JSON.stringify(err)}`);}}// [End change_State]private offConnectStateChange() {if (!this.mGattServer) {return;}try {this.mGattServer.off('connectionStateChange');} catch (err) {Logger.error(`offConnectStateChange: err = ${JSON.stringify(err)}`);}}
}let advertiseBluetoothViewModel = new AdvertiseBluetoothViewModel();export default advertiseBluetoothViewModel as AdvertiseBluetoothViewModel;

2.3  AdvData.ets文件负责构造广播数据包:

预定义了一个22字节的数据模板

SetPhoneId()方法将设备ID嵌入到指定位置

CreateData()生成最终的广播数据

// AdvData.ts
export class AdvData {private Fanal_DATA: Uint8Array = new Uint8Array([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x0]);private SetPhoneId(bytes: Uint8Array): void {for (let i = 0; i < 4; i++) {this.Fanal_DATA[10 + i] = bytes[i];}}private  toHexString(byteArray: Uint8Array): string {if (byteArray === null || byteArray.length < 1) return "";let hexString = "";for (const byte of byteArray) {hexString += " ";if ((byte & 0xff) < 0x10) {hexString += "0";}hexString += byte.toString(16);}return hexString.toLowerCase();}public CreateData(PhoneId: Uint8Array,): Uint8Array {this.SetPhoneId(PhoneId);let  mystr ="";mystr = this.toHexString(this.Fanal_DATA);console.log(`Fanal_DATA_1: ${mystr}`);return this.Fanal_DATA;}}let advData = new AdvData();export default advData as AdvData;

2.4  MathUtils.ets
 

export default class MathUtils {static getRandomInt(min: number, max: number): number {return Math.floor(Math.random() * (max - min + 1) + min);}
}

2.5  ArrayBufferUtils.ets

export default class ArrayBufferUtils {public static byteArray2ArrayBuffer(byteArr: Array<number>): ArrayBufferLike {return new Uint8Array(byteArr).buffer;}public static arrayBuffer2ByteArray(arrayBuffer: ArrayBuffer): Array<number> {return [...new Uint8Array(arrayBuffer)];}
}

2.6   Logger.ets

import { hilog } from '@kit.PerformanceAnalysisKit';export class Logger {private static domain: number = 0xFF00;private static prefix: string = 'BluetoothLowEnergy';private static format: string = '%{public}s';static debug(...args: string[]): void {hilog.debug(Logger.domain, Logger.prefix, Logger.format, args);}static info(...args: string[]): void {hilog.info(Logger.domain, Logger.prefix, Logger.format, args);}static warn(...args: string[]): void {hilog.warn(Logger.domain, Logger.prefix, Logger.format, args);}static error(...args: string[]): void {hilog.error(Logger.domain, Logger.prefix, Logger.format, args);}
}

2.7  module.json5权限文件

{"module": {"name": "entry","type": "entry","description": "$string:module_desc","mainElement": "EntryAbility","deviceTypes": ["phone"],"deliveryWithInstall": true,"installationFree": false,"pages": "$profile:main_pages","abilities": [{"name": "EntryAbility","srcEntry": "./ets/entryability/EntryAbility.ets","description": "$string:EntryAbility_desc","icon": "$media:layered_image","label": "$string:EntryAbility_label","startWindowIcon": "$media:startIcon","startWindowBackground": "$color:start_window_background","exported": true,"skills": [{"entities": ["entity.system.home"],"actions": ["action.system.home"]}]}],"extensionAbilities": [{"name": "EntryBackupAbility","srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets","type": "backup","exported": false,"metadata": [{"name": "ohos.extension.backup","resource": "$profile:backup_config"}],}],"requestPermissions": [{"name": 'ohos.permission.ACCESS_BLUETOOTH',"reason": '$string:reason',"usedScene": {"abilities": ["EntryAbility"],"when": "always"}}]}
}

三、演示效果

使用方法:

用户输入ID -> 转换为字节数组 -> 嵌入广播数据 -> 开始广播-> 通过GATT通知发送给客户端

华为 HarmonyNextOS 系统APP界面

使用安卓手机nrf Connect的App来检查数据,名字无法查看,rssi在30左右,点开可以看到数据

四、工程下载网址:https://download.csdn.net/download/ajassi2000/91685808?spm=1001.2014.3001.5503

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go语言并发编程 ------ 锁机制详解

Go语言提供了丰富的同步原语来处理并发编程中的共享资源访问问题。其中最基础也最常用的就是互斥锁&#xff08;Mutex&#xff09;和读写锁&#xff08;RWMutex&#xff09;。1. sync.Mutex&#xff08;互斥锁&#xff09;Mutex核心特性互斥性/排他性&#xff1a;同一时刻只有一…

8月17日星期天今日早报简报微语报早读

8月17日星期天&#xff0c;农历闰六月廿四&#xff0c;早报#微语早读。1、《南京照相馆》领跑&#xff0c;2025年暑期档电影总票房破95亿&#xff1b;2、神舟二十号圆满完成第三次出舱任务&#xff1b;3、宇树G1人形机器人100米障碍赛再夺金牌&#xff1b;4、广东佛山新增报告基…

在QML中使用Chart组件

目录前言1. 如何安装 Chart 组件2. 创建 QML 工程时的常见问题3. 解决方案&#xff1a;改用 QApplication QQuickView修改主函数&#xff08;main.cpp&#xff09;4. QApplication 与 QGuiApplication 的差异为什么 Qt Charts 需要 QApplication&#xff1f;总结示例下载前言 …

【P40 6-3】OpenCV Python——图像融合(两张相同属性的图片按比例叠加),addWeighted()

P40 6-3 文章目录import cv2 import numpy as npback cv2.imread(./back.jpeg) smallcat cv2.imread(./smallcat1.jpeg)#只有两张图的属性是一样的才可以进行溶合 print(back.shape) print(smallcat.shape)result cv2.addWeighted(smallcat, 0.7, back, 0.3, 0) cv2.imshow(…

传输层协议 TCP(1)

传输层协议 TCP&#xff08;1&#xff09; TCP 协议 TCP 全称为 “传输控制协议(Transmission Control Protocol”). 人如其名, 要对数据的传输进行一个详细的控制; TCP 协议段格式 • 源/目的端口号: 表示数据是从哪个进程来, 到哪个进程去; • 32 位序号/32 位确认号: 后面详…

黎阳之光:以动态感知与 AI 深度赋能,引领电力智慧化转型新革命

当全球能源结构加速向清洁低碳转型&#xff0c;新型电力系统建设成为国家战略核心&#xff0c;电力行业正经历从传统运维向智慧化管理的深刻变革。2024 年《加快构建新型电力系统行动方案》明确提出&#xff0c;到 2027 年需建成全国智慧调度体系&#xff0c;实现新能源消纳率突…

自动驾驶中的传感器技术34——Lidar(9)

补盲lidar设计&#xff1a;机械式和半固态这里不再讨论&#xff0c;这里主要针对全固态补盲Lidar进行讨论1、系统架构设计采用Flash方案&#xff0c; 设计目标10m10%&#xff0c;实现30m距离的点云覆盖&#xff0c;同时可以验证不同FOV镜头的设计下&#xff0c;组合为多款产品。…

Originality AI:原创度和AI内容检测工具

本文转载自&#xff1a;Originality AI&#xff1a;原创度和AI内容检测工具 - Hello123工具导航 ** 一、AI 内容诚信管理专家 Originality AI 是面向内容创作者的全栈式质量检测平台&#xff0c;整合 AI 内容识别、抄袭查验、事实核查与可读性分析四大核心功能&#xff0c;为…

OpenCV图像平滑处理方法详解

引言 在数字图像处理中&#xff0c;图像平滑是一项基础而重要的预处理技术。它主要用于消除图像中的噪声、减少细节层次&#xff0c;为后续的图像分析&#xff08;如边缘检测、目标识别等&#xff09;创造更好的条件。OpenCV作为最流行的计算机视觉库之一&#xff0c;提供了多种…

每天两道算法题:DAY1

题目一&#xff1a;金币 题目一&#xff1a;金币 1.题目来源&#xff1a; NOIP2015 普及组 T1&#xff0c;难度红色&#xff0c;入门签到题。 2.题目描述&#xff1a; 3.题目解析&#xff1a; 问题转化&#xff1a;求下面的一个数组的前 k 项和。 4.算法原理&#xff1a; …

C++核心语言元素与构建块全解析:从语法规范到高效设计

&#x1f4cc; 为什么需要双维度学习C&#xff1f;核心语言元素 → 掌握标准语法规则&#xff08;避免未定义行为Undefined behavior&#xff09;构建块&#xff08;Building Blocks&#xff09; → 像搭积木一样组合功能&#xff08;提升工程能力&#xff09; 例如&#xff1a…

RK3588开发板Ubuntu系统烧录

Ubuntu22.04——YOLOv8模型训练到RK3588设备部署和推理 文章中给出了通过ARM设备上面的NPU进行深度学习的模型推理过程,在此之前,我们在收到一块全新的rk3588开发板后,需要对其进行系统的烧录,这里以Ubuntu22.04系统为例。 目录 1.获取待烧录系统的镜像 2.烧录工具准备 2.1…

AI评测的科学之道:当Benchmark遇上统计学

AI评测的科学之道&#xff1a;当Benchmark遇上统计学 —— 如何客观评估大模型能力&#xff0c;避免落入数据陷阱 在人工智能尤其是大语言模型&#xff08;LLU&#xff09;爆发式发展的今天&#xff0c;各类模型榜单&#xff08;如Open LLM Leaderboard、LMSys Arena&#xff0…

CSS 基础入门教程:从零开始学习样式表

一、CSS 简介CSS&#xff08;Cascading Style Sheets&#xff0c;层叠样式表&#xff09;是一种用于描述 HTML 或 XML 等文档呈现方式的语言。它是现代网页设计的三大核心技术之一&#xff0c;与HTML&#xff08;结构层&#xff09;和JavaScript&#xff08;行为层&#xff09;…

图解简单选择排序C语言实现

1 简单选择排序 简单选择排序&#xff08;Simple Selection Sort&#xff09;是一种基础且直观的排序算法&#xff0c;其核心思想是通过重复选择未排序部分中的最小&#xff08;或最大&#xff09;元素&#xff0c;并将其放到已排序部分的末尾&#xff0c;逐步完成整个序列的排…

FPS游戏时,你的电脑都在干什么(CS2)

人物介绍&#xff1a;CPU > 你忠实的处理器 i5-13600KFGPU > 你花大价钱买的显卡 RTX3060&#xff08;不是自己的配置&#xff0c;自己的是XEON E5GTX1060&#xff0c;测不出来&#xff0c;上面是社区一个好心大哥的数据&#xff0c;较为精准&#xff09;&#…

MySQL完整重置密码流程(针对 macOS)

MySQL完整重置密码流程&#xff08;针对 macOS&#xff09; 1. 强制停止 MySQL 服务 sudo /usr/local/mysql/support-files/mysql.server stop sudo killall mysqld mysqld_safe # 确保所有进程停止2. 以安全模式启动&#xff08;跳过权限验证&#xff09; sudo /usr/local/my…

Python数据类型转换详解:从基础到实践

在Python编程中&#xff0c;数据类型转换是一项基础且频繁使用的操作。无论是处理用户输入、进行数值计算还是数据处理&#xff0c;都离不开类型转换。本文将系统介绍Python中的数据类型体系&#xff0c;详解类型转换的规则与实践技巧&#xff0c;帮助你在实际开发中灵活运用。…

智能制造——解读车企数字化转型构建高效经营管理数据治理体系【附全文阅读】

适应人群为车企数字化转型决策者、数据管理负责人、IT 部门从业者、财务及业务部门管理者。主要内容围绕车企数字化转型中经营管理数据治理体系构建展开,核心包括诊断背景(以经营管理数字化为切入点,聚焦财务业务在线化、零点月结等痛点,应对系统与数据问题);现状诊断(从…

STM32的UART奇偶校验注意

关键点&#xff1a;设置为9位数据位&#xff0c; STM32的UART奇偶校验注意_stm32串口奇校验初始化程序-CSDN博客https://blog.csdn.net/JacobFang/article/details/118993643 特此记录 anlog 2025年8月13日