在汽车电子和工业监测领域,BLE(蓝牙低功耗)技术因其低功耗、易连接的特点,成为胎压监测系统(TPMS)的理想选择。这套基于杰理平台的方案,专为需要实时压力监控的场景设计,比如汽车轮胎压力监测、工业设备液压系统监控等。
核心设计目标很明确:在保证数据实时性的前提下,最大限度降低功耗。设备99%的时间处于广播状态,平均电流可以控制在50μA以下;只有在连接状态下才会以2-3Hz的频率发送数据,这种间歇性工作模式使设备续航可达数月甚至数年。
关键设计权衡:2-3Hz的采样率是经过实测验证的平衡点。低于2Hz会丢失重要压力变化信息,高于3Hz则会使纽扣电池续航缩短30%以上。实际项目中要根据具体传感器响应速度调整这个参数。
整个系统可分为三个逻辑层:
状态机设计是系统的核心,必须严格遵循以下转换规则:
| 当前状态 | 触发事件 | 动作序列 | 新状态 |
|---|---|---|---|
| S_ADV | 连接建立 | 停止广播定时器,初始化连接参数 | S_CONNECTED_IDLE |
| S_CONNECTED_IDLE | 收到START命令且DATA CCCD已启用 | 启动333/500ms定时器,初始化rt_seq | S_STREAMING |
| S_STREAMING | 收到STOP命令 | 停止定时器,释放缓冲区 | S_CONNECTED_IDLE |
| 任意状态 | 连接断开 | 停止所有定时器,重置CCCD标志,启动广播 | S_ADV |
开发警示:很多BLE项目出问题都是因为状态机没有正确处理异常断开。必须确保在连接丢失事件中,无论当前处于什么状态,都要完整执行以下操作:1) 立即停止所有活跃定时器 2) 清除CCCD使能标志 3) 重置协议栈参数 4) 重新进入广播模式。
采用最小化设计原则,只保留必需的特征:
UUID选择有讲究:
0000FF00-1212-EFDE-1523-785FEABCD123)CCCD(Client Characteristic Configuration Descriptor)是Notify功能的总开关。在杰理平台,需要特别关注:
att_write_cb回调,参数handle可用于区分是CTRL还是DATA的CCCDc复制uint8_t ctrl_notify_en = 0; // CTRL特征Notify使能标志
uint8_t data_notify_en = 0; // DATA特征Notify使能标志
命令帧采用固定头+CRC校验的设计,实际开发中要注意:
典型START命令帧示例(十六进制):
code复制5A A5 01 01 01 00 02 02 00 00 3C
解析:
压力数据帧设计考虑了嵌入式系统的处理效率:
flags字段:使用位域节省空间
ts_ms时间戳:采用设备上电毫秒计时,比绝对时间更省电。注意处理32位溢出(约49天循环一次)
press_0_100:将实际压力值线性映射到0-100范围,例如:
c复制// 假设传感器量程0-500kPa
uint8_t press_0_100 = (raw_pressure * 100) / 500;
杰理SDK的定时器API有几个坑需要注意:
示例代码:
c复制static void stream_timer_cb(void) {
send_data_notify();
if(state == S_STREAMING) {
// 单次定时器模式,避免累积误差
jl_bt_timer_start(timer_id, (rate_hz==3)?333:500, 0);
}
}
BLE协议栈对内存有严格限制,建议:
c复制uint16_t mtu = jl_bt_att_get_mtu(conn_handle);
if(mtu < sizeof(data_frame)) {
// 触发错误处理
}
c复制#define QUEUE_SIZE 3
struct data_frame queue[QUEUE_SIZE];
uint8_t q_head = 0, q_tail = 0;
| 现象 | 可能原因 | 排查步骤 |
|---|---|---|
| 无法发现设备 | 广播间隔太长/广播数据不合法 | 1. 确认广播间隔在20ms-1s之间 2. 检查广播数据是否符合BLE规范 |
| 连接后立即断开 | 连接参数不兼容 | 1. 检查连接间隔(15-45ms) 2. 验证从机延迟(0-3) 3. 确认监控超时(2-10s) |
| DATA Notify不稳定 | CCCD未正确设置/MTU太小 | 1. 抓包确认CCCD写入 2. 协商更大的MTU(如247字节) |
| 数据丢包严重 | 定时器不准/缓冲区不足 | 1. 检查rt_seq连续性 2. 增加发送队列大小 |
使用nRF Sniffer或Ellisys等工具时,重点关注:
典型问题模式:
c复制#define ADV_INTERVAL_MS 500 // 平衡发现速度和功耗
jl_bt_gap_set_adv_param(ADV_INTERVAL_MS, ADV_INTERVAL_MS, 0);
c复制jl_bt_gap_set_adv_data(ADV_TYPE_DIRECT_IND, adv_data, sizeof(adv_data));
c复制static const jl_bt_conn_param_t conn_params = {
.min_interval = 15, // 最小值15ms
.max_interval = 30, // 最大值30ms
.latency = 2, // 允许跳过2个连接事件
.timeout = 2000 // 2秒超时
};
实际测试数据表明,经过这些优化后:
帧结构中的ver字段为未来升级预留空间,建议的版本策略:
0x03 CALIBRATE)向后兼容实现示例:
c复制void process_ctrl_frame(uint8_t *data) {
uint8_t ver = data[2];
switch(ver) {
case 0x01: process_v1_frame(data); break;
case 0x02: process_v2_frame(data); break;
default: send_error_ack(UNSUPPORTED_VERSION);
}
}
虽然方案基于杰理平台,但通过抽象硬件相关部分,可以方便移植到其他BLE芯片:
硬件抽象层(HAL)需要实现的接口:
c复制// ble_hal.h
void hal_ble_init(void);
void hal_ble_start_adv(void);
bool hal_ble_send_notify(uint16_t handle, uint8_t *data, uint16_t len);
平台差异处理:
在最近的一个工业压力监控项目中,我们仅用3天就完成了从杰理AC632N到nRF52832的移植,验证了这套架构的可移植性。