毕业设计记录-健康手环
0.设计功能及目标
老龄化社会的到来,让社会需要付出更多的人力和精力来照顾老去的一代,但是与社会上升的生产力需求形成了矛盾。结合信息化时代的特点,借助无线物联及传感器的解决方案,为老人的健康照料提供较为及时的信息反馈,解放一部分社会生产力,减轻一部分社会矛盾,也为老人及其家人提供老人较为及时、准确、较强参考性的健康信息。
- 老人的实时心率、血氧情况;
- 老人的体温情况;
- 老人的运动姿态(是否摔倒)
- QT上位机程序进行老人健康日志的生产和情况解析(参考)
- 后续功能待添加
1. 硬件方案设计
- 心率检测
1)目前市面上有四种较为成熟的心率检测方式
- 光电血氧法
利用携带氧气与不携带氧气的血红蛋白对不同光谱的吸收程度不同来进行测试,因为人体心脏泵血运输携带氧气的血红蛋白到达体表的过程,可以测试血红蛋白含氧量变化的情况来反应心率;
- 心电信号法
窦结心房进行收缩控制时候,生物电信号会向躯体四肢逐渐扩散,通过检测皮肤电极,可以对心脏的工作情况进行较为详细的了解;
- 生物阻抗法
由于血液的电阻抗低于其他生理组织,血液流过的时候呈现低阻,因此在血管切向测量电阻抗,就可以实时获得心率
- 动脉血压法
通过压迫动脉,动脉搜索扩张时候会发生压力情况的改变,可以通过压力传感采集获得心率情况;
2)介于便携性、舒适感以及成本,采用光电血氧进行心率和血氧采集的方案,采用max30102芯片。
美信生产的MAX30102是一个继承脉搏血氧和心率检测的生物传感器模块,通过IIC与外接口通讯,其内部有一个红外LED、红光LED、光电检测、光器件、温度传感。并且自带18位高精度ADC,本身还有FIFO,可以减轻一部分MCU负担。
STM32使用IIC协议访问MAX30102时序如下图,,具体IO口见后续程序。
MAX30102内部功能框图如下图,由图可见,RED和IR照射然后使用ADC进行数据采集,采集后的AD值经过数字滤波器进入数据寄存器,然后使用IIC进行数据采集,在转换AD值时,也可以采集温度值(用于校正)。
MAX30102内部全部寄存器如下图.
MAX30102FIFO最大可存72B的数据,其中存储数据如下图,第一字节存储IR值高八位,第二字节存储IR值的低八位,第三字节存储RED的高八位,第四字节存储RED的第八位,第五字节存储IR的高八位,依次类推。其中,数据始终左对齐.
工作模式有三种,分别是心率测试,血氧测试,以及混合测试,见下图。
IIC进行MAX30102器件访问时候,器件地址为0xAE,,写操作R/W=0,读操作R/W=1.具体格式如下图
官方指导电路:
网络上参考应用电路:
运动姿态检测
占坑,MPU6050;
体温检测
1)体温检测方式分为接触式和非接触式。
1.1)非接触类多为红外热感测量(体温枪)。
1.1.1)优点是:测温快速,测试部位不固定,可以在运动状态下进行测量。
1.1.2)缺点是容易受到环境热辐射和与测量物体间介质折射率影响,并且测试的直接结果是热辐射值,需要进行一个较复杂的发射率修正才能得到一个较为正确的值。并且由于其结构复杂的特性价格较高。
1.2)接触类可分为膨胀式(水银温度计)、压力式(压力式温度计)、热电偶式(热电偶测温仪)、电阻式(电子体温计)。
1.2.1)优点是测量稳定,测量精度较高,内部结构简单,价格便宜。
1.2.2)缺点是测量速度慢,结果滞后,测量有量程限制,容易受接触物体表面物质腐蚀,测量物体不能移动。
2)考虑到实际应用场景,选用了美信生产的MAX30205人体体温测量芯片。(找了些截图,但是上来发现似乎没有发布成功,就不做重复工作了,寄存器等具体见芯片手册)
在官网上发现一条采集建议:
无线通讯
占坑,ESP8266;
OLED模块
占坑,OLED0.96;
主控MCU
占坑,STM32F103Z8T6;
电源模块
占坑,DCDC-5v;
2. 软件方案设计
IIC协议
参考正点原子的iic协议文件,进行每个模块的配置
iic 功能函数
#include "siic.h"
#include "delay.h"
#define func_SCL_GPIO_CLOCK RCC_APB2Periph_GPIOC
#define func_SDA_GPIO_CLOCK RCC_APB2Periph_GPIOC
#define func_SCL_GPIO_PIN GPIO_Pin_12
#define func_SDA_GPIO_PIN GPIO_Pin_11
//IO操作函数
#define IIC_SCL PCout(12) //SCL
#define IIC_SDA PCout(11) //SDA
#define READ_SDA PCin(11) //输入SDA
//初始化IIC
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//RCC->APB2ENR|=1<<4;//先使能外设IO PORTC时钟
RCC_APB2PeriphClockCmd( func_SDL_GPIO_CLOCK, ENABLE );
GPIO_InitStructure.GPIO_Pin = func_SDL_GPIO_PIN|func_SDA_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
IIC_SCL=1;
IIC_SDA=1;
}
//产生IIC起始信号
void IIC_Start(void)
{
SDA_OUT(); //sda线输出
IIC_SDA=1;
IIC_SCL=1;
delay_us(4);
IIC_SDA=0;//START:when CLK is high,DATA change form high to low
delay_us(4);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}
//产生IIC停止信号
void IIC_Stop(void)
{
SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
delay_us(4);
IIC_SCL=1;
IIC_SDA=1;//发送I2C总线结束信号
delay_us(4);
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
SDA_IN(); //SDA设置为输入
IIC_SDA=1;delay_us(1);
IIC_SCL=1;delay_us(1);
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 1;
}
}
IIC_SCL=0;//时钟输出0
return 0;
}
//产生ACK应答
void IIC_Ack(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
//不产生ACK应答
void IIC_NAck(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
IIC_SCL=0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
IIC_SDA=(txd&0x80)>>7;
txd<<=1;
delay_us(2); //对TEA5767这三个延时都是必须的
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
delay_us(2);
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL=0;
delay_us(2);
IIC_SCL=1;
receive<<=1;
if(READ_SDA)receive++;
delay_us(1);
}
if (!ack)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}
IIC头文件:
#ifndef __SIIC_H
#define __SIIC_H
#include "sys.h"
//IO方向设置
#define SDA_IN() {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=8<<12;}
#define SDA_OUT() {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=3<<12;}
//IIC所有操作函数
void IIC_Init(void); //初始化IIC的IO口
void IIC_Start(void); //发送IIC开始信号
void IIC_Stop(void); //发送IIC停止信号
void IIC_Send_Byte(u8 txd); //IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC_Wait_Ack(void); //IIC等待ACK信号
void IIC_Ack(void); //IIC发送ACK信号
void IIC_NAck(void); //IIC不发送ACK信号
void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 IIC_Read_One_Byte(u8 daddr,u8 addr);
#endif