天天看點

電賽2020A題心電信号測量比賽代碼講解。 無線運動傳感器節點

這次的A題不是很難,直接開始吧

目錄

    • 按鍵掃描函數
    • 溫度處理函數
    • 心電顯示函數

初始化函數就不寫上去了,沒什麼價值。我把所有代碼打包了,想下載下傳的點這裡:

電賽2020A題心電信号測量比賽代碼

具體晶片的詳解可以留言,有人看就再詳細寫一下具體的晶片細節

——————————————————————————

先把引腳标注好,好的代碼風格會讓你事半功倍

/*心電圖

/RESET—PB10
START—PB11
/DRDY—PA8
/CS------PB12
MOSI---PB15
MISO---PB14
SCK-----PB13

*/

/*序列槽通信1
PA9
PA10
*/

/*
溫度子產品
PA0
*/

/*
藍牙子產品
PA2
PA3
*/

/*
按鍵子產品
PB8 按鍵
PB9 按鍵
PA1 燈
*/
           

我們先明确一下思路,就是通過按鍵去切換不同的模式,那我們就要寫一個按鍵掃描函數

按鍵掃描函數

這個是可以通過寫進去不同的mode來控制模式。mode=1就是摁一下執行一次,mode=0就是摁一下執行完了,key就等于0了,再摁一次,key就又等于1,這次不幹活,相當于保證安全。key=1的時候才幹活。

u8 KEY_Scan(u8 mode)
{
	static u8 key=1;
	if(key==1&&(KEY1==0||KEY2==0)) //任意一個按鍵按下
	{
		delay_ms(10);  //消抖
		key=0;
		if(KEY1==0)
		{
			return KEY1_VALUE; 
		}
		else if(KEY2==0)
		{
			return KEY2_VALUE; 
		}
	}
	else if(KEY1==1&&KEY2==1)    //無按鍵按下
	{
		key=1;
	}
	if(mode==1) //連續按鍵按下
	{
		key=1;
	}
	return 0;
}
           

溫度處理函數

然後是溫度子產品,用的是lmt70,室溫下它輸出的是900多毫伏的電壓,我們直接用stm32自帶的adc去轉換即可。

temp=(float)adcx*(3300.000/4096);這句,因為供電是3.3v,而且分辨率是4096,是以相當于把3.3分成4096份,adc讀出來多少份,乘以對應每份多少mv,就是結果。輸出結果乘個電壓和溫度關系的二次函數,就得到了溫度。

lmt70詳解點這裡:(挖坑,還沒寫)

void tempGET(void)
{	
	u16 adcx;
	float temp;
	float tem;
	while(1)
	{
		key=KEY_Scan(0);
		if(key==2){  return;  }
		adcx=Get_Adc(ADC_Channel_0);
		temp=(float)adcx*(3300.000/4096);
	
		//	printf("adcx:%d\t",adcx);
		//	printf("V:%f   ",temp);
		adcx=(unsigned long)(temp*1000);
	
		tem = (-0.0000084515) * temp * temp + (-0.176928) * temp + 204.393;
		//tem/=1000;
		printf("溫度:%f °C \r\n",tem);
		delay_ms(100);
	}
}
           

心電顯示函數

用的是ads1292晶片,這玩意有點複雜的。中文資料手冊我也上傳了,需要的自己下載下傳就好。連結:(挖坑,還沒上傳)

首先是初始化函數。data_to_send[]這個數組是放到時候傳輸的資料的。

這四個是幀頭,不用管他。

data_to_send[0] = 0xAA;
	data_to_send[1] = 0xAA;
	data_to_send[2] = 0xF1;
	data_to_send[3] = 8;
           

這個是選擇ads1292的模式。如果是自己調試的話,一定要先用内部測試信号,調通了再去正常采集

while (Set_ADS1292_Collect(0)) //0 正常采集  //1 1mV1Hz内部側試信号 //2 内部短接噪聲測試
	{
		printf("1292寄存器設定失敗\r\n");
		delay_s(1);
		DS3 = !DS3;
		DS4 = !DS4;
	}
           

這是初始化代碼

void ads1292Init(void)
{
	uart1_init(115200);												//序列槽初始化為115200
	DMA_Config(DMA1_Channel4, (u32)&USART1->DR, (u32)data_to_send); //序列槽1DMA設定2
	USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);					//DMA
	LED_Init();
	data_to_send[0] = 0xAA;
	data_to_send[1] = 0xAA;
	data_to_send[2] = 0xF1;
	data_to_send[3] = 8;

	PBout(10) = 1;
	PBout(11) = 0;
	ADS1292_Init(); //初始化ads1292

	while (Set_ADS1292_Collect(0)) //0 正常采集  //1 1mV1Hz内部側試信号 //2 内部短接噪聲測試
	{
		printf("1292寄存器設定失敗\r\n");
		delay_s(1);
		DS3 = !DS3;
		DS4 = !DS4;
	}
	printf("寄存器設定成功\r\n");
	delay_s(1);
	DS3 = LEDOFF;
	DS4 = LEDOFF;

	TIM2_Init(10000, 7200); //系統訓示
	//TIM4_Init(2000,7200);//按鍵消抖

	EXTI->IMR |= EXTI_Line8; //開DRDY中斷
}
           

這個是ads1292采集信号的函數。注意他和上邊那個溫度采集函數一樣,在函數裡while(1)去不停的采集,同時檢查按鍵,不按鍵切換的話他就移植采集下去。

p_Temp【0】是濾波完的,p_Temp【1】是還沒濾波的。一起顯示就能看出一點差別,0更平滑。但兩個都是心率。可以隻輸出p_Temp【0】。

void runADS1292(void)
{
	u8 res, i, sum;
	u8 usbstatus = 0;
	u32 cannle[2]; //存儲兩個通道的資料
	s32 p_Temp[2]; //資料緩存
	u8 flag = 0;
	u8 count = 0;
	s32 data1=0;
	u8 count1 = 0;
	s32 data1_fomer = 0;
	s32 average;
	s32 sum1;
	u32 average_timer;
	u32 sum_timer;
		float rate_fomer = 0;
	float rate = 0;
	s8 x = 0;
	s32 yuzhi = 0;
	TIM3_Int_Init(49, 7199);
	while(1)
	{
		key=KEY_Scan(0);
	if(key==1){  return;  }


	if (ads1292_recive_flag)
	{
		cannle[0] = ads1292_Cache[3] << 16 | ads1292_Cache[4] << 8 | ads1292_Cache[5]; //擷取原始資料
		cannle[1] = ads1292_Cache[6] << 16 | ads1292_Cache[7] << 8 | ads1292_Cache[8];

		p_Temp[0] = get_volt(cannle[0]); //把采到的3個位元組轉成有符号32位數
		p_Temp[1] = get_volt(cannle[1]); //把采到的3個位元組轉成有符号32位數

		p_Temp[0] = filterloop(p_Temp[1]);
		p_Temp[0] = filterloop(p_Temp[0]);
		p_Temp[0] = filterloop(p_Temp[0]);
data1=p_Temp[0];
		//有符号數為再轉為無符号,無符号數為邏輯右移
		cannle[0] = p_Temp[0];
		cannle[1] = p_Temp[1];
		data_to_send[4] = cannle[0] >> 24; //25-32位
		data_to_send[5] = cannle[0] >> 16; //17-24
		data_to_send[6] = cannle[0] >> 8;  //9-16
		data_to_send[7] = cannle[0];	   //1-8

		data_to_send[8] = cannle[1] >> 24; //25-32位
		data_to_send[9] = cannle[1] >> 16; //17-24
		data_to_send[10] = cannle[1] >> 8; //9-16
		data_to_send[11] = cannle[1];	   //1-8

		for (i = 0; i < 12; i++)
			sum += data_to_send[i];
		data_to_send[12] = sum;		   //校驗和
		DMA_Enable(DMA1_Channel4, 13); //序列槽1DMA

		ads1292_recive_flag = 0;
		sum = 0;
		
		if (((count1 % 20) == 0))
			{
				sum1 += data1;
			}

			if (count1 >= 200)
			{
				average = sum1 / 10;
				sum1 = 0;
				count1 = 1;
				yuzhi = average + 20000;
			}
			while (flag & (data1 >= yuzhi) & (timer >= 30))
			{
				count++;
				flag = 0;
				sum_timer += timer;
				x++;
				timer = 0;
				if (x == 5)
				{
					average_timer = (sum_timer / x);
					rate_fomer = rate;
					rate = 12000 / ((float)(average_timer));
					
					x = 0;
					sum_timer = 0;
				}
			}

			//收到的值降到門檻值以下時,清空标志位
			while (data1 <= yuzhi)
			{
				flag = 1;
				break;
			}
	}
}
}



s32 get_volt(u32 num)
{
	s32 temp;
	temp = num;
	temp <<= 8;
	temp >>= 8;
	return temp;
}
           

藍牙子產品的話我沒寫,就是用兩個藍牙子產品,闆子上一個,電腦上一個,藍牙是接到序列槽上,用序列槽發就行。