• 【毕业设计】基于Stm32的便携体测仪(心率 体温) - 单片机 嵌入式 物联网



    0 前言

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。

    为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天要分享的是

    🚩 基于Stm32的便携体测仪

    🥇学长这里给一个题目综合评分(每项满分5分)

    • 难度系数:4分
    • 工作量:4分
    • 创新点:3分

    🧿 选题指导, 项目分享:

    https://gitee.com/dancheng-senior/project-sharing-1/blob/master/%E6%AF%95%E8%AE%BE%E6%8C%87%E5%AF%BC/README.md


    1 简介

    本项目基于云平台+APP+设备端的身体参数测试系统,利用脉搏传感器、红外传感器、微弱信号检测电路等实现人体参数的采集,数据通过无线网或其他方式上传云端存储,并提供网页端交互界面,为用户构建一种人体参数管理平台。

    2 主要器件

    系统的硬件部分由MCU、心率传感器、温度传感器、电源、蓝牙模块、WiFi模块构成。

    • ESP8266
    • STM32F103C8T6
    • PL2303
    • LCD12864
    • LM1117等

    3 实现效果

    系统工作时,通过心率传感器和温度传感器分别采集心率和体温的原始AD信号,通过相应算法计算得出心率与温度值,通过WiFi上传到云服务器端。云服务器端对传输的数据进行处理、存储、分析,同时也通过对数据的分析进行预警和提示,用户只需登录到相应网页或手机APP即可查看自己或家人的实时与历史数据,另外本系统也提供了定位功能,用户可在地图上查看测量终端所在的位置。
    在这里插入图片描述
    在这里插入图片描述

    4 设计原理

    4.2 硬件部分

    MCU系统电路
    本系统采用STM32103C8T6,其作为主控芯片一方面对传感器数据进行采集,另一方面将数据通过算法进行处理,并转发到云服务器,因此在电路设计时将两个ADC接口接入传感器。对于STM32系统,其必要组成部分还包括了启动模式选择电路、晶振复位电路等,在设计时还我另外加入了指示灯与按键作为备用。STM32系统电路如图4所示。STM32的供电电压以及心率、温度传感器的电压都是3.3V,因此如果采用5V电压供电则还需要进行电压转换,本系统采用了LDO稳压器LM1117将5V转为3.3V。对于电源和开关的部分,系统采用MICO USB接口进行供电和下载程序,该部分电路如图所示。
    在这里插入图片描述

    USB转串口电路
    利用USB作为系统程序下载接口,需要对其电平进行转换才能与STM32的串口进行通信,本系统采用了CP2102作为转换芯片,CP2102集成度高,内置USB2.0全速功能控制器、USB收发器、晶体振荡器、EEPROM及异步串行数据总线(UART),支持调制解调器全功能信号,无需任何外部的USB器件。CP2102与其他USB-UART转接电路的工作原理类似,通过驱动程序将PC的USB口虚拟成COM口以达到扩展的目的。该部分的电路设计图如图所示。
    在这里插入图片描述

    WiFi模块
    WiFi模块采用了ESP8266模块,当使用该模块时需要设计其外部电路,包括电源电路、复位电路、模式选择电路等部分,设计完成的电路图如图所示。
    在这里插入图片描述

    4.3 软件部分

    主芯片程序设计
    STM32的程序设计基于RT-Thread行开发。系统初始化之外,在主程序中,完成如下功能:

    • 通过内部AD接口对传感器的AD数据进行采集;
    • 将数据通过算法进行处理;
    • 将处理好的数据打包提供WiFi模块发送给服务器;
    • 喂狗。

    按照以上4点功能进行设计,程序工作流程图如图所示
    在这里插入图片描述
    心率采集算法
    心率采集算法的目标是找到瞬间心跳的连续时刻,并测量两者之间的时间间隔(IBI)。通过遵循PPG波形的可预测的形状和模式,我们能够做到这一点。当心脏将血液泵入人体时,每次搏动都会有一个脉冲波(有点像冲击波)沿着所有的动脉传到脉搏传感器附着的毛细血管组织的末端。实际的血液循环比脉搏波传播慢得多。从下图所示的PPG上的T点开始跟踪事件。当脉搏波在传感器下方通过时,信号值迅速上升,然后信号回落到正常点。有时候,双向切口(向下尖峰)比其他更明显,但通常信号在下一个脉冲波冲洗之前稳定到背景噪声。由于波浪是重复的和可预测的,可以选择几乎任何可识别的特征作为参考点,比如峰值,并通过在每个峰值之间的时间计算心率。然而,这可能会从二分的切口中错误地读取,并且对基线噪声可能也是不准确的。理想情况下,想要找到心脏跳动的瞬间时刻需要准确的BPM计算,心率变异性(HRV)研究和脉搏传递时间(PTT)测量。
    在这里插入图片描述
    通过使用定时器中断,我们的节拍查找算法在后台运行,并自动更新变量值。整体的算法流程图如图所示

    在这里插入图片描述

    5 部分代码

    static int rt_hw_ssd1306_config(void)
    {
        /* config spi */
        {
            struct rt_spi_configuration cfg;
            cfg.data_width = 8;
            cfg.mode = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB;
      cfg.max_hz = 20 * 1000 *1000; /* 20M,SPI max 42MHz,ssd1306 4-wire spi */
      rt_spi_configure(&spi_dev_ssd1306, &cfg);
        }
    
    
    
    void set_column_address(rt_uint8_t start_address, rt_uint8_t end_address)
    {
        ssd1306_write_cmd(0x15);              //   Set Column Address
        ssd1306_write_data(start_address);    //   Default => 0x00 (Start Address)
        ssd1306_write_data(end_address);      //   Default => 0x7F (End Address)
    }
        void set_row_address(rt_uint8_t start_address, rt_uint8_t end_address)
    {
        ssd1306_write_cmd(0x75);              //   Set Row Address
        ssd1306_write_data(start_address);    //   Default => 0x00 (Start Address)
        ssd1306_write_data(end_address);      //   Default => 0x7F (End Address)
    }
    
    
    
    
    
     /* polling mode */
                  if (dev->flag & RT_DEVICE_FLAG_STREAM)
                  {
                         /* stream mode */
                         while (size)
                         {
                                if (*ptr == '\n')
                                {
                                       while (!(uart->uart_device->SR & USART_FLAG_TXE));
                                       uart->uart_device->DR = '\r';
                  /* interrupt mode Tx, does not support */
                  RT_ASSERT(0);
                                }   while (!(uart->uart_device->SR & USART_FLAG_TXE));
                                uart->uart_device->DR = (*ptr & 0x1FF);   ++ptr; --size;
                         }
                  }
                  else
                  {
                         /* write data directly */
                         while (size)
                         {
                                while (!(uart->uart_device->SR & USART_FLAG_TXE));
                                uart->uart_device->DR = (*ptr & 0x1FF);   ++ptr; --size;
                         }
                  }
    
    
    
    
    
    rt_err_t rt_hw_serial_register(rt_device_t device, const char* name, rt_uint32_t flag, struct stm32_serial_device *serial)
    {
           RT_ASSERT(device != RT_NULL);   if ((flag & RT_DEVICE_FLAG_DMA_RX) ||
                  (flag & RT_DEVICE_FLAG_INT_TX))
           {
                  RT_ASSERT(0);
           }   device->type              = RT_Device_Class_Char;
           device->rx_indicate = RT_NULL;
           device->tx_complete = RT_NULL;
           device->init               = rt_serial_init;
           device->open             = rt_serial_open;
           device->close             = rt_serial_close;
           device->read             = rt_serial_read;
           device->write            = rt_serial_write;
           device->control = rt_serial_control;
           device->user_data      = serial;   /* register a character device */
           return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR | flag);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78

    6 最后

  • 相关阅读:
    从老王三角到忍狠美三字诀
    浅析多服务在分布式系统下多事务通信处理机制方案
    Android HAL - hidl-gen
    《QEMU/KVM源码分析与应用》读书笔记3 —— 第一章 QEMU与KVM概述
    《数据结构》顺序表ArrayList
    如何使用 Nginx 创建临时和永久重定向
    java string.split(“,“)方法的坑
    C++---红黑树介绍及简单实现
    前端学习——初识jQuery
    【分享】“有赞商城“ 在集简云平台集成应用的常见问题与解决方案
  • 原文地址:https://blog.csdn.net/m0_71572576/article/details/126365565