stm32智能手表 - 实践
2026-01-18 17:36 tlnshuju 阅读(0) 评论(0) 收藏 举报成为粉丝可看全文。有相关代码、硬件和软件说明图。
主程序流程图

说明图:

主程序代码如下,可以修改为自己适用代码
#include "stm32f10x.h"
#include "OLED_I2C.h"
#include "ds1302.h"
#include "ds18b20.h"
#include "usart1.h"
#include "led.h"
#include "delay.h"
#include "max30102_read.h"
#include "myiic.h"
#include "key.h"
#include "iic.h"
#include "stdio.h"
#include "string.h"
#include "adxl345.h"
#include "timer.h"
#include
#include
#include
#define FLASH_SAVE_ADDR ((u32)0x0800F000) //设置FLASH 保存地址(必须为偶数)
#define STM32_RX1_BUF Usart1RecBuf
#define STM32_Rx1Counter RxCounter
#define STM32_RX1BUFF_SIZE USART1_RXBUFF_SIZE
unsigned char setn=0;
unsigned char p_r=0; //平年/润年 =0表示平年,=1表示润年
float adx,ady,adz;
float acc;
float acc2,acc3;
u8 flag=0;
u16 bushu=0;
long mileage=0;//里程
u16 mileage_bushu = 0;//里程的步数
u16 bu_long = 40;//步长
long warnMileage=1000;//提醒里程
short temperature=0;
u16 xinlvMin=60,xinlvMax=120;//心率下限上限
u16 spo2Min=80;//血氧下限
u16 tempMax=373;//温度上限
u16 tempMin=150;//温度下限
char display[16];
u8 shanshuo=0;
u8 beepFlag=0x00; //蜂鸣器报警标志
u8 page = 0; //页面切换变量
u8 sendFlag = 1;
/*定时时间*/
long timeCountRecord=0;
long shi=1,fen=0,miao=0;
bool startFlag=0; //开始定时标志
bool timingReminder=0; //定时时间提醒标志
bool mileageReminder=0; //里程提醒标志
bool sendSetValueFlag=0;
int32_t hrAvg;//心率
int32_t spo2Avg;//血氧浓度
void DisplayTime(void)//显示时间函数
{unsigned char i=0,x=0;u16 nian_temp;if(setn==0)DS1302_DateRead(&SysDate);//读时间nian_temp=2000+SysDate.year;if((nian_temp%400==0)||((nian_temp%100!=0)&&(nian_temp%4==0))) //判断是否为闰年p_r=1;elsep_r=0;if(setn<8 && page==0){OLED_ShowChar((x++)*8,0,'2',2,setn+1-1);OLED_ShowChar((x++)*8,0,'0',2,setn+1-1);OLED_ShowChar((x++)*8,0,SysDate.year/10+'0',2,setn+1-1);OLED_ShowChar((x++)*8,0,SysDate.year%10+'0',2,setn+1-1);OLED_ShowChar((x++)*8,0,'-',2,0);OLED_ShowChar((x++)*8,0,SysDate.mon/10+'0',2,setn+1-2);OLED_ShowChar((x++)*8,0,SysDate.mon%10+'0',2,setn+1-2);OLED_ShowChar((x++)*8,0,'-',2,0);OLED_ShowChar((x++)*8,0,SysDate.day/10+'0',2,setn+1-3);OLED_ShowChar((x++)*8,0,SysDate.day%10+'0',2,setn+1-3);OLED_ShowCN(i*16+88,0,0,setn+1-4);//测试显示中文:周switch(SysDate.week){case 1:OLED_ShowCN(i*16+104,0,1,setn+1-4);//测试显示中文:一break;case 2:OLED_ShowCN(i*16+104,0,2,setn+1-4);//测试显示中文:二break;case 3:OLED_ShowCN(i*16+104,0,3,setn+1-4);//测试显示中文:三break;case 4:OLED_ShowCN(i*16+104,0,4,setn+1-4);//测试显示中文:四break;case 5:OLED_ShowCN(i*16+104,0,i+5,setn+1-4);//测试显示中文:五break;case 6:OLED_ShowCN(i*16+104,0,6,setn+1-4);//测试显示中文:六break;case 7:OLED_ShowCN(i*16+104,0,7,setn+1-4);//测试显示中文:日break;}x=0;OLED_ShowChar((x++)*8,2,SysDate.hour/10+'0',2,setn+1-5);OLED_ShowChar((x++)*8,2,SysDate.hour%10+'0',2,setn+1-5);OLED_ShowChar((x++)*8,2,':',2,0);OLED_ShowChar((x++)*8,2,SysDate.min/10+'0',2,setn+1-6);OLED_ShowChar((x++)*8,2,SysDate.min%10+'0',2,setn+1-6);OLED_ShowChar((x++)*8,2,':',2,0);OLED_ShowChar((x++)*8,2,SysDate.sec/10+'0',2,setn+1-7);OLED_ShowChar((x++)*8,2,SysDate.sec%10+'0',2,setn+1-7);}
}
void GetHeartRateSpO2(void)
{unsigned char x=0;ReadHeartRateSpO2(); //读取心率血氧if(page==0){//显示相关的信息if(((hrAvg!=0)&&(hrAvg>=xinlvMax||hrAvg<=xinlvMin))&&shanshuo==1){OLED_ShowChar((x++)*8,6,' ',2,0);OLED_ShowChar((x++)*8,6,' ',2,0);OLED_ShowChar((x++)*8,6,' ',2,0);}else{//显示相关的信息OLED_ShowChar((x++)*8,6,hrAvg%1000/100+'0',2,0);OLED_ShowChar((x++)*8,6,hrAvg%100/10+'0',2,0);OLED_ShowChar((x++)*8,6,hrAvg%10+'0',2,0);}x=6;if(((spo2Avg!=0)&&(spo2Avg<=spo2Min))&&shanshuo==1){OLED_ShowChar((x++)*8,6,' ',2,0);OLED_ShowChar((x++)*8,6,' ',2,0);OLED_ShowChar((x++)*8,6,' ',2,0);}else{//显示相关的信息OLED_ShowChar((x++)*8,6,spo2Avg%1000/100+'0',2,0);OLED_ShowChar((x++)*8,6,spo2Avg%100/10+'0',2,0);OLED_ShowChar((x++)*8,6,spo2Avg%10+'0',2,0);}}
}
void DisplayTemperature(void)//显示温度函数
{unsigned char x=10;//显示的第几个字符temperature=DS18B20_Get_Temp();if(page==0){if((temperature<=tempMin||temperature>=tempMax)&&shanshuo==1){OLED_ShowChar((x++)*8,2,' ',2,0);OLED_ShowChar((x++)*8,2,' ',2,0);OLED_ShowChar((x++)*8,2,' ',2,0);OLED_ShowChar((x++)*8,2,' ',2,0);}else{OLED_ShowChar((x++)*8,2,temperature/100+'0',2,0);OLED_ShowChar((x++)*8,2,temperature%100/10+'0',2,0);OLED_ShowChar((x++)*8,2,'.',2,0);OLED_ShowChar((x++)*8,2,temperature%10+'0',2,0);}}
}
void Store_Data(void) //存储数据
{u16 DATA_BUF[10];DATA_BUF[0] = bushu;DATA_BUF[1] = mileage_bushu;DATA_BUF[2] = bu_long;DATA_BUF[3] = xinlvMin;DATA_BUF[4] = xinlvMax;DATA_BUF[5] = spo2Min;DATA_BUF[6] = tempMin;DATA_BUF[7] = tempMax;DATA_BUF[8] = (warnMileage>>16)&0xFFFF;DATA_BUF[9] = (warnMileage>>0)&0xFFFF;STMFLASH_Write(FLASH_SAVE_ADDR + 0x20,(u16*)DATA_BUF,10); //写入数据DelayMs(50);
}
void Read_Data(void) //读出数据
{u16 DATA_BUF[10];STM32F10x_Read(FLASH_SAVE_ADDR + 0x20,(u16*)DATA_BUF,10); //读取数据bushu = DATA_BUF[0];mileage_bushu = DATA_BUF[1];bu_long = DATA_BUF[2];xinlvMin = DATA_BUF[3];xinlvMax = DATA_BUF[4];spo2Min = DATA_BUF[5];tempMin = DATA_BUF[6];tempMax = DATA_BUF[7];warnMileage = DATA_BUF[8]<<16|DATA_BUF[9];
}
void CheckNewMcu(void) // 检查是否是新的单片机,是的话清空存储区,否则保留
{u8 comper_str[6];STM32F10x_Read(FLASH_SAVE_ADDR,(u16*)comper_str,5);comper_str[5] = '\0';if(strstr((char *)comper_str,"FDYDZ") == NULL) //新的单片机{STMFLASH_Write(FLASH_SAVE_ADDR,(u16*)"FDYDZ",5); //写入“FDYDZ”,方便下次校验DelayMs(50);Store_Data();//存储下初始数据DelayMs(50);}Read_Data(); //开机读取下相关数据(步数里程卡路里步长)
}
void GetSteps(void)//获取步数函数
{static u16 temp=0;float tempMileage=0.0;u16 x=11;adxl345_read_average(&adx,&ady,&adz,10);//获取数据acc=ady;if(acc>0)//在正轴{if(acc/10>=4&&flag==1)//加速度值,在正轴值是否大于5,并且flag为1,则视为一个周期完成,步数加1{flag=0;if(bushu<60000)bushu++; //步数加1if(mileage_bushu<60000)mileage_bushu++; //步数加1if(temp!=bushu)//当步数发生变化才去存储步数{temp=bushu;Store_Data(); //存储步数}}}if(acc<0)//在负轴{acc=-acc;if(acc/10>=4)//加速度值,在负轴是否小于-5{flag=1;//falg置1}}mileage = (mileage_bushu * bu_long)/100;//计算里程tempMileage = (float)mileage/1000;//转换为千米if(page==0){if(bushu>9999){OLED_ShowChar((x++)*8,6,bushu/10000+'0',2,0);OLED_ShowChar((x++)*8,6,bushu%10000/1000+'0',2,0);OLED_ShowChar((x++)*8,6,bushu%1000/100+'0',2,0);OLED_ShowChar((x++)*8,6,bushu%100/10+'0',2,0);OLED_ShowChar((x++)*8,6,bushu%10+'0',2,0);}else if(bushu>999){OLED_ShowChar((x++)*8,6,' ',2,0);OLED_ShowChar((x++)*8,6,bushu%10000/1000+'0',2,0);OLED_ShowChar((x++)*8,6,bushu%1000/100+'0',2,0);OLED_ShowChar((x++)*8,6,bushu%100/10+'0',2,0);OLED_ShowChar((x++)*8,6,bushu%10+'0',2,0);}else if(bushu>99){OLED_ShowChar((x++)*8,6,' ',2,0);OLED_ShowChar((x++)*8,6,' ',2,0);OLED_ShowChar((x++)*8,6,bushu%1000/100+'0',2,0);OLED_ShowChar((x++)*8,6,bushu%100/10+'0',2,0);OLED_ShowChar((x++)*8,6,bushu%10+'0',2,0);}else if(bushu>9){OLED_ShowChar((x++)*8,6,' ',2,0);OLED_ShowChar((x++)*8,6,' ',2,0);OLED_ShowChar((x++)*8,6,bushu%100/10+'0',2,0);OLED_ShowChar((x++)*8,6,bushu%10+'0',2,0);OLED_ShowChar((x++)*8,6,' ',2,0);}else{OLED_ShowChar((x++)*8,6,' ',2,0);OLED_ShowChar((x++)*8,6,' ',2,0);OLED_ShowChar((x++)*8,6,bushu%10+'0',2,0);OLED_ShowChar((x++)*8,6,' ',2,0);OLED_ShowChar((x++)*8,6,' ',2,0);}}else{sprintf(display,"%6.3fkm ",tempMileage);OLED_ShowStr(48,2,(u8 *)display,2);}
}
void DisplaySetValue(void) //显示设置值
{if(page==0){if(setn==8||setn==9){OLED_ShowChar(48,4,xinlvMin/100+'0',2,setn+1-8);//显示OLED_ShowChar(56,4,xinlvMin%100/10+'0',2,setn+1-8);//显示OLED_ShowChar(64,4,xinlvMin%10+'0',2,setn+1-8);//显示OLED_ShowChar(48,6,xinlvMax/100+'0',2,setn+1-9);//显示OLED_ShowChar(56,6,xinlvMax%100/10+'0',2,setn+1-9);//显示OLED_ShowChar(64,6,xinlvMax%10+'0',2,setn+1-9);//显示}if(setn==10){OLED_ShowChar(48,4,spo2Min/100+'0',2,setn+1-10);//显示OLED_ShowChar(56,4,spo2Min%100/10+'0',2,setn+1-10);//显示OLED_ShowChar(64,4,spo2Min%10+'0',2,setn+1-10);//显示}if(setn==11||setn==12){OLED_ShowChar(48,4,tempMin/100+'0',2,setn+1-11);//显示OLED_ShowChar(56,4,tempMin%100/10+'0',2,setn+1-11);//显示OLED_ShowChar(64,4,'.',2,setn+1-11);OLED_ShowChar(72,4,tempMin%10+'0',2,setn+1-11);//显示OLED_ShowChar(48,6,tempMax/100+'0',2,setn+1-12);//显示OLED_ShowChar(56,6,tempMax%100/10+'0',2,setn+1-12);//显示OLED_ShowChar(64,6,'.',2,setn+1-12);OLED_ShowChar(72,6,tempMax%10+'0',2,setn+1-12);//显示}}else{if(setn==4){sprintf((char *)display,"%dcm ",bu_long);OLED_ShowStr(48, 4, (u8*)display, 2);//显示经度}if(setn==5){sprintf(display,"%6.3fkm ",(float)warnMileage/1000);OLED_ShowStr(35,4,(u8 *)display,2);}}
}
bool press = 0;
void KeySettings(void)//按键设置函数
{unsigned char keynum = 0,i;static u16 pressCount=0;u16 beepCount=0;keynum = KEY_Scan(1);//获取按键值if(keynum==1)//设置{setn++;if(page==1){if(setn > 5){setn=0;sendSetValueFlag=1;Store_Data();OLED_CLS();//清屏for(i=0;i<2;i++)OLED_ShowCN(i*16,2,i+44,0);//显示中文:里程OLED_ShowChar(32,2,':',2,0);}if(setn==4){OLED_CLS();//清屏for(i=0;i<4;i++)OLED_ShowCN(i*16+32,0,i+46,0);//测试显示中文:设置步长}if(setn==5){for(i=0;i<6;i++)OLED_ShowCN(i*16+16,0,i+50,0);//测试显示中文:设置提醒里程}}else{if(setn > 12){setn=0;sendSetValueFlag=1;OLED_CLS();//清屏for(i=0;i<2;i++)OLED_ShowCN(i*16,4,i+16,1);//测试显示中文:心率for(i=0;i<2;i++)OLED_ShowCN(i*16+48,4,i+18,1);//测试显示中文:血氧for(i=0;i<2;i++)OLED_ShowCN(i*16+95,4,i+20,1);//测试显示中文:步数OLED_ShowCentigrade(112, 2); //℃DelayMs(50);Store_Data();}if(setn==8){OLED_CLS();//清屏for(i=0;i<4;i++)OLED_ShowCN(i*16+32,0,i+22,0);//测试显示中文:设置心率for(i=0;i<2;i++)OLED_ShowCN(i*16,4,i+26,0); //测试显示中文:下限for(i=0;i<2;i++)OLED_ShowCN(i*16,6,i+28,0); //测试显示中文:上限OLED_ShowChar(34,4,':',2,0);OLED_ShowChar(34,6,':',2,0);}if(setn==10){for(i=0;i<4;i++)OLED_ShowCN(i*16+32,0,i+30,0);//测试显示中文:设置血氧for(i=0;i<2;i++)OLED_ShowCN(i*16,4,i+26,0); //测试显示中文:下限OLED_ShowStr(0,6," ", 2);}if(setn==11){for(i=0;i<4;i++)OLED_ShowCN(i*16+32,0,i+34,0);//测试显示中文:设置温度for(i=0;i<2;i++)OLED_ShowCN(i*16,4,i+26,0); //测试显示中文:下限for(i=0;i<2;i++)OLED_ShowCN(i*16,6,i+28,0); //测试显示中文:上限OLED_ShowChar(34,4,':',2,0);OLED_ShowChar(34,6,':',2,0);}}DisplaySetValue();}if(keynum==2)//加{if(setn == 0 && page==1){if(pressCount<10)pressCount++;if(press==0){press=1;BEEP=1;DelayMs(100);BEEP=0;if(timingReminder==1) //如果是提醒时间到了,先关闭提醒{timingReminder=0;beepFlag&=0xFD;}else{startFlag=!startFlag;}}if(pressCount>=5) //长按进行时间清零{startFlag=0;timeCountRecord=0;while(beepCount<1000){BEEP=1;beepCount++;DelayMs(1);}BEEP=0;pressCount=0;}}if(page==1){if(setn == 1)//设置提醒时间的小时{shi ++;if(shi == 100)shi=0;}if(setn == 2)//设置提醒时间的分钟{fen ++;if(fen == 60)fen=0;}if(setn == 3)//设置提醒时间的秒{miao ++;if(miao == 60)miao=0;}if(setn == 4)//设置步长{if(bu_long<200)bu_long++;}if(setn == 5)//设置提醒里程{if(warnMileage<20000)warnMileage+=10;}}else{if(setn == 1)//设置年{SysDate.year ++;if(SysDate.year == 100)SysDate.year=0;DS1302_DateSet(&SysDate);//设置时间}if(setn == 2)//设置月{SysDate.mon ++;if(SysDate.mon == 13)SysDate.mon = 1;if((SysDate.mon==4)||(SysDate.mon==6)||(SysDate.mon==9)||(SysDate.mon==11)){if(SysDate.day>30)SysDate.day=1;}else{if(SysDate.mon==2){if(p_r==1){if(SysDate.day>29)SysDate.day=1;}else{if(SysDate.day>28)SysDate.day=1;}}}DS1302_DateSet(&SysDate);//设置时间}if(setn == 3)//设置日{SysDate.day ++;if((SysDate.mon==1)||(SysDate.mon==3)||(SysDate.mon==5)||(SysDate.mon==7)||(SysDate.mon==8)||(SysDate.mon==10)||(SysDate.mon==12))//大月{if(SysDate.day==32)//最大31天SysDate.day=1;//从1开始}else{if(SysDate.mon==2)//二月份{if(p_r==1)//闰年{if(SysDate.day==30)//最大29天SysDate.day=1;}else{if(SysDate.day==29)//最大28天SysDate.day=1;}}else{if(SysDate.day==31)//最大30天SysDate.day=1;}}DS1302_DateSet(&SysDate);//设置时间}if(setn == 4)//设置星期{SysDate.week ++;if(SysDate.week == 8)SysDate.week=1;DS1302_DateSet(&SysDate);//设置时间}if(setn == 5)//设置时{SysDate.hour ++;if(SysDate.hour == 24)SysDate.hour=0;DS1302_DateSet(&SysDate);//设置时间}if(setn == 6)//设置分{SysDate.min ++;if(SysDate.min == 60)SysDate.min=0;DS1302_DateSet(&SysDate);//设置时间}if(setn == 7)//设置秒{SysDate.sec ++;if(SysDate.sec == 60)SysDate.sec=0;DS1302_DateSet(&SysDate);//设置时间}if((setn==8)&&(xinlvMax-xinlvMin>1))xinlvMin++;if((setn==9)&&(xinlvMax<300))xinlvMax++;if((setn==10)&&(spo2Min<200))spo2Min++;if((setn==11)&&(tempMax-tempMin>1))tempMin++;if((setn==12)&&(tempMax<999))tempMax++;}DisplaySetValue();}else{if(press==1){press=0;pressCount=0;}}if(keynum==3)//减{if(page==1){if(setn == 0){if(mileageReminder==1) //如果是提醒里程到了,先关闭提醒{mileageReminder=0;BEEP=0;}else if(mileageReminder==0) //里程清零{mileage=0;mileage_bushu=0;Store_Data(); //存储步数}}if(setn == 1)//设置提醒时间的小时{if(shi == 0)shi=100;shi --;}if(setn == 2)//设置提醒时间的分钟{if(fen == 0)fen=60;fen --;}if(setn == 3)//设置提醒时间的秒{if(miao == 0)miao=60;miao --;}if(setn == 4)//设置步长{if(bu_long>0)bu_long--;}if(setn == 5)//设置提醒里程{if(warnMileage>=10)warnMileage-=10;}}else{if(setn == 1)//设置年{if(SysDate.year == 0)SysDate.year=100;SysDate.year --;DS1302_DateSet(&SysDate);}if(setn == 2)//设置月{if(SysDate.mon == 1)SysDate.mon=13;SysDate.mon --;if((SysDate.mon==4)||(SysDate.mon==6)||(SysDate.mon==9)||(SysDate.mon==11)){if(SysDate.day>30)SysDate.day=1;}else{if(SysDate.mon==2){if(p_r==1){if(SysDate.day>29)SysDate.day=1;}else{if(SysDate.day>28)SysDate.day=1;}}}DS1302_DateSet(&SysDate);}if(setn == 3)//设置日{SysDate.day --;if((SysDate.mon==1)||(SysDate.mon==3)||(SysDate.mon==5)||(SysDate.mon==7)||(SysDate.mon==8)||(SysDate.mon==10)||(SysDate.mon==12)){if(SysDate.day==0)SysDate.day=31;}else{if(SysDate.mon==2){if(p_r==1){if(SysDate.day==0)SysDate.day=29;}else{if(SysDate.day==0)SysDate.day=28;}}else{if(SysDate.day==0)SysDate.day=30;}}DS1302_DateSet(&SysDate);}if(setn == 4)//设置星期{if(SysDate.week == 1)SysDate.week=8;SysDate.week --;DS1302_DateSet(&SysDate);}if(setn == 5)//设置时{if(SysDate.hour == 0)SysDate.hour=24;SysDate.hour --;DS1302_DateSet(&SysDate);}if(setn == 6)//设置分{if(SysDate.min == 0)SysDate.min=60;SysDate.min --;DS1302_DateSet(&SysDate);}if(setn == 7)//设置秒{if(SysDate.sec == 0)SysDate.sec=60;SysDate.sec --;DS1302_DateSet(&SysDate);}if((setn==8)&&(xinlvMin>0))xinlvMin--;if((setn==9)&&(xinlvMax-xinlvMin>1))xinlvMax--;if((setn==10)&&(spo2Min>0))spo2Min--;if((setn==11)&&(tempMin>0))tempMin--;if((setn==12)&&(tempMax-tempMin>1))tempMax--;}DisplaySetValue();}if(keynum==4&&page==0)//步数清零{bushu = 0;Store_Data();//存储数据}if(keynum==5 && setn == 0)//切换显示界面{page=!page;OLED_CLS();//清屏if(page==0){for(i=0;i<2;i++)OLED_ShowCN(i*16,4,i+16,1);//测试显示中文:心率for(i=0;i<2;i++)OLED_ShowCN(i*16+48,4,i+18,1);//测试显示中文:血氧for(i=0;i<2;i++)OLED_ShowCN(i*16+95,4,i+20,1);//测试显示中文:步数OLED_ShowCentigrade(112, 2); //℃}else{for(i=0;i<2;i++)OLED_ShowCN(i*16,2,i+44,0);//显示中文:里程OLED_ShowChar(32,2,':',2,0);}}
}
void displayTimeCunt(void) //显示定时时间
{if(page==1){if(setn==0){OLED_ShowChar(32,0,timeCountRecord/3600/10+'0',2,0);OLED_ShowChar(40,0,timeCountRecord/3600%10+'0',2,0);OLED_ShowChar(48,0,':',2,0);OLED_ShowChar(56,0,timeCountRecord%3600/60/10+'0',2,0);OLED_ShowChar(64,0,timeCountRecord%3600/60%10+'0',2,0);OLED_ShowChar(72,0,':',2,0);OLED_ShowChar(80,0,timeCountRecord%3600%60/10+'0',2,0);OLED_ShowChar(88,0,timeCountRecord%3600%60%10+'0',2,0);}else{if(setn<4){OLED_ShowChar(32,0,shi/10+'0',2,setn+1-1);OLED_ShowChar(40,0,shi%10+'0',2,setn+1-1);OLED_ShowChar(48,0,':',2,0);OLED_ShowChar(56,0,fen/10+'0',2,setn+1-2);OLED_ShowChar(64,0,fen%10+'0',2,setn+1-2);OLED_ShowChar(72,0,':',2,0);OLED_ShowChar(80,0,miao/10+'0',2,setn+1-3);OLED_ShowChar(88,0,miao%10+'0',2,setn+1-3);}}}
}
void UsartSendReceiveData(void) //串口发送接收数据
{char *str1=0,*str2=0,i;int setValue=0;char setvalue[4]={0};if(strlen(STM32_RX1_BUF) > 0){DelayMs(10);if(strstr(STM32_RX1_BUF,"setHeartMin:")!=NULL) //接收到设置心率下限的指令{str1 = strstr(STM32_RX1_BUF,"setHeartMin:");while(*str1 < '0' || *str1 > '9') //判断是不是0到9有效数字{str1 = str1 + 1;DelayMs(10);}i = 0;while(*str1 >= '0' && *str1 <= '9') //判断是不是0到9有效数字{setvalue[i] = *str1;i ++; str1 ++;if(*str1 == '\r')break; //换行符,直接退出while循环DelayMs(10);}setvalue[i] = '\0'; //加上结尾符setValue = atoi(setvalue);if(setValue>=0 && setValue<=300){xinlvMin = setValue; //设置的心率下限DisplaySetValue();Store_Data();//存储数据}}if(strstr(STM32_RX1_BUF,"setHeartMax:")!=NULL) //接收到设置心率上限的指令{str1 = strstr(STM32_RX1_BUF,"setHeartMax:");while(*str1 < '0' || *str1 > '9') //判断是不是0到9有效数字{str1 = str1 + 1;DelayMs(10);}i = 0;while(*str1 >= '0' && *str1 <= '9') //判断是不是0到9有效数字{setvalue[i] = *str1;i ++; str1 ++;if(*str1 == '\r')break; //换行符,直接退出while循环DelayMs(10);}setvalue[i] = '\0'; //加上结尾符setValue = atoi(setvalue);if(setValue>=0 && setValue<=300){xinlvMax = setValue; //设置的心率上限DisplaySetValue();Store_Data();//存储数据}}if(strstr(STM32_RX1_BUF,"setSpo2Min:")!=NULL) //接收到设置血氧下限的指令{str1 = strstr(STM32_RX1_BUF,"setSpo2Min:");while(*str1 != ':') //判断是不是0到9有效数字{str1 = str1 + 1;DelayMs(10);}str1 = str1 + 1;i = 0;while(*str1 >= '0' && *str1 <= '9') //判断是不是0到9有效数字{setvalue[i] = *str1;i ++; str1 ++;if(*str1 == '\r')break; //换行符,直接退出while循环DelayMs(10);}setvalue[i] = '\0'; //加上结尾符setValue = atoi(setvalue);if(setValue>=0 && setValue<=200){spo2Min = setValue; //设置的血氧下限DisplaySetValue();Store_Data();//存储数据}}if(strstr(STM32_RX1_BUF,"setTempMin:")!=NULL) //接收到设置温度下限的指令{str1 = strstr(STM32_RX1_BUF,"setTempMin:");while(*str1 < '0' || *str1 > '9') //判断是不是0到9有效数字{str1 = str1 + 1;DelayMs(10);}i = 0;while(*str1 >= '0' && *str1 <= '9') //判断是不是0到9有效数字{setvalue[i] = *str1;i ++; str1 ++;if(*str1 == '.')break; //换行符,直接退出while循环DelayMs(10);}if(*str1 == '.'){str1 = str1 + 1;}if(*str1 >= '0' && *str1 <= '9'){setvalue[i] = *str1;}i = i + 1;setvalue[i] = '\0'; //加上结尾符setValue = atoi(setvalue);if(setValue>=0 && setValue<=999){tempMin = setValue; //设置的温度下限DisplaySetValue();Store_Data();//存储数据}}if(strstr(STM32_RX1_BUF,"setTempMax:")!=NULL) //接收到设置温度上限的指令{str1 = strstr(STM32_RX1_BUF,"setTempMax:");while(*str1 < '0' || *str1 > '9') //判断是不是0到9有效数字{str1 = str1 + 1;DelayMs(10);}i = 0;while(*str1 >= '0' && *str1 <= '9') //判断是不是0到9有效数字{setvalue[i] = *str1;i ++; str1 ++;if(*str1 == '.')break; //换行符,直接退出while循环DelayMs(10);}if(*str1 == '.'){str1 = str1 + 1;}if(*str1 >= '0' && *str1 <= '9'){setvalue[i] = *str1;}i = i + 1;setvalue[i] = '\0'; //加上结尾符setValue = atoi(setvalue);if(setValue>=0 && setValue<=999){tempMax = setValue; //设置的温度上限DisplaySetValue();Store_Data();//存储数据}}if(strstr(STM32_RX1_BUF,"setSteps:")!=NULL) //接收到设置步长的指令{str1 = strstr(STM32_RX1_BUF,"setSteps:");while(*str1 < '0' || *str1 > '9') //判断是不是0到9有效数字{str1 = str1 + 1;DelayMs(10);}i = 0;while(*str1 >= '0' && *str1 <= '9') //判断是不是0到9有效数字{setvalue[i] = *str1;i ++; str1 ++;if(*str1 == '\r')break; //换行符,直接退出while循环DelayMs(10);}setvalue[i] = '\0'; //加上结尾符setValue = atoi(setvalue);if(setValue>=0 && setValue<=200){bu_long = setValue; //设置的步长DisplaySetValue();Store_Data();//存储数据}}if(strstr(STM32_RX1_BUF,"setMileage:")!=NULL) //接收到设置里程的指令{str1 = strstr(STM32_RX1_BUF,"setMileage:");while(*str1 < '0' || *str1 > '9') //判断是不是0到9有效数字{str1 = str1 + 1;DelayMs(10);}i = 0;while(*str1 >= '0' && *str1 <= '9') //判断是不是0到9有效数字{setvalue[i] = *str1;i ++; str1 ++;if(*str1 == '.')break; //换行符,直接退出while循环DelayMs(10);}if(*str1 == '.'){str1 = str1 + 1;}while(*str1 >= '0' && *str1 <= '9') //判断是不是0到9有效数字{setvalue[i] = *str1;i ++; str1 ++;if(*str1 == '\r')break; //换行符,直接退出while循环DelayMs(10);}setvalue[i] = '\0'; //加上结尾符setValue = atoi(setvalue);if(setValue>=0 && setValue<=999){warnMileage = setValue*10; //设置的提醒里程DisplaySetValue();Store_Data();//存储数据}}if(strstr(STM32_RX1_BUF,"warntime")!=NULL) //接收到设置提醒时间的指令{press=1;BEEP = 1;DelayMs(80);BEEP = 0;str2 = strstr(STM32_RX1_BUF,"warntime");while(*str2 < '0' || *str2 > '9') //判断是不是0到9有效数字{str2 = str2 + 1;DelayMs(10);}i = 0;while(*str2 >= '0' && *str2 <= '9') //判断是不是0到9有效数字{setvalue[i] = *str2;i ++; str2 ++;if(*str2 == ':')break;DelayMs(10);}setvalue[i] = '\0'; //加上结尾符setValue = atoi(setvalue);if(setValue>=0 && setValue<=99){shi = setValue; //提醒时间的小时displayTimeCunt();}str2 = str2 + 1;i = 0;while(*str2 >= '0' && *str2 <= '9') //判断是不是0到9有效数字{setvalue[i] = *str2;i ++; str2 ++;if(*str2 == ':')break;DelayMs(10);}setvalue[i] = '\0'; //加上结尾符setValue = atoi(setvalue);if(setValue>=0 && setValue<=59){fen = setValue; //提醒时间的分钟displayTimeCunt();}str2 = str2 + 1;i = 0;while(*str2 >= '0' && *str2 <= '9') //判断是不是0到9有效数字{setvalue[i] = *str2;i ++; str2 ++;if(*str2 == '\r')break;DelayMs(10);}setvalue[i] = '\0'; //加上结尾符setValue = atoi(setvalue);if(setValue>=0 && setValue<=59){miao = setValue; //提醒时间的秒displayTimeCunt();}}if(strstr(STM32_RX1_BUF,"stepsClear")!=NULL) //收到步数清零指令{press=1;BEEP = 1;DelayMs(80);BEEP = 0;bushu = 0;Store_Data(); //存储数据}if(strstr(STM32_RX1_BUF,"mileageClear")!=NULL) //收到里程清零指令{press=1;BEEP = 1;DelayMs(80);BEEP = 0;mileage=0;mileage_bushu=0;Store_Data(); //存储数据}if(strstr(STM32_RX1_BUF,"timeClear")!=NULL) //收到时间清零指令{press=1;BEEP = 1;DelayMs(80);BEEP = 0;timingReminder=0;beepFlag&=0xFD;startFlag=0;timeCountRecord=0;}if(strstr(STM32_RX1_BUF,"startTiming")!=NULL) //收到开始定时指令{press=1;BEEP = 1;DelayMs(80);BEEP = 0;startFlag=1;}if(strstr(STM32_RX1_BUF,"pauseTiming")!=NULL)//收到暂停定时指令{press=1;BEEP = 1;DelayMs(80);BEEP = 0;startFlag=0;}if(strstr(STM32_RX1_BUF,"offMileage")!=NULL) //收到关闭里程提醒指令{press=1;BEEP = 1;DelayMs(80);BEEP = 0;mileageReminder=0;}if(strstr(STM32_RX1_BUF,"offTime")!=NULL)//收到关闭时间提醒指令{press=1;BEEP = 1;DelayMs(80);BEEP = 0;timingReminder=0;beepFlag&=0xFD;}memset(STM32_RX1_BUF, 0, STM32_RX1BUFF_SIZE);//清除缓存STM32_Rx1Counter = 0;}/* 蓝牙发送数据 */if(sendFlag==1){sendFlag = 0;printf("$Heartrate:%d#,$Spo2:%d#,$Temperature:%4.1f#,",hrAvg,spo2Avg,(float)temperature/10);printf("$Steps:%d#,$Mileage:%6.3f#,",bushu,(float)mileage/1000);printf("$Hour:%02d#,",(int)(timeCountRecord/3600));printf("$Min:%02d#,",(int)(timeCountRecord%3600/60));printf("$Sec:%02d#",(int)(timeCountRecord%3600%60));printf("send ok.");if(sendSetValueFlag==1){sendSetValueFlag=0;DelayMs(500);printf("$setHeartMin:%d#,",xinlvMin);printf("$setHeartMax:%d#,",xinlvMax);printf("$setSpo2Min:%d#,",spo2Min);printf("$setTempMin:%4.1f#,",(float)tempMin/10);printf("$setTempMax:%4.1f#,",(float)tempMax/10);printf("send test data.");printf("$setLength:%d#,",bu_long);printf("$setMileage:%5.2f#\r\n",(float)warnMileage/1000);}}
}
int main(void)
{unsigned char i;DelayInit();NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级KEY_Init(); //按键初始化DelayMs(200);I2C_Configuration(); //IIC初始化OLED_Init(); //OLED初始化CheckNewMcu();OLED_CLS();//清屏DS18B20_Init();DS1302_Init(&SysDate);uart1_Init(9600);DelayMs(100);for(i=0;i<8;i++)OLED_ShowCN(i*16,2,i+8,0);//测试显示中文:欢迎使用使能手环DelayMs(1000);OLED_CLS();//清屏DS1302_DateRead(&SysDate);//读时间OLED_CLS();//清屏for(i=0;i<2;i++)OLED_ShowCN(i*16,4,i+16,1);//测试显示中文:心率for(i=0;i<2;i++)OLED_ShowCN(i*16+48,4,i+18,1);//测试显示中文:血氧for(i=0;i<2;i++)OLED_ShowCN(i*16+95,4,i+20,1);//测试显示中文:步数OLED_ShowCentigrade(112, 2); //℃IIC_init();//IIC初始化adxl345_init();//ADXL345初始化Init_MAX30102();//MAX30102初始化memset(STM32_RX1_BUF, 0, STM32_RX1BUFF_SIZE);//清除缓存STM32_Rx1Counter = 0;TIM2_Init(99,719); //定时器初始化,定时1ms//Tout = ((arr+1)*(psc+1))/Tclk ;//Tclk:定时器输入频率(单位MHZ)//Tout:定时器溢出时间(单位us)while(1){shanshuo=!shanshuo;KeySettings();DisplayTime();displayTimeCunt();if(setn == 0)//不在设置状态下,读取相关数据{DisplayTemperature();GetSteps();GetHeartRateSpO2();}UsartSendReceiveData();DelayMs(10);}
}
void TIM2_IRQHandler(void)//定时器2中断服务程序,用于记录时间
{static u16 timeCount1 = 0;static u16 timeCount2 = 0;static u16 timeCount3 = 0;static u16 timeCount4 = 0;if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源{TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除中断标志位/* 蜂鸣器提醒优先级:跌倒 > 心率血氧温度报警 > 时间提醒 > 里程提醒 */if(timingReminder==1 && (!(beepFlag&0x01))) //时间提醒{timeCount1 ++;if(timeCount1==1)BEEP=1;if(timeCount1==100)BEEP=0;if(timeCount1>=1000){timeCount1=0;}}else{timeCount1=0;}timeCount2 ++;if(timeCount2 >= 1000) //1s{timeCount2 = 0;if(startFlag==1){if(timeCountRecord<(98*3600+59*60)){timeCountRecord ++; //时间计时}if(timeCountRecord==(shi*3600+fen*60+miao))//时间到了提醒标志置1{timingReminder=1;beepFlag|=0x02;}}sendFlag = 1;}timeCount3 ++;if(timeCount3 >= 100){timeCount3=0;if(((hrAvg!=0)&&(hrAvg>=xinlvMax||hrAvg<=xinlvMin))||((spo2Avg!=0)&&(spo2Avg<=spo2Min))||(temperature>=tempMax||temperature<=tempMin))//不在范围蜂鸣器报警{BEEP=~BEEP;beepFlag|=0x01;}else{beepFlag&=0xFE;if(timingReminder==0 && mileageReminder==0 && press==0)BEEP=0;if(mileage>=warnMileage) //里程达标,提醒标志置1{if((beepFlag>>2)==0){beepFlag|=0x04;mileageReminder=1;}}else{beepFlag&=0xFB;mileageReminder=0;}}}timeCount4 ++;if(timeCount4>=50) //50ms{static u8 BeepCount=0;timeCount4=0;if(mileageReminder==1 && (!(beepFlag&0x03))) //里程到了蜂鸣器提醒{BeepCount++;if(BeepCount==3)BEEP=1;if(BeepCount==6)BEEP=0;if(BeepCount==9)BEEP=1;if(BeepCount==12)BEEP=0;if(BeepCount==15)BEEP=1;if(BeepCount==18)BEEP=0;if(BeepCount==40){BEEP=0;BeepCount=0;}}}}
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1178939.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!相关文章
YOLOv8模型瘦身到极致:LAMP剪枝实战,部署速度翻倍
YOLOv8模型瘦身术:深度解析与实战LAMP剪枝 (2021) 文章目录 YOLOv8模型瘦身术:深度解析与实战LAMP剪枝 (2021) 引言:为何模型剪枝至关重要? 1. 理论深潜:LAMP剪枝的核心思想与创新 1.1 幅度剪枝 (MP) 的“简单与粗暴” 1.2 LAMP 的核心创新点:最小化L2失真 1.3 巧妙化简:…
2025年行业内比较好的花灯销售厂家排行榜单,机械花灯/宫灯/景区灯会/传统花灯/大型花灯,花灯供应厂家如何选 - 品牌推荐师
近年来,随着文旅夜游经济的蓬勃发展,花灯作为传统节庆与现代文旅融合的核心载体,其市场需求持续攀升。从景区夜游项目到城市文化IP打造,花灯行业正经历从“单一装饰”向“智能互动”“文化赋能”的转型。然而,行业…
YOLOv13结构优化新方案:替换GSConv,轻量化同时mAP狂涨6.56%!
绿色线条为优化后的模型,map50提升2.31个点!map50 文章目录 移植 创建ultralytics\cfg\models\v13\yolov13-GSConv.yaml 修改ultralytics\nn\tasks.py 修改ultralytics/nn/modules/__init__.py 修改ultralytics\nn\modules\block.py GSConv卷积架构深度原理解析 引言 设计背景…
【WMS】把 WMS 系统彻底讲清楚:从底层逻辑到落地细节,一篇说透
把 WMS 系统彻底讲清楚:从底层逻辑到落地细节,一篇说透一、先纠正一个根本误区:WMS ≠ 仓库自动化二、WMS 的底层逻辑,其实就三件事三、WMS 覆盖的不是“流程”,而是“决策点”四、为什么 WMS 上线后,现场反…
2026选购指南:包装全自动流水线厂家,质量如何把关?高位码垛机/全自动封箱机/立柱码垛机,流水线直销厂家口碑排行榜 - 品牌推荐师
当前,包装行业正经历智能化转型浪潮,企业对全自动流水线的需求激增。然而,市场鱼龙混杂,部分厂家以低价为噱头,实则技术滞后、售后缺失,导致设备故障频发、效率低下。如何筛选出真正具备技术实力、服务保障与商业…
RK3588 实战级 YOLOv5 Android 全解析:NPU 量化 + 多线程 + 跟踪算法,源码一次买齐
文章目录 一、项目概述与目标 为什么选择RK3588? 二、开发环境准备 硬件与软件配置 项目源码获取 三、快速上手:编译与运行 项目目录结构解析 一键运行 四、系统架构深度解析 核心挑战与解决方案 1. 相机集成挑战 2. 并发处理难题 3. 图像格式转换 4. 数据缓存管理 系统整体架…
工商银行app很多bug ,u盾必须现场解除才能提取额度,手机上传社保卡无法识别,建议更新
工商银行app很多bug ,u盾必须现场解除才能提取额度,手机上传社保卡无法识别,建议更新
PostgreSQL实战:详细讲述UUID主键,以及如何生成无热点的分布式主键
文章目录一、分布式主键概述1.1 传统自增主键的局限性1.2 分布式主键的核心要求1.3 各方案综合对比1.4 常见误区澄清二、PostgreSQL 中 UUID 基础使用2.1 启用 UUID 支持2.2 UUID 数据类型2.3 生成 UUID 的方法三、UUIDv4 作为主键的性能陷阱:写入热点与索引碎片3.1…
YOLOv13检测效果不理想?手把手教你引入注意力机制快速提精度
文章目录 @[toc] 深度解析与实践:在YOLOv13中集成注意力机制 引言:YOLOv13与深度学习的焦点 第一章:理解注意力机制——为什么以及是什么? 1.1 为什么目标检测需要注意力机制? 1.2 注意力机制的分类与基本原理 第二章:精选注意力模块的原理与实现 2.1 模块一:Squeeze-an…
YOLOv8融合HAttention深度解析:激活像素级注意力的新范式
文章目录 《YOLOv8融合HAttention:激活更多像素的注意力机制科研实践指南》 一、为什么HAttention是像素激活的“密钥”? 二、HAttention的原理深度解析 1. 核心设计:层级化像素激活与融合 2. 与传统注意力机制的对比 三、HAttention的代码实现与YOLOv8集成 1. HAttention核…
基于深度学习的苹果新鲜度检测系统(YOLOv10+YOLO数据集+UI界面+模型)
一、项目介绍 YOLOv10苹果检测系统 是一个基于YOLOv10(You Only Look Once version 10)目标检测算法的智能系统,专门用于检测和分类苹果的状态。该系统能够自动识别苹果并将其分类为两类:apple(正常苹果) 和…
2026年国内做得好的离婚律师机构找哪家,北京继承律师哪个好/离婚纠纷律师/北京丰台离婚律师,离婚律师机构推荐榜单 - 品牌推荐师
随着社会观念的演进与家庭结构的多元化,离婚法律服务市场正经历着深刻变革。当事人不再仅仅满足于程序性的诉讼代理,而是对法律服务的专业性、情感支持、隐私保护及财产分割方案的精细化提出了更高要求。尤其在资产构…
多模态大模型架构深度解析:模块化vs原生架构工作原理全解析
文章详细介绍了多模态大模型的两种架构:模块化架构(需连接器转译图像)和原生架构(共享底层逻辑)。解释了图像Token化的原理,对比了两种架构的工作流程、训练阶段和应用场景,指出多模态大模型的终极目标是消除模态间的"翻译感"&…
编写一个Buildroot 内核驱动
编写一个Buildroot 内核驱动PS:内核驱动只能在/kernel/drivers/目录下Makefile文件的编写主要注意Makefile文件的编写(路径,包含)
在该路径下先新建一个用户内核驱动文件夹,用于存放用户编写的驱动
user_rk3566_-k…
基于深度学习的冰箱内食物检测系统(YOLOv10+YOLO数据集+UI界面+模型)
一、项目介绍
YOLOv10冰箱内部成分检测系统 是一个基于YOLOv10(You Only Look Once version 10)目标检测算法的智能系统,专门用于检测和识别冰箱内部的多种食物成分。该系统能够自动识别冰箱中的30种常见食物,包括水果、蔬菜、肉…
AI产品经理思维框架:从技术小白到商业落地的实战指南
文章提出了AI产品经理必备的六大思维能力框架:技术理解力、场景洞察力、数据思维、体验设计力、商业思维和伦理风险意识。强调AI产品经理不仅需要了解AI技术,更需要找到技术与商业的平衡点,将AI技术转化为解决用户问题、创造商业价值的产品。…
大模型技术全景图:从理论到应用,一篇全掌握!建议收藏
本文系统梳理了大模型技术框架,从神经网络基础到实际应用。大模型通过预训练实现智能,但存在知识更新慢和领域适应性差的问题,可通过RAG技术、微调和提示词工程解决。智能体Agent将大模型与外部工具结合实现复杂任务处理。学习大模型需系统性…
基于深度学习的苹果腐烂检测系统(YOLOv10+YOLO数据集+UI界面+模型)
一、项目介绍 基于深度学习的苹果腐烂检测系统 是一个专注于检测苹果腐烂状态的智能系统,采用先进的深度学习技术(如YOLOv10或其他目标检测算法)实现高精度检测。该系统能够自动识别并定位腐烂的苹果(damaged_apple)&a…
课程论文别再凑字数!宏智树 AI 教你高效写出高分范文
作为深耕论文写作科普的教育博主,后台每天都能收到大学生的吐槽:“课程论文到底怎么写?凑够字数就被导师批没逻辑”“找文献花三天,写论文两小时,结果分数惨不忍睹”“格式改了八遍,还是不符合学术规范”。…