BMD101传感器协议解析与STM32实现(LCD显示波形)

编程入门 行业动态 更新时间:2024-10-10 21:32:28

BMD101传感器协议解析与STM32实现(LCD显示<a href=https://www.elefans.com/category/jswz/34/1768516.html style=波形)"/>

BMD101传感器协议解析与STM32实现(LCD显示波形)

1 前言

BMD101传感器是神念科技开发的心电传感器。目前有一些商家开发了BMD101传感器模块,基本上都是利用蓝牙直接传输数据到PC或手机端。而本文介绍通过串口将数据传送给单片机,并在单片机上完成数据解析和心电波形LCD显示的功能。

2 通信协议解读

BMD101 通过 UART 接口通信。这是一个标准的 UART 接口,定义为 1 个起始位,8 个数据位,1 停止位格式,波特率 57600。
串口输出的数据包格式如下:

包括Header(帧头)、data payload(数据有效载荷)、CRC校验字节三个部分。

帧头包括两个SYNC字节(其值均为0xAA),用于指示一帧数据的开始。帧头的plength字节用于指示数据有效载荷部分的字节数。它的值可能是0-169的某一值。

Data Payload 是由一系列连续的 DataRow 组成。分析 Data Payload 涉及到解析每个 DataRow。DataRow的组成如下:

DataRow 起始位可能有零个或多个[EXCODE](扩展代码)字节,这些字节的值均为 0x55。EXCODE 字节数表示 Extended Code Level。Extended Code Level 是用来与[CODE]字节一起确定DataRow的数据表示的是什么方面的信息。 如下表所示,例如:Extended Code Level为0和[CODE]=0x02决定了当前DataRow表示的是信号质量的信息。

如果[CODE]字节在 0x00 和 0x7F 之间,那么DataRow就没有[LENGTH]字节,紧跟着[CODE]的是一个字节的[DATA]值,然后 DataRow 结束。

如果[CODE]字节的值在 0x80 和 0xFF 之间,那么紧跟着是[LENGTH],它表示[DATA]的字节数。

通常我们从BMD101接收到的DataRow主要有三种:[CODE]=0x02,即信号质量数据,信号质量是一个介于0-200之间的数据,数值越大表示传感器采集到的信号质量越好,等于0时可能是因为电极与人体接触不良。

[CODE]=0x03,即实时的心率数据,用一个字节表示。这也是BMD101的方便之处,开发者不必再通过算法求出心率,只需通过读取串口发送的心率数据即可,心率数据一般每秒发送一次,但在信号质量不佳时仍然会输出心率数据,因此在使用心率数据前应该验证信号质量是否过差。

[CODE]=0x80时,输出的数据[DATA]表示原始的心电波形数据,每一个数据由16位补码组成,其值范围为-32768到32767之间。这16位数据的第一个字节是高8位字节,第二个字节是低8位,为了通过这两个字节还原心电波形数据值,可以通过以下代码完成:
short raw =(Value[0]<<8) | Value[1];
[DATA]可能包含了很多个心电数据,因此可能由很多个字节组成,通常BMD101每秒输出512个原始心电波形数据,即采样率为512Hz。

数据包解析步骤

  1. 从数据流中连续读取字节,直到[SYNC]字节(0xAA)时。
  2. 读取下一个字节,并确保它也是一个[SYNC]字节(如果没有,返回步骤 1)。
  3. 读[PLENGTH]字节。
  4. 从[PAYLOAD…]中读取下一个 PLENGTH 字节,把它们保存在一个存储区域(如
    unsigned char payload [ 256 ]数组)。按照接收的顺序累加每一个字节到校验器中。
  5. 使校验器中的低 8 位取反。这里是 C 代码:
    checksum &= 0xff;
    checksum = ~ checksum & 0xff;
  6. 读取[CRC]字节并验证它是否符合你的计算校验和(如果没有,返回到步骤 1)。
  7. 循环,直到 payload[]数组中所有字节(也就是 DataRows)被解析:
    a)解析和计算[EXCODE]字节的数值(0x55),一般在当前 DataRow 的开始。 b)解析当前 DataRow 中的[CODE]字节数据。 c)如果适用,解析当前 DataRow 中的[LENGTH]字节数据。d)分析和处理 当前 DataRow 中的[DATA…]字节(或数组),基于 DataRow 的 [EXCODE]等级、[CODE]和[LENGTH]。 e)如果不是所有的字节都从 payload []数组中解析完成,返回 a)解析下一个DataRow。

3 STM32实现数据包解析

配置STM32串口为中断接收方式,在中断服务函数中,完成数据包的接收与保存工作,代码如下:

u8 Uart2_Buffer[256];        //接收缓冲区
u8 Uart2_Rx = 0;             //Uart2_Buffer下标
u8 Uart2_Len;                //数据长度(第三字节以后包含crc)
int checksum=0;              //根据Payload计算出的校验值
u8 Uart2_Sta=0;                //数据帧正确标志
u8 Uart2_check;              //帧尾的校验值
u8 sig_quality=200;            //信号质量
//@brief: Receive a packet.If the packet is received correctly, 
//function parsePayload will be called,else this packet will be discarded
void USART2_IRQHandler() 
{ if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET) { USART_ClearITPendingBit(USART2,USART_IT_RXNE);Uart2_Buffer[Uart2_Rx] = USART_ReceiveData(USART2); Uart2_Rx++; }if(Uart2_Rx < 3)   //判断是否完成帧头接收{if(Uart2_Buffer[Uart2_Rx-1] != SYNC) // 异常{Uart2_Rx = 0; //下标清0Uart2_Sta = 0; //标志置0}}else if(Uart2_Rx == 3) //得到Payload长度Uart2_Len = Uart2_Buffer [Uart2_Rx-1]; else if(Uart2_Rx < 4 + Uart2_Len) //接收Payload{checksum += Uart2_Buffer[Uart2_Rx-1];  //计算校验值//checksum &= 0xFF; }else  //接收校验位{Uart2_check = Uart2_Buffer[Uart2_Rx-1];checksum &= 0xFF ;checksum = ~checksum & 0xFF;if(checksum != Uart2_check) //校验错误 ,丢弃该数据包{Uart2_Rx = 0; //下标清0Uart2_Sta = 0; //标志置0checksum = 0;}elseUart2_Sta = 1;//接收完成}if(Uart2_Sta) //检测到标志,说明成功接收{ parse_payload();   //调用数据解析函数Uart2_Rx = 0; //下标清0Uart2_Sta = 0; //标志置0checksum = 0;}
}

下面给出数据解析的函数:

void parse_payload(void) //对有效负载的内容作分析处理
{u8 bytesParsed = 0;//已处理的字节数u8 code;u8 length;  //当前DataRow包含的Value的字节数u8 extendedCodeLevel;short int rawValue = 0; //心电数据while(bytesParsed < Uart2_Len){extendedCodeLevel=0;while(Uart2_Buffer[3+bytesParsed] == EXCODE){extendedCodeLevel++;bytesParsed++;}code = Uart2_Buffer[3+bytesParsed];bytesParsed++;if(code >= 0x80){length = Uart2_Buffer[3+bytesParsed];bytesParsed++;}else length = 1;//now we get ExCodeLevel,code and the length of DataValue//in fact,Extended Code Level is always 0,so we can ignore it		switch(code){case 0x80://two bytes signed data of raw wave value,big-endianif(sig_quality > 0){rawValue = Uart2_Buffer[3+bytesParsed];rawValue <<= 8;rawValue |= Uart2_Buffer[4+bytesParsed];drawCurve(rawValue);}elseLCD_Clear(WHITE);//信号质量不佳,清屏countData=0;break; case 0x02://one byte data of signal quality,0 stands for poor quality while 200 stands for good sig_quality=Uart2_Buffer[3+bytesParsed];break;case 0x03://one byte data of heart rate valueLCD_ShowNum(290,50,Uart2_Buffer[3+bytesParsed],2,12);  //在屏幕上显示心率值break;}bytesParsed += length;}
}

点击下载完整Keil工程文件
LCD显示用的是正点原子Mini板,以及相应的LCD库函数。drawCurve(rawValue);是根据心电数据在屏幕上绘制心电波形,具体实现参考我的另一篇博客

实现效果如下:

由于没有滤波处理,BMD101的输出信号噪声还是比较多的。另外BMD101对噪声十分敏感,传感器的串口不应该直接与开发板的串口通过杜邦线直接连接,否则波形失真严重。可以在两者之间增加一个数字隔离模块。

更多推荐

BMD101传感器协议解析与STM32实现(LCD显示波形)

本文发布于:2024-02-06 11:25:52,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1748758.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:波形   传感器   协议   LCD

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!