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黑下载附件…………
复制代码
|