⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ecg.c

📁 用于心电数据压缩。解压。重构
💻 C
字号:
//Hardware      : ADuC7020
//Reference     : ADCtimer.c(C:\ADuC_Beta702x\code\Keil Code Examples
//                             \ADuC7020\ADC\ADCtimer\ADCtimer.c)
#include <ADuC7020.h>				// 	Include ADuC7020 Header File
#define sample 177 	
// ADuC7020设置为采样率200Hz, 但PC端接收到的数据为177/8 Hz. 
//可能是串口速度太慢,而且是在加心率算法后的结果
#define baseline 2000

int adc,hr=0;
int ecgadc0=0,ecgadc1=0,ecgadc2=0,ecgadc3=0,ecgadc4=0;		
//这部分变量是采样和心率,滑动平均时用,但是实际并没有用到		   
int sequ=0,Rtime=100,Stime=0,Rwaveold=0,Rwavenew=0;			
//这部分变量处理R波位置和心率计算, 计算一次心率需要2个R波
int Rwave[2],r=0;											
int RRinterval[4]={0,0,0,0},*rr,RRaverage=0,j=0;	
// 计算R-R间的平均值
int Max=0,Min=5000,Maxold=0,Maxnew=0;						
//这部分变量是关于阀值设置的.
int Maxthreshold,Minthreshold;
int pMax,pMin;
int Max_Minarray[6]={2000,2000,2000,2000,2000,2000},temp=0;
char ignoflag=1,threflag=1,calflag=0,reversalflag=0;         
char HRcountflag=0,aflag=0,iflag=0,maxflag=0;
/*int count=0,countp=0,countpold=0,countpnew=0;	 
//these variables are used to count QRS complex and to follow baseline.
long base=0;									 
//But baseline following has not finished yet.
int basec=0,baseave=2000;
char normalflag=1;
int QRSwave=0;*/
void initialization_chip();				  //Initialize ADuC7020.
void ADCpoweron(int);					  //ADC need power on time.
void Leadchoose(int);
void Modechoose(int);
void failure(void);						  //If communicate with PC failed  
void ADC_interrupt();
void UART_interrupt();
void Parameter_reset();						  
int findMax();
int findMin();	
int main (void)  
{
	short int lead,mode,leadflag=1,modeflag=1;
	char trx;
	initialization_chip();                           
//from initialization_chip_060323.c to suit for hardware version 3.0
	while(leadflag)						                        		 
	{
		leadflag=0;
	    while(!(0x01==(COMSTA0 & 0x01))){}			
 //wait PC's data	
		trx=COMRX;
		lead=(short int)trx;				 
		switch(lead)						 
	   {
		// Lead   	input	   ADG658+	ADG658-
	       	case '1': Leadchoose(0x3ff90000); break;   
		//LeadI  ,	LA and RA,		S8 		S5
		  	case '2':Leadchoose(0x3fe10000); break;      
		//LeadII ,	LL and RA,  	S2 		S5
		  	case '3': Leadchoose(0x3fe30000); break;     
		//leadIII,	LL and LA,  	S2 		S7
		  	case '4': Leadchoose(0x3ff50000); break;     
		//1mv cal,	LL and AGND 	S4 		S6
		 	case '5': Leadchoose(0x3fec0000);break;      
		//aVR	  ,	RA and L+F, 	S6 		S2
		  	case '6': Leadchoose(0x3ffa0000);break;		 
		//aVL	  ,	La and R+F, 	S8 		S3
		  	case '7': Leadchoose(0x3fe60000);break;		 
		//aVF	  ,	LL and R+L, 	S2 		S4
		  	case '8':Leadchoose(0x3fc000ff);break;		 
		//V1	  ,	C  and R+L+F,	S1 		S1	 the difference with case
			case '9':Leadchoose(0x3fc00000);break;       
		//V2~V6  ,	C  and R+L+F,	S1 		S1	 8 and 9,because Vi need 
			default :  failure();leadflag=1;           	 //										 reversal
	    }
	}
	while(modeflag)
	{
		modeflag=0;
		while(!(0x01==(COMSTA0 & 0x01))){}
		trx=COMRX;
		mode=(short int)trx;
		switch(mode)
		{														
			// Mode		ADG704
				case '1': Modechoose(0x0000c000);break;		//monitor	  S4
				case '2': Modechoose(0x00000000);break;	 	//diagnostic  S1
				case '3': Modechoose(0x00008000);break;		//surgery	  S3
			default:  failure();modeflag=1;
		}
	} 
	IRQEN = ADC_BIT+UART_BIT;	        // Enable ADC and UART IRQ ( 0x80 )
	while(1){  }				        //waiting interrupt
	return 0 ;
}
/********************************************************************/
/*		IRQ Service Program									        */
/********************************************************************/
void IRQ_Handler(void)__irq		
//Do NOT change the writing format about interrupt program. 不要改函数名	
{	
	if(IRQSIG&0x00004000)
	{
		UART_interrupt();		//Do NOT change the interrupt program name.
	}
	if(IRQSIG&0x00000080)
	{
		ADC_interrupt();
	}
}
void ADC_interrupt()
{
	int s=0;
	char send,da;
	int ecgsum,ecgwave;
	GP0DAT ^= 0x00400000;							
// Complement P0.6 WS: V3.0硬件. LED每进一次中断会改变一次状态
	adc=ADCDAT>>16;
	adc &= 0x00000fff;                          
	while(!(0x020==(COMSTA0 & 0x020))){}     
// output test byte 通信协议的头
	COMTX = 0xA5;		            
    send =adc>>8;
	da = (char)send;
	while(!(0x020==(COMSTA0 & 0x020))){}
	COMTX = da;	        			// output ECG wave high byte
    send=adc&0x00ff;
	da = (char)send;
	while(!(0x020==(COMSTA0 & 0x020))){}
	COMTX = da;						// output ECG wave low byte
	send=hr;
	da = (char)send;
	while(!(0x020==(COMSTA0 & 0x020))){}
	COMTX = da;						// output the rhythm of heart
	while(!(0x020==(COMSTA0 & 0x020))){}
	COMTX = 0xff;					// output end byte	 
	if(calflag==0xFF)				
 //generate the square wave for 1mV calibration,P4.2
	{
		if((++sequ)%100==0)GP4DAT^=0x00040000;
		if(sequ==3000)sequ=0;
		return;
	}
	if(reversalflag)adc=4096-adc;
//If lead choosed V1 and aVR, the adc need to reversal first. 显示为实际波形。但计算心率时需要将这些信号翻转以统一算法
	/*ecgadc0=ecgadc1;
//滑动平均并没有使用。原因可能是信号源及硬件滤波效果较好
    ecgadc1=ecgadc2;			  
    ecgadc2=ecgadc3;
    ecgadc3=ecgadc4;
	ecgadc4=adc;
	ecgsum=ecgadc0;
    ecgsum+=ecgadc1;
    ecgsum+=ecgadc2;
    ecgsum+=ecgadc3;
    ecgsum+=ecgadc4;
	ecgwave=ecgsum/5;*/
	//++count;
	if((++sequ<sample*23)&&ignoflag)return;			
//the first 23secs(4600samples) are ignored,because the hardware. 由于硬件需要一定时间来稳定,故刚上电及导联切换后需要等待一段时间
    ignoflag=0;
	Max_Minarray[temp]=Max_Minarray[temp+3]=adc;
	if(++temp==3)temp=0;
	if(sequ==sample*25)								
//另外附加2秒时间用来决定初始的各个阈值
	{
		threflag=0;
		sequ=0;
	}						   
	if(threflag)			//初始各个阈值决定,与后续找R波的方法不一样		
	{
		findMax();
		if((aflag)&&(Max<pMax))Max=pMax;
		findMin();
		if((iflag)&&(Min>pMin))Min=pMin;
		Maxthreshold=Min+((Max-Min)>>1);
		Minthreshold=Min+(((Max-Min)*3)>>3);
		return;                                         	 
	}
	if(sequ>3000)Parameter_reset();					
//遇到心电信号突然改变时,较长时间找不到QRS波,则重置各阈值
	if(HRcountflag)
	{
		rr=RRinterval;	
    	RRinterval[j]=(Rwave[1]-Rwave[0]);			
//made the previously MaxTime subtract from the following MaxTime
		if(++j==4)j=0;
//the RRinterval is the point number between two R waves
		for(s=0;s<4;s++)
		{
			RRaverage+=*rr;				//get a average of RRinterval
			rr++;
		}						
		RRaverage>>=2;					//hr=(sample rate*60)/RRaverage
		hr=sample*60/RRaverage;
		RRaverage=0;
		HRcountflag=0;
		Rtime=100;
		Stime=0;										   
	}
	findMax();
	if((aflag)&&(pMax>Maxthreshold))				
//When adc bigger than max threshold, find the biggest one.  初步确定R波
	{						//The biggest wave can be seen as the R wave.
		Max=pMax;
		Rtime=sequ-1;
		maxflag=1;
		//countp=count;
		return;
	}
	if(maxflag)	//After find the "R wave", to look for the "S wave" immediately
	{
		findMin();
		if((iflag)&&(pMin<=Minthreshold))
		{
			Min=pMin;
			Stime=sequ-1;
		}
		else return;
		if(((Stime-Rtime)>0)&&((Stime-Rtime)<=12))	
//Afer find the "S wave" and "R wave",judge their location interval. 
		{											
//The interval must be very close. If the interval doesn't match, 
			//++QRSwave;							
//that means this "R wave" is not the real R wave.
			Rwaveold=Rwavenew;
			Rwavenew=Rtime;
			//countpold=countpnew;
			//countpnew=countp;
			Maxold=Maxnew;
			Maxnew=pMax;
			if((Rwavenew-Rwaveold)<(sample>>2))		 
//Then judge if this "R wave" is near with privious "R wave". 按照最高心率300次计算,在200Hz采样率下2各R波之间间隔最小为50
			{
				//QRSwave-=1;
				if(Maxold>Maxnew)					
 //If both the "R wave" are closely, the bigger wave is seen as the 
				{									 //real R wave.
					Rwavenew=Rwaveold;
					//countpnew=countpold;
				}
			}
			else	//Otherwise, prepare for looking for next R wave and calculate 
			{				 //threshold by this R wave. 
				if(++r==2)	 //If find two R waves, it can set flag to count rhythm.
				{
					r=0;
					sequ=0;
					Rwavenew=0;
					HRcountflag=1;
				}
				Maxthreshold=Min+((Max-Min)>>1);
				Minthreshold=Min+(((Max-Min)*7)>>4);
			}
			Rwave[r]=Rwavenew;			 //Note this R wave.
			maxflag=0;
		}
	}
	return;
}
void Parameter_reset()
{
	sequ=0;
	threflag=1;
	HRcountflag=0;
	Max=0;
	Min=5500;
	Rtime=100;
	Stime=0;
	r=0;
	RRinterval[0]=0;RRinterval[1]=0;RRinterval[2]=0;RRinterval[3]=0;
	j=0;
	RRaverage=0;
	return;
}
void UART_interrupt()
{
	char leadflag=1,modeflag=1,lead,mode,head;
	while(!(0x020==(COMSTA0 & 0x020))){}
	head=COMRX;	
	if(head==0xFF)	//选导联
	{
		while(leadflag)						                        		 
		{
			leadflag=0;
	    	while(!(0x020==(COMSTA0 & 0x020))){}	//wait PC's data
			lead=COMRX;	 
			switch(lead)						 
	   		{												    
// Lead   	  input	     ADG658+  ADG658-
	       		case '1': Leadchoose(0x3ff90000); break;     	
//LeadI  ,	LA and RA,		S8 		S5
		  	case '2':Leadchoose(0x3fe10000); break;      		
//LeadII ,	LL and RA,  	S2 		S5
		  	case '3': Leadchoose(0x3fe30000); break;     		
//leadIII,	LL and LA,  	S2 		S7
		  	case '4': Leadchoose(0x3ff50000); break;     		
//1mv cal,	LL and AGND 	S4 		S6
		 	case '5': Leadchoose(0x3fec0000);break;      		
//aVR	  ,	RA and L+F, 	S6 		S2
		  	case '6': Leadchoose(0x3ffa0000);break;		 		
//aVL	  ,	La and R+F, 	S8 		S3
		  	case '7': Leadchoose(0x3fe60000);break;		 		
//aVF	  ,	LL and R+L, 	S2 		S4
		  	case '8':Leadchoose(0x3fc000ff);break;		 		
//V1	  ,	C  and R+L+F,	S1 		S1
			case '9':Leadchoose(0x3fc00000);break;       		
//V2~V6  ,	C  and R+L+F,	S1 		S1
				default : failure();leadflag=1;           
	    	}
		}
	}
	if(head==0xFE)	//选模式
	{
		while(modeflag)
		{
			modeflag=0;
			while(!(0x020==(COMSTA0 & 0x020))){}
			mode=COMRX;
			switch(mode)
			{								//Mode			ADG704
				case '1': Modechoose(0x0000c000);break;	//monitor		  S4
				case '2': Modechoose(0x00000000);break;	//diagnostic	  S1
				case '3': Modechoose(0x00008000);break;	//surgery		  S3
				default: failure();modeflag=1;
			}
		}
	}
	Parameter_reset();
	return;	
}
void Leadchoose(int contr)	
{
    int temp;
	temp=GP1DAT;
	temp>>2;
	temp&=0x0000ffff;
	temp|=contr;
	temp<<2;
	GP1DAT=temp;							 
	while(!(0x020==(COMSTA0 & 0x020))){}
	COMTX = 0xAA;
	if((contr==0x3fc000ff)||(contr==0x3fec0000))reversalflag=1;
	if(contr==0x3ff50000)calflag=0xff;
 }
void Modechoose(int ctr)
{
	int tem;
	tem=GP1DAT;
	tem>>2;
	tem&=0xffff0000;
	tem|=ctr;
	tem<<2;
	GP1DAT=tem;
	while(!(0x020==(COMSTA0 & 0x020))){}
	COMTX = 0xAC;	
}
void failure(void)
{
 	while(!(0x020==(COMSTA0 & 0x020))){}
	COMTX = 0xFA;
}
int findMax()
{
	if((Max_Minarray[temp]<=Max_Minarray[temp+1])&&
		(Max_Minarray[temp+1]>=Max_Minarray[temp+2]))
	{
		pMax=Max_Minarray[temp+1];
		aflag=1;
		return;
	}
	aflag=0;
	return;
}
int findMin()
{
	if((Max_Minarray[temp]>=Max_Minarray[temp+1])&&
		(Max_Minarray[temp+1]<=Max_Minarray[temp+2]))
	{
		pMin=Max_Minarray[temp+1];
		iflag=1;
		return;
	}
	iflag=0;
	return;
}
void initialization_chip()	   //this function used to suit for prototype board
{
	//set core clock 
	POWKEY1=0x01;
	POWCON=0x00;				   //core clock=40.96MHz,CD bit=0
	POWKEY2=0xF4;
	//set ADC registers
	ADCpoweron(20000);				// power on ADC								
	ADCCP  = 0x02;              // select ADC positive Channel 0 ;2 for temporary
	ADCCN  = 0x02;                  // select ADC negative Channel 0
	ADCCON = 0x04A2;				// ADC clock speed :fADC/2
									// ADC acquisition time: 2clocks
									// disable ADCbusy pin
	                                // single end mode
									// enable time0 as a conversion input		
	REFCON = 0x01;			// use the internal reference for ADC conversions
	                        // connect internal 2.5V reference to VREF pin
	//Setup rx & tx pins on P1.0 and P1.1
	GP1CON = 0x00000011;
    //Start setting up UART at 9600bps
	COMCON0 = 0x80;					// Setting DLAB
	COMDIV0 = 0x85;			
   	COMDIV1 = 0x00;
   	COMCON0 = 0x07;					// Clearing DLAB
	COMIEN0=0x01;                   //enable receive buffer full interrupt
	//timer0 configuration			 
	T0LD = 0x3200;					//12800*16/40960000Hz=5ms,0x6400for 100Hz,
	T0CON = 0x000000C4;				// enable timer0
									// periodic mode
									// prescale /16
	//Set P4.2
	GP4CON&= 0xfff0ffff;
	GP4DAT = 0x04000000;			//	Configure P4.2 output low level
	//Configure Multiplexer control pin
	GP0CON&=0x1000ffff;				//P0.4,P0.5,P0.6 as GPIO
	GP0DAT=0x70000000;              //P0.4,P0.5,P0.6 output low levels 
	GP1CON&=0x0000ffff;            	//P1.4,P1.5,P1.6,P1.7 as GPIO
	GP1DAT=0xF0200000;				//P1.4,P1.5,P1.6,P1.7 output low levels
}
 /*void initialization_chip()	   //this is the new initialization function for hardware 3.0 控制管脚、RS-232口的定义不一样
{
	//set core clock 
	POWKEY1=0x01;
	POWCON=0x00;				   //core clock=40.96MHz,CD bit=0
	POWKEY2=0xF4;
	//Setup rx & tx pins on P0.7 and P2.0 (Mode 2)
	GP0CON=0x20001000;				//P0.7 SIN, P0.6 GPIO, P0.3 TRST, P0.0 BM
	GP2CON=0x00000002;				//p2.0 SOUT
 	//Set P0.6
	GP0DAT=0x40000000;				//light the LED
    //Start setting up UART at 9600bps
	COMCON0 = 0x80;					// Setting DLAB
	COMDIV0 = 0x85;			
   	COMDIV1 = 0x00;
   	COMCON0 = 0x07;					// Clearing DLAB
	COMIEN0=0x01;                   //enable receive buffer full interrupt
	//timer0 configuration			 
	T0LD = 0x3200;					//12800*16/40960000Hz=5ms,0x6400for 100Hz,
	T0CON = 0x000000C4;				// enable timer0
									// periodic mode
									// prescale /16
	//set ADC registers
	ADCpoweron(20000);				// power on ADC								
	ADCCP  = 0x04;                  // select ADC positive Channel 4 ;
	ADCCN  = 0x04;                  // select ADC negative Channel 0
	ADCCON = 0x04A2;				// ADC clock speed :fADC/2
									// ADC acquisition time: 2clocks
									// disable ADCbusy pin
	                                // single end mode
									// enable time0 as a conversion input	
	REFCON = 0x01;			// use the internal reference for ADC conversions
	                        // connect internal 2.5V reference to VREF pin
	//Configure Multiplexer control pin
	GP1CON=0x00000000;            	
//P1.7~P1.0 as GPIO, P1.0&P1.1 control ADG704 to select working mode(default is 
//HPF 0.05Hz, LPF 112Hz).P1.2~P1.7 control two ADG658 to select lead(default is 
//Lead C).P1.2~P1.4 control negative input, P1.5~P1.7 control positive input.	
	GP1DAT=0xff000000;	//P1.7~P1.0 output low levels
	GP4CON=0x00000000;	//P4.2 as GPIO,control ADG719 to generate a 1mV square wave.
	GP4DAT=0x04000000;	//P4.2 output low levels
	GP0DAT=0x40400000;  //quench the LED
} */
void ADCpoweron(int time)
{
	ADCCON=0x0422;
	while(time>=0)--time;
}									

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -