0 前言
🔥
这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。
为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天要分享的是
🚩 毕业设计 stm32单片机便携体检仪(源码+硬件+论文)
🥇学长这里给一个题目综合评分(每项满分5分)
- 难度系数:3分
- 工作量:3分
- 创新点:4分
🧿 项目分享:见文末!
1 主要功能
便携式采用STM32为核心控制模块,该核心模块包括STM32小系统,液晶屏触摸电路,SD卡储存电路,按键电路等常用的面向用户模块。在STM32核心模块周围外接各种测量生理参数的电路,包括身高模块、体重模块、血压模块、体温模块、肺活量模块、心电模块、血氧饱和度模块等。各模块受STM32控制独立工作,互不影响。STM32控制各个模块测量生理信号,再通过内部的AD采样口对各模块检测的电信号进行采集,并根据各个模块的测量要求处理数据,把最后得到的生理指标数据显示到液晶屏上并保存到SD卡中,以便以后复查或者提供给医生查看。
2 硬件设计(原理图)
3 核心软件设计
交互界面的设计
交互界面由底层显示驱动、界面跳转、使用提示帮助等部分组成。程序设计时由底层显示驱动构建出字符显示函数,通过字符显示函数显示ASCII码表字符。在字符显示函数基础上构建字符串显示函数,浮点数显示函数。将要显示的界面编写成相关功能模块,在又外部事件触发后调用相应界面,以实现界面的动态交互。
在本设计中,主要设计了欢迎界面、功能选择界面以及各个参数测量时的工作界面。在界面中加入了人性化的提示功能,用户可以通过在提示的指引下顺利完成对用户体检进行的过程,使用十分简便。
用户输入交互
用户键盘采用了矩阵式键盘,在程序设计时候通过矩阵扫描实现按键信息的录入。将录入的按键信息传人相关处理函数,由处理函数根据按键信息处理结果,进行相关界面切换和进行各个功能模块的工作的选择。
本设计中,采用定时器作为矩阵键盘功能的基础,通过扫描采集按键信息,通过延时消抖处理得出确切的按键信息,再将按键信息编码传入公共变量。由界面交互函数检测有按键录入即根据按键录入编码值进行功能模块调用,切换界面显示,切换显示提示。
其他功能模块程序设计
身高功能模块:程序设计中将定时器定时周期设置成为125us产生80kHz为周期的中断信号,当进入中断后,将超声波控制器输出电平标记值取反。在超声波发射使能后就将标记值传输到超声波端口,让超声波端口产生40kHz的超声波信号,在发射禁能后输出低电平,中止超声波信号发射。在模块工作时先使能超声波发送,并记下发送时刻,当接收到超声波中断后记下接收时* 刻,将两个时刻相减得出传输时间,通过计算得到测量的身高。
- 体重模块:通过A/D采样电阻应变片经差模放大器测出的值,在通过基准值计算出体重测量的结果。
- 体温模块:体温的测量直接通过将AD590得到的电压信号进行A/D采样后得到体温的温度值,经过计算后修正得到准确的体温值。
- 血氧饱和度模块:血氧饱和度测试程序,先使能650nm光波模块工作,A/D采样得到的硅光电池信号值。再使能940nm光模块工作,测量出相应硅光电池信号值。通过计算取得血氧饱和度。
- 肺活量模块:肺活量测量过程中将MPX5010DP测试的信号进行滤波处理后进行积分运算,通过程序计算出结果即是肺活量值。
- 血压模块:血压测量功能启动后,程序控制电机工作进行打气,然后缓慢放气,同时检测GXP550传输信号,依次测得血液的收缩压和舒张压。
- 心电模块:通过将测得的信号进行实时采用记录,并移送显示得出心电图,通过程序控制实时采样保证心电图准确。
关键代码
/** \file max30102.cpp ******************************************************
*
* Project: MAXREFDES117#
* Filename: max30102.cpp
* Description: This module is an embedded controller driver for the MAX30102
*
* Revision History:
*\n 1-18-2016 Rev 01.00 GL Initial release.
*\n
*/
#include "max30102.h"
#include "myiic.h"
#define max30102_WR_address 0xAE
bool maxim_max30102_write_reg(uint8_t uch_addr, uint8_t uch_data)
/**
* \brief Write a value to a MAX30102 register
* \par Details
* This function writes a value to a MAX30102 register
*
* \param[in] uch_addr - register address
* \param[in] uch_data - register data
*
* \retval true on success
*/
{
/* 第1步:发起I2C总线启动信号 */
i2c_Start();
/* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
i2c_SendByte(max30102_WR_address | I2C_WR); /* 此处是写指令 */
/* 第3步:发送ACK */
if (i2c_WaitAck() != 0)
{
goto cmd_fail; /* EEPROM器件无应答 */
}
/* 第4步:发送字节地址 */
i2c_SendByte(uch_addr);
if (i2c_WaitAck() != 0)
{
goto cmd_fail; /* EEPROM器件无应答 */
}
/* 第5步:开始写入数据 */
i2c_SendByte(uch_data);
/* 第6步:发送ACK */
if (i2c_WaitAck() != 0)
{
goto cmd_fail; /* EEPROM器件无应答 */
}
/* 发送I2C总线停止信号 */
i2c_Stop();
return true; /* 执行成功 */
cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */
/* 发送I2C总线停止信号 */
i2c_Stop();
return false;
}
bool maxim_max30102_read_reg(uint8_t uch_addr, uint8_t *puch_data)
/**
* \brief Read a MAX30102 register
* \par Details
* This function reads a MAX30102 register
*
* \param[in] uch_addr - register address
* \param[out] puch_data - pointer that stores the register data
*
* \retval true on success
*/
{
/* 第1步:发起I2C总线启动信号 */
i2c_Start();
/* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
i2c_SendByte(max30102_WR_address | I2C_WR); /* 此处是写指令 */
/* 第3步:发送ACK */
if (i2c_WaitAck() != 0)
{
goto cmd_fail; /* EEPROM器件无应答 */
}
/* 第4步:发送字节地址, */
i2c_SendByte((uint8_t)uch_addr);
if (i2c_WaitAck() != 0)
{
goto cmd_fail; /* EEPROM器件无应答 */
}
/* 第6步:重新启动I2C总线。下面开始读取数据 */
i2c_Start();
/* 第7步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
i2c_SendByte(max30102_WR_address | I2C_RD); /* 此处是读指令 */
/* 第8步:发送ACK */
if (i2c_WaitAck() != 0)
{
goto cmd_fail; /* EEPROM器件无应答 */
}
/* 第9步:读取数据 */
{
*puch_data = i2c_ReadByte(); /* 读1个字节 */
i2c_NAck(); /* 最后1个字节读完后,CPU产生NACK信号(驱动SDA = 1) */
}
/* 发送I2C总线停止信号 */
i2c_Stop();
return true; /* 执行成功 返回data值 */
cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */
/* 发送I2C总线停止信号 */
i2c_Stop();
return false;
}
bool maxim_max30102_init(void)
/**
* \brief Initialize the MAX30102
* \par Details
* This function initializes the MAX30102
*
* \param None
*
* \retval true on success
*/
{
if(!maxim_max30102_write_reg(REG_INTR_ENABLE_1, 0xc0)) // INTR setting
return false;
if(!maxim_max30102_write_reg(REG_INTR_ENABLE_2, 0x00))
return false;
if(!maxim_max30102_write_reg(REG_FIFO_WR_PTR, 0x00)) //FIFO_WR_PTR[4:0]
return false;
if(!maxim_max30102_write_reg(REG_OVF_COUNTER, 0x00)) //OVF_COUNTER[4:0]
return false;
if(!maxim_max30102_write_reg(REG_FIFO_RD_PTR, 0x00)) //FIFO_RD_PTR[4:0]
return false;
if(!maxim_max30102_write_reg(REG_FIFO_CONFIG, 0x6f)) //sample avg = 8, fifo rollover=false, fifo almost full = 17
return false;
if(!maxim_max30102_write_reg(REG_MODE_CONFIG, 0x03)) //0x02 for Red only, 0x03 for SpO2 mode 0x07 multimode LED
return false;
if(!maxim_max30102_write_reg(REG_SPO2_CONFIG, 0x2F)) // SPO2_ADC range = 4096nA, SPO2 sample rate (400 Hz), LED pulseWidth (411uS)
return false;
if(!maxim_max30102_write_reg(REG_LED1_PA, 0x17)) //Choose value for ~ 4.5mA for LED1
return false;
if(!maxim_max30102_write_reg(REG_LED2_PA, 0x17)) // Choose value for ~ 4.5mA for LED2
return false;
if(!maxim_max30102_write_reg(REG_PILOT_PA, 0x7f)) // Choose value for ~ 25mA for Pilot LED
return false;
return true;
}
bool maxim_max30102_read_fifo(uint32_t *pun_red_led, uint32_t *pun_ir_led)
/**
* \brief Read a set of samples from the MAX30102 FIFO register
* \par Details
* This function reads a set of samples from the MAX30102 FIFO register
*
* \param[out] *pun_red_led - pointer that stores the red LED reading data
* \param[out] *pun_ir_led - pointer that stores the IR LED reading data
*
* \retval true on success
*/
{
uint32_t un_temp;
uint8_t uch_temp;
*pun_ir_led = 0;
*pun_red_led = 0;
maxim_max30102_read_reg(REG_INTR_STATUS_1, &uch_temp);
maxim_max30102_read_reg(REG_INTR_STATUS_2, &uch_temp);
/* 第1步:发起I2C总线启动信号 */
i2c_Start();
/* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
i2c_SendByte(max30102_WR_address | I2C_WR); /* 此处是写指令 */
/* 第3步:发送ACK */
if (i2c_WaitAck() != 0)
{
printf("read fifo failed");
goto cmd_fail; /* EEPROM器件无应答 */
}
/* 第4步:发送字节地址, */
i2c_SendByte((uint8_t)REG_FIFO_DATA);
if (i2c_WaitAck() != 0)
{
goto cmd_fail; /* EEPROM器件无应答 */
}
/* 第6步:重新启动I2C总线。下面开始读取数据 */
i2c_Start();
/* 第7步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
i2c_SendByte(max30102_WR_address | I2C_RD); /* 此处是读指令 */
/* 第8步:发送ACK */
if (i2c_WaitAck() != 0)
{
goto cmd_fail; /* EEPROM器件无应答 */
}
un_temp = i2c_ReadByte();
i2c_Ack();
un_temp <<= 16;
*pun_red_led += un_temp;
un_temp = i2c_ReadByte();
i2c_Ack();
un_temp <<= 8;
*pun_red_led += un_temp;
un_temp = i2c_ReadByte();
i2c_Ack();
*pun_red_led += un_temp;
un_temp = i2c_ReadByte();
i2c_Ack();
un_temp <<= 16;
*pun_ir_led += un_temp;
un_temp = i2c_ReadByte();
i2c_Ack();
un_temp <<= 8;
*pun_ir_led += un_temp;
un_temp = i2c_ReadByte();
i2c_Ack();
*pun_ir_led += un_temp;
*pun_red_led &= 0x03FFFF; //Mask MSB [23:18]
*pun_ir_led &= 0x03FFFF; //Mask MSB [23:18]
/* 发送I2C总线停止信号 */
i2c_Stop();
return true;
cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */
/* 发送I2C总线停止信号 */
i2c_Stop();
return false;
}
bool maxim_max30102_reset()
/**
* \brief Reset the MAX30102
* \par Details
* This function resets the MAX30102
*
* \param None
*
* \retval true on success
*/
{
if(!maxim_max30102_write_reg(REG_MODE_CONFIG, 0x40))
return false;
else
return true;
}
4 实现效果
5 最后
包含内容
🧿 项目分享:见文末!