STM32项目分享:基于STM32的泳池防溺水检测手环
“我们不做一锤子买卖,只做技术成长的长期伙伴!”
目录
一、视频展示
二、项目简介
三、原理图设计
四、PCB硬件设计
五、程序设计
六、资料分享
一、视频展示
基于STM32的泳池防溺水检测手环 -视频分享
二、项目简介
题目:基于STM32的泳池防溺水检测手环
主控:STM32
显示:oled显示
传感器:
MAX30102
气压传感器(模拟水压)
三按键
DC供电
声光报警:蜂鸣器+led
功能:
1、屏幕显示当前心率血氧,压力。
2、可按键设置最大心率,最低心率,最低血氧,最大压力阈值。
3、如果心率大于最大心率阈值或者低于最低就会触发蜂鸣器报警。
4、如果血氧低于最低血氧阈值,则进行蜂鸣器报警。
5、如果压力大于阈值,则进行蜂鸣器报警。
三、原理图设计
四、PCB硬件设计
五、程序设计
#include "stm32f10x.h" // Device header
#include "delay.h"
#include "lcd.h"
#include "timer.h"
#include "IOput.h"
#include "max30102.h"
#include "myiic.h"
#include "algorithm.h"
#include "usart.h"
#include "adc.h"
#include <math.h>
u32 press,pre,pree;
int ADC;
float Pressure_V=0.0;
long pressure=0;char V_disbuff[5]={0};
char P_disbuff[6]={0};const float VCC =3300; // ADC参考电压为mVconst float Voltage_0 =160; // 零点电压值mV 校准时需修改
const float Voltage_40 =3750 ; // 满量程输出电压值mV 需修改long map(long x, long in_min, long in_max, long out_min, long out_max);void BEND_Value_Conversion()
{/*显示电压值*/V_disbuff[0]=(long int)(Pressure_V)/1000+'0';V_disbuff[1]=(long int)(Pressure_V)%1000/100+'0'; V_disbuff[2]=(long int)(Pressure_V)%100/10+'0';V_disbuff[3]=(long int)(Pressure_V)%10+'0';pre= V_disbuff[0]*1000+V_disbuff[1]*100+V_disbuff[2]*10+V_disbuff[3];
// OLED_ShowString(36,2,V_disbuff,2);OLED_ShowNum(64,6,pre,4,16);/*显示气压值*/if(pressure<=0){pressure=0;}if(pressure>=40000){pressure=40000;}P_disbuff[0]=(int)((pressure))/10000+'0'; P_disbuff[1]=(int)((pressure))%10000/1000+'0';P_disbuff[2]=(int)((pressure))%1000/100+'0';P_disbuff[3]=(int)((pressure))%100/10+'0';P_disbuff[4]=(int)((pressure))%10+'0';pree= P_disbuff[0]*10000+P_disbuff[1]*1000+P_disbuff[2]*100+P_disbuff[3]*10+P_disbuff[4];
// OLED_ShowString(27,4,P_disbuff,2); OLED_ShowNum(64,4,pree,5,16);
}u8 max_yali=30;
u8 show_flag;uint32_t aun_ir_buffer[500]; //IR LED sensor data
int32_t n_ir_buffer_length; //data length
uint32_t aun_red_buffer[500]; //Red LED sensor data
int32_t n_sp02; //SPO2 value
int8_t ch_spo2_valid; //indicator to show if the SP02 calculation is valid
int32_t n_heart_rate; //heart rate value
int8_t ch_hr_valid; //indicator to show if the heart rate calculation is valid
uint8_t uch_dummy;
u8 dis_hr=0,dis_spo2=0;u8 max_hr = 140,min_spo2 = 90,max_wd = 38,dec_hr = 40;
#define MAX_BRIGHTNESS 255
//variables to calculate the on-board LED brightness that reflects the heartbeatsuint32_t un_min, un_max, un_prev_data; int i;int32_t n_brightness;float f_temp;u8 temp_num=0;u8 temp[6];u8 str[100];void dis_DrawCurve(u32* data,u8 x);void MAX30102_Read_Data(void)
{i=0;un_min=0x3FFFF;un_max=0;//dumping the first 100 sets of samples in the memory and shift the last 400 sets of samples to the topfor(i=100;i<500;i++){aun_red_buffer[i-100]=aun_red_buffer[i];aun_ir_buffer[i-100]=aun_ir_buffer[i];//update the signal min and maxif(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];}//take 100 sets of samples before calculating the heart rate.for(i=400;i<500;i++){un_prev_data=aun_red_buffer[i-1];while(MAX30102_INT==1);max30102_FIFO_ReadBytes(REG_FIFO_DATA,temp);aun_red_buffer[i] = (long)((long)((long)temp[0]&0x03)<<16) | (long)temp[1]<<8 | (long)temp[2]; // Combine values to get the actual numberaun_ir_buffer[i] = (long)((long)((long)temp[3] & 0x03)<<16) |(long)temp[4]<<8 | (long)temp[5]; // Combine values to get the actual numberif(aun_red_buffer[i]>un_prev_data){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;}//send samples and calculation result to terminal program through UARTif(ch_hr_valid == 1 && n_heart_rate<120)//**/ ch_hr_valid == 1 && ch_spo2_valid ==1 && n_heart_rate<120 && n_sp02<101{dis_hr = n_heart_rate;dis_spo2 = n_sp02;}else{dis_hr = 0;dis_spo2 = 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);//显示刷新if(dis_hr == 0 && dis_spo2 == 0) //**dis_hr == 0 && dis_spo2 == 0{// sprintf((char *)str,"HR:--- SpO2:--- ");//**HR:--- SpO2:--- OLED_ShowString(48,2,"---",16);OLED_ShowString(48,4,"---",16);}else{// sprintf((char *)str,"HR:%3d SpO2:%3d ",dis_hr,dis_spo2);//**HR:%3d SpO2:%3d OLED_ShowNum(48,2,dis_hr,3,16);OLED_ShowNum(48,4,dis_spo2,3,16);}}void Show_State(void)
{OLED_ShowCHinese(0,2,0);OLED_ShowCHinese(16,2,1);OLED_ShowChar(40,2,':',16);OLED_ShowCHinese(0,4,2);OLED_ShowCHinese(16,4,3);OLED_ShowChar(40,4,':',16);}int main (void)
{delay_init();NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);OLED_Init();delay_ms(1);OLED_Clear();input_init();output_init();TIM2_Int_Init(71,9999);max30102_init();un_min=0x3FFFF;un_max=0;n_ir_buffer_length=500; //buffer length of 100 stores 5 seconds of samples running at 100sps//read the first 500 samples, and determine the signal rangefor(i=0;i<n_ir_buffer_length;i++){while(MAX30102_INT==1); //wait until the interrupt pin assertsmax30102_FIFO_ReadBytes(REG_FIFO_DATA,temp);aun_red_buffer[i] = (long)((long)((long)temp[0]&0x03)<<16) | (long)temp[1]<<8 | (long)temp[2]; // Combine values to get the actual numberaun_ir_buffer[i] = (long)((long)((long)temp[3] & 0x03)<<16) |(long)temp[4]<<8 | (long)temp[5]; // Combine values to get the actual numberif(un_min>aun_red_buffer[i])un_min=aun_red_buffer[i]; //update signal minif(un_max<aun_red_buffer[i])un_max=aun_red_buffer[i]; //update signal max}un_prev_data=aun_red_buffer[i];//calculate heart rate and SpO2 after first 500 samples (first 5 seconds of samples)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); Adc_Init();while(1){press=Get_Adc_Average(1,10)*40/4095;key_scan(1,0,0);if(set_flag == 1){OLED_Clear();set_flag = 0;show_flag ++;if(show_flag >= 5)show_flag = 0;}if(show_flag == 1){
// ADC = Get_Adc_Average(1,10); //10次平均值
// Pressure_V=(ADC*VCC)/4096;
//// pressure = map(Pressure_V, Voltage_0, Voltage_40, 0, 40000.0);
// BEND_Value_Conversion();
// delay_ms(500);OLED_Showdecimal(48,6,press,2,2,16);OLED_ShowCH(0,0," 阈 值 修 改 ");OLED_ShowCH(0,2,"最大心率:");OLED_ShowNum(40,4,max_hr,3,16);if(dec_flag == 1){dec_flag = 0;max_hr --;}if(add_flag == 1){add_flag = 0;max_hr ++;}}if(show_flag == 2){OLED_ShowCH(0,0," 阈 值 修 改 ");OLED_ShowCH(0,2,"血氧:");OLED_ShowNum(40,4,min_spo2,3,16);if(dec_flag == 1){dec_flag = 0;min_spo2 --;}if(add_flag == 1){add_flag = 0;min_spo2 ++;}}if(show_flag == 3){OLED_ShowCH(0,0," 阈 值 修 改 ");OLED_ShowCH(0,2,"最小心率:");OLED_ShowNum(40,4,dec_hr,3,16);if(dec_flag == 1){dec_flag = 0;dec_hr --;}if(add_flag == 1){add_flag = 0;dec_hr ++;}}if(show_flag == 4){OLED_ShowCH(0,0," 阈 值 修 改 ");OLED_ShowCH(0,2,"压力:");OLED_ShowNum(40,4,max_yali,3,16);if(dec_flag == 1){dec_flag = 0;max_yali --;}if(add_flag == 1){add_flag = 0;max_yali ++;}if(max_yali>=41 || max_yali<=0)max_yali=0;}if(show_flag == 0){OLED_ShowCH(0,0," 防溺水检测手环 ");if((dis_hr > max_hr) || ((dis_spo2 > 0) && (dis_spo2 < min_spo2)) || ((dis_hr > 0)&&dis_hr<=dec_hr) || press>=max_yali) //**dis_hr == 0 && dis_spo2 == 0BEEP = 0;elseBEEP = 1;Show_State();MAX30102_Read_Data();OLED_ShowCH(0,6,"压力:");OLED_Showdecimal(48,6,press,2,2,16);}}
}
六、资料分享
点击即可查看当前资料分享。