10 Commits
Author SHA1 Message Date
wangfq 16f5e9b738 feat(DLD154Pro): V3.04 — 0x24追加LOOP_MEASURE_BASE归一化基数(与DLD110S对齐) + 文档同步 2026-08-26 18:10:06 +08:00
wangfq fcbe7698a3 docs(DLD154Pro): 新增蓝牙小程序接口协议文档 (依据 dbn_ble_srv.c)
- §1 BLE 服务: 0xFFE0 服务, Char1(0xFFE1 RW 命令下发)/Char4(0xFFE4 Notify)
- §2 帧格式: Magic(8F/7F)+Header+Len+CMD+Data+XOR+SUM
- §3 分包: 14B 写死 (MTU=23 旧假设), Header=(amount<<4)|seq
- §4-5 命令: 0x10/0x1F/0x23/0x24/0x31/0x8A/0x92/0xC5 逐字段
- §6 主动上报 0xC0: type=5 线圈动态 (频率+360补偿, variation 3B有符号)
- §7 坑清单: sensitvity 1~4 (≠vd960Loop 0~3), 0xC5 超时疑bug, 0x8A 写表依赖重载
- devlog 置顶 2026-08-25 条目
2026-08-25 16:48:52 +08:00
wangfq 1757674318 docs: V3.03 文档同步 (devlog+product-manual+technical-spec) 2026-07-31 18:09:56 +08:00
wangfq 1da7b984f1 feat: 使能硬件看门狗 WWDG, ~558ms 超时, 主循环喂狗 2026-07-31 11:58:58 +08:00
wangfq e2099ae12f docs: 光耦呼吸加速 文档同步 (devlog+product-manual+technical-spec) 2026-07-31 11:50:54 +08:00
wangfq 1790a9fd42 opt: 光耦呼吸加速 STEP 16→32 (~0.5s 周期) 2026-07-31 11:44:49 +08:00
wangfq 7be0c83cb1 feat: 光耦有信号时红灯呼吸加速 (~1.9s→~0.9s), 复位模式除外 2026-07-31 11:19:18 +08:00
wangfq 0fbb2cb461 docs: DLD154Tool README 增加 Windows/Linux 打包说明 2026-07-31 09:59:12 +08:00
wangfq 3ba5b4824c release: DLD154Tool v1.0.0 — 版本显示+PyInstaller打包 2026-07-31 09:50:35 +08:00
wangfq 7a0304ee65 docs: V3.02 — 开发日志+产品说明书+技术规格书同步更新 2026-07-31 09:36:55 +08:00
12 changed files with 544 additions and 54 deletions
@@ -635,6 +635,10 @@ void manage_dbn_ble_default(uint8_t *pkg, uint8_t len)
tmp_ble_buf[i++] = (g_loop_power_up_state == 0) ? 1 : ((uint8_t)(g_loop_cut_amount)); tmp_ble_buf[i++] = (g_loop_power_up_state == 0) ? 1 : ((uint8_t)(g_loop_cut_amount));
tmp_ble_buf[i++] = (uint8_t)(g_loop_cut_amount >> 8); tmp_ble_buf[i++] = (uint8_t)(g_loop_cut_amount >> 8);
tmp_ble_buf[i++] = g_loop_cng_unit.direction_mode; tmp_ble_buf[i++] = g_loop_cng_unit.direction_mode;
/* V3.04: 追加归一化基数 LOOP_MEASURE_BASE (2^19=524288, LE), 供第三方 variation 换算 dL/L */
tmp_ble_buf[i++] = (uint8_t)(LOOP_MEASURE_BASE);
tmp_ble_buf[i++] = (uint8_t)(LOOP_MEASURE_BASE >> 8);
tmp_ble_buf[i++] = (uint8_t)(LOOP_MEASURE_BASE >> 16);
set_response_buf(&g_buf_ble_response, MAGIC_BYTE_DBN_DEFAULT, _cmd, tmp_ble_buf, i); set_response_buf(&g_buf_ble_response, MAGIC_BYTE_DBN_DEFAULT, _cmd, tmp_ble_buf, i);
// PRINT("\nGet_Cjq_param\n"); // PRINT("\nGet_Cjq_param\n");
@@ -17,10 +17,13 @@
*/ */
#define PRODUCT_MODEL "DLD154Pro" #define PRODUCT_MODEL "DLD154Pro"
#define FIRMWARE_VER "3.02" #define FIRMWARE_VER "3.04"
#define HARDWARE_VER "3.01" #define HARDWARE_VER "3.01"
#define FIRMWARE_VER_MAIN 3 #define FIRMWARE_VER_MAIN 3
#define FIRMWARE_VER_SUB 2 #define FIRMWARE_VER_SUB 4
/* 归一化基数: variation 换算 dL/L 时除以该值 (2^19=524288, 必须与 peripheral_main.c MEASUREMENT_BASE 同步) */
#define LOOP_MEASURE_BASE 524288L
#define HARDWARE_VER_MAIN 3 #define HARDWARE_VER_MAIN 3
#define HARDWARE_VER_SUB 1 #define HARDWARE_VER_SUB 1
@@ -729,6 +729,7 @@ static void simpleProfileChangeCB(uint8_t paramID, uint8_t *pValue, uint16_t len
g_ble_rcv_buf.buf[3] == 'O' && g_ble_rcv_buf.buf[4] == 'T' && g_ble_rcv_buf.buf[5] == 'A'){ g_ble_rcv_buf.buf[3] == 'O' && g_ble_rcv_buf.buf[4] == 'T' && g_ble_rcv_buf.buf[5] == 'A'){
// 0x4F, 0x54, 0x41 // 0x4F, 0x54, 0x41
// PRINT("jump OTA \n"); // PRINT("jump OTA \n");
WWDG_ResetCfg(DISABLE);
mDelaymS(5); mDelaymS(5);
Jump_OTA(); Jump_OTA();
} }
@@ -29,6 +29,7 @@
#include "cmcng.h" #include "cmcng.h"
#include "dbn_ble_srv.h" #include "dbn_ble_srv.h"
#include "CH59x_pwm.h" #include "CH59x_pwm.h"
#include "CH59x_sys.h" /* WWDG 看门狗 */
#include "rs485_700bs.h" #include "rs485_700bs.h"
#include "rs485_modbus.h" #include "rs485_modbus.h"
@@ -83,20 +84,29 @@ uint8_t g_rs485_id = 0;
#define OPT_IN1 (GPIOB_ReadPortPin(GPIO_Pin_10)) #define OPT_IN1 (GPIOB_ReadPortPin(GPIO_Pin_10))
/*=========================================================================== /*===========================================================================
* LEDB 红色呼吸灯 (PB23, PWM11) — 快速心跳指示 (~2s 周期) * LEDB 红色呼吸灯 (PB23, PWM11) — 心跳指示
* PWM freq ≈ 60MHz / (PWM_CLK_DIV * 128) ≈ 5.86kHz @DIV=80 * PWM freq ≈ 60MHz / (PWM_CLK_DIV * 128) ≈ 5.86kHz @DIV=80
* 周期 = 16步渐亮 + 3tick高亮 + 16步渐灭 + 3tick低亮 * 无光耦信号: 周期 16步×2 + 3tick×2 ≈ 1.9s (DUTY_STEP=8, HOLD=3)
* ≈ (16*50ms)*2 + 150ms*2 ≈ 1.9s * 光耦有信号: 周期 ≈ 4步×2 + 1tick×2 ≈ 0.5s (DUTY_STEP=32, HOLD=1)
* 复位模式(6)除外,光耦有信号不加速
*===========================================================================*/ *===========================================================================*/
#define PWM_CLK_DIV 80 #define PWM_CLK_DIV 80
#define PWM_CYCLE 128 // 7-bit 分辨率 (0~127) #define PWM_CYCLE 128 // 7-bit 分辨率 (0~127)
#define BREATH_STEP_DELAY 1 // 每 50ms 更新一次 #define BREATH_STEP_DELAY 1 // 每 50ms 更新一次
#define BREATH_DUTY_STEP 8 // 每步跳 8 级占空比 #define BREATH_DUTY_STEP 8 // 每步跳 8 级占空比
#define BREATH_HOLD_TICKS 3 // 高/低电平保持 tick 数
#define BREATH_FADE_IN 0 #define BREATH_FADE_IN 0
#define BREATH_HOLD_HIGH 1 #define BREATH_HOLD_HIGH 1
#define BREATH_FADE_OUT 2 #define BREATH_FADE_OUT 2
#define BREATH_HOLD_LOW 3 #define BREATH_HOLD_LOW 3
/* 光耦有信号时加速参数 (周期 ~1s) */
#define BREATH_OPTO_DUTY_STEP 32 // 步长 4x → 渐亮/渐灭各 4 步 (~0.5s 周期)
#define BREATH_OPTO_HOLD_TICKS 1 // 保持 50ms
/* 看门狗超时: Fsys=60MHz, WDOG_CLK=Fsys/131072≈458Hz, 0xFF≈558ms */
#define WDOG_TIMEOUT 0xFF
static uint8_t g_breath_phase = BREATH_FADE_IN; static uint8_t g_breath_phase = BREATH_FADE_IN;
static uint8_t g_breath_duty = 0; static uint8_t g_breath_duty = 0;
static uint8_t g_breath_tick = 0; static uint8_t g_breath_tick = 0;
@@ -129,7 +139,6 @@ uint32_t mstick(void){
return TimingDelayInc; return TimingDelayInc;
} }
uint32_t u32CountWdt = 0;
uint8_t g_loop_cut_last = 0; uint8_t g_loop_cut_last = 0;
uint32_t g_loop_cut_amount = 0; uint32_t g_loop_cut_amount = 0;
@@ -160,6 +169,8 @@ uint8_t Flt_Reg = 0;
uint8_t TM1cnt = 0; uint8_t TM1cnt = 0;
uint16_t g_hold_time = 0; uint16_t g_hold_time = 0;
uint16_t g_wdg_counter = 0;
/*=========================================================================== /*===========================================================================
* 捕获 & 测量 * 捕获 & 测量
*===========================================================================*/ *===========================================================================*/
@@ -1016,6 +1027,15 @@ static void opt_input_poll(void)
} }
} }
void poll_wdg(void)
{
if(g_wdg_counter >= 100) //500ms
{
g_wdg_counter = 0;
WWDG_SetCounter(0);
}
}
/********************************************************************* /*********************************************************************
* @fn Main_Circulation * @fn Main_Circulation
@@ -1050,6 +1070,8 @@ void Main_Circulation()
g_dbn_ble_state_acs_enable.enable = 0; g_dbn_ble_state_acs_enable.enable = 0;
} }
} }
poll_wdg(); // 喂狗
} }
} }
@@ -1093,6 +1115,11 @@ int main(void)
HAL_Init(); HAL_Init();
GAPRole_PeripheralInit(); GAPRole_PeripheralInit();
Peripheral_Init(); Peripheral_Init();
/* 使能看门狗复位: 超时 ~558ms, 主循环喂狗 */
WWDG_ResetCfg(ENABLE);
WWDG_SetCounter(0);
Main_Circulation(); Main_Circulation();
} }
@@ -1196,7 +1223,7 @@ void TMR1_IRQHandler(void)
} }
TimingDelayInc++; TimingDelayInc++;
u32CountWdt++; g_wdg_counter++;
/*--- LED: 断开中 200ms 快闪; 稳定期 200ms 慢闪 ---*/ /*--- LED: 断开中 200ms 快闪; 稳定期 200ms 慢闪 ---*/
if(g_disconnect_active || !g_loop_power_up_state) if(g_disconnect_active || !g_loop_power_up_state)
@@ -1335,49 +1362,62 @@ void TMR1_IRQHandler(void)
} }
} }
/*--- LEDB 红色呼吸灯 (PWM11, 50ms tick, ~1.9s 心跳周期) ---*/ /*--- LEDB 红色呼吸灯 (PWM11, 50ms tick, 光耦有信号时加速 ~1s) ---*/
{
uint8_t _step, _hold;
/* 非复位模式下光耦有信号 → 红灯快闪 (现场判断光耦是否正常) */
if (g_opt_trigger && g_output_radar_mode != OUTPUT_MODE_LOOP_X_RESET) {
_step = BREATH_OPTO_DUTY_STEP;
_hold = BREATH_OPTO_HOLD_TICKS;
} else {
_step = BREATH_DUTY_STEP;
_hold = BREATH_HOLD_TICKS;
}
g_breath_tick++; g_breath_tick++;
switch (g_breath_phase) { switch (g_breath_phase) {
case BREATH_FADE_IN: // 渐亮 0 → max, ~800ms case BREATH_FADE_IN:
if (g_breath_tick >= BREATH_STEP_DELAY) { if (g_breath_tick >= BREATH_STEP_DELAY) {
g_breath_tick = 0; g_breath_tick = 0;
if (g_breath_duty + BREATH_DUTY_STEP >= PWM_CYCLE) { if (g_breath_duty + _step >= PWM_CYCLE) {
g_breath_duty = PWM_CYCLE - 1; g_breath_duty = PWM_CYCLE - 1;
g_breath_phase = BREATH_HOLD_HIGH; g_breath_phase = BREATH_HOLD_HIGH;
g_breath_tick = 0; g_breath_tick = 0;
} else { } else {
g_breath_duty += BREATH_DUTY_STEP; g_breath_duty += _step;
} }
PWM11_ActDataWidth(g_breath_duty); PWM11_ActDataWidth(g_breath_duty);
} }
break; break;
case BREATH_HOLD_HIGH: // 最亮保持 ~150ms case BREATH_HOLD_HIGH:
if (g_breath_tick >= 3) { if (g_breath_tick >= _hold) {
g_breath_phase = BREATH_FADE_OUT; g_breath_phase = BREATH_FADE_OUT;
g_breath_tick = 0; g_breath_tick = 0;
} }
break; break;
case BREATH_FADE_OUT: // 渐灭 max → 0, ~800ms case BREATH_FADE_OUT:
if (g_breath_tick >= BREATH_STEP_DELAY) { if (g_breath_tick >= BREATH_STEP_DELAY) {
g_breath_tick = 0; g_breath_tick = 0;
if (g_breath_duty <= BREATH_DUTY_STEP) { if (g_breath_duty <= _step) {
g_breath_duty = 0; g_breath_duty = 0;
g_breath_phase = BREATH_HOLD_LOW; g_breath_phase = BREATH_HOLD_LOW;
g_breath_tick = 0; g_breath_tick = 0;
} else { } else {
g_breath_duty -= BREATH_DUTY_STEP; g_breath_duty -= _step;
} }
PWM11_ActDataWidth(g_breath_duty); PWM11_ActDataWidth(g_breath_duty);
} }
break; break;
case BREATH_HOLD_LOW: // 最暗保持 ~150ms case BREATH_HOLD_LOW:
if (g_breath_tick >= 3) { if (g_breath_tick >= _hold) {
g_breath_phase = BREATH_FADE_IN; g_breath_phase = BREATH_FADE_IN;
g_breath_tick = 0; g_breath_tick = 0;
} }
break; break;
} }
} }
}
/*--- 线圈载波检测 & 继电器输出刷新 (每 5ms) ---*/ /*--- 线圈载波检测 & 继电器输出刷新 (每 5ms) ---*/
if(loop1_RF_FLAG) if(loop1_RF_FLAG)
+2
View File
@@ -2,3 +2,5 @@ venv/
__pycache__/ __pycache__/
*.pyc *.pyc
.DS_Store .DS_Store
build/
dist/
+46
View File
@@ -0,0 +1,46 @@
# -*- mode: python ; coding: utf-8 -*-
# DLD154Tool PyInstaller spec — 单文件 Windows/Linux 打包
a = Analysis(
['main.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[
'PySide6.QtCore',
'PySide6.QtGui',
'PySide6.QtWidgets',
'PySide6.QtSerialPort',
'serial',
],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='DLD154Tool',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=None,
)
+26
View File
@@ -57,11 +57,37 @@ DLD154Tool/
├── serial_client.py # 串口抽象层 (扫描/连接/收发) ├── serial_client.py # 串口抽象层 (扫描/连接/收发)
├── protocol_700bs.py # 700BS 协议编解码 ├── protocol_700bs.py # 700BS 协议编解码
├── protocol_modbus.py # Modbus RTU 协议编解码 + CRC16 ├── protocol_modbus.py # Modbus RTU 协议编解码 + CRC16
├── DLD154Tool.spec # PyInstaller 打包配置
├── requirements.txt # pyside6, pyserial ├── requirements.txt # pyside6, pyserial
├── .gitignore ├── .gitignore
├── dist/ # 打包产物 (gitignored)
└── README.md └── README.md
``` ```
## 打包为可执行文件
PyInstaller **不支持跨平台交叉编译**,需要在目标系统上执行。
### Linux
```bash
pip install pyinstaller
pyinstaller DLD154Tool.spec
# → dist/DLD154Tool (69MB, 单文件 ELF x86-64)
```
### Windows
```cmd
python -m venv venv
venv\Scripts\activate
pip install -r requirements.txt pyinstaller
pyinstaller DLD154Tool.spec
:: → dist\DLD154Tool.exe (单文件,双击运行)
```
> spec 文件已预置,无需重新生成。产物 `dist/` 目录已加入 `.gitignore`。
## RS485 接线 ## RS485 接线
``` ```
+6 -1
View File
@@ -8,6 +8,8 @@ DLD154Tool — DLD154Pro 桌面串口调试工具
依赖: PySide6, pyserial 依赖: PySide6, pyserial
""" """
TOOL_VERSION = "1.0.0"
import sys import sys
import struct import struct
import threading import threading
@@ -553,7 +555,7 @@ class LogTab(QWidget):
class MainWindow(QMainWindow): class MainWindow(QMainWindow):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.setWindowTitle("DLD154Tool — DLD154Pro 串口调试工具") self.setWindowTitle(f"DLD154Tool v{TOOL_VERSION} — DLD154Pro 串口调试工具")
self.setMinimumSize(800, 650) self.setMinimumSize(800, 650)
self._sc = SerialClient() self._sc = SerialClient()
@@ -586,6 +588,9 @@ class MainWindow(QMainWindow):
self._log_tab.append("DLD154Tool 启动") self._log_tab.append("DLD154Tool 启动")
# 状态栏: 显示版本
self.statusBar().showMessage(f"DLD154Tool v{TOOL_VERSION} | 就绪")
def _on_connect_changed(self, connected: bool): def _on_connect_changed(self, connected: bool):
if connected: if connected:
self._start_worker() self._start_worker()
+247
View File
@@ -0,0 +1,247 @@
# DLD154Pro 蓝牙小程序接口协议
> 依据源码整理:`BLE/DLD154Pro_Peripheral_28K/APP/dbn_ble_srv.c`(主逻辑)、`peripheral.c`/`Profile/gattprofile.c`BLE 服务)、`include/storage.h`(配置结构)、`include/cmcng.h`(常量)
> 固件版本:V3.04cmcng.h `FIRMWARE_VER`| 硬件版本:V3.01 | 产品型号:DLD154Pro
---
## 1. BLE 服务与特征
| 服务/特征 | UUID | 属性 | 长度 | 用途 |
|-----------|------|------|------|------|
| 服务 SIMPLEPROFILE | 0xFFE0 | — | — | 广播服务 UUID |
| Char1 | 0xFFE1 | 读写 (RW) | 64B | **小程序 → 芯片:命令下发** |
| Char2 | 0xFFE2 | 读 | 1B | 预留 |
| Char3 | 0xFFE3 | 写 | 8B | 预留 |
| Char4 | 0xFFE4 | **通知 (Notify)** | 32B | **芯片 → 小程序:命令响应 + 主动上报** |
| Char5 | 0xFFE5 | 读 | 5B | 预留 |
- 设备名:`DLD154Pro`(广播 + GATT Device Name
- **MTU**:默认 23,连接后协商(`ATT_MTU_UPDATED_EVENT``peripheralMTU = clientRxMTU`)。notify 单包 payload ≤ `peripheralMTU 3`peripheral.c:677 强制检查,超限返回 FAIL 不发送)
- **交互模型**:小程序写 Char1 下发命令帧 → 芯片处理 → Char4 notify 返回响应帧;芯片主动上报也走 Char4
---
## 2. 帧格式与校验
```
| Magic 1B | Header 1B | Len 1B | CMD 1B | Data N B | XOR 1B | SUM 1B |
```
| 字段 | 说明 |
|------|------|
| Magic | `0x8F` = 车检器默认协议;`0x7F` = 透传(显示屏/地感/探头协议) |
| Header | 单包 = `0x00`;分包 = `(pkg_amount << 4) \| pkg_seq`(高 4 位总包数,低 4 位当前序号,seq 从 1 起) |
| Len | `1CMD+ NData 字节数)` |
| CMD | 命令码,见 §4 |
| XOR | 异或校验:从 Header 到 Data 末尾逐字节 XOR |
| SUM | 和校验:从 Header 到 Data 末尾逐字节求和(低 8 位) |
**校验示例**`compute_ckb`dbn_ble_srv.c:168):
```c
dxor = Header ^ Len ^ CMD ^ Data[0] ^ ... ^ Data[N-1];
dsum = Header + Len + CMD + Data[0] + ... + Data[N-1]; // 取低 8 位
// 发送顺序: [dxor] [dsum & 0xFF]
```
**接收校验**`check_pkg`dbn_ble_srv.c:75):最小帧长 6`Len + 5 < 实际长度` 判非法;XOR/SUM 任一不符丢弃。
---
## 3. 分包机制
- **发送(响应/上报)**`set_response_buf()``MAX_BLE_DAT_RESPONSE_LEN = 14`= BLE_BUFF_MAX_LEN4,基于 MTU=23 的旧假设)计算 `pkg_amount = ceil(dat_len / 14)`。多包时 Header = `(amount<<4)|seq`seq 从 1 递增,最后一包 `amount == seq` 后清除响应缓冲。
- **接收(命令)**`unpack_packs()` 支持按 `(amount<<4)|seq` 重组分包,校验 amount/cmd/seq 连续性,异常时清空缓冲。DLD154Pro 当前仅 0x1C/0x1D 使用(已注释),其余命令单包即可。
- **⚠ 分包粒度写死 14**:即使 MTU 协商到更大(如 96/185),分包仍按 14B 切——不丢包但效率低。小程序侧按 Header 分包重组即可。
---
## 4. 命令总览
| CMD | 名称 | 方向 | 说明 |
|-----|------|------|------|
| 0x10 | GET_DEV_INFO | 小程序→芯片 | 读设备信息(MAC/版本/型号) |
| 0x1F | RESET_DEV | 小程序→芯片 | 复位设备(SYS_ResetExecute |
| 0x23 | SET_CJQ_PARAM | 小程序→芯片 | 设置车检器参数(灵敏度/频率/延时/输出等) |
| 0x24 | GET_CJQ_PARAM | 小程序→芯片 | 读车检器参数 |
| 0x31 | RW_UART_BAUD | 小程序→芯片 | 读写 RS485 波特率/地址/蓝牙空闲超时 |
| 0x8A | LOOP_SENS_LIST | 小程序→芯片 | 读写灵敏度表(sens_in/sens_out |
| 0x92 | SET_CJQ_FACTORY | 小程序→芯片 | 恢复出厂 |
| 0xC5 | SENS_ACS_ENABLE | 小程序→芯片 | 主动上报使能 |
| 0xC0 | SUB_SENS_REPORT | 芯片→小程序 | 主动上报线圈动态(不可下发) |
**未实现(源码已注释)**0x1C 校验密码 / 0x1D 修改密码 / 0x1E 出厂 / 0x20-0x22 notify 与子功能 / 0x6D 复位 / 0x87 采样参数 / 0x88 平衡参数 / 0x89 释放参数。小程序不应下发,芯片无响应。
---
## 5. 命令详述
### 5.1 0x10 读设备信息
无 Data。响应 Data
| 偏移 | 字节 | 内容 |
|------|------|------|
| 0-5 | 6 | MAC 地址(MACAddr[6] |
| 6-7 | 2 | 硬件版本 MAIN/SUBV3.01 → 03 01 |
| 8-9 | 2 | 固件版本 MAIN/SUBV3.04 → 03 04 |
| 10 | 1 | 产品型号长度 |
| 11.. | N | 产品型号 ASCII"DLD154Pro" |
| .. | 6 | 设备编号(g_dev_number[6] |
| .. | 2 | sub_code(固定 0 |
| .. | 2 | 总线设备数(固定 0) |
### 5.2 0x1F 复位设备
无 Data。芯片执行 `SYS_ResetExecute()`(整机冷复位),**无响应帧**。
### 5.3 0x23 设置车检器参数
Data5B):
| 偏移 | 内容 |
|------|------|
| 0 | `sensitvity(低4位) \| loopFreq_Level(高4位)` |
| 1 | delay_time(离开延时) |
| 2 | `output_mode(低2位) \| loopSafe_Timeout(高5位)` |
| 3 | exist_mode(有限存在时长,单位 10s) |
| 4 | direction_mode(低 4 位=输出融合模式;高 4 位=功能模式) |
**sensitvity 语义(DLD154Pro 特有)**:协议层 **1~4**1=最低灵敏度,4=最高),内部 `g_freq_sens = sensitvity 1`(0~3)索引灵敏度表。与 vd960Loop 的 0~3 不同,**小程序发送 1~4**。
**direction_mode 解析**unpack_pkg_set_cjq_paramdbn_ble_srv.c:431):
```
g_function_mode = direction_mode >> 4 (功能模式)
g_fm_700bs_disable = g_function_mode & 0x01 (0=700BS协议, 1=Modbus)
g_output_radar_mode = direction_mode & 0x0F (输出融合模式, 见 DLD_OUTPUT_MODE)
g_hold_time = exist_mode * 20 * 5 (tick)
```
处理:更新全局 → `write_cfg_to_store(4, tmp, 7)` 写 flash → `para_store_init()` 重载。响应:1B status(固定 0)。
### 5.4 0x24 读车检器参数
无 Data。响应 Data11B):
| 偏移 | 内容 |
|------|------|
| 0 | `(g_freq_sens + 1) \| (loopFreq_Level << 4)`sensitvity 回读为 1~4 |
| 1 | delay_time |
| 2 | `output_mode \| (loopSafe_Timeout << 3)` |
| 3 | exist_mode |
| 4 | `sens_list.total << 4`(灵敏度档数,高 4 位) |
| 5 | 线圈断开次数低字节(g_loop_cut_amount,上电持续累计) |
| 6 | 线圈断开次数高字节 |
| 7 | direction_mode |
| 8-10 | **归一化基数 LOOP_MEASURE_BASE3B LE= 524288**V3.04 追加) |
> ⚠ **偏移 8-10 用途(V3.042026-08-26 追加)**variation 换算 ΔL/L 的归一化基数。
> 第三方应用连接后读一次 0x24 缓存该值:`Δf/f ≈ variation / LOOP_MEASURE_BASE``ΔL/L ≈ -2 × variation / LOOP_MEASURE_BASE`。
> **背景**DLD154Pro 的 MEASUREMENT_BASE = 5242882^19 @60MHz),与 DLD110S 相同、与 DLD154V4B 的 131072 不同。固件显式上报后第三方无需猜测(曾出现照搬 131072 导致百分比放大 4 倍的问题,DLD110S 2026-08-26 实测发现)。
> 向后兼容:老小程序只读前 8B 不受影响;新小程序读 11B。
### 5.5 0x31 读写 UART 参数
Data`[rw] [status] ...`
**读(rw=0**:响应 Data8B):
```
[0] rw=0
[1] status=0
[2] 蓝牙空闲超时(分钟, g_max_counter_bt_min)
[3-5] RS485 波特率 3B LE (g_storage_uart_baud)
[6] RS485 从机地址 (g_rs485_id)
[7-9] Reserved 3B
```
**写(rw≠0**Data 后续:`[bt_timeout] [baud 3B LE] [rs485_id] [3B reserved]`,共 5B 有效写入 `write_cfg_to_store(0x10, 5B)`。响应回读当前值(同读格式)。
### 5.6 0x8A 读写灵敏度表
**读(pkg[4]=0**:响应 Data
```
[0] 0x10 (读标志)
[1] total (灵敏度档数)
[2..] total × [sens_in 2B LE | sens_out 2B LE]
```
**写(pkg[4]≠0**Data 从 pkg[5] 起:`[total] [sens0_in LE2 | sens0_out LE2] [sens1...]`。写 flash `Addr_Loop_Sens_List_Offset(0x20)` + `para_store_init()` 重载。**注意:写路径不直接改 RAM 的 g_loop_sens_list,依赖 para_store_init 从 flash 重读生效**。
出厂默认 4 档(storage.c):`{108,54,28,14}`sens_in/ `{81,32,16,12}`sens_out,滞回 ~75/59/57/86%)。
### 5.7 0x92 恢复出厂
无 Data。执行 `set_factory_param() + factory_dev()` → flash 重写出厂配置 → `para_store_init()` 重载。响应:1B status=0。
### 5.8 0xC5 主动上报使能
Data`[enable] [interval] [timeout_min]`
- enable1=开启,0=关闭
- interval:上报间隔系数,实际 `interval × 0x7F`127
- timeout_min:超时分钟数(0=不限时)
处理(dbn_ble_srv.c:830):开启时 `timeout_counter = timeout_min × 60 × 100`**源码 TODO 标注 min→ms60×100=6000 疑应为 60000**,若按 6000 则实际超时 = timeout_min 分钟 ÷ 10,注意现场验证)。关闭时 flag=0。
---
## 6. 主动上报 0xC0(芯片 → 小程序)
组包:`usart_packet_processing_acs_loop()`dbn_ble_srv.c:452),type = 5SENS_LOOP_DYNAMIC)。
| 偏移 | 字节 | 内容 |
|------|------|------|
| 0 | 1 | `0x05`SENS_LOOP_DYNAMIC 线圈动态) |
| 1 | 1 | `loop_num<<6 \| freq_level<<4 \| condition&0x0F` |
| 2 | 1 | `relay2_state<<6 \| relay2_cng<<4 \| relay1_state<<2 \| relay1_cng&0x3` |
| 3 | 1 | `loop1_FLAG_CUT<<7 \| car_state<<4 \| direction&0x0F` |
| 4-6 | 3 | 线圈断开次数(LEpower_up_state==0 时为 1 |
| 7-9 | 3 | 实际频率(LE`freq = sclk_freq/CAPVD×LPCNT + 360` 补偿) |
| 10-12 | 3 | variation 变化量(**3B 有符号补码 LE**,正=车/金属进入方向) |
**触发条件**report_sens_acsdbn_ble_srv.c:531):
- 事件:`flag_event` 置位(车进出等事件)立即上报
- 周期:`report_counter >= 120` 周期上报(120 × 50ms ≈ 6s
- 前提:`g_dbn_ble_state_acs_enable.enable == 1`0xC5 开启)
**variation 接收端注意**:int32_t 截断 3B,负值需符号扩展(`if (v & 0x800000) v |= 0xFF000000`),与 vd960Loop V1.05 同口径。
**condition**:环境状态评估值 0~15`g_env_activity/10`,>150 取 15;线圈断开强制 15),值越大干扰越大。
---
## 7. 实现细节与坑(对照源码)
1. **sensitvity 1~4 vs 0~3**DLD154Pro 协议层 1~4,内部 `g_freq_sens = sensitvity-1`。0x24 回读 `+1`。**与 vd960Loop(0~3)不一致,小程序需按产品区分**
2. **分包粒度 14B 写死**`MAX_BLE_DAT_RESPONSE_LEN = BLE_BUFF_MAX_LEN - 4 = 14`(基于 MTU 23);MTU 协商更大后不重新分包——正确但低效
3. **0xC5 超时疑似 bug**`timeout_min × 60 × 100`,若意图 ms 则应为 ×1000(待现场验证)
4. **0x8A 写灵敏度表不直接更新 RAM**:依赖 `para_store_init()` 重读 flash;写完立即读可能拿到旧值
5. **0xC0 frequent +360 补偿**`_current_freq = freq_tmp + 360`(经验补偿值,示波器标定用)
6. **0x1F/0x1E 无响应**:复位/出厂类命令执行后设备重启,小程序不应等待响应帧
7. **notify 超限静默丢弃**`peripheralChar4Notify``len > (peripheralMTU-3)` 时返回 FAIL,不重发——长响应必须分包
8. **密码命令未实现**:0x1C/0x1D 已注释,小程序不应依赖加密鉴权
---
## 8. 交互示例
**读取设备信息**(无 DataLen=1):
```
下发: 8F 00 01 10 11 11
│ │ │ │ │ └ SUM = 0x00+0x01+0x10 = 0x11
│ │ │ │ └─ XOR = 0x00^0x01^0x10 = 0x11
│ │ │ └─ CMD = 0x10
│ │ └─ Len = 1 (CMD only)
│ └─ Header = 0 (单包)
└─ Magic = 0x8F
芯片 → Char4 notify: 8F 00 10 XX [MAC6][03 01][03 04][0A "DLD154Pro"][dev_no6][00 00][00 00] [XOR] [SUM]
Len=0x10(16): CMD + 15B Data
```
**设置灵敏度为 2 档(协议值 2**
```
下发: 8F 00 06 23 20 00 00 00 00 [XOR] [SUM]
Len=6: CMD(0x23)+Data5
Data[0]=0x20: sensitvity=2(低4位) | freq_level=0(高4位)
Data[1..4]=延时/输出/存在/方向模式
```
+110
View File
@@ -4,6 +4,116 @@
--- ---
## 2026-08-26 — V3.040x24 追加 LOOP_MEASURE_BASE 归一化基数(与 DLD110S 对齐)
### 背景
DLD110S 2026-08-26 实测发现小程序评估把 variation 归一化基数写错(照搬 DLD154V4B 的 131072DLD110S/154Pro 实为 524288 2^19 @60MHz)→ 所有百分比放大 4 倍。根治方案:固件 0x24 显式上报基数。DLD110S 已完成(协议 V1.1),**DLD154Pro 同步对齐**。
### 改动
| 文件 | 改动 |
|------|------|
| `APP/include/cmcng.h` | 版本 V3.03→V3.04;新增 `#define LOOP_MEASURE_BASE 524288L` |
| `APP/dbn_ble_srv.c` | 0x24 读参响应尾部追加 3B LELOOP_MEASURE_BASE(响应 8B→11B,仍单包 ≤14B,无分包) |
| `docs/ble-protocol.md` | §5.4 响应表加偏移 8-10 + 换算公式 + 背景说明 |
| `docs/product-manual.md` | 版本号 V3.04 + 版本历史 |
| `docs/technical-spec.md` | 版本号 V3.04 + 版本历史 |
### 对照 110S 差异结论(不需要改的部分)
- **断开次数双变量**:154Pro 不需要——LED 快闪不依赖 cut_amount 次数(走 `g_disconnect_active`),`g_loop_cut_amount` 本身就是上电持续累计,无 3 次上限
- **0x24 偏移 7 direction_mode**154Pro 已经是完整字节(dbn_ble_srv.c:637),与 110S V4.31 语义一致
- **重连 g_loop_cut_last = 0**154Pro 已有(peripheral_main.c:815
- ⚠ 位含义差异:两产品 direction_mode 低 4 位语义不同(110S=方向/触发;154Pro=输出融合模式 7 种),小程序按产品区分
### 涉及文件
| 文件 | 内容 |
|------|------|
| `BLE/DLD154Pro_Peripheral_28K/APP/include/cmcng.h` | V3.04 + LOOP_MEASURE_BASE |
| `BLE/DLD154Pro_Peripheral_28K/APP/dbn_ble_srv.c` | 0x24 追加 3B |
| `docs/ble-protocol.md` / `product-manual.md` / `technical-spec.md` | 同步 V3.04 |
---
## 2026-08-25 — 蓝牙小程序接口协议文档
### 背景
根据 `dbn_ble_srv.c`+ peripheral.c/gattprofile.c/storage.h/cmcng.h)整理蓝牙小程序与芯片交互的完整接口协议,供小程序开发对接。
### 文档要点
| 章节 | 内容 |
|------|------|
| §1 BLE 服务 | 服务 0xFFE0Char1(0xFFE1 RW 命令下发)、Char4(0xFFE4 Notify 响应/上报)MTU 协商 + notify ≤ MTU3 |
| §2 帧格式 | Magic(8F/7F)+Header+Len+CMD+Data+XOR+SUM;校验从 Header 起 |
| §3 分包 | 发送按 14B 写死分包(MTU=23 旧假设);Header=(amount<<4)\|seq |
| §4-5 命令 | 0x10/0x1F/0x23/0x24/0x31/0x8A/0x92/0xC5 逐字段 |
| §6 主动上报 | 0xC0 线圈动态(type=5,含频率+360 补偿、variation 3B 有符号) |
| §7 坑清单 | sensitvity 1~4(≠vd960Loop 0~3)、0xC5 超时疑 bug、0x8A 写表依赖 para_store_init、notify 超限静默丢弃 |
### 关键发现(源码事实)
1. **sensitvity 协议层 1~4**,内部 `g_freq_sens = sensitvity 1`0~3 索引灵敏度表 {108,54,28,14}),0x24 回读 +1——**与 vd960Loop 的 0~3 不同**
2. **0xC5 超时疑似 bug**`timeout_counter = timeout_min × 60 × 100`,若意图 ms 应为 ×1000(现场验证)
3. 0x8A 写灵敏度表不直接更新 RAM,依赖 `para_store_init()` 重读
4. 0x1F/0x92 复位/出厂类命令无响应帧
### 涉及文件
| 文件 | 内容 |
|------|------|
| `docs/ble-protocol.md` | 新增(依据 dbn_ble_srv.c 整理,固件 V3.03 |
---
## 2026-07-31 — 发布 V3.03
### 变更摘要
| 变更 | 说明 |
|------|------|
| 硬件看门狗 (WWDG) | 使能窗口看门狗,TMR1 ISR 5ms tick 驱动 `g_wdg_counter`,主循环 `poll_wdg()` 每 500ms 喂狗,超时 ~558ms 自动复位 |
| OTA 安全 | 跳转 OTA 前 `WWDG_ResetCfg(DISABLE)` 关闭看门狗,防止 OTA 期间超时复位 |
| 固件版本 | V3.02 → V3.03 |
### 涉及文件
| 文件 | 变更 |
|------|------|
| `peripheral_main.c` | +`poll_wdg()` + `g_wdg_counter`;移除 `u32CountWdt``main()``WWDG_ResetCfg(ENABLE)` |
| `peripheral.c` | OTA 跳转前 `WWDG_ResetCfg(DISABLE)` |
| `cmcng.h` | `FIRMWARE_VER` 3.02→3.03 |
---
## 2026-07-31 — 发布 V3.02
### 变更摘要
| 变更 | 说明 |
|------|------|
| `g_loop_cut_amount` 累加修复 | 重连路径补充 `g_loop_cut_last = 0` 边沿记忆清零,放开 3 次上限 |
| Modbus 主动上报线圈事件 | 线圈断开/重连立即触发主动上报(对齐 700BS) |
| 0x2C 复位指令重构 | 700BS: `SYS_ResetExecute()` MCU 全复位;Modbus: HR 0x0012=0x2C2C |
| DLD154Tool v1.0.0 | 版本显示 + PyInstaller 打包;Modbus 复位按钮 |
| RS485 初始化时序 | 移至 `para_store_init()` 之后 |
| 光耦呼吸加速 | 红灯在非复位模式下光耦有信号时加速 (~0.5s),便于现场判断光耦状态 |
### 涉及文件
| 文件 | 变更 |
|------|------|
| `peripheral_main.c` | cut_amount 修复 + RS485 时序 + 光耦呼吸加速 (BREATH_OPTO_DUTY_STEP=32) |
| `rs485_700bs.c` | `handle_reset_init()``SYS_ResetExecute()` |
| `rs485_modbus.c/h` | +HR 0x0012 (System Cmd) |
| `protocol_modbus.py` / `main.py` | +`build_reset_mcu()` + 复位按钮 |
| `DLD154Tool.spec` / `.gitignore` | PyInstaller 打包配置 |
| `rs485-modbus-protocol.md` | V1.6→V1.7 |
| `devlog.md` / `product-manual.md` / `technical-spec.md` | V3.02 文档同步 |
## 2026-07-30 — Modbus RTU V1.6 私有协议编码实现 ## 2026-07-30 — Modbus RTU V1.6 私有协议编码实现
### 背景 ### 背景
+9 -6
View File
@@ -1,6 +1,6 @@
# DLD154Pro 产品说明书 # DLD154Pro 产品说明书
> 单路线圈蓝牙车辆检测器 | 型号: DLD154Pro | 版本: V3.01 > 单路线圈蓝牙车辆检测器 | 型号: DLD154Pro | 版本: V3.04
> 适用于停车场、收费站、交通卡口等场景的车辆到达/离开检测 > 适用于停车场、收费站、交通卡口等场景的车辆到达/离开检测
--- ---
@@ -86,10 +86,10 @@ DLD154Pro 是一款基于 RISC-V 微控制器的**单通道环形线圈蓝牙车
### 3.2 指示灯 ### 3.2 指示灯
| 指示灯 | 颜色 | 功能 | | 灯 | 颜色 | 功能 |
|--------|------|------| |--------|------|------|
| 绿灯 (LEDA) | 绿色 | 车辆检测指示 / 自检。初始化/稳定期慢闪,有车亮,无车灭 | | 绿灯 (LEDA) | 绿色 | 车辆检测指示 / 自检。初始化/稳定期慢闪,有车亮,无车灭 |
| 红灯 (LEDB) | 红色 | 系统运行指示(呼吸灯,表示正常工作) | | 红灯 (LEDB) | 红色 | 系统运行指示(呼吸灯)。光耦有信号时加速至 ~0.5s 周期 |
### 3.3 内部跳线/配置 ### 3.3 内部跳线/配置
@@ -194,8 +194,9 @@ DLD154Pro 支持通过光耦输入接入外部雷达/车检器的干接点信号
|------|------|------| |------|------|------|
| 上电初始化 / 基线学习中 | **慢闪** (200ms 亮/灭) | 呼吸 (~1.9s 周期) | | 上电初始化 / 基线学习中 | **慢闪** (200ms 亮/灭) | 呼吸 (~1.9s 周期) |
| 线圈断开 | **灭** | 呼吸 | | 线圈断开 | **灭** | 呼吸 |
| 正常运行,无车 | **灭** | 呼吸 | | 正常运行,无车 | **灭** | 呼吸 (~1.9s) |
| 正常运行,有车 | **亮** | 呼吸 | | 正常运行,有车 | **亮** | 呼吸 |
| 光耦有信号 (非复位模式) | — | **快闪 (~0.5s)** |
> **提示**:上电后绿灯慢闪约 1.2s 后熄灭,表示线圈稳定就绪。如果绿灯一直慢闪不灭(超过 5s),说明线圈可能未连接或电感异常。 > **提示**:上电后绿灯慢闪约 1.2s 后熄灭,表示线圈稳定就绪。如果绿灯一直慢闪不灭(超过 5s),说明线圈可能未连接或电感异常。
@@ -273,7 +274,7 @@ DLD154Pro 支持两种 RS485 协议,通过 BLE 小程序切换:
| IR | 0x000203 | CAPVD | 归一化周期值,32-bit | | IR | 0x000203 | CAPVD | 归一化周期值,32-bit |
| HR | 0x0000 | Sensitivity | 灵敏度 02R/W | | HR | 0x0000 | Sensitivity | 灵敏度 02R/W |
| HR | 0x0001 | Fusion Mode | 融合模式 06R/W | | HR | 0x0001 | Fusion Mode | 融合模式 06R/W |
| HR | 0x00FF | Device Reset | 写 0x5A5A 复位 | | HR | 0x0012 | System Cmd | 写 0x2C2C 复位 MCU |
> 完整寄存器映射见 `docs/rs485-modbus-protocol.md`。 > 完整寄存器映射见 `docs/rs485-modbus-protocol.md`。
@@ -283,8 +284,10 @@ DLD154Pro 支持两种 RS485 协议,通过 BLE 小程序切换:
| 版本 | 日期 | 说明 | | 版本 | 日期 | 说明 |
|------|------|------| |------|------|------|
| V3.00 | 2026-07-21 | 项目初始化:从 DLD110SV4 移植 + 硬件适配 CH591R | | V3.04 | 2026-08-26 | 0x24 追加 LOOP_MEASURE_BASE 归一化基数(3B LE=524288);断开次数语义明确为上电持续累计 |
| V3.03 | 2026-07-31 | 硬件看门狗 (WWDG ~558ms 超时)OTA 安全关闭看门狗 |
| V3.01 | 2026-07-28 | 光耦输出融合模式(6 种);LEDA 同步继电器状态 | | V3.01 | 2026-07-28 | 光耦输出融合模式(6 种);LEDA 同步继电器状态 |
| V3.00 | 2026-07-21 | 项目初始化:从 DLD110SV4 移植 + 硬件适配 CH591R |
--- ---
+6 -3
View File
@@ -1,6 +1,6 @@
# DLD154Pro 技术规格书 # DLD154Pro 技术规格书
> 单路线圈蓝牙车辆检测器 | 固件版本: V3.01 | 硬件版本: V3.01 > 单路线圈蓝牙车辆检测器 | 固件版本: V3.04 | 硬件版本: V3.01
> 本文档面向工程开发、系统集成及故障深度分析 > 本文档面向工程开发、系统集成及故障深度分析
--- ---
@@ -429,7 +429,7 @@ TMR1 ISR (每 5ms)
### 7.3 红灯行为 ### 7.3 红灯行为
呼吸灯 (PWM11, ~1.9s 周期),始终运行,指示系统正常工作。不参与车辆/故障指示 呼吸灯 (PWM11),始终运行,指示系统正常工作。**非复位模式下光耦有信号时加速至 ~0.5s 周期**(DUTY_STEP=32),便于现场判断光耦输入是否正常。无光耦信号时 ~1.9s 周期(DUTY_STEP=8
--- ---
@@ -555,8 +555,11 @@ Magic | Addr/Sub | Len | CMD | Data | XOR | SUM
| 版本 | 日期 | 说明 | | 版本 | 日期 | 说明 |
|------|------|------| |------|------|------|
| V3.00 | 2026-07-21 | 项目初始化:从 DLD110SV4 复制基线 + 硬件适配 (CH591R) | | V3.04 | 2026-08-26 | 0x24 响应追加 LOOP_MEASURE_BASE 归一化基数(3B LE=524288variation 换算 ΔL/L 用);断开次数语义明确为上电持续累计 |
| V3.03 | 2026-07-31 | 硬件看门狗 WWDG (~558ms 超时, 5ms tick + 500ms 喂狗)OTA 安全关闭看门狗 |
| V3.02 | 2026-07-31 | Modbus RTU 协议 + 主动上报;0x2C/HR 0x0012 复位改为 `SYS_ResetExecute()``g_loop_cut_amount` 累加修复;RS485 初始化时序调整 |
| V3.01 | 2026-07-28 | 光耦输出模式完整实现 (6 种融合逻辑 + 状态机);LEDA 同步继电器状态 | | V3.01 | 2026-07-28 | 光耦输出模式完整实现 (6 种融合逻辑 + 状态机);LEDA 同步继电器状态 |
| V3.00 | 2026-07-21 | 项目初始化:从 DLD110SV4 复制基线 + 硬件适配 (CH591R) |
--- ---