心率采集,stm32采集心率,stm32心率采集,OLED实时显示,wifi上传心率,app显示心率,上位机显示心率 实现的功能: 1:STM32采集心率传感器数据 2:OLED实时显示心率数据和心率曲线 3:wifi上传心率数据 4:APP实时显示心率数据 5:C#上位机实时显示心率,心率数据存储,历史数据查看

搞过心率监测项目的朋友都知道,硬件选型直接决定开发难度。我这里选的是MAX30102传感器,这货自带算法处理能省不少事。不过实际用起来发现IIC通信偶尔会丢包,后来在初始化代码里加了重试机制才稳定:

void MAX30102_Init() {
    while(!HAL_I2C_IsDeviceReady(&hi2c1, MAX30102_ADDRESS, 3, 100)) {
        printf("传感器连接中...\n");
        HAL_Delay(200);
    }
    // 配置寄存器
    MAX30102_WriteReg(REG_MODE_CONFIG, 0x40); // 复位
    HAL_Delay(50);
    MAX30102_WriteReg(REG_SPO2_CONFIG, 0x47); // 采样率100Hz
}

OLED显示心率波形是个视觉活。128x64的屏幕要画动态曲线,我用了双缓冲机制——当前页显示时后台准备下一帧数据。注意这里用到了STM32的硬件加速,直接操作显存地址:

void draw_waveform(int new_value) {
    static uint8_t buffer[128];
    // 左移旧数据
    memmove(buffer, buffer+1, 127); 
    buffer[127] = 64 - new_value/4; // 数据归一化
    
    // 写入显存
    for(int x=0; x<128; x++) {
        ssd1306_DrawPixel(x, buffer[x], White);
    }
}

WiFi传输用ESP8266省时省力,但要注意JSON数据格式处理。这里用了个骚操作——直接内存操作拼接字符串,避免频繁调用printf耗资源:

char* build_json(int hr) {
    static char json[50];
    char *p = json;
    memcpy(p, "{\"hr\":", 6);
    p += 6;
    itoa(hr, p, 10);
    p += strlen(p);
    memcpy(p, "}", 1);
    return json;
}

上位机用C#搞了个带历史回放功能的界面。重点说下实时曲线绘制——用PictureBox双缓冲+队列缓存最近500个数据点。这里有个坑:直接使用Chart控件刷新率上不去,改用手动画线反而更流畅:

private void timer_Tick(object sender, EventArgs e) {
    if(dataQueue.Count > 0) {
        using (var g = Graphics.FromImage(bufferImage)) {
            g.DrawLine(Pens.Red, lastX, lastY, currentX, currentY);
            // 计算新坐标
            lastX = currentX;
            currentX = (currentX + 2) % pictureBox.Width;
        }
        pictureBox.Invalidate();
    }
}

调试时发现STM32的ADC采集和WiFi发送存在资源竞争,后来用DMA+双缓冲模式才解决。具体是把采样数据存到环形缓冲区,WiFi模块通过中断方式取数据,这样两边互不干扰。

心率采集,stm32采集心率,stm32心率采集,OLED实时显示,wifi上传心率,app显示心率,上位机显示心率 实现的功能: 1:STM32采集心率传感器数据 2:OLED实时显示心率数据和心率曲线 3:wifi上传心率数据 4:APP实时显示心率数据 5:C#上位机实时显示心率,心率数据存储,历史数据查看

存储方案本来想用SD卡,后来发现直接存到上位机的SQLite里更方便。C#端用EntityFramework做ORM,查询历史数据时能按时间范围筛选:

using (var db = new HeartRateContext()) {
    var records = db.Records
        .Where(r => r.Timestamp >= startDate && r.Timestamp <= endDate)
        .OrderBy(r => r.Timestamp)
        .ToList();
}

最后给Android端写了个极简APP,用WebSocket接收数据。重点说下心跳动画效果——用ValueAnimator实现缩放动画,配合心形图标缩放:

ValueAnimator anim = ValueAnimator.ofFloat(1f, 1.2f);
anim.addUpdateListener(animation -> {
    float scale = (float) animation.getAnimatedValue();
    heartView.setScaleX(scale);
    heartView.setScaleY(scale);
});
anim.setRepeatMode(ValueAnimator.REVERSE);
anim.start();

整个项目最难的不是技术实现,而是各模块的时间同步。比如OLED刷新率要控制在30fps以上才不卡顿,WiFi发送频率又不能太高否则会丢包,最后用定时器分配不同任务的时间片才搞定。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐