当前位置: 首页 > ai >正文

基于FPGA的血氧和心率蓝牙监测系统设计-max30102

文章目录

  • 前言
  • 一、芯片手册分析
  • 二、串口接口的血氧模块使用讲解
  • 三、仿真时序分析
  • 四、代码分析
    • 1.蓝牙数据发送
    • 2.心率数据采集
  • 总结


前言

本产品的核心是基于心率传感器的智能心率监测系统,通过硬件端的心率传感器获取人体的心率和血氧浓度等信息,并进行实时监测。APP端与硬件端通过蓝牙进行通信配对,显示用户的实时心率数据并提供曲线图展示,同时也支持异常数据查询和历史数据查询功能。 在云平台端,数据流能够实时展示,并且提供数据分析和处理,方便用户更加深入地了解自身的身体状况。
模块链接如下,这个模块是一个串口接口的。
在这里插入图片描述
题外话:
最开始用的是这个模块,跟上面两个本质上是一样的,不过这个模块做的是iic的接口,我也通过芯片手册对寄存器进行了相关的配置,发送命令等等,但是最终读取出来的6字节数据为0,一直读不出数据,检查时序也没找到问题,后来换了串口接口的模块,就没什么问题。因为时间比较紧张,所以也没深究问题到底出现在哪里,反正我觉得iic通信是没什么问题的。
在这里插入图片描述
当时iic通信截的图:

在这里插入图片描述
在这里插入图片描述
iic相关的驱动以及发送数据都是正确的,但是往里面读数据就是读不出来。
就当重新学习了一些iic通信吧。

一、芯片手册分析

其实按理来说,做iic通信是需要进行芯片手册阅读,确定设备地址,字节地址,控制指令等等,进而才能完成寄存器的配置以及读取数据的操作。
下面这个图是人家芯片手册给出来的最终读取数据的一个时序图吧,因为数据是6个字节,前面3个字节是心率,后面3个字节是血氧。但是我实际读的时候时序一致,但是没数据。简单记录一下吧,做过的大佬可以评论交流一下。
在这里插入图片描述
设备地址:
在这里插入图片描述
写数据:0xAE 读数据:0xAF

字节地址:0x00-0x0a

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
相关操作都阅读上面可以知道。

二、串口接口的血氧模块使用讲解

上面的都是iic通信的相关描述,后来我换了串口接口的血氧模块,就直接用指令集就可以了。
在这里插入图片描述
其实就用两条,一条是读心率,一条是读血氧。

三、仿真时序分析

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如图所示,图注就可以看懂了。

四、代码分析

vivado和Quartus版本都有,代码通用。
在这里插入图片描述

1.蓝牙数据发送

module Bluetooth_data(input           clk,input           rst_n,input  [3 :0]   HEART_data_h,input  [3 :0]   HEART_data_l,input  [3 :0]   SPO2_data_h,input  [3 :0]   SPO2_data_l,input           uart_tx_done,input  [7 :0]   uart_rx_data,input           uart_rx_done,output  reg             uart_tx_en,output  reg     [7:0]   uart_tx_data);parameter IDLE              = 4'd0;parameter WAIT_1s           = 4'd1;parameter SEND              = 4'd2;parameter OVER              = 4'd3;parameter count_max              = 32'd50000000;//spo2:23.6  ---->  74 65 6D 70 3A 32 33 2E 36 0d 0a//hert:23.6  ---->  68 75 6D 69 3A 32 33 2E 36 0d 0areg  [87:0]   cmd_temp    ={8'h53,8'h50,8'h4F,8'h32,8'h3a,8'h32,8'h33,8'h2e,8'h30,8'h0d,8'h0a};reg  [87:0]   cmd_humi    ={8'h48,8'h45,8'h41,8'h52,8'h54,8'h32,8'h33,8'h2e,8'h30,8'h0d,8'h0a};reg	[3: 0]	state;reg	[31:0]	count;reg  [5 :0]   tx_count;reg	[1: 0]	tx_en_count;reg           uart_tx_en_temp;reg	[1 :0]	change_count;wire	[7:0]		HEART_data_1;wire	[7:0]		HEART_data_2;wire	[7:0]		SPO2_data_1;wire	[7:0]		SPO2_data_2;
 assign HEART_data_1=8'h30+HEART_data_h;assign HEART_data_2=8'h30+HEART_data_l;assign SPO2_data_1=8'h30+SPO2_data_h;assign SPO2_data_2=8'h30+SPO2_data_l;
  //����״̬tx_dataalways @(posedge clk or negedge rst_n) beginif(!rst_n) beginuart_tx_data <= 8'd0;endelse if(change_count==2'd0)beginif((state==SEND) && tx_count<8'd5 ) beginuart_tx_data <= cmd_temp[87 - tx_count *8 -:8];endelse if((state==SEND) && tx_count==8'd5 ) beginuart_tx_data <= SPO2_data_1;endelse if((state==SEND) && tx_count==8'd6 ) beginuart_tx_data <= SPO2_data_2;endelse if((state==SEND) && tx_count==8'd7 ) beginuart_tx_data <= cmd_temp[87 - tx_count *8 -:8];endelse if((state==SEND) && tx_count==8'd8 ) beginuart_tx_data <= 8'h30;endelse if((state==SEND) && tx_count<8'd11 ) beginuart_tx_data <= cmd_temp[87 - tx_count *8 -:8];end	endelse if(change_count==2'd1)beginif((state==SEND) && tx_count<8'd5 ) beginuart_tx_data <= cmd_humi[87 - tx_count *8 -:8];endelse if((state==SEND) && tx_count==8'd5 ) beginuart_tx_data <= HEART_data_1;endelse if((state==SEND) && tx_count==8'd6 ) beginuart_tx_data <= HEART_data_2;endelse if((state==SEND) && tx_count==8'd7 ) beginuart_tx_data <= cmd_humi[87 - tx_count *8 -:8];endelse if((state==SEND) && tx_count==8'd8 ) beginuart_tx_data <= 8'h30;endelse if((state==SEND) && tx_count<8'd11 ) beginuart_tx_data <= cmd_humi[87 - tx_count *8 -:8];end	endend
  //tx_en timealways @(posedge clk or negedge rst_n) beginif(!rst_n) begintx_en_count <= 2'b0;endelse if((state==SEND) && tx_en_count<2'd1 && tx_count==8'd0) begintx_en_count <=tx_en_count+ 1'd1;endelse if((state==SEND) && tx_en_count==2'd1 && tx_count==8'd0) begintx_en_count <= 2'd3;endelse if(state==OVER)begintx_en_count <= 2'd0;endelse begintx_en_count <= tx_en_count;end
end//����״̬tx_countalways @(posedge clk or negedge rst_n) beginif(!rst_n) begintx_count <= 8'd0;endelse if(state==SEND) beginif(uart_tx_done==1'd1)tx_count <= tx_count+1'b1;endelse begintx_count <= 8'd0;end
end
  //����״̬data_tx_enalways @(posedge clk or negedge rst_n) beginif(!rst_n) beginuart_tx_en_temp <= 1'b0;uart_tx_en <= uart_tx_en_temp;endelse if((state==SEND ) && tx_en_count==1) beginuart_tx_en_temp <= 1'b1;uart_tx_en <= uart_tx_en_temp;endelse if((state==SEND ) && tx_count<8'd10 && uart_tx_done==1)beginuart_tx_en_temp <= 1'b1;uart_tx_en <= uart_tx_en_temp;endelse beginuart_tx_en_temp <= 1'b0;uart_tx_en <= uart_tx_en_temp;endend//state go always @(posedge clk or negedge rst_n) beginif(!rst_n) begincount <= 32'd0;endelse if(state == WAIT_1s && count < count_max)begincount <= count + 32'd1;endelse if(state == WAIT_1s && count == count_max)begincount <= 32'd0;endelse begincount <= count;endend
 //state go always @(posedge clk or negedge rst_n) beginif(!rst_n) beginstate <= IDLE;change_count<=2'd0;endelse begincase(state)IDLE:beginstate<=WAIT_1s;endWAIT_1s:beginif(count==count_max)beginstate<=SEND;endelse beginstate<=WAIT_1s;endendSEND:beginif(tx_count==6'd11)beginstate <= OVER;endelse beginstate <= SEND;endendOVER:beginstate <= IDLE;if(change_count<2'd1)beginchange_count<=change_count+2'd1;endelse if(change_count==2'd1)beginchange_count<=2'd0;endenddefault:state <= IDLE;endcaseendendendmodule

2.心率数据采集

module max13012_data(input           clk,input           rst_n,input           key_rst,input           key_data,input           uart_tx_done,input  [7:0]    uart_rx_data,input           uart_rx_done,output  reg     [7:0]   HEART_data_1,output  reg     [7:0]   HEART_data_2,output  reg     [7:0]   SPO2_data_1,output  reg     [7:0]   SPO2_data_2,output  reg             uart_tx_en,output  reg     [7:0]   uart_tx_data);parameter time_20ms         = 20'd1000000;parameter IDLE              = 8'd0;parameter RST               = 8'd1;parameter HEART             = 8'd2;parameter WAK_HEART         = 8'd3;parameter SPO2              = 8'd4;parameter WAK_SPO2          = 8'd5;parameter OVER              = 8'd6;//10��reg     [79:0]   cmd_RESET         ={8'h41,8'h54,8'h2B,8'h52,8'h45,8'h53,8'h45,8'h54,8'h0D,8'h0A};//"AT+RESET\r\n"reg     [79:0]   cmd_HEATR         ={8'h41,8'h54,8'h2B,8'h48,8'h45,8'h41,8'h52,8'h54,8'h0D,8'h0A};//"AT+HEART\r\n"//9��reg     [71:0]   cmd_SPO2          ={8'h41,8'h54,8'h2B,8'h53,8'h50,8'h4f,8'h32,8'h0D,8'h0A};//"AT+SPO2\r\n"reg     [7:0]    state;reg     [7:0]    tx_count;reg     [7:0]    rx_count;reg              uart_tx_en_temp;reg     [1:0]    tx_en_count;reg     [19:0]   wait_count;
//rx_Data always @(posedge clk or negedge rst_n) beginif(!rst_n) beginHEART_data_1 <= 8'd0;HEART_data_2 <= 8'd0;SPO2_data_1<=8'd0;SPO2_data_2<=8'd0;rx_count<=8'd0;endelse if(state==WAK_HEART)beginif(uart_rx_done==1'b1 && uart_rx_data==8'h3d && rx_count==8'd0)beginrx_count<=rx_count + 1'b1;endelse if(uart_rx_done==1'b1 && rx_count==8'd1)beginrx_count<=rx_count + 1'b1;HEART_data_1<=uart_rx_data;endelse if(uart_rx_done==1'b1 && rx_count==8'd2)beginrx_count<=rx_count + 1'b1;HEART_data_1<=uart_rx_data;endendelse if(state==WAK_SPO2)beginif(uart_rx_done==1'b1 && uart_rx_data==8'h3d && rx_count==8'd0)beginrx_count<=rx_count + 1'b1;endelse if(uart_rx_done==1'b1 && rx_count==8'd1)beginrx_count<=rx_count + 1'b1;SPO2_data_1<=uart_rx_data;endelse if(uart_rx_done==1'b1 && rx_count==8'd2)beginrx_count<=rx_count + 1'b1;SPO2_data_2<=uart_rx_data;endendelse beginHEART_data_1 <= HEART_data_1;HEART_data_2 <= HEART_data_2;SPO2_data_1<=SPO2_data_1;SPO2_data_2<=SPO2_data_2;rx_count<=8'd0;end endalways @(posedge clk or negedge rst_n) beginif(!rst_n) beginuart_tx_data <= 8'd0;endelse if((state==RST) && tx_count<8'd10 ) beginuart_tx_data <= cmd_RESET[79 - tx_count *8 -:8];endelse if((state==HEART) && tx_count<8'd10 ) beginuart_tx_data <= cmd_HEATR[79 - tx_count *8 -:8];endelse if((state==SPO2) && tx_count<8'd9 ) beginuart_tx_data <= cmd_SPO2[71 - tx_count *8 -:8];endelse beginuart_tx_data <= uart_tx_data;endend//����״̬tx_countalways @(posedge clk or negedge rst_n) beginif(!rst_n) begintx_count <= 8'd0;endelse if(state==RST || state==HEART || state==SPO2) beginif(uart_tx_done==1'd1)tx_count <= tx_count+1'b1;endelse begintx_count <= 8'd0;endend//tx_en timealways @(posedge clk or negedge rst_n) beginif(!rst_n) begintx_en_count <= 2'b0;endelse if((state==RST || state==HEART || state==SPO2) && tx_en_count<2'd1 && tx_count==8'd0) begintx_en_count <=tx_en_count+ 1'd1;endelse if((state==RST || state==HEART || state==SPO2) && tx_en_count==2'd1 && tx_count==8'd0) begintx_en_count <= 2'd3;endelse if(state==OVER || state==WAK_HEART || state==WAK_SPO2 || state==IDLE)begintx_en_count <= 2'd0;endelse begintx_en_count <= tx_en_count;end
end//����״̬data_tx_enalways @(posedge clk or negedge rst_n) beginif(!rst_n) beginuart_tx_en_temp <= 1'b0;uart_tx_en <= uart_tx_en_temp;endelse if((state==RST || state==HEART || state==SPO2 ) && tx_en_count==1) beginuart_tx_en_temp <= 1'b1;uart_tx_en <= uart_tx_en_temp;endelse if((state==RST || state==HEART ) && tx_count<8'd9 && uart_tx_done==1)beginuart_tx_en_temp <= 1'b1;uart_tx_en <= uart_tx_en_temp;endelse if((state==SPO2 ) && tx_count<8'd8 && uart_tx_done==1)beginuart_tx_en_temp <= 1'b1;uart_tx_en <= uart_tx_en_temp;endelse beginuart_tx_en_temp <= 1'b0;uart_tx_en <= uart_tx_en_temp;endendalways @(posedge clk or negedge rst_n) beginif(!rst_n) beginstate <= IDLE;endelse begincase(state)IDLE:beginif(key_rst)beginstate <= RST;endelse if(key_data)beginstate <= HEART;endendRST:beginif(tx_count==8'd10)beginstate <= IDLE;endelse beginstate <= RST;endendHEART:beginif(tx_count==8'd10)beginstate <= WAK_HEART;endelse beginstate <= HEART;endendWAK_HEART:beginif(wait_count==time_20ms)beginstate <= SPO2;endelse beginstate <= WAK_HEART;end      endSPO2:beginif(tx_count==8'd9)beginstate <= WAK_SPO2;endelse beginstate <= SPO2;endendWAK_SPO2:beginif(wait_count==time_20ms)beginstate <= OVER;endelse beginstate <= WAK_SPO2;end endOVER:beginstate <= IDLE;enddefault:state <= IDLE;endcaseend
end//wait timealways @(posedge clk or negedge rst_n) beginif(!rst_n) beginwait_count <= 20'd0;endelse if((state==WAK_HEART || state==WAK_SPO2) && wait_count<time_20ms)beginwait_count <= wait_count+20'd1;endelse if((state==WAK_HEART || state==WAK_SPO2) && wait_count==time_20ms)beginwait_count <= 20'd0;endendendmodule

总结

视频展示:

基于FPGA的血氧和心率蓝牙监测系统设计

http://www.xdnf.cn/news/4708.html

相关文章:

  • SHA系列算法
  • 秋招准备——2.跨时钟相关
  • 大疆无人机(全系列,包括mini)拉流至电脑,实现直播
  • 机器学习第一讲:机器学习本质:让机器通过数据自动寻找规律
  • SpringCloud服务拆分:Nacos服务注册中心 + LoadBalancer服务负载均衡使用
  • 使用C# ASP.NET创建一个可以由服务端推送信息至客户端的WEB应用(2)
  • 视频编解码学习六之视频采集和存储
  • Linux环境下部署MaxScale
  • 安卓基础(静态方法)
  • 企业级可观测性实现:OpenObserve云原生平台的本地化部署与远程访问解析
  • DeepSeek+即梦AI实战:图片制作教程
  • 电机的控制字和状态字各个位在各个模式下的含义
  • Maven使用教程
  • flutter利用 injectable和injectable_generator 自动get_it注册
  • 最新阿里九宫格识别模型,连线,231 协议算法
  • 【Python从入门到精通】--‘@‘符号的作用
  • 架空输电线巡检机器人轨迹优化设计
  • 探索网络设备安全:Shodan 的原理与合法应用
  • Early clock flow
  • web 自动化之 selenium+webdriver 环境搭建及原理讲解
  • 图书推荐(协同过滤)算法的实现:基于订单购买实现相似用户的图书推荐
  • Python在自动驾驶实时数据处理中的应用:让AI驾驶更智能、更高效
  • 算法题(142):木材加工
  • .NET中使用HTTPS全解析
  • k8s术语之Horizontal Pod Autoscaling
  • 学习设计模式《八》——原型模式
  • 基于互信息分解表示学习的多模态情感分析
  • Dense 与 MoE 系列模型架构的全面对比与应用策略
  • git可视化工具Fork软件的详细使用教程
  • QTDesinger如何给label加边框