【2020-01-08】使用gatttool和bluepy来测试ESP32蓝牙实例

发布时间:2026/7/23 21:01:00

【2020-01-08】使用gatttool和bluepy来测试ESP32蓝牙实例
[历史归档]本文原发布于 cstriker1407.info 个人博客内容为历史存档仅供参考。发布时间2020-01-08 标题使用gatttool和bluepy来测试ESP32蓝牙实例分类编程 / python jython / 网络通讯 / Bluetooth 标签wireshark·bluetooth·hciconfig·gatttool·ESP32·bluepy·hcitool使用gatttool和bluepy来测试ESP32蓝牙实例参考链接ESP32代码分析命令行连接bluepy连接wireshark抓包bluepy本文笔记了如何使用Linux命令行工具和bluepy来测试ESP32蓝牙实例。参考链接【 https://cstriker1407.info/blog/esp32-simple-introduce-note/ 】【 https://cstriker1407.info/blog/bluetooth-hcitool-gatttool/ 】【 https://cstriker1407.info/blog/install-bt-stack-on-linux/ 】ESP32官方IDF中包含了很多蓝牙实例这里以【gatt_server_service_table】为例子笔记下在Linux下如何连接上该蓝牙Server。ESP32代码分析连接上ESP32开发板然后直接编译烧录【gatt_server_service_table】。esp/esp-idf/examples/bluetooth/bluedroid/ble/gatt_server_service_table$ idf.py flash esp/esp-idf/examples/bluetooth/bluedroid/ble/gatt_server_service_table$ idf.py monitor该实例中的gatt的设置代码如下/* Full Database Description - Used to add attributes into the database */staticconstesp_gatts_attr_db_tgatt_db[HRS_IDX_NB]{// Service Declaration[IDX_SVC]{{ESP_GATT_AUTO_RSP},{ESP_UUID_LEN_16,(uint8_t*)primary_service_uuid,ESP_GATT_PERM_READ,sizeof(uint16_t),sizeof(GATTS_SERVICE_UUID_TEST),(uint8_t*)GATTS_SERVICE_UUID_TEST}},/* Characteristic Declaration */[IDX_CHAR_A]{{ESP_GATT_AUTO_RSP},{ESP_UUID_LEN_16,(uint8_t*)character_declaration_uuid,ESP_GATT_PERM_READ,CHAR_DECLARATION_SIZE,CHAR_DECLARATION_SIZE,(uint8_t*)char_prop_read_write_notify}},/* Characteristic Value */[IDX_CHAR_VAL_A]{{ESP_GATT_AUTO_RSP},{ESP_UUID_LEN_16,(uint8_t*)GATTS_CHAR_UUID_TEST_A,ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,GATTS_DEMO_CHAR_VAL_LEN_MAX,sizeof(char_value),(uint8_t*)char_value}},/* Client Characteristic Configuration Descriptor */[IDX_CHAR_CFG_A]{{ESP_GATT_AUTO_RSP},{ESP_UUID_LEN_16,(uint8_t*)character_client_config_uuid,ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,sizeof(uint16_t),sizeof(heart_measurement_ccc),(uint8_t*)heart_measurement_ccc}},/* Characteristic Declaration */[IDX_CHAR_B]{{ESP_GATT_AUTO_RSP},{ESP_UUID_LEN_16,(uint8_t*)character_declaration_uuid,ESP_GATT_PERM_READ,CHAR_DECLARATION_SIZE,CHAR_DECLARATION_SIZE,(uint8_t*)char_prop_read}},/* Characteristic Value */[IDX_CHAR_VAL_B]{{ESP_GATT_AUTO_RSP},{ESP_UUID_LEN_16,(uint8_t*)GATTS_CHAR_UUID_TEST_B,ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,GATTS_DEMO_CHAR_VAL_LEN_MAX,sizeof(char_value),(uint8_t*)char_value}},/* Characteristic Declaration */[IDX_CHAR_C]{{ESP_GATT_AUTO_RSP},{ESP_UUID_LEN_16,(uint8_t*)character_declaration_uuid,ESP_GATT_PERM_READ,CHAR_DECLARATION_SIZE,CHAR_DECLARATION_SIZE,(uint8_t*)char_prop_write}},/* Characteristic Value */[IDX_CHAR_VAL_C]{{ESP_GATT_AUTO_RSP},{ESP_UUID_LEN_16,(uint8_t*)GATTS_CHAR_UUID_TEST_C,ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,GATTS_DEMO_CHAR_VAL_LEN_MAX,sizeof(char_value),(uint8_t*)char_value}},};通过分析gatt的设置代码表可知GATT Server建立了一个primary serviceUUID为0xFF(GATTS_SERVICE_UUID_TEST)该service下面有3个Characteristic第一个0xFF01(GATTS_CHAR_UUID_TEST_A)可读可写可通知(0x1A ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_NOTIFY)第二个0xFF02(GATTS_CHAR_UUID_TEST_B)可读(0x02 ESP_GATT_CHAR_PROP_BIT_READ)第二个0xFF03(GATTS_CHAR_UUID_TEST_C)可写(0x08 ESP_GATT_CHAR_PROP_BIT_WRITE)继续分析其他代码可以发现当Notify设置发生变化时ESP32会主动发送一个Notify/Indicate通知由于第一个Characteristic功能最为丰富我们主要测试第一个Characteristic。命令行连接首先使用hcitool搜索该Server如下$sudohcitool lescan 。。。。。 C4:4F:33:16:F8:AF ESP_GATTS_DEMO 。。。。。可以看到该Server的Mac地址为【C4:4F:33:16:F8:AF】然后使用gatttool连接如下$ gatttool-I[][LE]helphelpShow thishelpexitExit interactive mode quit Exit interactive mode connect]Connect to a remote device disconnect Disconnect from a remote device primary[UUID]Primary Service Discovery included]Find Included Services characteristics]]Characteristics Discovery char-desc Characteristics Descriptor Discovery char-read-hndhandleCharacteristics Value/Descriptor Read by handle char-read-uuidUUIDCharacteristics Value/Descriptor Read by UUID char-write-reqhandlenew valueCharacteristic Value Write(Write Request)char-write-cmdhandlenew valueCharacteristic Value Write(No response)sec-level Set security level. Default: low mtuvalueExchange MTUforGATT/ATT[][LE]connect C4:4F:33:16:F8:AF#连接ESP32Attempting to connect to C4:4F:33:16:F8:AF Connection successful[C4:4F:33:16:F8:AF][LE]primary attr handle: 0x0001, end grp handle: 0x0005 uuid: 00001801-0000-1000-8000-00805f9b34fb attr handle: 0x0014, end grp handle: 0x001c uuid: 00001800-0000-1000-8000-00805f9b34fb attr handle: 0x0028, end grp handle: 0xffff uuid: 000000ff-0000-1000-8000-00805f9b34fb[C4:4F:33:16:F8:AF][LE]characteristics handle: 0x0002, char properties: 0x20, char value handle: 0x0003, uuid: 00002a05-0000-1000-8000-00805f9b34fb handle: 0x0015, char properties: 0x02, char value handle: 0x0016, uuid: 00002a00-0000-1000-8000-00805f9b34fb handle: 0x0017, char properties: 0x02, char value handle: 0x0018, uuid: 00002a01-0000-1000-8000-00805f9b34fb handle: 0x0019, char properties: 0x02, char value handle: 0x001a, uuid: 00002aa6-0000-1000-8000-00805f9b34fb handle: 0x0029, char properties: 0x1a, char value handle: 0x002a, uuid: 0000ff01-0000-1000-8000-00805f9b34fb#操作handle为0x0029属性为可读可写可通知0x1Avalue的handle为0x2a,UUID为0xFF01handle: 0x002c, char properties: 0x02, char value handle: 0x002d, uuid: 0000ff02-0000-1000-8000-00805f9b34fb handle: 0x002e, char properties: 0x08, char value handle: 0x002f, uuid: 0000ff03-0000-1000-8000-00805f9b34fb[C4:4F:33:16:F8:AF][LE]char-desc handle: 0x0001, uuid: 00002800-0000-1000-8000-00805f9b34fb handle: 0x0002, uuid: 00002803-0000-1000-8000-00805f9b34fb handle: 0x0003, uuid: 00002a05-0000-1000-8000-00805f9b34fb handle: 0x0004, uuid: 00002902-0000-1000-8000-00805f9b34fb handle: 0x0014, uuid: 00002800-0000-1000-8000-00805f9b34fb handle: 0x0015, uuid: 00002803-0000-1000-8000-00805f9b34fb handle: 0x0016, uuid: 00002a00-0000-1000-8000-00805f9b34fb handle: 0x0017, uuid: 00002803-0000-1000-8000-00805f9b34fb handle: 0x0018, uuid: 00002a01-0000-1000-8000-00805f9b34fb handle: 0x0019, uuid: 00002803-0000-1000-8000-00805f9b34fb handle: 0x001a, uuid: 00002aa6-0000-1000-8000-00805f9b34fb handle: 0x0028, uuid: 00002800-0000-1000-8000-00805f9b34fb handle: 0x0029, uuid: 00002803-0000-1000-8000-00805f9b34fb#操作handle为0x002b的UUID为0x2803(ESP_GATT_UUID_CHAR_DECLARE)表示characteristics的定义handle: 0x002a, uuid: 0000ff01-0000-1000-8000-00805f9b34fb#操作handle为0x002a的UUID为0xff01表示characteristics的值所在的uuidhandle: 0x002b, uuid: 00002902-0000-1000-8000-00805f9b34fb#操作handle为0x002b的UUID为0x2902(ESP_GATT_UUID_CHAR_CLIENT_CONFIG)表示characteristics的Notify配置handle: 0x002c, uuid: 00002803-0000-1000-8000-00805f9b34fb handle: 0x002d, uuid: 0000ff02-0000-1000-8000-00805f9b34fb handle: 0x002e, uuid: 00002803-0000-1000-8000-00805f9b34fb handle: 0x002f, uuid: 0000ff03-0000-1000-8000-00805f9b34fb[C4:4F:33:16:F8:AF][LE]char-read-hnd 0x0029#读一下0xFF01的定义Characteristic value/descriptor: 1a 2a 00 01 ff[C4:4F:33:16:F8:AF][LE]char-read-hnd 0x002a#读一下0xFF01的值Characteristic value/descriptor:11223344[C4:4F:33:16:F8:AF][LE]char-read-hnd 0x002b#读一下0xFF01的Notify配置Characteristic value/descriptor: 00 00[C4:4F:33:16:F8:AF][LE]char-write-cmd 0x002a aabbccdd#更改0xFF01的值[C4:4F:33:16:F8:AF][LE]char-read-hnd 0x002a#读一下0xFF01的值Characteristic value/descriptor: aa bb ccdd[C4:4F:33:16:F8:AF][LE]char-write-req 0x002a12345678#更改0xFF01的值需要回复Characteristic value was written successfully[C4:4F:33:16:F8:AF][LE]char-read-hnd 0x002a#读一下0xFF01的值Characteristic value/descriptor:12345678[C4:4F:33:16:F8:AF][LE]char-read-hnd 0x002b#读一下0xFF01的Notify配置Characteristic value/descriptor: 00 00[C4:4F:33:16:F8:AF][LE]char-write-cmd 0x002b 0100#打开NotifyNotification handle0x002a value: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e[C4:4F:33:16:F8:AF][LE]char-write-cmd 0x002b 0200#打开IndicateIndication handle0x002a value: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e[C4:4F:33:16:F8:AF][LE]char-write-cmd 0x002b 0000#关闭[C4:4F:33:16:F8:AF][LE]disconnect#解除连接bluepy连接bluepy的API都非常简洁明了这里就直接贴代码和日志输出通过对比日志和GATT表可以很清晰的了解API#!/usr/bin/env python# codingutf-8frombluepy.btleimport*importtimedefble_adv_scan(scan_time):ble_scannerScanner()print(Ble Scan Begin. scan_time: {} --.format(scan_time))ble_devicesble_scanner.scan(scan_time)fordevinble_devices:dev_macdev.addr dev_addr_typedev.addrType dev_rssidev.rssiprint( Find Dev:{}({}):{}.format(dev_mac,dev_addr_type,dev_rssi))for(adtype,desc,value)indev.getScanData():print(---- {}({}):{}.format(adtype,desc,value))print(Ble Scan Finish. scan_time: {} --.format(scan_time))defble_services_enum(mac_addr):remote_devPeripheral(mac_addr)print(Remote Services:)remote_servicesremote_dev.getServices()forsingle_serviceinremote_services:print( service uuid:{}.format(single_service.uuid))charssingle_service.getCharacteristics()print( handle property can read uuid)forsingle_charinchars:print( {} {}({}) {} {}.format(hex(single_char.getHandle()),single_char.propertiesToString(),hex(single_char.properties),single_char.supportsRead(),single_char.uuid))print(Remote Characteristics:)remote_charsremote_dev.getCharacteristics()print( handle can read property uuid)forsingle_charinremote_chars:print( {} {}({}) {} {}.format(hex(single_char.getHandle()),single_char.propertiesToString(),hex(single_char.properties),single_char.supportsRead(),single_char.uuid))print(Remote Descriptors:)remote_decsremote_dev.getDescriptors()forremote_decsinremote_decs:print( {}.format(remote_decs))remote_dev.disconnect()classNotifyDelegate(DefaultDelegate):def__init__(self):DefaultDelegate.__init__(self)defhandleNotification(self,cHandle,data):print(Rev Data{}:{}.format(hex(cHandle),bytes.hex(data)))defble_char_operate():remote_devPeripheral(C4:4F:33:16:F8:AF)main_serviceremote_dev.getServiceByUUID(0x000000ff)target_charmain_service.getCharacteristics(0x0000ff01)[0]target_char_handletarget_char.getHandle()print(-- Characteristics Operate --)print(ReadHex:{}.format(bytes.hex(target_char.read())))print(Write with No Response)target_char.write(bAABBCCDD)print(Write with Response)target_char.write(bytes.fromhex(223344),True)print(-- Peripheral Operate --)print(ReadHex:{}.format(bytes.hex(remote_dev.readCharacteristic(target_char_handle))))print(Write with No Response)remote_dev.writeCharacteristic(target_char_handle,b55667788)print(Write with Response)remote_dev.writeCharacteristic(target_char_handle,bytes.fromhex(44332211),True)print(-- Characteristics Notify/Indicate Operate --)remote_dev.withDelegate(NotifyDelegate())target_char_notify_handletarget_char_handle1print(Enable Notify)remote_dev.writeCharacteristic(target_char_notify_handle,bytes.fromhex(0100))remote_dev.waitForNotifications(10)print(Enable Indicate)remote_dev.writeCharacteristic(target_char_notify_handle,bytes.fromhex(0200))remote_dev.waitForNotifications(10)print(Disable All)remote_dev.writeCharacteristic(target_char_notify_handle,bytes.fromhex(0000))time.sleep(3)remote_dev.disconnect()if__name____main__:print(func ble_adv_scan begin)ble_adv_scan(5)print(func ble_services_enum begin)ble_services_enum(C4:4F:33:16:F8:AF)print(func ble_char_operate begin)ble_char_operate()输出如下$sudopython3 hello_bluepy.py func ble_adv_scan begin Ble Scan Begin. scan_time:5--。。。。。。 Find Dev:c4:4f:33:16:f8:af(public):-45 ----1(Flags):06 ----10(Tx Power):eb ----3(Complete 16b Services):000000ff-0000-1000-8000-00805f9b34fb ----9(Complete Local Name):ESP_GATTS_DEMO 。。。。。。 Ble Scan Finish. scan_time:5--funcble_services_enum beginRemote Services: service uuid:00001801-0000-1000-8000-00805f9b34fb handle property can read uuid 0x3 INDICATE (0x20) False 00002a05-0000-1000-8000-00805f9b34fb service uuid:00001800-0000-1000-8000-00805f9b34fb handle property can read uuid 0x16 READ (0x2) True 00002a00-0000-1000-8000-00805f9b34fb 0x18 READ (0x2) True 00002a01-0000-1000-8000-00805f9b34fb 0x1a READ (0x2) True 00002aa6-0000-1000-8000-00805f9b34fb service uuid:000000ff-0000-1000-8000-00805f9b34fb handle property can read uuid 0x2a READ WRITE NOTIFY (0x1a) True 0000ff01-0000-1000-8000-00805f9b34fb 0x2d READ (0x2) True 0000ff02-0000-1000-8000-00805f9b34fb 0x2f WRITE (0x8) False 0000ff03-0000-1000-8000-00805f9b34fb Remote Characteristics: handle can read property uuid 0x3 INDICATE (0x20) False 00002a05-0000-1000-8000-00805f9b34fb 0x16 READ (0x2) True 00002a00-0000-1000-8000-00805f9b34fb 0x18 READ (0x2) True 00002a01-0000-1000-8000-00805f9b34fb 0x1a READ (0x2) True 00002aa6-0000-1000-8000-00805f9b34fb 0x2a READ WRITE NOTIFY (0x1a) True 0000ff01-0000-1000-8000-00805f9b34fb 0x2d READ (0x2) True 0000ff02-0000-1000-8000-00805f9b34fb 0x2f WRITE (0x8) False 0000ff03-0000-1000-8000-00805f9b34fb Remote Descriptors: Descriptor Primary Service Declaration Descriptor Characteristic Declaration Descriptor Service Changed Descriptor Client Characteristic Configuration Descriptor Primary Service Declaration Descriptor Characteristic Declaration Descriptor Device Name Descriptor Characteristic Declaration Descriptor Appearance Descriptor Characteristic Declaration Descriptor Central Address Resolution Descriptor Primary Service Declaration Descriptor Characteristic Declaration Descriptor ff01 Descriptor Client Characteristic Configuration Descriptor Characteristic Declaration Descriptor ff02 Descriptor Characteristic Declaration Descriptor ff03 funcble_char_operate begin -- Characteristics Operate -- ReadHex:44332211 Write with No Response Write with Response -- Peripheral Operate -- ReadHex:223344 Write with No Response Write with Response -- Characteristics Notify/Indicate Operate -- Enable Notify Rev Data0x2a:000102030405060708090a0b0c0d0e Enable Indicate Rev Data0x2a:000102030405060708090a0b0c0d0e Disable Allwireshark抓包bluepy因为是本地蓝牙通讯因此可以通过wireshark抓取本地蓝牙模组的协议报文这里简单的贴一下。首先是抓取的adapter直接选取Bluetooth即可。ble_adv_scan()ble_services_enum(“C4:4F:33:16:F8:AF”)ble_char_operate()

相关新闻

【2020-01-02】linux strip readelf nm 简单应用和安全分析

【2020-01-02】linux strip readelf nm 简单应用和安全分析

2026/7/23 21:01:00

[历史归档] 本文原发布于 cstriker1407.info 个人博客,内容为历史存档,仅供参考。 发布时间: 2020-01-02 | 标题:linux strip readelf nm 简单应用和安全分析 | 分类: 操作系统 / linux / 安…

【2020-02-25】【转】IPv6邻居发现协议

【2020-02-25】【转】IPv6邻居发现协议

2026/7/23 21:01:00

[历史归档] 本文原发布于 cstriker1407.info 个人博客,内容为历史存档,仅供参考。 发布时间: 2020-02-25 | 标题:【转】IPv6邻居发现协议 | 分类: 网络通讯 / IPV6 | 标签&…

90后35岁时我决定从运维转行:找一门越老越吃香的职业!

90后35岁时我决定从运维转行:找一门越老越吃香的职业!

2026/7/23 20:50:59

90 后 35岁时我决定从运维转行:找一门越老越吃香的职业! 35岁之前,我总认为运维这个职位只要能熬得住、愿意加班的话,就一定能够熬出头来。但是真正做了几年之后才明白过来,巡检、处理报警、半夜救火等事情已经成为了…

【RT-DETR涨点改进】TGRS 2026 | 卷积创新改进篇 | 引入 3DSBE 三维光谱瓶颈增强模块,增强模型对通道间互补信息的利用能力,助力高光谱目标检测、遥感目标检测任务,有效涨点

【RT-DETR涨点改进】TGRS 2026 | 卷积创新改进篇 | 引入 3DSBE 三维光谱瓶颈增强模块,增强模型对通道间互补信息的利用能力,助力高光谱目标检测、遥感目标检测任务,有效涨点

2026/7/23 21:51:02

一、本文介绍 🔥本文给大家介绍使用 3DSBE 三维光谱瓶颈增强模块 改进RT-DETR网络模型,主要作用是在特征提取阶段强化不同通道或波段之间的相关性,减少冗余信息,并为后续多尺度融合提供更具判别力的特征表示。该模块通过空间下采样与通道扩展降低计算负担,再采用主、辅双…

为什么你的AI自动化项目卡在85%?资深架构师亲授“最后一公里”攻坚清单

为什么你的AI自动化项目卡在85%?资深架构师亲授“最后一公里”攻坚清单

2026/7/23 21:51:02

更多请点击: https://kaifayun.com 第一章:为什么你的AI自动化项目卡在85%? 当模型在验证集上稳定达到84.7%–85.3%准确率却再难提升时,问题往往不在算法本身,而在于数据闭环的断裂与工程化落地的盲区。大量团队将精力…

AgentLock 首跑不要先测“能否拦截”:先验证 ALLOW、DENY、DEFER 与版本边界

AgentLock 首跑不要先测“能否拦截”:先验证 ALLOW、DENY、DEFER 与版本边界

2026/7/23 21:51:02

很多 Agent 安全测试一上来就塞一段提示注入,然后看工具有没有被拦住。这个顺序不可靠:如果你没有记录安装的版本、策略文件、上下文来源和最终决策,测试结果无法复现。我在 AgentLock 的首跑里先做四件事。第一,分清证据版本。Do…

【免费赠书活动】吃透大模型底层数学,从公式原理到产业实战,打通AI进阶全链路

【免费赠书活动】吃透大模型底层数学,从公式原理到产业实战,打通AI进阶全链路

2026/7/23 21:51:02

人工智能大模型数学基础从数学公式到智能模型,打通AI底层逻辑——线性代数、微积分、概率与统计三大支柱,结合BERT、GPT、Stable Diffusion等前沿实战,带你从理论推导到代码落地,真正掌握大模型的数学引擎。本书特点基础→进阶→A…

TVA驱动的具身智能迭代逻辑(3)

TVA驱动的具身智能迭代逻辑(3)

2026/7/23 21:51:02

前沿技术探索:AI智能体视觉(TVA,Transformer-based Vision Agent)是依托Transformer架构与“因式智能体”理论所构建的颠覆性工业视觉技术,是集深度强化学习(DRL)、卷积神经网络(CNN…

2026年ERP实施服务指南

2026年ERP实施服务指南

2026/7/23 21:41:01

在数字经济与智能制造深度融合的2026年,企业资源规划(ERP)系统已不再是大型企业的专属奢侈品,而是决定中小型制造企业生存与发展的核心基础设施。面对日益复杂的供应链、激烈的市场竞争以及不断攀升的合规成本,一套契合…

微服务进阶:服务网格与Istio

微服务进阶:服务网格与Istio

2026/7/23 3:40:08

541|微服务进阶:服务网格与Istio 上篇文章我们聊了微服务的基本概念和拆分方法。 但微服务多了,问题也多了: 服务之间怎么通信? 怎么监控每个服务的调用链路? 熔断、限流、重试怎么做? 安全认证怎么统一? 以前这些都靠SDK库(比如Hystrix、Feign),每个服务都要集成…

零售超级终端全域协同:ShareKit 碰一碰商品流转业务落地案例

零售超级终端全域协同:ShareKit 碰一碰商品流转业务落地案例

2026/7/23 4:40:05

一、零售门店全域协同业务背景与行业痛点 1.1 门店超级终端设备矩阵(连锁便利店/商超标准配置) 自助收银Kiosk一体机:顾客结算、自助核销优惠券、商品素材预览;运营折叠平板:店长后台商品上新、图片录入、活动配置、…

噗叽短视频界面分析

噗叽短视频界面分析

2026/7/23 1:54:13

1 和小红书类似,可以采用类似判断方法------------其实他比小红书好判断,因为他没有图片,控件位置几乎是固定的,都不用判断------------2 因为他没有点赞按钮------------而且几乎所有控件位置都是完全一样的,所以我就…

企业级AI搜索落地选型实战手册(含LLM+RAG+Hybrid架构对比矩阵与ROI测算模板)

企业级AI搜索落地选型实战手册(含LLM+RAG+Hybrid架构对比矩阵与ROI测算模板)

2026/7/23 0:09:56

更多请点击: https://kaifayun.com 第一章:企业级AI搜索落地选型实战手册(含LLMRAGHybrid架构对比矩阵与ROI测算模板) 企业级AI搜索系统落地成败,核心在于技术选型与业务价值的精准对齐。盲目堆砌大模型能力或过度依赖…

TM4C129LNCZAD外设实战:LCD、比较器与PWM寄存器配置详解

TM4C129LNCZAD外设实战:LCD、比较器与PWM寄存器配置详解

2026/7/23 0:09:56

1. 项目概述与核心价值在嵌入式系统开发,尤其是基于ARM Cortex-M内核的微控制器项目中,深入理解并熟练配置芯片的片上外设,是从“点亮LED”迈向“实现复杂系统功能”的关键一步。Tiva™ TM4C129LNCZAD作为TI公司Cortex-M4F家族中的高性能成员…

AtomCode `fmt_dur` 争议溯源:两个函数、三段演进、四个事实

AtomCode `fmt_dur` 争议溯源:两个函数、三段演进、四个事实

2026/7/23 0:09:56

一、快速声明与争议背景本文是对 AtomCode 终端 spinner 时长显示 fmt_dur 相关说法的事实性核验。2026 年 7 月 CSDN 上出现两篇互相矛盾的博文,近期又有 AI 在对话中输出格式描述 XhYm / YmZs / Zs。本文基于 AtomCode 仓库 main4677ddfa 及全分支 Git 历史给出可…