【MAX30100】血氧心率检测仪DIY开源【STM32】
kmakise2021/08/08原创 仪器仪表 IP:河北
关键词
血氧饱和度心率

Github 项目链接

attachment icon MAX30100.zip 27.44MB ZIP 610次下载

发一个之前做的血氧心率检测的小东西,使用的是美信的MAX30100和30102

芯片框图:

upload_downloader_1628401817272_44436819.png

7VU1A@NAMVHFC3GUXN0DWB1.png

携带氧气的红血球能吸收较多红外光(850-1000nm),未携带氧气的红血球则是吸收较多的红光(600-750nm),通过这个特性就可以计算血液的血氧饱和度。

大概效果如下图:

2.jpg

1.jpg


数据处理方式:

首先配置传感器工作在FIFO模式下然后周期性读取FIFO,通过1024点的FFT变换得到频域数据,然后选择频带内的最高幅值为心率,通过对比两个幅值的幅度计算出血氧饱和度。通过平均其他频点的差值来标定两个波长数据。

数据波形图:

血氧1.jpg

QQ截图20210729191204.jpg

部分算法代码:

struct compx FFTBUF1[FFT_N+16];
struct compx FFTBUF2[FFT_N+16];
uint16_t g_fft_index = 0;         	 
BloodData g_blooddata = {0};				


void test(float data1,float data2)
{
		static uint8_t str[50];
		sprintf((char *)str,"%f,%f\r\n",data1,data2);
		HAL_UART_Transmit_DMA(&huart1,str,sizeof(str));
}

//血液检测信息更新
void blood_data_update(void)
{	
	static DC_FilterData dc1 = {.w = 0,.init = 0,.a = 0.8};
	static DC_FilterData dc2 = {.w = 0,.init = 0,.a = 0.8};
	
	static float data1buf[20];
	static uint8_t data1cur = 0;
	static float data2buf[20];
	static uint8_t data2cur = 0;
	
	uint16_t temp_num=0;
	uint16_t fifo_word_buff[1][2];

	temp_num = max30100_Bus_Read(INTERRUPT_REG);
	
	if (INTERRUPT_REG_A_FULL&temp_num)
	{
		max30100_FIFO_Read(0x05,fifo_word_buff,1); //read the hr and spo2 data form fifo in reg=0x05
		
		float data1 = dc_filter(fifo_word_buff[0][0],&dc1)+100.0;
		float data2 = dc_filter(fifo_word_buff[0][1],&dc2)+100.0;
		
		data1buf[data1cur] = data1;
		data2buf[data2cur] = data2;
		
		data1 = 0;
		data2 = 0;
		
		for(int i = 0;i < 20;i++)
		{
			data1 += data1buf[i];
			data2 += data2buf[i];
		}

		data1 /= 20;
		data2 /= 20;
		
		data1cur = (data1cur < 19) ? data1cur + 1 : 0;
		data2cur = (data2cur < 19) ? data2cur + 1 : 0;
		
//		fifo_word_buff[0][0] = data1;
//		fifo_word_buff[0][1] = data2;
		
//		test(data1,data2);
		
		g_blooddata.hb = data1 + 50;
		g_blooddata.hbo2 = data2 + 50;
		
		//将数据写入fft输入并清除输出
		for(int i = 0;i < 1;i++)
		{
			if(g_fft_index < FFT_N)
			{
				FFTBUF1[g_fft_index].real = fifo_word_buff[i][0];
				FFTBUF1[g_fft_index].imag= 0;
				FFTBUF2[g_fft_index].real = fifo_word_buff[i][1];
				FFTBUF2[g_fft_index].imag= 0;
				g_fft_index++;
			}
		}
		
		//信息更新标志位
		g_blooddata.update++;
		
	}
}
//血液信息转换
void blood_data_translate(void)
{	
	//缓冲区写入结束
	if(g_fft_index>=FFT_N)
	{
		//快速傅里叶变换
		FFT(FFTBUF1);
		FFT(FFTBUF2);
		
		//解平方
		for(int i = 0;i < FFT_N;i++) 
		{
			FFTBUF1[i].real = sqrtf(FFTBUF1[i].real * FFTBUF1[i].real + FFTBUF1[i].imag * FFTBUF1[i].imag);
			FFTBUF2[i].real = sqrtf(FFTBUF2[i].real * FFTBUF2[i].real + FFTBUF2[i].imag * FFTBUF2[i].imag);
		}
		
		//读取峰值点 10-100带通 频率范围30-292次/分钟
		uint16_t s1_max_index = find_max_num_index(FFTBUF1, 100);
		uint16_t s2_max_index = find_max_num_index(FFTBUF2, 100);
		
		//检查HbO2和Hb的变化频率是否一致
		if(s1_max_index == s2_max_index)
		{
			//心率计算
			uint16_t Heart_Rate = 60 * SAMPLES_PER_SECOND * 
														s2_max_index / FFT_N;
			
			g_blooddata.heart = Heart_Rate;
			
			//血氧含量计算
			float sp02_num = (FFTBUF1[s1_max_index].real * FFTBUF1[0].real)
											/(FFTBUF2[s1_max_index].real * FFTBUF2[0].real);
			
			sp02_num = sp02_num * SAMPLES_PER_SECOND + CORRECTED_VALUE;
			
			g_blooddata.SpO2 = sp02_num;
			
			//状态正常
			g_blooddata.state = BLD_NORMAL;
			

//			for(int i = 0;i < FFT_N;i++)
//			{
//				static uint8_t str[50];
//				sprintf((char *)str,"%f,%f\r\n\0",FFTBUF1[i].real,FFTBUF2[i].real);
//				HAL_UART_Transmit(&huart1,str,sizeof(str),20);
//			}
//			static uint8_t str[50];
//			sprintf((char *)str,"H:%d,S:%f\r\n",g_blooddata.heart,g_blooddata.SpO2 );
//			HAL_UART_Transmit(&huart1,str,sizeof(str),20);
			
		}
		else //数据发生异常
		{
			g_blooddata.heart = 0;
			g_blooddata.SpO2 	= 0;
			g_blooddata.state = BLD_ERROR;
		}
		
		g_fft_index = 0;
	}
}




来自:仪器与装备 / 仪器仪表动手实践:实验报导严肃内容:专业科普
4
 
5
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
虎哥
3年3个月前 IP:广东
895845

代码挺漂亮

引用
评论
1
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
zRed洲虹
3年3个月前 IP:四川
895859
引用虎哥发表于1楼的内容
代码挺漂亮

sticker 猫子虎哥,突然回复这么多贴

引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
kmakise作者
3年3个月前 IP:河北
895864
引用虎哥发表于1楼的内容
代码挺漂亮

感谢大佬夸奖

引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
niewne
2年8个月前 IP:广东
902464

现在美信的样片不好申请了

引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
上级专业
同级专业
kmakise
进士 机友 笔友
文章
3
回复
10
学术分
0
2021/08/07注册,3年3个月前活动

bilibili:XXXXXXXXXXXXXXXXXXXXXXXXXX/22908638 github:XXXXXXXXXXXXXXXXXX/kmakise

主体类型:个人
所属领域:无
认证方式:手机号
IP归属地:河北
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
支持的图片格式:jpg, jpeg, png
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}