Heart Rate 13 Click with Clicker 4 for STM32F4

Published 4月 10, 2025

点击板

Heart Rate 13 Click
Oximeter 5 Click

开发板

Clicker 4 for STM32F4

编译器

NECTO Studio

微控制器单元

STM32F407VGT6

Heartbeat & Oxygen Monitor Solution

实时追踪心率和血氧饱和度,通过双传感器集成和实时图表可视化

你将学到和构建的内容

简介

Heartbeat & Oxygen Monitor 解决方案集成了 Heart Rate 13 ClickOximeter 5 Click,实现心率与血氧饱和度(SpO₂)的同步实时监测。该方案专为个人健康追踪、健身监控和健康应用而设计,利用脉搏和红外传感器准确采集生理数据,并通过 NECTO Studio 的 Plot 工具进行实时可视化显示。通过为心率和血氧分别提供清晰的图表,该方案为现代健康科技应用中的生命体征追踪提供了一种直观而高效的方法。

mikroBUS 1

Heart Rate 13 Click

Heart Rate 13 Click 是一款用于精确可靠生命体征监测的紧凑型扩展板。该板搭载来自 ams OSRAM 的 SFH 7074 生物监测传感器,并由 Analog Devices 的 ADPD1080 光电前端负责信号处理。SFH 7074 专为光电容积脉搏波描记法(PPG)应用优化,具备强大的光学信号、集成光屏障以防止串扰以及高静电保护能力。ADPD1080 则通过内建的干扰抑制功能和 14 位 ADC 确保在环境光条件下依然能够稳定准确地进行信号转换。与主控 MCU 的通信采用 I2C 接口,并提供额外的中断和时钟控制引脚。Heart Rate 13 Click 非常适用于可穿戴健康设备、健身追踪器以及医疗诊断类应用场景,可用于实时获取心率、血氧饱和度等重要生命体征数据。

Heart Rate 13 Click front-background image

mikroBUS 2

Oximeter 5 Click

Oximeter 5 Click 是一款适用于血氧饱和度测量的紧凑型扩展板。该板搭载来自 Analog Devices 的 MAX30102 模块,是一款集成式脉搏血氧仪与心率监测器。MAX30102 集成了内部 LED、光电探测器、光学元件以及具备环境光抑制功能的低噪声电子电路。它通过 mikroBUS™ 电源轨供电,内部 LED 使用 1.8V 单电源驱动,并通过标准 I2C 接口与主控通信。该模块支持通过软件关闭功能,在待机状态下电流为零,同时电源轨可始终保持上电状态。这款 Click 板™ 是用于光学脉搏血氧检测与健康监测应用的理想选择。

Oximeter 5 Click front-background image

功能概述

开发板

Clicker 4 for STM32F4 是一款紧凑型开发板,专为快速构建自定义设备而设计。它配备 STM32F407VGT6 MCU、四个 mikroBUS™ 插座(用于 Click board™ 连接)、电源管理等功能,使其成为快速应用开发的理想选择。核心采用 STM32F407VGT6 MCU,该芯片基于 Arm® Cortex®-M4 32 位处理器,运行频率高达 168 MHz,提供充足的计算能力以满足高负载任务需求。除了两个 1x20 排针接口外,四个 mikroBUS™ 插座可支持庞大且不断增长的 Click boards™ 生态系统。开发板上清晰标记的功能区域提供直观、易用的界面,加快开发进程。Clicker 4 不仅能加速原型设计,还可直接集成到项目中,无需额外的硬件修改。四个 4.2mm(0.165”)的安装孔位于角落,便于使用螺丝固定,实现简便安装。

Clicker 4 for STM32F4 front image

微控制器概述 

MCU卡片 / MCU

default

建筑

ARM Cortex-M4

MCU 内存 (KB)

10

硅供应商

STMicroelectronics

引脚数

100

RAM (字节)

100

一步一步来

项目组装

Clicker 4 for STM32F4 front image hardware assembly

首先,选择您的开发板 - Clicker 4 for STM32F4

Clicker 4 for STM32F4 front image hardware assembly
LTE IoT 5 Click front-background image hardware assembly
Calypso Click front-background image hardware assembly
Board mapper by product7 hardware assembly
Necto image step 2 hardware assembly
Necto image step 3 hardware assembly
Necto image step 4 hardware assembly
Necto image step 5 hardware assembly
NECTO Output Selection Step Image hardware assembly
Necto image step 6 hardware assembly
Clicker 4 for STM32F4 HA MCU Step hardware assembly
Necto image step 8 hardware assembly
Necto image step 9 hardware assembly
Necto image step 10 hardware assembly
Necto PreFlash Image hardware assembly

实时跟踪您的结果

应用程序输出

1. 应用程序输出 - 在调试模式下,“应用程序输出”窗口支持实时数据监控,直接提供执行结果的可视化。请按照提供的教程正确配置环境,以确保数据正确显示。

2. UART 终端 - 使用UART Terminal通过USB to UART converter监视数据传输,实现Click board™与开发系统之间的直接通信。请根据项目需求配置波特率和其他串行设置,以确保正常运行。有关分步设置说明,请参考提供的教程

3. Plot 输出 - Plot功能提供了一种强大的方式来可视化实时传感器数据,使趋势分析、调试和多个数据点的对比变得更加直观。要正确设置,请按照提供的教程,其中包含使用Plot功能显示Click board™读数的分步示例。在代码中使用Plot功能时,请使用以下函数:plot(insert_graph_name, variable_name);。这是一个通用格式,用户需要将“insert_graph_name”替换为实际图表名称,并将“variable_name”替换为要显示的参数。

软件支持

库描述

Heartbeat & Oxygen Monitor Solution 使用 NECTO Studio 开发,确保兼容 mikroSDK 的开源库和工具。该解决方案采用即插即用的设计,支持快速实施和测试,并与所有配备 mikroBUS™ 插座的开发板、入门套件和 mikromedia 板完全兼容。

示例描述
Heartbeat & Oxygen Monitor 解决方案集成了 Heart Rate 13 Click 和 Oximeter 5 Click,用于测量心率和血氧饱和度(SpO₂)。Heart Rate 13 Click 通过其传感器检测脉搏来提供心率数据,而 Oximeter 5 Click 使用基于红外光的传感器来测量血氧水平。收集到的数据通过 NECTO Studio 的 Plot 工具可视化,其中心率和 SpO₂ 值分别显示在两个独立的图表上,便于清晰区分。该解决方案非常适用于健康监测、健康追踪以及健身设备等应用。

关键功能:

  • heartrate13_init - 初始化 Heart Rate 13 Click,用于心率测量。

  • heartrate13_default_cfg - 使用默认设置配置 Heart Rate 13 Click,以实现心率检测。

  • heartrate13_get_pd_data - 使用默认设置配置 Heart Rate 13 Click,以实现心率检测。

  • oximeter5_init - 初始化 Oximeter 5 Click,用于 SpO₂ 测量。

  • oximeter5_default_cfg - 使用默认设置配置 Oximeter 5 Click,以采集 SpO₂ 和脉搏血氧数据。

  • oximeter5_get_oxygen_saturation - 从 Oximeter 5 Click 获取基于传感器数据计算的 SpO₂ 值。

  • oximeter5_check_interrupt - 检查是否有新数据可读取的中断信号。

  • plot - 在 Plot 应用中显示心率和 SpO₂ 的数值,用于实时可视化。

应用初始化
初始化序列为心率和 SpO₂ 监测配置系统:

1. 初始化 UART 日志记录器,用于调试。

2. 设置 Heart Rate 13 Click 以进行心率测量。

3. 初始化 Oximeter 5 Click 用于 SpO₂ 测量。

4. 准备传感器数据采集缓冲区,并进行初始读取以确保正常运行。

若任一初始化步骤失败,系统将记录错误并停止运行以避免异常行为。

应用任务
主循环持续执行以下操作:

1. 等待来自 Heart Rate 13 Click 和 Oximeter 5 Click 的数据

2. 读取 Heart Rate 13 Click 的心率数据和 Oximeter 5 Click 的 SpO₂ 数据。

3. 在 Plot 工具中分别在两个图表上显示心率和 SpO₂ 值。

4. 等待用户将手指放在相应传感器上以开始数据采集。

5. 使用最新测量值更新图表。

6. 重复此过程,持续实时监测心率和 SpO₂ 数值。

开源

代码示例

完整的应用程序代码和一个现成的项目可以通过NECTO Studio包管理器直接安装到NECTO Studio 应用程序代码也可以在MIKROE的GitHub账户中找到。

/*!
 * Solution Name: Heartbeat & Oxygen Monitor
 *
 * # Description
 * This example demonstrates the use of Heart Rate 13 Click and
 * Oximeter 5 Click boards for measuring heart rate and SpO2 values,
 * which can be visualized on the Plot application.
 *
 * The demo application is composed of three sections:
 *
 * ## Application Init
 * Initializes the drivers for both the Heart Rate 13 Click and
 * Oximeter 5 Click, performs the default configurations for heart rate
 * and SpO2 measurements, and prepares the necessary buffers for data
 * acquisition.
 *
 * ## Application Task
 * The task waits for data from both Click boards, then reads the
 * heart rate and SpO2 measurements, and displays them on the Plot
 * tool. The user can visualize heart rate on one chart and SpO2 on another
 * chart after creating separate charts within Plot. The heart rate
 * data is visualized upon placing a finger on the Heart Rate 13 Click's
 * sensor, and the SpO2 data is visualized by placing 
 * a finger on the Oximeter 5 Click's sensor. 
 * 
 * ## Plot Functionality
 * To visualize the data:
 * 1. Run the debug feature by pressing F9 on the keyboard.
 * 2. Navigate to the Plot feature by pressing `CTRL` + `F9`.
 * 3. Press F6 to start the application.
 * 4. First, place a finger on the Heart Rate 13 Click`s sensor to visualize
 *    the heart rate on the plot.
 * 5. Next, place a finger on the Oximeter 5 Click`s sensor to visualize
 *    the SpO2 value on the plot. 
 *    Create a new chart by selecting the 'Create separate charts' option
 *    in Plot to see both heart rate and SpO2 values on distinct charts.
 *
 * @note
 * It is important to create separate charts for the heart rate and SpO2
 * measurements in the Plot tool to clearly distinguish between
 * the two readings.
 *
 * Author: Branko Jaksic
 * Date: April, 2025
 *
 */

// ------------------------------------------------------------------- INCLUDES
#include "log.h"
#include "board.h"
#include "oximeter5.h"
#include "heartrate13.h"

// ------------------------------------------------------------------ VARIABLES
static log_t logger;
static oximeter5_t oximeter5;
static heartrate13_t heartrate13;

// Oximeter 5 Click variables
static uint32_t aun_ir_buffer[ 100 ];
static uint32_t aun_red_buffer[ 100 ];
static uint32_t un_min, un_max, un_prev_data, un_brightness;
static float f_temp;
static uint8_t n_spo2;

// ------------------------------------------------------ APPLICATION FUNCTIONS
void application_init ( void ) 
{
    log_cfg_t log_cfg;  /**< Logger config object. */
    heartrate13_cfg_t heartrate13_cfg;  /**< Click config object. */
    oximeter5_cfg_t oximeter5_cfg;  /**< Click config object. */

    /** 
     * Logger initialization.
     * Default baud rate: 115200
     * Default log level: LOG_LEVEL_DEBUG
     * @note If USB_UART_RX and USB_UART_TX 
     * are defined as HAL_PIN_NC, you will 
     * need to define them manually for log to work. 
     * See @b LOG_MAP_USB_UART macro definition for detailed explanation.
     */
    LOG_MAP_USB_UART( log_cfg );
    log_init( &logger, &log_cfg );
    log_info( &logger, " Application Init " );

    // Heart Rate 13 Click initialization.
    heartrate13_cfg_setup( &heartrate13_cfg );
    HEARTRATE13_MAP_MIKROBUS( heartrate13_cfg, MIKROBUS_1 );
    if ( I2C_MASTER_ERROR == heartrate13_init( &heartrate13,
                                               &heartrate13_cfg ) ) 
    {
        log_error( &logger, " Communication init." );
        for ( ; ; );
    }

    if ( HEARTRATE13_ERROR == heartrate13_default_cfg ( &heartrate13 ) )
    {
        log_error( &logger, " Default configuration." );
        for ( ; ; );
    }

    // Oximeter 5 Click initialization.
    oximeter5_cfg_setup( &oximeter5_cfg );
    OXIMETER5_MAP_MIKROBUS( oximeter5_cfg, MIKROBUS_2 );
    if ( I2C_MASTER_ERROR == oximeter5_init( &oximeter5, &oximeter5_cfg ) ) 
    {
        log_error( &logger, " Communication init." );
        for ( ; ; );
    }
    Delay_ms ( 100 );

    if ( OXIMETER5_ERROR == oximeter5_default_cfg ( &oximeter5 ) )
    {
        log_error( &logger, " Default configuration." );
        for ( ; ; );
    }
    Delay_ms ( 100 ); 

    un_brightness = 0;
    un_min = 0x3FFFF;
    un_max = 0;

    for ( uint8_t n_cnt = 0; n_cnt < 100; n_cnt++ )
    {
        while ( oximeter5_check_interrupt( &oximeter5 ) == OXIMETER5_INTERRUPT_ACTIVE );

        oximeter5_read_sensor_data( &oximeter5,
                                    &aun_red_buffer[ n_cnt ],
                                    &aun_ir_buffer[ n_cnt ] );

        if ( un_min > aun_red_buffer[ n_cnt ] )
        {
            un_min = aun_red_buffer[ n_cnt ];
        }

        if ( un_max < aun_red_buffer[ n_cnt ] )
        {
            un_max = aun_red_buffer[ n_cnt ];
        }
    }

    oximeter5_get_oxygen_saturation( &aun_ir_buffer[ 0 ], 100,
                                     &aun_red_buffer[ 0 ], &n_spo2 );
    log_info( &logger, " Application Task " );
    Delay_ms ( 100 ); 
}

void application_task ( void ) 
{
    heartrate13_pd_data_t pd_data;

    // Switch I2C communication to Heart rate 13 Click.
    i2c_master_set_slave_address(&heartrate13.i2c, heartrate13.slave_address);

    if ( HEARTRATE13_OK == heartrate13_get_pd_data ( &heartrate13, &pd_data ) )
    {
        log_printf ( &logger, "%u\r\n", pd_data.pd3 );
        plot("HEART RATE: ", pd_data.pd3);
    }

    // Switch I2C communication to Oximeter 5 Click.
    i2c_master_set_slave_address(&oximeter5.i2c, oximeter5.slave_address);

    for ( uint8_t n_cnt = 25; n_cnt < 100; n_cnt++ )
    {
        aun_red_buffer[ n_cnt - 25 ] = aun_red_buffer[ n_cnt ];
        aun_ir_buffer[ n_cnt - 25 ] = aun_ir_buffer[ n_cnt ];

        if ( un_min > aun_red_buffer[ n_cnt ] )
        {
            un_min = aun_red_buffer[ n_cnt ];
        }
      
        if ( un_max < aun_red_buffer[ n_cnt ] )
        {
            un_max=aun_red_buffer[n_cnt];
        }
    }

    for ( uint8_t n_cnt = 75; n_cnt < 100; n_cnt++ )
    {
        un_prev_data = aun_red_buffer[ n_cnt - 1 ];
        while ( oximeter5_check_interrupt( &oximeter5 ) == OXIMETER5_INTERRUPT_ACTIVE ); 

        oximeter5_read_sensor_data( &oximeter5,
                                    &aun_red_buffer[ n_cnt ],
                                    &aun_ir_buffer[ n_cnt ] );

        if ( aun_red_buffer[ n_cnt ] > un_prev_data )
        {
            f_temp = aun_red_buffer[ n_cnt ]-un_prev_data;
            f_temp /= ( un_max - un_min );
            f_temp *= MAX_BRIGHTNESS;
            f_temp = un_brightness - f_temp;
        
            if ( f_temp < 0 )
            {
                un_brightness = 0;
            }
            else
            {
                un_brightness = ( uint32_t ) f_temp;
            }
        }
        else
        {
            f_temp = un_prev_data - aun_red_buffer[ n_cnt ];
            f_temp /= ( un_max - un_min );
            f_temp *= MAX_BRIGHTNESS;
            un_brightness += ( uint32_t ) f_temp;

            if ( un_brightness > MAX_BRIGHTNESS )
            {
                un_brightness = MAX_BRIGHTNESS;
            }
        }

        if ( ( OXIMETER5_OK == oximeter5_get_oxygen_saturation( &aun_ir_buffer[ 0 ],
                                                                100,
                                                                &aun_red_buffer[ 0 ],
                                                                &n_spo2 ) ) )
        {
            if ( aun_ir_buffer[n_cnt] > 10000  ) 
            {
                log_printf( &logger, "\tIR    : %lu \r\n", aun_ir_buffer[ n_cnt ] );
                log_printf( &logger, "\tRED   : %lu \r\n", aun_red_buffer[ n_cnt ] ); 
                log_printf( &logger, "- - - - - - - - - - - - - - -\r\n" );
                log_printf( &logger, "\tSPO2  : %d %%\r\n", ( uint16_t ) n_spo2 );
                log_printf( &logger, "-----------------------------\r\n" );
                plot("SpO2 (0% - 100%): ", ( uint16_t ) n_spo2 );
                Delay_ms ( 100 );       
            }
            else
            {
                Delay_ms ( 10 );      
            }
        }
    }
}

int main ( void ) 
{
    /* Do not remove this line or clock might not be set correctly. */
    #ifdef PREINIT_SUPPORTED
    preinit();
    #endif

    application_init( );

    for ( ; ; ) 
    {
        application_task( );
    }

    return 0;
}

// ------------------------------------------------------------------------ END

额外支持

资源

喜欢这个项目吗?

'购买此套件' 按钮会直接带您进入购物车,您可以在购物车中轻松添加或移除产品。