[原创]一款超级低功耗的BLE远程同步振动传感器-双方的振动信息进行远程实时共享

芯片方案选型对比

** Nordic nRF52系列 vs TI CC2640系列 vs Dialog DA14580系列 **

nRF52832/nRF52840

  • 优势:
    超低功耗(2.4GHz下接收电流5.4mA,发射电流5.3mA@0dBm),支持BLE 5.0,内置DSP指令加速振动信号处理。
    丰富外设(12位ADC、PWM输出驱动马达),Flash容量512KB/1MB,适合复杂逻辑。
  • 劣势:成本略高。

TI CC2640R2F

  • 优势:
    专为传感器设计(待机电流1μA),集成可编程传感器控制器。
  • 劣势:BLE 4.2协议栈,内存受限(128KB Flash)。

Dialog DA14580

  • 优势:
    最低功耗(峰值电流4.9mA),成本最低。
  • 劣势:资源有限(128KB ROM,无内置DSP),需外置Flash。

推荐方案
选用nRF52840,因其平衡功耗与性能,支持BLE长距离模式(Coded PHY),内置硬件加速适合实时信号处理。


传感器端代码实现(C语言)

硬件初始化
#include "nrfx_saadc.h"
#include "nrfx_timer.h"
#include "nrf_pwm.h"

void hardware_init() {
    // ADC配置(振动传感器输入)
    nrfx_saadc_config_t adc_config = NRFX_SAADC_DEFAULT_CONFIG;
    nrfx_saadc_init(&adc_config, saadc_handler);
    nrf_saadc_channel_config_t channel_cfg = 
        NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN1);
    nrfx_saadc_channel_init(0, &channel_cfg);

    // PWM配置(振动马达输出)
    nrf_pwm_config_t pwm_cfg = {
        .output_pins  = {NRF_GPIO_PIN_MAP(0, 12), NRF_PWM_PIN_NOT_CONNECTED},
        .irq_priority = 4,
        .base_clock   = NRF_PWM_CLK_1MHz,
        .count_mode   = NRF_PWM_MODE_UP,
        .top_value    = 1000,
        .load_mode    = NRF_PWM_LOAD_COMMON,
        .step_mode    = NRF_PWM_STEP_AUTO
    };
    nrf_pwm_init(NRF_PWM0, &pwm_cfg);
}

振动信号采集
#define SAMPLE_RATE 100 // Hz
static nrfx_timer_t timer = NRFX_TIMER_INSTANCE(1);

void vibration_sampling_start() {
    nrfx_timer_config_t timer_cfg = {
        .frequency = NRF_TIMER_FREQ_1MHz,
        .mode      = NRF_TIMER_MODE_TIMER,
        .bit_width = NRF_TIMER_BIT_WIDTH_32
    };
    nrfx_timer_init(&timer, &timer_cfg, timer_handler);
    nrfx_timer_extended_compare(&timer, NRF_TIMER_CC_CHANNEL0, 
                                (1000000/SAMPLE_RATE), NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);
    nrfx_timer_enable(&timer);
}

void saadc_handler(nrfx_saadc_evt_t const *p_event) {
    if (p_event->type == NRFX_SAADC_EVT_DONE) {
        int16_t raw_value = p_event->data.done.p_buffer[0];
        ble_send_vibration_data(raw_value); // BLE发送数据
    }
}

BLE数据传输
#include "ble_nus.h"

static ble_nus_t m_nus; // BLE Nordic UART Service

void ble_init() {
    ble_nus_init_t nus_init = {0};
    nus_init.data_handler = nus_data_handler;
    ble_nus_init(&m_nus, &nus_init);
}

void ble_send_vibration_data(int16_t data) {
    uint8_t buffer[2];
    buffer[0] = (data >> 8) & 0xFF;
    buffer[1] = data & 0xFF;
    ble_nus_data_send(&m_nus, buffer, 2, NULL);
}

void nus_data_handler(ble_nus_evt_t *p_evt) {
    if (p_evt->type == BLE_NUS_EVT_RX_DATA) {
        // 接收远程振动数据并驱动马达
        int16_t remote_data = (p_evt->params.rx_data.p_data[0] << 8) | p_evt->params.rx_data.p_data[1];
        nrf_pwm_sequence_t seq = {
            .values.p_common = &remote_data,
            .length = 1
        };
        nrf_pwm_simple_playback(NRF_PWM0, &seq, 1, NRF_PWM_FLAG_LOOP);
    }
}


手机APP端实现(Android Kotlin)

BLE数据接收与MQTT上传
class BleManager(context: Context) {
    private val mqttClient = MqttClient(context, "tcp://mqtt.server.com:1883")

    private val nusCallback = object : BleManagerGattCallback() {
        override fun onCharacteristicChanged(device: BluetoothDevice, data: ByteArray) {
            val vibrationData = ByteBuffer.wrap(data).short
            mqttClient.publish("user/${device.address}/vibration", data)
        }
    }

    fun connectToDevice(device: BluetoothDevice) {
        connect(device).useAutoConnect(false).with(nusCallback).enqueue()
    }
}

MQTT数据接收与振动反馈
class MqttClient(context: Context, brokerUrl: String) : MqttAndroidClient(context, brokerUrl, "clientId") {
    init {
        setCallback(object : MqttCallback {
            override fun messageArrived(topic: String, message: MqttMessage) {
                if (topic.contains("/vibration")) {
                    val vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
                    vibrator.vibrate(VibrationEffect.createOneShot(message.payload.toShort().toLong(), 255))
                }
            }
        })
    }
}


服务器端实现(Python)

MQTT消息路由
import paho.mqtt.client as mqtt
import json

def on_connect(client, userdata, flags, rc):
    client.subscribe("user/+/vibration")

def on_message(client, userdata, msg):
    topic_parts = msg.topic.split('/')
    sender_id = topic_parts[1]
    receiver_id = get_pair_user(sender_id)  # 从数据库查询配对用户
    client.publish(f"user/{receiver_id}/vibration", msg.payload)

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect("localhost", 1883)
client.loop_forever()

用户配对数据库(SQLite)
import sqlite3

def init_db():
    conn = sqlite3.connect('users.db')
    cursor = conn.cursor()
    cursor.execute('''CREATE TABLE IF NOT EXISTS users
                      (id TEXT PRIMARY KEY, name TEXT, paired_with TEXT)''')
    conn.commit()

def get_pair_user(user_id):
    conn = sqlite3.connect('users.db')
    cursor = conn.cursor()
    cursor.execute("SELECT paired_with FROM users WHERE id=?", (user_id,))
    return cursor.fetchone()[0]


信号链时序说明

  1. A点传感器

    • ADC采样频率100Hz,通过BLE通知手机APP(nRF52840广播间隔可配置为30ms)。
    • 手机APP收到数据后通过MQTT QoS1级别发布到服务器。
  2. 服务器路由

    • 根据用户配对表将数据转发给B用户订阅的主题。
  3. B点设备

    • 手机APP通过BLE连接将振动数据写入nRF52840的PWM模块,驱动马达。

功耗优化

  • nRF52840使用事件驱动架构,ADC和BLE仅在数据就绪时唤醒。
  • 采用BLE连接参数协商(例如connInterval=100ms,slaveLatency=4)。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值