這次的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;
}
藍牙子產品的話我沒寫,就是用兩個藍牙子產品,闆子上一個,電腦上一個,藍牙是接到序列槽上,用序列槽發就行。