B49 - STM32 마이크로컨트롤러 기반의 심박수 혈액 산소 감지 및 원격 위치 경보 장치

본 시스템은 심박수, 혈중산소량을 실시간으로 모니터링하고 GPS 위도 및 경도 데이터를 획득할 수 있는 장치를 설계하고 모니터링 데이터를 무선통신모듈을 통해 육상의 인명구조요원이 장착한 무선 인명구조장치에 신속하게 개시할 수 있는 시스템이다. 비상 조치. 이 장은 구명 장치 하드웨어 모듈 및 회로 설계의 선택을 완료하는 데 사용됩니다.
설계 요구 사항은 다음과 같습니다.
(1) 심박수 및 혈중 산소 모니터링 모듈: MAX30102는 사용자의 심박수 및 혈중 산소 데이터를 감지하는 데 사용되며 수집된 심박수 및 혈중 산소 정보는 직렬 포트를 통해 마이크로 컨트롤러로 전송됩니다. . 센서 입력 전압은 3.3~5.0V를 지원하고 기본 풀업 전압은 3.3V이며 내장 ADC 정확도는 16비트입니다.
(2) 장치를 착용하고 물에 들어갈 때 사용자의 심박수와 혈중 산소가 수중에서 비정상적인 수준에 있는 것으로 감지되면 이산화탄소 팽창식 구급차 슈트를 제어할 수 있습니다(릴레이 모듈을 사용하여 제어 개폐, 릴레이 모듈의 작동 전압은 3.3V, 높은 수준의 닫힘, 낮은 수준의 열림), 플로팅 기능을 실현합니다.
(3) 물에 들어가기 위해 시스템을 착용할 때 구급차 시스템은 정상적인 상황(릴레이 꺼짐)에서 부풀려지지 않아 사용자가 자유형으로 수영하는 데 편리합니다.
(5) 사용자 자기 구조 기능 실현: 사용자가 자유형을 할 수 없다고 느끼고 감지 시스템이 팽창 기능을 켜지 않을 때(릴레이가 켜짐) 사용자는 버튼을 통해 수동으로 팽창 기능을 켤 수 있습니다. 자기 구조를 실현하기 위해.
(6) 원격 제어 기능 실현: 사용자가 익사할 때 해안의 인명구조원은 원격 제어 기능을 통해 인플레이션을 실현할 수 있습니다(원격 버튼을 누르면 릴레이가 켜지고 원격 전송은 GT-38을 사용합니다. 모듈, 433M 무선 통신 주파수 및 전송 거리 이론 1200 미터, 직렬 포트 통신) 적시 인명 구조를 실현합니다.
(7) 심박수 및 혈중산소모니터링이 비정상일 때 발광하는 LED등(심박수 표시용 적색 LED, 혈중산소량 표시용 적색 LED, 알람 표시용 적색 LED, 정상적인 표시를 위한 녹색 LED.LED 표시등의 작동 전압은 3.3V, 높은 수준 꺼짐, 낮은 수준 켜짐), 사용자의 위치를 ​​프롬프트하는 기능을 달성하여 구조 대원이 제 시간에 찾고 구조하는 데 편리합니다.
(8) 심박수 및 혈중 산소 모니터링이 비정상일 때 부저 알람이 실행됩니다(해당 LED가 켜져 있고 알람 표시기에는 빨간색 LED가 켜지고 정상 표시기에는 녹색 LED가 꺼집니다. 작동 부저 모듈의 전압은 3.3V이며 로우 레벨, 하이 스톱에서 작동합니다.
(9) GPS 포지셔닝 기능 실현 해안의 인명구조원은 LCD 화면에 표시된 사용자의 GPS 좌표를 통해 물속에서 사용자의 위치를 ​​찾을 수 있습니다(GPS 모듈의 작동 전압은 3.3V, 직렬 통신, NMEA 프로토콜, 포지셔닝 정확도는 2.5미터 이내이며 초기 전원 켜기 시간은 40초 미만이며 메모리 기능 포함).
(10) 화면은 LCD를 사용하여 GPS 좌표와 인명 구조 시스템 상태 정보를 표시합니다.
이 시스템의 설계는 심박수 모니터링 오류가 ±2 비트/분 이내여야 합니다. 심박수가 갑자기 변하고 설정된 심박수 혈중 산소 임계값을 초과하면 시스템이 자동으로 알람 기능을 시작할 수 있습니다. 혈중 산소 포화도 정확도는 ±0.2%이며, 혈중산소량이 설정한 임계값보다 낮을 때 시스템 알람 기능이 작동되며, 시스템은 인명 구조에 의한 인공 감지를 위해 수영자의 신체 정보를 수신하는 원격 제어 기능을 갖추고 있습니다. 물가에 인원이 있고 원격 모듈에는 수영자의 인명 구조 시스템을 제어하기 위한 키 입력 기능이 있습니다. 수영자의 신체 매개변수가 갑자기 비정상이 되면 인명 구조 요원이 수동으로 원격 버튼을 통해 인명 구조 시스템을 제 시간에 트리거할 수 있습니다.
이 장치에는 LCD 화면 심박수 및 GPS 좌표 표시가 장착되어 있습니다.이 디자인의 경보 시스템이 작동되면 원격 장치는 수영자가 착용하는 구명 시스템의 경보 정보, 체혈 산소, 심박수 지수를 수신할 수 있습니다. 정보 및 GPS 좌표 정보 , 원격 장치의 LCD 디스플레이에 표시될 수 있습니다. 따라서 이 시스템에서 수집한 정보는 GPS 좌표를 얻기 위한 GPS 모듈, 착용자의 심박수와 혈중 산소 데이터를 얻기 위한 심박수 및 혈중 산소 모듈, 데이터 통신을 위한 무선 통신 모듈, 데이터의 시각적 표시 및 구성 설정을 위한 버튼 모듈. 시스템 설계 프레임워크는 아래 그림과 같습니다.
여기에 이미지 설명 삽입

종류

여기에 이미지 설명 삽입
여기에 이미지 설명 삽입

이 시스템은 심박수 혈액 산소 센서 데이터를 수집하고 GPS 위도 및 경도 데이터를 수집하여 수집된 데이터를 OLED 화면에 표시합니다.심박수 센서가 수집한 위치에 손가락을 놓으면 센서가 해당 심박수 혈액을 수집합니다. 산소 값을 시리얼 포트를 통해 마이크로컨트롤러로 전송, 싱글칩 마이크로컴퓨터는 수신 분석 프로그램을 통과하고 성공적으로 분석한 후 데이터를 화면에 표시 GPS 획득 방법은 혈액과 유사 둘 다 직렬 포트 방식인 산소 센서, 차이점은 프로토콜과 내용입니다
.
여기에 이미지 설명 삽입
LCD 화면 표시는 직렬 포트 화면을 사용하며 글꼴 크기, 색상 등과 같은 지침을 통해 해당 정보를 전송하여 표시 기능을 완료할 수 있습니다. 그림 5.4와 같이 이번에 MCU를 통해 LCD 화면으로 보내는 명령은 문자열 형태이다. 콘텐츠는 DC16, 즉 전송되는 디스플레이 콘텐츠의 폰트 사이즈는 16 * 16이며, 0, 11 등의 후속 숫자는 디스플레이 위치이며, 0은 X축 방향의 0번째 픽셀을 나타내고, 11은 Y축 방향으로 11번째 픽셀 위치는 0부터 시작하여 화면 픽셀 크기는 128*64 즉 가로 128픽셀 높이 64픽셀 화면 회전을 지원합니다. 즉, X축의 값 범위는 0-63이고 Y축의 값 범위는 0-123입니다. 다음 작은 따옴표는 표시 내용이고 마지막 작은 따옴표는 표시 글꼴의 색상입니다. 이 시스템은 GT38 무선 전송 모듈을 통해 마스터와 슬레이브 머신 정보를 동기화합니다.수신 범위 내에 있을 때 마스터 머신에서 수집한 정보는 슬레이브 머신에 동시에 표시됩니다.이 시스템의 전체 하드웨어 표시는 다음과 같습니다. 아래 그림과 같이 센서가 수집된 후 수집된 정보가 동기화되는 것을 볼 수 있습니다(이번에는 대비를 높이기 위해 검정색 배경을 사용하고 흰색 글꼴을 표시함).
여기에 이미지 설명 삽입

하드웨어 설계

주인

여기에 이미지 설명 삽입

노예

여기에 이미지 설명 삽입

심박수 혈액 산소 센서 모듈

MAX30102는 맥박산소측정기와 심박계를 통합한 바이오센서 모듈이다[3]. 이번에 사용한 심박수 및 혈중산소 모듈은 MAX30102[12]로, STM32 시리즈 중 저전력 제품인 STM32F07 싱글칩 마이크로컴퓨터를 사용한 모듈로 칩 패키지는 작고 성능은 높다. 이 단일 칩 마이크로 컴퓨터를 사용하여 심박수와 혈중 산소를 읽으십시오 값은 알고리즘에 의해 처리되고 모듈의 직렬 인터페이스를 통해 전송됩니다.모듈의 직렬 통신의 전송 속도는 조정 가능하며 모듈은 AT 명령의 통신 프로토콜. 이 모듈의 심박수 측정 범위는 20-200회/분으로 넓고 혈중 산소 측정 범위는 50%-100%입니다.이 모듈은 직렬 포트 출력을 사용하므로 데이터 읽기 및 MAX30102의 처리.심박수 혈액 산소 값을 얻기 위해 직렬 포트를 통해 AT 명령을 전송하여 심박수 혈액 산소 프로그램의 설계를 크게 용이하게 합니다. 모듈의 기본 정보는 아래 그림과 같다 모듈이 MAX30102 센서와 STM32F070F6P6 마이크로컨트롤러로 구성되어 있음을 회로도에서 알 수 있으며 STM32F070F6P6 마이크로컨트롤러는 MAX30102의 데이터를 수집하여 시리얼로 출력한다. 처리 후 AT 프로토콜을 사용하는 포트. 따라서 이 시스템은 단일 칩 마이크로컴퓨터의 직렬 포트 3 인터페이스 PB10 및 PB11을 사용하여 센서 모듈의 해당 직렬 포트 핀에 연결하여 통신 데이터를 얻고 심박수 및 혈중 산소 함량을 분석합니다.
여기에 이미지 설명 삽입

GPS 모듈

이 설계는 수영자의 위치 데이터를 수집해야 하며, 수영자가 신체적 이상이 있을 때 시스템은 인명 구조원이 정확하게 구조할 수 있도록 사용자의 위치를 ​​적시에 보고할 수 있습니다. 이번에 사용한 GPS 포지셔닝 모듈은 ATGM336H-5N입니다. ATGM336H-5N 모듈은 감도가 매우 높고 전력 소비가 적습니다.작동 전류는 25mA[4]에 불과합니다.전원을 켰을 때 모듈의 첫 번째 포지셔닝 시간이 상대적으로 짧습니다.열린 상태에서 32초 안에 수행할 수 있습니다. 첫 번째 오리엔테이션을 완료합니다. 모듈에는 안테나 감지 및 안테나 단락 보호 기능이 내장되어 있습니다. ATGM336H-5N 모듈의 출력 모드는 직렬 포트 전송입니다. ATGM336H-5N 모듈의 기본 상황은 아래 그림과 같습니다. 이 시스템은 마이크로 컨트롤러의 직렬 포트 1의 수신 핀 RXD에 해당하는 PA10 포트를 사용하여 모듈과 연결합니다.
여기에 이미지 설명 삽입

여기에 이미지 설명 삽입

무선 전송 모듈

이 시스템은 GT38을 무선 통신 모듈로 사용합니다. 모듈의 최대 통신 거리는 대피소가 없는 열린 공간에서 1200m이며 모듈의 전력 소비는 최대 전력이 100mW로 상대적으로 낮습니다. 그림과 같이 GT38 무선 통신 모듈은 직렬 케이블을 통해 교차 연결, 즉 직렬 포트의 TX는 다른 모듈의 직렬 포트의 RX에 연결되며, 이에 따라 RX는 다른 모듈의 직렬 포트의 TX 모듈은 동시에 데이터 송수신을 지원하지 않으므로 반이중 상태에서만 작업할 수 있으며 데이터를 수신한 후에 데이터를 보냅니다. 본 시스템은 이 모듈을 이용하여 사용자의 심박수, 혈중산소량, 메인제어보드에서 측정한 GPS 위도 및 경도 데이터를 슬레이브 기기로 전송하며, 이 무선전송 모듈을 이용하여 전송거리가 긴 시스템이다. 모듈 통신은 직렬 포트를 채택하므로 이 설계는 마스터 마이크로 컨트롤러의 직렬 포트 2와 슬레이브 마이크로 컨트롤러의 직렬 포트 1을 사용하여 데이터를 보내거나 받습니다.연결 개략도는 그림에 나와 있습니다.
여기에 이미지 설명 삽입
여기에 이미지 설명 삽입

소스 프로그램

/*******************************************************************************

\* 文件名称:基于STM32单片机的心率血氧检测与远程定位报警装置

\* 实验目的:1.

\* 2.

\* 程序说明:完整程序Q:277 227 2579;@: itworkstation@ hotmail.com

\* 日期版本:本项目分享关键细节,熟悉使用单片机的可做参考代码。完整讲解+源代码工程可联系获取,可定制。

*******************************************************************************/

GPS 획득 드라이버

#ifndef __gps_h
#define __gps_h
#include "stm32f10x.h"

#define GPS_USART_REC_LEN  			200  	//定义最大接收字节数 200
extern char GPS_USART_RX_BUF[GPS_USART_REC_LEN];  //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 

//定义数组长度
#define GPS_Buffer_Length 80
#define UTCTime_Length 11
#define latitude_Length 11
#define N_S_Length 2
#define longitude_Length 12
#define E_W_Length 2 

#define false 0
#define true 1
	
typedef struct SaveData 
{
    
    
	char GPS_Buffer[GPS_Buffer_Length];
	char isGetData;		//是否获取到GPS数据
	char isParseData;	//是否解析完成
	char UTCTime[UTCTime_Length];		//UTC时间
	char latitude[latitude_Length];		//纬度
	char N_S[N_S_Length];		//N/S
	char longitude[longitude_Length];		//经度
	char E_W[E_W_Length];		//E/W
	char isUsefull;		//定位信息是否有效
} _SaveData;
extern _SaveData Save_Data;

void CLR_Buf(void);
void clrStruct(void);
void GPS_RecHandle(u8 res);
void parseGpsBuffer(void);  //parse:分析GPS数据

#endif 



#include "gps.h"
#include <string.h>
#include <stdio.h>

#include "led.h"

u16 point1 = 0;  //接收数组定位
char GPS_USART_RX_BUF[GPS_USART_REC_LEN];      //接收缓冲,最大USART_REC_LEN个字节.
_SaveData Save_Data;

void CLR_Buf(void)                           // 串口缓存清理
{
    
    
	memset(GPS_USART_RX_BUF, 0, GPS_USART_REC_LEN);      //清空
	point1 = 0;                    
}
void clrStruct(void)
{
    
    
	Save_Data.isGetData = false;
	Save_Data.isParseData = false;
	Save_Data.isUsefull = false;
	memset(Save_Data.GPS_Buffer, 0, GPS_Buffer_Length);      //清空
	memset(Save_Data.UTCTime, 0, UTCTime_Length);
	memset(Save_Data.latitude, 0, latitude_Length);
	memset(Save_Data.N_S, 0, N_S_Length);
	memset(Save_Data.longitude, 0, longitude_Length);
	memset(Save_Data.E_W, 0, E_W_Length);
}
void GPS_RecHandle(u8 Res)
{
    
    
	if(Res == '$')
	{
    
    
		point1 = 0;	
	}
	GPS_USART_RX_BUF[point1++] = Res;
	if(GPS_USART_RX_BUF[0] == '$' && GPS_USART_RX_BUF[4] == 'M' && GPS_USART_RX_BUF[5] == 'C')			//确定是否收到"GPRMC/GNRMC"这一帧数据
	{
    
    
		if(Res == '\n')									   
		{
    
    
			memset(Save_Data.GPS_Buffer, 0, GPS_Buffer_Length);      //清空
			memcpy(Save_Data.GPS_Buffer, GPS_USART_RX_BUF, point1); 	//保存数据
			Save_Data.isGetData = true;
			point1 = 0;
			memset(GPS_USART_RX_BUF, 0, GPS_USART_REC_LEN);      //清空				
		}					
	}	
	if(point1 >= GPS_USART_REC_LEN)
	{
    
    
		point1 = GPS_USART_REC_LEN;
	}	
}
void errorLog(int num)
{
    
    	
//	while (1)
//	{
    
    
//	  	printf("ERROR%d\r\n",num);
//	}
	LED_Control(ON);
}
void parseGpsBuffer(void)  //parse:分析GPS数据
{
    
    
	char *subString;
	char *subStringNext;
	char i = 0;
	if (Save_Data.isGetData)
	{
    
    
		Save_Data.isGetData = false;
//		printf("**************\r\n");
//		printf(Save_Data.GPS_Buffer);

		
		for (i = 0 ; i <= 6 ; i++)
		{
    
    
			if (i == 0)
			{
    
    
				if ((subString = strstr(Save_Data.GPS_Buffer, ",")) == NULL)
					errorLog(1);	//解析错误
			}
			else
			{
    
    
				subString++;
				if ((subStringNext = strstr(subString, ",")) != NULL)
				{
    
    
					char usefullBuffer[2]; 
					switch(i)
					{
    
    
						case 1:memcpy(Save_Data.UTCTime, subString, subStringNext - subString);break;	//获取UTC时间
						case 2:memcpy(usefullBuffer, subString, subStringNext - subString);break;	//获取UTC时间
						case 3:memcpy(Save_Data.latitude, subString, subStringNext - subString);break;	//获取纬度信息
						case 4:memcpy(Save_Data.N_S, subString, subStringNext - subString);break;	//获取N/S
						case 5:memcpy(Save_Data.longitude, subString, subStringNext - subString);break;	//获取经度信息
						case 6:memcpy(Save_Data.E_W, subString, subStringNext - subString);break;	//获取E/W

						default:break;
					}
					subString = subStringNext;
					Save_Data.isParseData = true;
					if(usefullBuffer[0] == 'A')
						Save_Data.isUsefull = true;
					else if(usefullBuffer[0] == 'V')
						Save_Data.isUsefull = false;
				}
				else
				{
    
    
					errorLog(2);	//解析错误
				}
			}
		}
	}
}

무선 통신 드라이버

#ifndef __WUXIAN_H
#define __WUXIAN_H

#include "Def_config.h"

#include "stm32f10x.h"

#define XinLv_Length 5
#define XueYang_Length 5
#define latitude_Length 11
#define N_S_Length 2
#define longitude_Length 12
#define E_W_Length 2 
#define WuXian_RX_BUF_Length 100

#define JUDGE_Length 2
typedef struct
{
    
    	
	char WuXian_Buffer[WuXian_RX_BUF_Length];
	char isGetData;		//是否获取到 数据
	char isParseData;	//是否解析完成
	char XinLv[XinLv_Length];		//心率值,字符串形式存储
	char XueYang[XueYang_Length];		//血氧数据
	char latitude[latitude_Length];		//纬度
	char N_S[N_S_Length];		//N/S
	char longitude[longitude_Length];		//经度
	char E_W[E_W_Length];		//E/W
	
	char is_XinLvWarn[JUDGE_Length];
	char is_XueYangWarn[JUDGE_Length];
	char is_HandWarn[JUDGE_Length];
} _SendData;
extern _SendData Send_Data;

#define false 0
#define true 1
	
void parseWuXianBuffer(void); 
void WuXian_Rec(u8 Res);
void WuXian_Clear(void);

#endif



#include "wuxian.h"
#include <string.h>
#include <stdio.h>
#include "lcdUart.h"
#include "usart1.h"
u8 point1 = 0;	
u8 WuXian_RX_BUF[WuXian_RX_BUF_Length];
_SendData Send_Data;

void WuXian_Clear(void)
{
    
    
	memset(Send_Data.WuXian_Buffer,'\0', WuXian_RX_BUF_Length);    
	memset(Send_Data.XinLv,'\0', WuXian_RX_BUF_Length);   
	memset(Send_Data.XueYang,'\0', WuXian_RX_BUF_Length);   
	memset(Send_Data.latitude,'\0', WuXian_RX_BUF_Length);   
	memset(Send_Data.N_S,'\0', WuXian_RX_BUF_Length);   
	memset(Send_Data.longitude,'\0', WuXian_RX_BUF_Length);   
	memset(Send_Data.E_W,'\0', WuXian_RX_BUF_Length);   
	
	memset(Send_Data.is_XinLvWarn,'\0', WuXian_RX_BUF_Length);   
	memset(Send_Data.is_XueYangWarn,'\0', WuXian_RX_BUF_Length);  
	memset(Send_Data.is_HandWarn,'\0', WuXian_RX_BUF_Length); 	
	
	Send_Data.isGetData = FALSE;
	Send_Data.isParseData = FALSE;
}
void WuXian_Rec(u8 Res)
{
    
    
	if(Res == '$')
	{
    
    
		point1 = 0;	
	}
	WuXian_RX_BUF[point1++] = Res;
	if(Res == '\n')									   
	{
    
    
		memset(Send_Data.WuXian_Buffer,'\0', WuXian_RX_BUF_Length);      //清空
		memcpy(Send_Data.WuXian_Buffer, WuXian_RX_BUF, point1); 	//保存数据
		Send_Data.isGetData = true; 
		point1 = 0;
		
		USART1_SendString((u8 *)Send_Data.WuXian_Buffer);
//		printf("DCV16(0,7,'%s',%d);\r\n",WuXian_RX_BUF,1);
//		LCD_CheckBusy(); 
		memset(WuXian_RX_BUF,'\0', WuXian_RX_BUF_Length);      //清空	
	}	
	if(point1 >= WuXian_RX_BUF_Length)
	{
    
    
		point1 = WuXian_RX_BUF_Length;
	}	
}
void parseWuXianBuffer(void)  //parse:分析数据
{
    
    
	char *subString;
	char *subStringNext;
	char i = 0;
	if (Send_Data.isGetData)
	{
    
    
		Send_Data.isGetData = false;
		for(i=0;i<9;i++)
		{
    
    
			if (i == 0)
			{
    
    
				if ((subString = strstr(Send_Data.WuXian_Buffer, "$")) != NULL)
				{
    
    
					subString++;
					if ((subStringNext = strstr(subString, ",")) != NULL)
					{
    
    
						memcpy(Send_Data.XinLv, subString, subStringNext - subString);		
						subString = subStringNext;
					}
				}
			}
			else if(i<8)
			{
    
    
				subString++;
				if((subStringNext = strstr(subString, ",")) != NULL)
				{
    
    
					switch(i)
					{
    
    
						case 1:
							memcpy(Send_Data.XueYang, subString, subStringNext - subString);
						break;
						case 2:
							memcpy(Send_Data.latitude, subString, subStringNext - subString);
						break;
						case 3:
							memcpy(Send_Data.N_S, subString, subStringNext - subString);
						break;
						case 4:
							memcpy(Send_Data.longitude, subString, subStringNext - subString);
						break;
						case 5:
							memcpy(Send_Data.E_W, subString, subStringNext - subString);
						break;
						case 6:
							memcpy(Send_Data.is_XinLvWarn, subString, subStringNext - subString);
						break;
						case 7:
							memcpy(Send_Data.is_XueYangWarn, subString, subStringNext - subString);
						break;
						default:break;
					}
					subString = subStringNext;
				}							
			}
			else
			{
    
    
				subString++;
				if((subStringNext = strstr(subString, "\r")) != NULL)
				{
    
    
					memcpy(Send_Data.is_HandWarn, subString, subStringNext - subString);
				}
			}			
		}	
		Send_Data.isParseData = true;	
	}
	
}



심박수 혈액 산소 수집 드라이버

#ifndef __XINLV_H
#define __XINLV_H

#include "stm32f10x.h"
#define XinLv_Buffer_Length 200
#define XinLv_Length 5
#define XueYang_Length 5
#define false 0
#define true 1
typedef struct
{
    
    
	char XinLv_Rec_Buffer[XinLv_Buffer_Length];
	char isGetData;		//是否获取到数据
	char isParseData;	//是否解析完成
	char XinLv[XinLv_Length];		//心率值,字符串形式存储
	char XueYang[XueYang_Length];		//血氧数据
	char isUsefull;		//信息是否有效
	int count_erroTime;
} _XinLvData;
extern _XinLvData XinLv_Data;

void XinLv_RecHandle(u8 Res);
void parseXinLvBuffer(void);

#endif 




#include "xinLv.h" 
#include <string.h>
#include <stdio.h>
#include "usart3.h" 
u8 point2 = 0;
char  XinLv_RX_BUF[XinLv_Buffer_Length]; //接收缓冲,最大XinLv_Buffer_Length个字节.末字节为换行符 
_XinLvData XinLv_Data;
u8 XinLv_Find(char *a)                   // 串口命令识别函数
{
    
     
    if(strstr(XinLv_Data.XinLv_Rec_Buffer,a)!=NULL)
	    return 1;
	else
		return 0;
}
void XinLv_Clear_Data(void)
{
    
    
	XinLv_Data.isGetData = false;
	XinLv_Data.isParseData = false;
	XinLv_Data.isUsefull = false;
	memset(XinLv_Data.XinLv, 0, XinLv_Length);      //清空
	memset(XinLv_Data.XueYang, 0, XueYang_Length);      //清空
	memset(XinLv_Data.XinLv_Rec_Buffer, 0, XinLv_Buffer_Length);      //清空
}
void XinLv_RecHandle(u8 Res)
{
    
    
	if(Res == '+')
	{
    
    
		point2 = 0;	
	}
	XinLv_RX_BUF[point2++] = Res;
	if(Res == 'K')									   
	{
    
    
		memset(XinLv_Data.XinLv_Rec_Buffer, 0, XinLv_Buffer_Length);      //清空
		memcpy(XinLv_Data.XinLv_Rec_Buffer, XinLv_RX_BUF, point2); 	//保存数据
		XinLv_Data.isGetData = true; 
		point2 = 0;
		memset(XinLv_RX_BUF, 0, XinLv_Buffer_Length);      //清空
		if(XinLv_Find("NULL"))
		{
    
    
			XinLv_Clear_Data();
		}	
	}		
	if(point2 >= XinLv_Buffer_Length)
	{
    
    
		point2 = XinLv_Buffer_Length;
	}	
}

void parseXinLvBuffer(void)
{
    
    
	char *subString;
	char *subStringNext;
	if (XinLv_Data.isGetData)
	{
    
    
		XinLv_Data.isGetData = false;
		if(XinLv_Find("HEART"))
		{
    
    
			subString = strstr(XinLv_Data.XinLv_Rec_Buffer, "=")+1;
			subStringNext = strstr(XinLv_Data.XinLv_Rec_Buffer, "\r");
			memset(XinLv_Data.XinLv,'\0', XinLv_Length);      //清空
			memset(XinLv_Data.XinLv,' ', 3);      //清空
			memcpy(XinLv_Data.XinLv, subString, subStringNext - subString);		
			XinLv_Data.isParseData = true;
			XinLv_Data.isUsefull = true;
			XinLv_Data.count_erroTime = 0;
		}
		if(XinLv_Find("SPO2"))
		{
    
    
			subString = strstr(XinLv_Data.XinLv_Rec_Buffer, "=")+1;
			subStringNext = strstr(XinLv_Data.XinLv_Rec_Buffer, "\r");
			memset(XinLv_Data.XueYang,'\0', XueYang_Length);      //清空
			memset(XinLv_Data.XueYang,' ', 3);      //清空
			memcpy(XinLv_Data.XueYang, subString, subStringNext - subString);	
//			USART3_SendString((char *)XinLv_Data.XueYang);	
			XinLv_Data.isParseData = true;	
			XinLv_Data.isUsefull = true;	
			XinLv_Data.count_erroTime = 0;			
		}
	}
}


추천

출처blog.csdn.net/qq_20467929/article/details/126141905