【沁恒CH585开发板免费试用体验】4、从ADC采集到BLE-Web实时可视化 - RISC-V MCU技术社区 - 电子技术论坛 - 广受欢迎的专业电子论坛
分享 收藏 返回

【沁恒CH585开发板免费试用体验】4、从ADC采集到BLE-Web实时可视化

继续在CH585EVT\EVT\EXAM\BLE\Peripheral进行扩展

一、ADC采集片上温度

在peripheral.C增加adc_temperature函数,代码从ADC示例中获取,只保留到整数位,精度不高。

uint32_t adc_temperature(void)
{
    int i;
    uint32_t temperature=0;
    /* 温度采样并输出 */
    ADC_InterTSSampInit();

    ADC_ExcutSingleConver();//时间足够时建议再次转换并丢弃首次ADC数据
    for(i = 0; i < 20; i++)
    {
        adcBuff[i] = ADC_ExcutSingleConver(); // 连续采样20次
    }
    for(i = 0; i < 20; i++)
    {
        //uint32_t C25 = 0;
        //C25 = (*((PUINT32)ROM_CFG_TMP_25C));
        //PRINT("%d %d %d \\n", adc_to_temperature_celsius(adcBuff[i]),adcBuff[i],C25);
        temperature+=adc_to_temperature_celsius(adcBuff[i]);
    }
    return temperature/20;
}

二、BLE notify采集的温度数值

performPeriodicTask函数中,增加notiData[0]=adc_temperature();,这样所有订阅该特征值的用户可以收到温度值。

static void performPeriodicTask(void)
{
    uint8_t notiData[SIMPLEPROFILE_CHAR4_LEN] = {0x88};
    notiData[0]=adc_temperature();
    peripheralChar4Notify(notiData, SIMPLEPROFILE_CHAR4_LEN);
}

三、编写一个HTML

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>BLE数据曲线监控</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
	
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 1000px;
            margin: 0 auto;
            padding: 20px;
        }
        .panel {
            margin-bottom: 20px;
            padding: 15px;
            border: 1px solid #ddd;
            border-radius: 5px;
        }
        .chart-container {
            position: relative;
            height: 400px;
            width: 100%;
        }
        button {
            background-color: #4285f4;
            color: white;
            border: none;
            border-radius: 4px;
            padding: 10px 15px;
            margin: 5px;
            cursor: pointer;
        }
        button:hover {
            background-color: #3367d6;
        }
        button:disabled {
            background-color: #cccccc;
            cursor: not-allowed;
        }
        .status {
            font-weight: bold;
            padding: 5px;
            border-radius: 3px;
            display: inline-block;
        }
        .connected {
            background-color: #e6f4ea;
            color: #34a853;
        }
        .disconnected {
            background-color: #fce8e6;
            color: #d93025;
        }
        .control-group {
            margin: 15px 0;
        }
        .value-display {
            font-family: monospace;
            font-size: 16px;
            margin: 10px 0;
        }
    </style>
</head>
<body>
    <h1>BLE数据曲线监控</h1>
    
    <div class="panel">
        <h2>设备连接</h2>
        <div>
            <span class="status disconnected" id="connection-status">未连接</span>
        </div>
        <div class="control-group">
            <button id="connect-btn">连接设备</button>
            <button id="disconnect-btn" disabled>断开连接</button>
        </div>
    </div>
    
    <div class="panel">
        <h2>服务配置</h2>
        <div class="control-group">
            <label for="service-uuid">服务UUID: </label>
            <input type="text" id="service-uuid" placeholder="0000ffe0-0000-1000-8000-00805f9b34fb" value="0000ffe0-0000-1000-8000-00805f9b34fb" size="40">
        </div>
        <div class="control-group">
            <label for="characteristic-uuid">特征值UUID: </label>
            <input type="text" id="characteristic-uuid" placeholder="0000ffe4-0000-1000-8000-00805f9b34fb" value="0000ffe4-0000-1000-8000-00805f9b34fb" size="40">
        </div>
        <div class="control-group">
            <button id="get-characteristic-btn" disabled>获取特征值</button>
        </div>
    </div>
    
    <div class="panel">
        <h2>数据监控</h2>
        <div class="control-group">
            <button id="start-monitor-btn" disabled>开始监控</button>
            <button id="stop-monitor-btn" disabled>停止监控</button>
           
        </div>
        <div class="value-display">
            当前值: <span id="current-value">-</span>
            历史记录: <span id="history-count">0</span></div>
        <div class="chart-container">
            <canvas id="data-chart"></canvas>
        </div>
    </div>

    <script>
        // 全局变量
        let device = null;
        let characteristic = null;
        let chart = null;
        let monitorInterval = null;
        let dataPoints = [];
        const maxDataPoints = 100; // 最大显示数据点数
        
        // DOM元素
        const connectBtn = document.getElementById('connect-btn');
        const disconnectBtn = document.getElementById('disconnect-btn');
        const getCharacteristicBtn = document.getElementById('get-characteristic-btn');
        const startMonitorBtn = document.getElementById('start-monitor-btn');
        const stopMonitorBtn = document.getElementById('stop-monitor-btn');
        const connectionStatus = document.getElementById('connection-status');
        const currentValue = document.getElementById('current-value');
        const historyCount = document.getElementById('history-count');
        const sampleInterval = document.getElementById('sample-interval');
        
        // 初始化图表
        function initChart() {
            const ctx = document.getElementById('data-chart').getContext('2d');
            chart = new Chart(ctx, {
                type: 'line',
                data: {
                    labels: [],
                    datasets: [{
                        label: '特征值数据',
                        data: [],
                        borderColor: 'rgb(75, 192, 192)',
                        tension: 0.1,
                        fill: false
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    scales: {
                        y: {
                            beginAtZero: false
                        }
                    },
                    animation: {
                        duration: 0 // 禁用动画以获得更流畅的更新
                    }
                }
            });
        }
        
        // 更新图表数据
        function updateChart(value, timestamp) {
            // 添加新数据点
            dataPoints.push({
                x: timestamp || new Date().toLocaleTimeString(),
                y: value
            });
            
            // 限制数据点数量
            if (dataPoints.length > maxDataPoints) {
                dataPoints.shift();
            }
            
            // 更新图表
            chart.data.labels = dataPoints.map(point => point.x);
            chart.data.datasets[0].data = dataPoints.map(point => point.y);
            chart.update();
            
            // 更新UI显示
            currentValue.textContent = value;
            historyCount.textContent = dataPoints.length;
        }
        
        // 连接设备
        connectBtn.addEventListener('click', async () => {
            try {
                connectionStatus.textContent = "正在连接...";
                connectionStatus.className = "status";
                
                 device = await navigator.bluetooth.requestDevice({
					acceptAllDevices: true,
                    //optionalServices: ['generic_access'] // 默认包含的服务
					optionalServices: ['0000ffe0-0000-1000-8000-00805f9b34fb']
                    //filters: [ 
					//{ namePrefix: 'simple' } 
					//],
                });
                
                const server = await device.gatt.connect();
                connectionStatus.textContent = "已连接";
                connectionStatus.className = "status connected";
                connectBtn.disabled = true;
                disconnectBtn.disabled = false;
                getCharacteristicBtn.disabled = false;
                
                device.addEventListener('gattserverdisconnected', onDisconnected);
                
                // 初始化图表
                if (!chart) {
                    initChart();
                }
                
            } catch (error) {
                console.error("连接失败:", error);
                connectionStatus.textContent = "连接失败";
                connectionStatus.className = "status disconnected";
            }
        });
        
        // 断开连接
        disconnectBtn.addEventListener('click', () => {
            if (device && device.gatt.connected) {
                device.gatt.disconnect();
            }
        });
        
        // 断开连接处理
        function onDisconnected() {
            connectionStatus.textContent = "未连接";
            connectionStatus.className = "status disconnected";
            connectBtn.disabled = false;
            disconnectBtn.disabled = true;
            getCharacteristicBtn.disabled = true;
            startMonitorBtn.disabled = true;
            stopMonitorBtn.disabled = true;
            
            // 停止监控
            stopMonitoring();
            
            device = null;
            characteristic = null;
        }
        
        // 获取特征值
        getCharacteristicBtn.addEventListener('click', async () => {
            const serviceUuid = document.getElementById('service-uuid').value.trim();
            const characteristicUuid = document.getElementById('characteristic-uuid').value.trim();
            
            if (!serviceUuid || !characteristicUuid) {
                alert("请输入服务UUID和特征值UUID");
                return;
            }
            
            try {
                const server = await device.gatt.connect();
                const service = await server.getPrimaryService(serviceUuid);
                characteristic = await service.getCharacteristic(characteristicUuid);
                
                // 检查特征值属性
                const properties = [];
                if (characteristic.properties.read) properties.push('读');
                if (characteristic.properties.notify) properties.push('通知');
                
                alert(`特征值获取成功,支持: ${properties.join(', ')}`);
                
                // 启用监控按钮
                startMonitorBtn.disabled = false;
                
            } catch (error) {
                console.error("获取特征值失败:", error);
                alert("获取特征值失败,请检查UUID是否正确");
            }
        });
        
        // 开始监控
        startMonitorBtn.addEventListener('click', () => {
            startMonitoring();
            startMonitorBtn.disabled = true;
            stopMonitorBtn.disabled = false;
        });
        
        // 停止监控
        stopMonitorBtn.addEventListener('click', () => {
            stopMonitoring();
            startMonitorBtn.disabled = false;
            stopMonitorBtn.disabled = true;
        });
        
        // 替换原有的 startMonitoring 和 readCharacteristicValue 函数
function startMonitoring() {
    if (!characteristic) return;
    
    // 检查是否支持Notify
    if (!characteristic.properties.notify) {
        alert("该特征值不支持Notify特性");
        return;
    }
    
    // 启动通知
    characteristic.startNotifications()
        .then(() => {
            console.log("已启用通知");
            // 添加事件监听
            characteristic.addEventListener('characteristicvaluechanged', 
                handleNotifications);
            
            startMonitorBtn.disabled = true;
            stopMonitorBtn.disabled = false;
        })
        .catch(error => {
            console.error("启用通知失败:", error);
        });
}

// 停止监控修改为停止通知
function stopMonitoring() {
    if (characteristic) {
        characteristic.stopNotifications()
            .then(() => {
                characteristic.removeEventListener('characteristicvaluechanged',
                    handleNotifications);
                console.log("已停止通知");
                
                startMonitorBtn.disabled = false;
                stopMonitorBtn.disabled = true;
            })
            .catch(error => {
                console.error("停止通知失败:", error);
            });
    }
}

// 新增通知处理函数
function handleNotifications(event) {
    const value = event.target.value;
    // 根据实际数据格式解析 - 这里假设是单字节无符号整数
    const numericValue = value.getUint8(0);
    const timestamp = new Date().toLocaleTimeString();
    
    updateChart(numericValue, timestamp);
}
        
        // 读取特征值
        async function readCharacteristicValue() {
            if (!characteristic) return;
            
            try {
                const value = await characteristic.readValue();
                
                // 假设是单字节无符号整数
                const numericValue = value.getUint8(0);
                const timestamp = new Date().toLocaleTimeString();
                
                updateChart(numericValue, timestamp);
                
            } catch (error) {
                console.error("读取特征值失败:", error);
                stopMonitoring();
                startMonitorBtn.disabled = false;
                stopMonitorBtn.disabled = true;
            }
        }
        
        // 初始化
        initChart();
    </script>
</body>
</html>

运行的效果是这样的:
3.png

录制的时候,温度一直很稳定26度,看不出变化

Video_250704153107

更多回帖

×
发帖