BLE AT指令实战:从GAP广播到GATT服务构建的嵌入式蓝牙开发指南

news2026/5/16 21:20:19
1. 项目概述与BLE AT指令核心价值如果你正在捣鼓物联网设备、可穿戴硬件或者任何需要无线连接的嵌入式项目蓝牙低功耗BLE技术大概率是你绕不开的一环。它功耗低、连接快非常适合那些需要长时间运行、间歇性传输少量数据的场景。但当你拿到一个BLE模块比如Adafruit的Bluefruit LE系列准备让它干点“正经事”时往往会发现光有硬件和基础的蓝牙协议栈还不够。你需要一种高效、直接的方式来告诉模块“现在开始广播”、“以这个名称出现”、“提供这个数据服务”、“当连接上时把这个值发给手机”。这时AT指令集就成了你和BLE模块之间最直接的“对话语言”。AT指令这个源自早期调制解调器“Attention”命令的古老协议在嵌入式无线模块领域焕发了新生。它通过简单的文本命令和响应让开发者能够在不深入底层射频协议和驱动代码的情况下完成对模块绝大部分功能的配置与控制。对于Adafruit Bluefruit LE模块而言其AT指令集尤其强大几乎覆盖了从最基础的GAP通用访问配置文件广播、连接到复杂的GATT通用属性配置文件服务构建的全部流程。这意味着你可以通过串口发送几条指令就实现一个自定义的传感器数据服务或者让模块变身成一个MIDI控制器而无需编写一行C语言的蓝牙协议栈代码。这篇文章我将结合自己多年在嵌入式蓝牙开发中踩过的坑和积累的经验为你深入解析Bluefruit LE模块AT指令集中最核心、最实用的部分——GAP配置与GATT服务构建。我们会从原理出发理解每条指令背后的蓝牙规范逻辑然后通过具体的配置案例如自定义广播数据、创建电池电量服务、实现MIDI事件传输等手把手带你掌握这套高效的工具。无论你是想快速原型验证还是为产品设计稳定的蓝牙功能这些内容都将为你提供扎实的实践基础。2. BLE通信基础与AT指令角色再认识在深入AT指令细节之前我们有必要快速统一一下对BLE核心架构的理解。这能帮助我们在配置时不仅知道“怎么配”更明白“为什么这么配”。GAP通用访问配置文件你可以把它想象成设备的“社交名片”和“连接规则”。它决定了你的设备如何被外界发现广播允许谁连接可连接性以及连接后的一些基本参数如连接间隔。GAP层处理的是设备级别的交互。例如一个温度传感器通过GAP广播自己的存在和名称手机作为中央设备扫描到它并发起连接。AT指令中的ATGAPDEVNAME、ATGAPSTARTADV、ATGAPINTERVALS等都是直接操作这一层的。GATT通用属性配置文件则定义了连接建立后数据如何被组织和交换。它基于客户端-服务器模型。你的BLE模块通常作为GATT服务器它就像一个提供数据服务的商店。这个“商店”里有很多“柜台”服务Service每个“柜台”又摆放着不同种类的“商品”特征值Characteristic。手机作为GATT客户端则是顾客它可以来“读取”Read商品信息或者“写入”Write指令来改变商品状态还可以“订阅”Notify/Indicate某个商品的变化让商店在有新货时主动通知它。我们使用ATGATTADDSERVICE和ATGATTADDCHAR就是在构建这个“商店”和“柜台”。AT指令在这里扮演的角色就是一套标准化的“装修和管理工具”。它让你能够动态配置无需修改和编译底层固件通过串口实时更改模块行为。快速原型几分钟内就能搭建出一个具备自定义服务的BLE外设。调试与诊断通过查询指令如ATGAPGETCONN,ATGATTLIST实时了解模块状态。生产与维护可以编写简单的脚本通过AT指令对出厂设备进行批量配置或固件升级后的参数恢复。理解了这个框架我们再去看每一条具体的AT指令就会清晰很多它们无非是在GAP或GATT的某个特定环节为我们提供了一个便捷的接口。3. GAP配置详解从设备广播到连接管理GAP配置是设备与外界建立联系的第一步配置得当与否直接影响到设备的可发现性、连接成功率和功耗。Bluefruit LE的AT指令提供了非常细致的GAP控制能力。3.1 设备标识与广播控制设备名称是最直观的标识。使用ATGAPDEVNAME可以读取或设置它。这里有一个关键细节修改设备名称后指令返回OK仅代表设置值已被模块接收并存储到非易失性内存中但并不会立即生效。你必须发送ATZ命令让模块执行软复位新的名称才会在广播包中体现。这是一个常见的“坑”很多新手会疑惑为什么改名后手机扫描到的还是旧名字。# 读取当前设备名称 ATGAPDEVNAME UART OK # 设置新设备名称 ATGAPDEVNAMEMySensorNode OK # 必须执行复位以使新名称生效 ATZ OK广播的开启与关闭由ATGAPSTARTADV和ATGAPSTOPADV控制。需要注意的是如果设备当前已经处于广播状态再次执行ATGAPSTARTADV会返回ERROR同样如果设备已经连接也无法启动广播。这种设计避免了状态混乱。3.2 广播参数精细调优连接与功耗的平衡ATGAPINTERVALS这条指令是功耗和连接速度调节的核心但也是“高危”指令使用需格外谨慎。它控制四个关键参数固件0.7.0及以上版本为五个最小连接间隔设备与中央设备如手机两次数据交换之间的最短时间。单位毫秒(ms)。值越小数据吞吐延迟越低连接响应越快但功耗越高。最大连接间隔两次数据交换之间的最长时间。中央设备会在这个范围内与外围设备协商一个实际的连接间隔。快速广播间隔在“快速广播”阶段发送两个广播包之间的时间间隔。间隔越短被手机快速发现的概率越大但功耗也越高。快速广播超时设备以“快速广播间隔”持续广播的时间。超过这个时间后设备会自动切换到“低功耗广播间隔”以节省电量。低功耗广播间隔固件 0.7.0快速广播超时后的广播间隔。默认是417.5ms。参数设置的黄金法则不要随意修改默认值除非你明确知道自己在做什么。许多手机操作系统对连接参数有严格的范围偏好超出其接受范围可能导致无法连接。例如将最小连接间隔设得过小如7.5ms某些iPhone可能直接拒绝连接。建议在大多数应用中使用默认值或仅在蓝牙联盟建议的范围内微调。# 读取当前的GAP间隔参数 ATGAPINTERVALS 20,100,100,30 # 输出解释最小连接间隔20ms最大连接间隔100ms快速广播间隔100ms快速广播超时30秒 # 如果你只想修改广播间隔为150ms其他保持不变可以这样写注意逗号占位 ATGAPINTERVALS,,150, OK3.3 高级广播数据自定义ATGAPSETADVDATA这是为高级玩家准备的利器也伴随着最高风险。默认情况下模块的广播包包含了设备名称、发射功率、支持的Service UUID列表等标准信息。ATGAPSETADVDATA允许你完全自定义原始的广播数据载荷覆盖默认内容。为什么需要自定义兼容性某些手机App特别是某些厂商的定制测试App只扫描包含特定Service UUID的广播包。你需要手动将这个UUID加入广播数据。精简数据移除不必要的默认信息缩短广播包长度可能有助于降低功耗微乎其微或满足特定协议。厂商自定义数据可以加入一些自定义的厂商数据字段供你自己的扫描端App识别。广播数据格式遵循蓝牙核心规范每个广播数据单元都是一个[长度][类型][数据]的三段式结构。长度1字节表示“类型数据”部分的总字节数。类型1字节定义该数据的含义。例如0x01代表“Flags”0x03代表“完整的16位UUID列表”。数据N字节具体内容。一个实战案例假设我们需要广播一个设备它仅支持BLE不支持经典蓝牙处于可发现模式并且声明它支持“电池服务”UUID: 0x180F和“设备信息服务”UUID: 0x180A。Flags字段0x01类型。数据0x06二进制00000110表示比特11LE通用可发现模式比特21不支持BR/EDR。长度0x02类型1字节数据1字节。所以第一部分是02-01-06。服务UUID列表字段0x03类型完整的16位UUID列表。我们要加入两个UUID0x180F和0x180A。注意蓝牙规范中UUID是小端字节序低位在前所以0x180F写作0F-180x180A写作0A-18。数据部分共4字节。长度0x05类型1字节数据4字节。所以第二部分是05-03-0F-18-0A-18。组合将两部分拼接起来02-01-06-05-03-0F-18-0A-18。# 设置自定义广播数据 ATGAPSETADVDATA02-01-06-05-03-0F-18-0A-18 OK # 同样需要ATZ复位生效 ATZ OK严重警告错误地使用此命令特别是错误配置了Flags可能导致你的设备对手机完全不可见。如果误操作最直接的恢复方法是执行ATFACTORYRESET恢复出厂设置这将清除所有自定义配置包括GATT服务并恢复默认广播数据。4. GATT服务构建实战从电池服务到自定义数据GATT是BLE数据交互的灵魂。通过AT指令构建GATT服务是一个从抽象定义到具体实现的过程。让我们以两个最典型的例子来贯穿整个流程标准的电池服务和自定义的传感器数据服务。4.1 使用内置电池服务快速上手的捷径对于标准的、已由蓝牙技术联盟SIG定义好的服务如电池服务Battery Service, UUID: 0x180FBluefruit LE固件提供了更便捷的指令无需我们手动构建GATT结构。启用电池服务ATBLEBATTEN1。这条指令相当于在后台自动执行了ATGATTADDSERVICE和ATGATTADDCHAR创建了一个符合SIG标准规范的电池服务其中包含一个电池电量特征Battery Level Characteristic, UUID: 0x2A19属性为“可读”和“可通知”。启用后需要复位(ATZ)生效。更新电量值ATBLEBATTVAL72。这条指令用于更新电池电量特征的值范围0-100。手机上的客户端可以读取这个值或者订阅其通知当电量变化时自动接收更新。这是最快捷的为设备添加标准服务的方法适用于需要快速实现标准功能的场景。4.2 手动构建自定义GATT服务以环境监测为例当我们需要传输非标准数据时如温湿度、GPS坐标、自定义控制命令就必须手动创建服务和特征。这个过程遵循一个清晰的流程清空 - 添加服务 - 添加特征。第一步清空现有配置在开始新的配置前务必先使用ATGATTCLEAR清除之前定义的所有自定义服务和特征避免冲突。ATGATTCLEAR OK第二步添加一个自定义服务我们创建一个用于环境监测的服务使用一个128位的自定义UUID以确保唯一性。ATGATTADDSERVICEUUID12800-11-22-33-44-55-66-77-88-99-AA-BB-CC-DD-EE-FF 1 OK命令成功执行后会返回一个服务索引ID这里是1。请务必记下这个ID后续为该服务添加特征时需要知道它属于哪个服务虽然AT指令通过“最后一个添加的服务”来关联但记录ID有助于调试。第三步为服务添加特征现在为我们刚创建的环境监测服务添加两个特征一个用于“只读”温度数据另一个用于“写通知”的风扇控制命令。特征1温度数据只读可通知ATGATTADDCHARUUID0x2A6E,PROPERTIES0x0A,MIN_LEN2,MAX_LEN2,VALUE00-00,DATATYPE2,DESCRIPTIONTemperature Celsius 1 OKUUID0x2A6E这里我们“借用”了SIG定义的“温度”特征UUID。当然你也可以用自定义的16位UUID如0x1234但使用标准UUID能让一些通用App如nRF Connect自动识别和解析数据格式。PROPERTIES0x0A这是属性位掩码。0x02是读0x08是写0x10是通知。0x0A0x02(读) 0x08(写) 等等这里似乎有误。对于只读温度我们可能只需要0x02读或0x12读通知。假设我们希望手机能订阅温度变化应使用0x120x02 0x10。这是一个关键点PROPERTIES的值需要仔细计算。MIN_LEN/MAX_LEN2我们假设温度用16位有符号整数表示单位0.01摄氏度所以长度固定为2字节。VALUE00-00初始温度值设为0。DATATYPE2指明VALUE是字节数组格式。DESCRIPTION添加一个用户描述方便调试时识别。纠正后的命令假设需要可读和可通知ATGATTADDCHARUUID0x2A6E,PROPERTIES0x12,MIN_LEN2,MAX_LEN2,VALUE00-00,DATATYPE2,DESCRIPTIONTemperature Celsius 1 OK特征2风扇控制可写可通知ATGATTADDCHARUUID0xFF01,PROPERTIES0x1C,MIN_LEN1,MAX_LEN1,VALUE00,DATATYPE2,DESCRIPTIONFan Speed Control 2 OKUUID0xFF01使用一个自定义的UUID在0xFFxx范围内。PROPERTIES0x1C0x04(无响应写) 0x08(有响应写) 0x10(通知) 0x1C。这允许手机发送控制命令写并且当模块端风扇速度因其他原因改变时可以通知手机通知。MIN_LEN/MAX_LEN1控制命令用1字节表示比如0x00关0x01低速0x02高速。VALUE00初始状态为关闭。第四步查看与验证使用ATGATTLIST可以列出所有已定义的服务和特征这是非常重要的调试手段。ATGATTLIST ID01,UUID12800-11-22-33-44-55-66-77-88-99-AA-BB-CC-DD-EE-FF ID01,UUID0x2A6E,PROPERTIES0x12,MIN_LEN2,MAX_LEN2,VALUE0x0000,DATATYPE2,DESCRIPTIONTemperature Celsius ID02,UUID0xFF01,PROPERTIES0x1C,MIN_LEN1,MAX_LEN1,VALUE0x00,DATATYPE2,DESCRIPTIONFan Speed Control OK第五步读写特征值读取温度ATGATTCHAR1读取索引为1的特征值设置风扇速度ATGATTCHAR2,0x02写入0x02到索引为2的特征最后别忘了复位所有GATT相关的配置在完成后都需要执行ATZ复位才能生效并对外提供服务。4.3 关键参数解析与避坑指南在构建GATT服务时以下几个参数需要特别关注PROPERTIES属性这是一个位掩码字段决定了客户端能对这个特征做什么。最常见的组合0x02只读。用于传感器数据客户端只能读取。0x08或0x0C(0x040x08)可写。用于接收控制命令。0x08Write要求服务器回复确认更可靠0x04Write without Response不回复速度更快但可能丢失。0x10通知。服务器可以主动向已订阅的客户端推送数据更新客户端无需轮询。这是实现实时数据流如心率、传感器读数的首选方式功耗远低于客户端不断读取。0x12(0x020x10)可读通知。经典组合客户端可以读取初始值并订阅后续变化。0x1A(0x020x080x10)可读、可写、可通知。功能最全。UUID冲突规则当使用128位UUID定义服务时为该服务添加的16位UUID特征其值不能与128位UUID的第3、4字节相同。这是蓝牙协议栈实现的一个限制。例如服务UUID为00-11-**22-33**-44-55-...那么特征的16位UUID就不能是0x3322。DATATYPE数据类型固件0.7.0这个参数非常有用它告诉模块如何解析和处理VALUE以及后续通过ATGATTCHAR写入的数据。AUTO (0)模块自动猜测默认。STRING (1)作为字符串处理。BYTEARRAY (2)作为原始字节数组处理。这是最常用、最可控的方式。INTEGER (3)作为整数处理。 明确设置DATATYPE可以避免数据格式歧义尤其是在处理二进制数据时。5. 专用服务指令解析MIDI与电池服务实践除了通用的GATT构建指令Bluefruit LE模块还针对特定应用场景提供了封装好的高级AT指令极大简化了配置流程。MIDI服务和电池服务就是典型例子。5.1 BLE MIDI服务实践BLE MIDI允许你将模块变成一个无线MIDI设备连接支持BLE MIDI的音乐软件或硬件。这比传统USB-MIDI或5针DIN接口更方便。启用MIDI服务ATBLEMIDIEN1。这条指令会在GATT服务器中创建符合MIDI over BLE规范的服务和特征。同样需要复位生效。发送MIDI事件ATBLEMIDITX是核心指令。它接受一个十六进制数组格式的MIDI事件流。MIDI事件格式标准的MIDI消息如90-3C-7F表示“通道10x90音符C30x3C力度1270x7F”音符开。指令优势它可以一次性打包发送多个MIDI事件最多4个完整事件或1个完整事件加最多7个“运行状态”事件这提高了传输效率对于快速的音符序列至关重要。# 发送一个“音符开”事件通道1音符C3力度最大 ATBLEMIDITX90-3C-7F OK # 发送两个连续事件C3音符开A2弯音轮事件 ATBLEMIDITX90-3C-7F-E0-00-40 OK # 发送一个完整事件后跟随一个“运行状态”事件省略状态字节 # 第一个事件90-3C-7F (通道1C3开) # 第二个事件3C-00 (运行状态C3关因为状态字节与前一事件相同故省略) ATBLEMIDITX90-3C-7F-3C-00 OK接收MIDI事件当连接的中央设备如电脑DAW发送MIDI数据到模块时数据会被缓存。你可以使用ATBLEMIDIRX来读取下一个可用的MIDI事件。如果缓存区为空该命令会立即返回OK而不带数据如果有数据则返回十六进制格式的MIDI事件。实战技巧低延迟优化MIDI对实时性要求高。确保设备的GAP连接间隔ATGAPINTERVALS设置得较小如20-40ms以减少数据传输延迟。数据打包尽量利用ATBLEMIDITX的多事件打包能力将短时间内发生的多个MIDI事件如一个和弦的所有音符打包成一条指令发送可以减少协议开销和连接事件次数提高效率和稳定性。5.2 电池服务实践如前所述电池服务是标准服务。除了基本的启用和设置电量还有一些细节需要注意电量更新策略不要过于频繁地调用ATBLEBATTVAL。电池电量变化缓慢通常每分钟或电量变化超过1%时更新一次即可。频繁更新会浪费连接事件增加功耗。通知功能启用电池服务后其电量特征默认支持“通知”。这意味着你可以在手机端订阅该特征。当模块端电量变化并调用ATBLEBATTVAL更新后手机会自动收到通知无需主动查询。这是实现低功耗电量监控的最佳实践。与自定义服务共存电池服务可以和你自定义的其他GATT服务完美共存。ATGATTLIST会列出所有服务包括通过ATBLEBATTEN添加的标准电池服务。6. 调试指令与生产维护技巧开发过程中难免遇到问题Bluefruit LE提供了一组调试指令用于深入排查。6.1 连接与状态查询ATGAPGETCONN快速检查当前是否已连接。返回1为已连接0为未连接。这是编写连接状态逻辑判断的基础。ATGAPDISCONNECT主动断开当前连接。用于测试重连逻辑或复位连接状态。6.2 内存与配置诊断谨慎使用ATDBGNVMRD读取非易失性存储中的原始配置数据。输出是一长串十六进制数对应着设备名称、GAP间隔、GATT服务结构等所有通过AT指令设置的参数。当你发现配置行为异常怀疑配置存储损坏时可以查看此输出虽然可读性差。与一份已知的正常配置对比或许能发现问题。ATDBGSTACKSIZE返回当前栈内存使用量。对于深度嵌入式开发监控栈使用情况有助于防止栈溢出导致系统崩溃。警告ATDBGMEMRD读取原始内存和ATDBGSTACKDUMP堆栈转储是极其底层的指令。错误地访问内存地址如非对齐访问会直接导致ARM内核触发硬件错误HardFault使模块停止响应通常需要断电重启。除非你在Adafruit技术支持的确切指导下进行深度调试否则不要使用这些指令。6.3 生产与部署流程建议配置脚本化将一系列AT指令设置名称、GAP参数、GATT服务、使能特定功能等写在一个文本文件里通过串口工具一次性发送。这确保了每次生产烧录的一致性。出厂前复位测试在完成所有AT指令配置后执行ATZ复位然后使用手机蓝牙扫描验证设备是否以正确的名称、正确的服务出现并可以正常连接和通信。备份配置对于复杂的GATT配置可以将成功的ATGATTLIST输出保存下来作为“配置清单”便于后续复查或复制到其他设备。恢复出厂设置ATFACTORYRESET是终极武器。它会清除所有自定义配置包括通过AT指令设置的一切恢复模块到出厂状态。当配置混乱或实验失败时使用。7. 常见问题与故障排查实录即使按照文档操作在实际项目中你还是会遇到各种问题。下面是我总结的一些典型场景和解决方法。问题1手机扫描不到设备。检查广播是否开启确认已发送ATGAPSTARTADV且返回OK。如果已连接需要先断开或停止广播。检查设备名称和广播数据如果你使用了ATGAPSETADVDATA一个错误的Flags设置比如漏掉了可发现模式会导致设备“隐身”。最稳妥的方法是先ATFACTORYRESET用默认配置测试是否能被发现再逐步添加自定义广播数据。检查广播间隔ATGAPINTERVALS中的广播间隔是否被设得过大比如超过几秒这会导致手机需要很长时间才能扫描到。物理距离与干扰确保设备在手机附近几米内并远离强烈的Wi-Fi路由器、微波炉等2.4GHz干扰源。问题2手机能扫描到但连接失败或瞬间断开。检查GAP连接参数这是最常见的原因。手机操作系统对连接间隔有兼容性要求。尝试将ATGAPINTERVALS的最小/最大连接间隔改为更宽松、更通用的值如ATGAPINTERVALS30,100,100,30。绝对不要使用像7.5ms这样的极端值除非你明确知道两端设备都支持。检查电源确保模块供电充足且稳定。连接瞬间的射频发射电流较大劣质USB线或电量不足的电池可能导致电压跌落致使模块复位。问题3连接成功但手机App找不到我自定义的服务或特征。确认复位在ATGATTADDSERVICE和ATGATTADDCHAR之后是否执行了ATZ没有复位新的GATT表不会生效。检查UUID格式和冲突确认128位UUID字符串格式正确16字节以短横线分隔。确认16位特征UUID没有与父服务128位UUID的第3、4字节冲突。使用专业App调试在手机上安装“nRF Connect”或“LightBlue”这类通用BLE调试App。它们能列出设备的所有服务和特征并显示其UUID、属性和值。这是验证GATT配置是否正确的黄金标准。对比App中显示的内容与你通过AT指令配置的是否一致。问题4通过ATGATTCHAR写入数据成功但手机端读到的值没变。检查特征属性确认该特征的PROPERTIES包含了0x02读或0x10通知。如果属性是0x08只写那么客户端是无法读取的。通知的使能对于“通知”属性手机客户端需要先向该特征的CCCD客户端特征配置描述符写入0x0001来启用通知。模块端更新特征值后数据才会被推送。如果手机只是被动读取则需要你主动发送ATGATTCHAR写命令后手机再发起读请求才能看到新值。理解“读”、“写”、“通知”三种交互方式的区别至关重要。问题5发送ATBLEMIDITX后电脑DAW没有收到MIDI信号。确认MIDI服务已启用并复位ATBLEMIDIEN1后必须ATZ。检查电脑蓝牙和DAW设置确保电脑蓝牙已开启并已配对/连接你的模块。在DAW如Ableton Live, Logic Pro的MIDI设置中需要将BLE设备添加为MIDI输入端口。检查MIDI通道你的MIDI事件如90-...是发送到通道1。确保DAW的MIDI轨道监听的是正确的通道通常是通道1或“All Channels”。使用MIDI监控工具在电脑上运行一个独立的MIDI监控软件如MIDI-OX on Windows, MIDI Monitor on Mac查看是否有原始MIDI数据流入这可以排除DAW软件自身设置的问题。通过系统性地理解GAP/GATT原理熟练掌握这些AT指令并运用上述的调试方法你就能从容地驾驭Bluefruit LE模块为你的嵌入式项目注入稳定、高效的蓝牙连接能力。从简单的数据透传到复杂的自定义协议这套工具链都能提供坚实的支撑。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…