STM32血氧程序
- #include "stm32f103c8t6.h"
- //#include "stm32f1xx_hal_gpio.h"
- #include "mbed.h"
- #include "algorithm.h"
- #include "MAX30102.h"
- //#include "lcd_5110.h"
- #include "ascii5x8.h" //5x8ASCII字符集
- #include "charcode.h" //12x16(14)漢字子集
- #include "asciicode.h" //5x8(8)ASCII子集
- //#include "sys.h"
- /************ 定義LCD相關的管腳功能 ***********/
- #define LCD_RST_SET do{HAL_GPIO_WritePin(GPIOB,GPIO_PIN_11,GPIO_PIN_SET);}while(0) //復位腳① PB11
- #define LCD_RST_RESET do{HAL_GPIO_WritePin(GPIOB,GPIO_PIN_11,GPIO_PIN_RESET);}while(0)
- #define LCD_CE_SET do{HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_SET);}while(0) //片選腳②PB10
- #define LCD_CE_RESET do{HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);}while(0)
- #define LCD_DC_SET do{HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET);}while(0) //數據/命令選擇腳③PB0
- #define LCD_DC_RESET do{HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);}while(0)
- #define LCD_DIN_SET do{HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);}while(0) //數據輸入④PB1
- #define LCD_DIN_RESET do{HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);}while(0)
- #define LCD_CLK_SET do{HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET);}while(0) //時鐘信號腳⑤PB5
- #define LCD_CLK_RESET do{HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_RESET);}while(0)
- /************** 結束管腳定義 *****************/
- #define CLOCK 72/8 //時鐘=72M
- #define MAX_BRIGHTNESS 255
- uint32_t aun_ir_buffer[500]; //紅外LED傳感器數據
- int32_t n_ir_buffer_length; //數據長度
- uint32_t aun_red_buffer[500];//紅色LED傳感器數據
- int32_t n_sp02; //SPO2血氧值
- int8_t ch_spo2_valid; //血氧值有效標志
- int32_t n_heart_rate; //心率值
- int8_t ch_hr_valid; //心率值有效標志
- uint8_t uch_dummy;
- const uint8_t level[]={0x80,0xC0,0xE0,0xF0,0xF8,0xFC,0xFE,0xFF};//波形
- //const uint8_t level[]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};//曲線
- uint8_t disp=1; //動態顯示列
- Serial pc(SERIAL_TX, SERIAL_RX);//初始化串行端口, TX-PA2, RX-PA3
- PwmOut pwmled(PB_3); //初始化連接到LED的PWM輸出PB3(亮度變化)
- DigitalIn INT(PB_7); //PB7連接MAX30102的INT輸出引腳
- DigitalOut led(PC_13); //PC13連接板載用戶LED
- void LCD_Config(void); //LCD配置引腳
- void LCD_init(void); //LCD初始化
- void LCD_write_byte(uint8_t dat,uint8_t dc);//LCD寫字節
- void LCD_set_XY(uint8_t X,uint8_t Y);//LCD設置坐標
- void LCD_clear(void); //LCD清屏
- void LCD_write_ASCII(uint8_t X,uint8_t Y,uint8_t *stru);//LCD顯示5x7字符串
- void LCD_write_ASC_SIN(uint8_t X,uint8_t Y,uint8_t cid);//LCD顯示5x7字符
- void LCD_write_ASC7x12(uint8_t X,uint8_t Y,uint8_t cid);//LCD顯示7x12字符
- void LCD_write_char(uint8_t x,uint8_t y,uint8_t cid); //LCD顯示12x14字符
- void LCD_write_value(uint8_t X,uint8_t Y,uint8_t L,uint8_t D,uint16_t val);//LCD顯示變量
- void LCD_write_string(uint8_t x,uint8_t y,uint8_t *stru);//LCD顯示12x14字符串
- void display_main(void); //主屏幕顯示
- void display_erro(void); //信號錯誤
- void display_wait(void); //等待信號
- void display_ir(uint16_t ir);//動態顯示曲線
- /*------------------------------------------------------------
- us延時函數
- ------------------------------------------------------------*/
- void delay_us(uint16_t us)
- {
- uint8_t n;
- while(us--)for(n=0;n<CLOCK;n++);
- }
- /*------------------------------------------------------------
- ms延時函數
- ------------------------------------------------------------*/
- void delay_ms(uint16_t ms)
- {
- while(ms--)delay_us(1000);
- }
- // 當您按重置時,設置程序運行一次。
- int main() {
- uint32_t un_min, un_max, un_prev_data;//用于計算反映心跳的車載LED亮度的變量
- int i;
- int32_t n_brightness;
- float f_temp;
- uint8_t flag = 0;
-
- maxim_max30102_reset(); //重置MAX30102
-
- //初始化串行口波特率
- pc.baud(115200);
- pc.format(8,SerialBase::None,1);
- wait(1);
-
- //初始化LCD5110
- LCD_init();
- display_main();
-
- //讀取和清除狀態寄存器
- maxim_max30102_read_reg(0,&uch_dummy);
-
- maxim_max30102_init(); //初始化MAX30102
-
- n_brightness=0;
- un_min=0x3FFFF;
- un_max=0;
-
- n_ir_buffer_length=500; //緩沖區長度100存儲以100sps運行的5秒樣本
-
- //讀取前500個樣本,確定信號范圍
- for(i=0;i<n_ir_buffer_length;i++)
- {
- while(INT.read()==1);//等待直到中斷pin生效
-
- maxim_max30102_read_fifo((aun_red_buffer+i),(aun_ir_buffer+i));//從MAX30102的FIFO讀數據
-
- if(un_min>aun_red_buffer[i])
- un_min=aun_red_buffer[i];//更新信號最小值
- if(un_max<aun_red_buffer[i])
- un_max=aun_red_buffer[i];//更新信號最大值
- pc.printf("red=");
- pc.printf("%i", aun_red_buffer[i]);
- pc.printf(", ir=");
- pc.printf("%i\n\r", aun_ir_buffer[i]);
-
- }
- un_prev_data=aun_red_buffer[i];
- //計算前500個樣本(前5秒樣本)后的心率和血氧數值。
- maxim_heart_rate_and_oxygen_saturation(aun_ir_buffer, n_ir_buffer_length, aun_red_buffer, &n_sp02, &ch_spo2_valid, &n_heart_rate, &ch_hr_valid);
- //從MAX31022連續取樣。每1秒計算一次心率和血氧飽和度。
-
- while(1)
- {
- i=0;
- un_min=0x3FFFF;
- un_max=0;
- //將前100組樣本轉儲到內存中,并將最后400組樣本移到頂部
- for(i=100;i<500;i++)
- {
- aun_red_buffer[i-100]=aun_red_buffer[i];
- aun_ir_buffer[i-100]=aun_ir_buffer[i];
- //更新信號最小值和最大值
- if(un_min>aun_red_buffer[i])
- un_min=aun_red_buffer[i];
- if(un_max<aun_red_buffer[i])
- un_max=aun_red_buffer[i];
- }
- //在計算心率前取100組樣本。
- for(i=400;i<500;i++)
- {
- un_prev_data=aun_red_buffer[i-1];
- while(INT.read()==1); //等待傳感器信號
- maxim_max30102_read_fifo((aun_red_buffer+i), (aun_ir_buffer+i));
-
- if(aun_red_buffer[i]>un_prev_data) //只是根據相鄰兩個AD數據的偏差來確定LED的亮度
- {
- f_temp=aun_red_buffer[i]-un_prev_data;
- f_temp/=(un_max-un_min);
- f_temp*=MAX_BRIGHTNESS;
- n_brightness-=(int)f_temp;
- if(n_brightness<0)
- n_brightness=0;
- }
- else
- {
- f_temp=un_prev_data-aun_red_buffer[i];
- f_temp/=(un_max-un_min);
- f_temp*=MAX_BRIGHTNESS;
- n_brightness+=(int)f_temp;
- if(n_brightness>MAX_BRIGHTNESS)
- n_brightness=MAX_BRIGHTNESS;
- }
-
- if(flag==0) //兩個循環顯示一次
- {
- if(n_heart_rate>180)//脈搏過速
- display_erro();
- else
- {
- if(n_heart_rate<20)
- display_wait();
- else
- display_ir((float)n_brightness/5);
- }
- flag++;
- }
- else
- flag = 0;
-
- pwmled.write(1-(float)n_brightness/256);//PWM控制LED亮度
- if(n_brightness<120)
- led=1;
- else
- led=0;
- }
- maxim_heart_rate_and_oxygen_saturation(aun_ir_buffer, n_ir_buffer_length, aun_red_buffer, &n_sp02, &ch_spo2_valid, &n_heart_rate, &ch_hr_valid);
- pc.printf("HR=%i, ", n_heart_rate);
- pc.printf("SpO2=%i",n_sp02);
-
- LCD_write_value(24,5,3,0,n_sp02);
- LCD_write_value(67,5,3,0,n_heart_rate);
-
- }
- }
- /*********************************************
- * 函數名稱:LCD_Config
- * 函數功能:配置LCD引腳
- * 入口參數:無
- * 出口參數:無
- *********************************************/
- void LCD_Config(void)
- {
- GPIO_InitTypeDef GPIO_InitTypeDef; //定義結構體
- GPIO_InitTypeDef.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_5 | GPIO_PIN_10 | GPIO_PIN_11; //配置LCD引腳
- GPIO_InitTypeDef.Mode = GPIO_MODE_OUTPUT_PP; //推挽輸出
- GPIO_InitTypeDef.Speed = GPIO_SPEED_FREQ_HIGH; //速度
- HAL_GPIO_Init(GPIOB, &GPIO_InitTypeDef); //初始化GPIO
- }
- /*********************************************
- * 函數名稱:LCD_init
- * 函數功能:5110初始化
- * 入口參數:無
- * 出口參數:無
- * 備注:接通電源后需要一個RES低電平脈沖復位,當VDD變為高電平之后
- * 最多100ms,RST輸入低電平(<0.3VDD)
- *********************************************/
- void LCD_init(void)
- {
- LCD_Config(); //配置LCD連線
- LCD_RST_RESET; //LCD_RST = 0 復位LCD5110
-
- delay_us(2);
- LCD_RST_SET; //LCD_RST = 1;
- LCD_CE_RESET; //LCD_CE = 0; 關閉LCD
- delay_us(2);
- LCD_CE_SET; //LCD_CE = 1; 關閉LCD
- LCD_write_byte(0x21,0); //使用擴展LCD令設置LCD模式
- LCD_write_byte(0xc8,0); //設置液晶偏置電壓
- LCD_write_byte(0x06,0); //溫度校正(溫度系數2)
- LCD_write_byte(0x13,0); //1:48
- LCD_write_byte(0x20,0); //使用基本命令,V=0,水平尋址
- LCD_write_byte(0x0c,0); //設定顯示模式,正常顯示
- LCD_clear(); //清屏
- LCD_CE_SET; //LCD_CE = 1; //關閉LCD
- }
- /*********************************************
- * 函數名稱:LCD_write_byte
- * 函數功能:模擬SPI接口時序寫數據/命令LCD
- * 入口參數:data :寫入的數據;
- * dc :寫數據1/命令0選擇
- * 出口參數:無
- * 備注:管腳D/C(LCD_DC)用于選擇寫的是命令(D/C=0)還是數據(D/C=1)
- *********************************************/
- void LCD_write_byte(uint8_t dat,uint8_t dc)
- {
- uint8_t i;
-
- LCD_CLK_RESET; //先拉低時鐘CLK
-
- LCD_CE_RESET; //LCD_CE = 0; 選擇5110
-
- if (dc == 1)
- {
- LCD_DC_SET; //LCD_DC = dc; dc=0數據,dc=1命令
- }
- else {
- LCD_DC_RESET;
- }
- for (i=0; i<8; i++) //發送8位
- {
- if (dat & 0x80)
- {
- LCD_DIN_SET; //LCD_DIN = 1;
- }
- else {
- LCD_DIN_RESET; //LCD_DIN = 0;
- }
- LCD_CLK_SET; //LCD_CLK = 1;
- delay_us(1);
- dat = dat << 1; //移位,準備發送下一位
- LCD_CLK_RESET; //LCD_CLK = 0; //發送同步時鐘
- }
-
- LCD_CE_SET; //LCD_CE = 1; //關閉5110
- }
- /*********************************************
- * 函數名稱:LCD_set_XY
- * 函數功能:設置LCD坐標函數
- * 入口參數:X :0-83;
- * Y :0-5
- * 出口參數:無
- * 備注:
- *********************************************/
- void LCD_set_XY(uint8_t X,uint8_t Y)
- {
- LCD_write_byte(0x40 | Y,0); //column?
- LCD_write_byte(0x80 | X,0); //row?
- }
- /*********************************************
- * 函數名稱:LCD_clear
- * 函數功能:5110清屏(用空白寫滿屏幕)
- * 入口參數:無
- * 出口參數:無
- * 備注:
- *********************************************/
- void LCD_clear(void)
- {
- uint8_t i,j;
- LCD_set_XY(0,0); //定位左上角
- for (i=0; i<6; i++)
- {
- for (j=0; j<84; j++)
- {
- LCD_write_byte(0x00,1);
- }
- }
- }
- /*********************************************
- * 函數名稱:LCD_write_ASCII
- * 函數功能:顯示字符串5*7(8)
- * 入口參數:x,y,cid :顯示ASCII字符
- * 出口參數:無 編號(行號)32~127
- * 備注:ASCII碼表的數組ASC_5[95][8]來尋址
- *********************************************/
- void LCD_write_ASCII(uint8_t X,uint8_t Y,uint8_t *stru)
- {
- uint8_t i;
- LCD_set_XY(X,Y); //定位(左上角)
- while (1)
- {
- for ( i=0; i<5; i++) //輸出一個5*7字符
- {
- LCD_write_byte(ASC_5[*stru-32][i],1);
- }
- stru++;
-
- if(*stru == '\0') break; //在每個字符串的最后,會有一個'\0'
- LCD_write_byte(0x00,1); //插入空列
- }
- }
- /*********************************************
- * 函數名稱:LCD_write_ASC_SIN
- * 函數功能:顯示單個字符5*7(8)
- * 入口參數:x,y,cid :顯示ASCII字符
- * 出口參數:無 編號(行號)32~127
- * 備注:ASCII碼表的數組ASC_5[95][8]來尋址
- *********************************************/
- void LCD_write_ASC_SIN(uint8_t X,uint8_t Y,uint8_t cid)
- {
- uint8_t i;
- LCD_set_XY(X,Y); //定位(左上角)
- for ( i=0; i<5; i++) //輸出一個5*7字符
- {
- LCD_write_byte(ASC_5[cid-32][i],1);
- }
- }
- /*********************************************
- * 函數名稱:LCD_write_ASC7x12
- * 函數功能:顯示自定義字符7*12(16)
- * 入口參數:x,y,cid :顯示的字符 0 1 2 3 4 5 6 7 8 9 = m s
- * 出口參數:無 編號(行號)0,1,2,3,4,5,6,7,8,9,10,11,12
- * 備注:ASCII碼表的數組ASC_7[13][14]來尋址
- *********************************************/
- void LCD_write_ASC7x12(uint8_t X,uint8_t Y,uint8_t cid)
- {
- uint8_t i;
-
- LCD_set_XY(X,Y); //定位{左上角)
- for (i=0; i<7; i++) //顯示字符的上半部分(7列)
- {
- LCD_write_byte(ASC_7[cid][i],1);
- }
-
- LCD_set_XY(X,Y+1); //顯示字符的下半部分
- for (i=7; i<14; i++)
- {
- LCD_write_byte(ASC_7[cid][i],1);
- }
- }
- /*********************************************
- * 函數名稱:LCD_write_CHAR
- * 函數功能:顯示自定義字符12*14(16)
- * 入口參數:x,y,cid :顯示的字符 電子點焊機接間隔毫秒時
- * 出口參數:無 編號(行號)0,1,2,3,4,5,6,7,8,9,10
- * 備注:CHAR字庫的數組CHAR_12[11][24]來尋址
- ***********************************************/
- void LCD_write_char(uint8_t x,uint8_t y,uint8_t cid)
- {
- uint8_t i;
-
- LCD_set_XY(x,y); //定位(左上角)
- for (i=0; i<12; i++) //寫字符的上半部分(12列)
- {
- LCD_write_byte(CHAR_12[cid][i],1);
- }
-
- LCD_set_XY(x,y+1); //寫字符的下半部分
- for (i=12; i<24; i++)
- {
- LCD_write_byte(CHAR_12[cid][i],1);
- }
- }
- /*********************************************
- * 函數名稱:LCD_write_value
- * 函數功能:顯示變量字符5*7(8)或7*12(16)
- * 入口參數:x,y,L,val :座標、長度、小數、變量
- * 出口參數:無 編號(行號)
- * 備注:ASCII碼表的數組ASC_5[95][8]來尋址
- *********************************************/
- void LCD_write_value(uint8_t X,uint8_t Y,uint8_t L,uint8_t D,uint16_t val)
- {
- uint8_t i,j,f = 0; //列循環、字循環、顯示標志
- uint16_t n,t,cid; //當前倍數、余數、當前數字
- t = val;
- n = 1;
- for (j = 0; j < L; j++)
- n = n * 10;
-
- LCD_set_XY(X,Y); //定位(左上角)
- for (j = L; j > 0; j--) //字符循環開始
- {
- n = j < 2 ? 1: n / 10; //計算當前的倍數
- cid = t / n; //當前位數字
- t = t - (cid * n);
- if (cid > 0)
- f = 16;
- for ( i=0; i<5; i++) //寫一個5*7字符
- {
- LCD_write_byte(ASC_5[cid + f][i],1);
- }
- if ( D > 0 & D == (j - 1))
- {
- for ( i=0; i<5; i++) //寫小數點
- {
- LCD_write_byte(ASC_5[14][i],1);
- }
- }
- else
- if(j>1) LCD_write_byte(0x00,1);//插入空列
- }
- }
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
|