【Proteus仿真】【STM32单片机】智能助眠机系统设计

文章目录


一、功能简介

本项目使用Proteus8仿真STM32单片机控制器,使用蜂鸣器闹铃模块、LCD1602显示模块、心率血氧模块、PCF8691 ADC模块、按键模块等。

主要功能:

系统运行后,LCD1602显示传感器采集的心率和血氧值以及当前时间;可通过K3键进入时间修改模式,K3用于切换时、分、秒,K1和K2键调节;时间修改完成后可按下K4键保存并返回主界面。

可通过K4键进入助眠和起床闹铃设置模式,K4用于切换助眠时/分,起床时/分,K1和K2键调节。闹铃设置好后可按下K3键保存并返回主界面。若当前时间到达助眠时间或起床闹钟时间,则开启蜂鸣器闹铃,可通过K2键取消正在闹铃。

正常界面下,可通过K1键查阅监测心率和血氧的数据信息,LCD1602显示心率及血氧的最小和最大值。


二、软件设计

c 复制代码
/*
作者:嗨小易(QQ:3443792007)

*/


//系统数据显示
void sys_data_show(void)
{
	while(1)
	{
		//未查阅
		if(sys_ctrl.find==0)
		{
			//未进入设置闹钟模式
			if(sys_ctrl.set_alarm_mode==0)
			{
				//显示时间
				lcd1602_show_nums(6,0,sys_ctrl.hour,2,0x80);
				lcd1602_show_nums(9,0,sys_ctrl.min,2,0x80);
				lcd1602_show_nums(12,0,sys_ctrl.sec,2,0x80);
					
				//心率显示
				lcd1602_show_nums(3,1,sys_ctrl.heart,3,0);
				//血氧显示
				lcd1602_show_nums(12,1,sys_ctrl.oxygen,3,0);
				
				//时间调节位置闪烁
				switch(sys_ctrl.set_time_mode)
				{
					case 1://时
						lcd1602_show_string(6,0,"  ");
						delay_ms(50);
						lcd1602_show_nums(6,0,sys_ctrl.hour,2,0x80);
						break;
					case 2://分
						lcd1602_show_string(9,0,"  ");
						delay_ms(50);
						lcd1602_show_nums(9,0,sys_ctrl.min,2,0x80);
						break;
					case 3://秒
						lcd1602_show_string(12,0,"  ");
						delay_ms(50);
						lcd1602_show_nums(12,0,sys_ctrl.sec,2,0x80);
						break;
				}	
			}
			//进入闹钟设置模式
			else
			{
				//显示助眠时间
				lcd1602_show_nums(7,0,sys_ctrl.alarm_time[0][0],2,0x80);
				lcd1602_show_nums(10,0,sys_ctrl.alarm_time[0][1],2,0x80);
				//显示起床时间
				lcd1602_show_nums(7,1,sys_ctrl.alarm_time[1][0],2,0x80);
				lcd1602_show_nums(10,1,sys_ctrl.alarm_time[1][1],2,0x80);
				
				//时间调节位置闪烁
				switch(sys_ctrl.set_alarm_mode)	
				{
					case 1://助眠时
						lcd1602_show_string(7,0,"  ");
						delay_ms(50);
						lcd1602_show_nums(7,0,sys_ctrl.alarm_time[0][0],2,0x80);
						break;
					case 2://助眠分
						lcd1602_show_string(10,0,"  ");
						delay_ms(50);
						lcd1602_show_nums(10,0,sys_ctrl.alarm_time[0][1],2,0x80);
						break;
					case 3://起床时
						lcd1602_show_string(7,1,"  ");
						delay_ms(50);
						lcd1602_show_nums(7,1,sys_ctrl.alarm_time[1][0],2,0x80);
						break;
					case 4://起床分
						lcd1602_show_string(10,1,"  ");
						delay_ms(50);
						lcd1602_show_nums(10,1,sys_ctrl.alarm_time[1][1],2,0x80);
						break;
				}	
			}	
		}
		//正在查阅
		else
		{
			//显示心率最小和最大值
			lcd1602_show_nums(8,0,sys_ctrl.heart_lh[0],3,0x80);
			lcd1602_show_nums(12,0,sys_ctrl.heart_lh[1],3,0x80);
			//显示血氧最小和最大值
			lcd1602_show_nums(8,1,sys_ctrl.oxygen_lh[0],3,0x80);
			lcd1602_show_nums(12,1,sys_ctrl.oxygen_lh[1],3,0x80);	
		}

		break;			
	}
}


//系统数据设置
void sys_data_set(void)
{
	u8 key=0;
	static u8 oneflag=0;
	
	key=KEY_Scan(0);
	//设置时间
	if(key==KEY3_PRESS)
	{
		//未进入设置闹钟模式
		if(sys_ctrl.set_alarm_mode==0)
		{
			TIM_Cmd(TIM2,DISABLE);//关闭定时器
			sys_ctrl.set_time_mode++;
			if(sys_ctrl.set_time_mode>=4)sys_ctrl.set_time_mode=1;	
		}
		//闹钟设置模式,确定
		else
		{
			oneflag=0;
			sys_ctrl.set_alarm_mode=0;
			sys_open_show();//开机界面显示
			TIM_Cmd(TIM2,ENABLE);//开启定时器	
		}		
	}
	//加
	else if(key==KEY1_PRESS)
	{
		//时间设置模式
		switch(sys_ctrl.set_time_mode)
		{
			case 1://时
				sys_ctrl.hour++;
				if(sys_ctrl.hour>23)sys_ctrl.hour=0;
				break;
			case 2://分
				sys_ctrl.min++;
				if(sys_ctrl.min>59)sys_ctrl.min=0;
				break;
			case 3://秒
				sys_ctrl.sec++;
				if(sys_ctrl.sec>59)sys_ctrl.sec=0;
				break;
		}	
		//闹钟设置模式
		switch(sys_ctrl.set_alarm_mode)
		{
			case 1://助眠时
				sys_ctrl.alarm_time[0][0]++;
				if(sys_ctrl.alarm_time[0][0]>23)sys_ctrl.alarm_time[0][0]=0;
				break;
			case 2://助眠分
				sys_ctrl.alarm_time[0][1]++;
				if(sys_ctrl.alarm_time[0][1]>59)sys_ctrl.alarm_time[0][1]=0;
				break;
			case 3://起床时
				sys_ctrl.alarm_time[1][0]++;
				if(sys_ctrl.alarm_time[1][0]>23)sys_ctrl.alarm_time[1][0]=0;
				break;
			case 4://起床分
				sys_ctrl.alarm_time[1][1]++;
				if(sys_ctrl.alarm_time[1][1]>59)sys_ctrl.alarm_time[1][1]=0;
				break;		
		}
		//正常模式下,查阅血氧心率信息
		if(sys_ctrl.set_time_mode==0 && sys_ctrl.set_alarm_mode==0)
		{
			sys_ctrl.find=!sys_ctrl.find;
			//查阅
			if(sys_ctrl.find==1)
			{
				lcd1602_clear();
				lcd1602_show_string(0,0," Heart->000-000");
				lcd1602_show_string(0,1,"Oxygen->000-000");		
			}
			//退出查阅
			else
			{
				sys_open_show();//开机界面显示	
			}	
		}	
	}
	//减
	else if(key==KEY2_PRESS)
	{
		//时间设置模式
		switch(sys_ctrl.set_time_mode)
		{
			case 1://时
				sys_ctrl.hour--;
				if(sys_ctrl.hour<0)sys_ctrl.hour=23;
				break;
			case 2://分
				sys_ctrl.min--;
				if(sys_ctrl.min<0)sys_ctrl.min=59;
				break;
			case 3://秒
				sys_ctrl.sec--;
				if(sys_ctrl.sec<0)sys_ctrl.sec=59;
				break;
		}
		//闹钟设置模式
		switch(sys_ctrl.set_alarm_mode)
		{
			case 1://助眠时
				sys_ctrl.alarm_time[0][0]--;
				if(sys_ctrl.alarm_time[0][0]<0)sys_ctrl.alarm_time[0][0]=23;
				break;
			case 2://助眠分
				sys_ctrl.alarm_time[0][1]--;
				if(sys_ctrl.alarm_time[0][1]<0)sys_ctrl.alarm_time[0][1]=59;
				break;
			case 3://起床时
				sys_ctrl.alarm_time[1][0]--;
				if(sys_ctrl.alarm_time[1][0]<0)sys_ctrl.alarm_time[1][0]=23;
				break;
			case 4://起床分
				sys_ctrl.alarm_time[1][1]--;
				if(sys_ctrl.alarm_time[1][1]<0)sys_ctrl.alarm_time[1][1]=59;
				break;		
		}
		sys_ctrl.alarm_flag=0;//解除闹铃			
	}
	//确定
	else if(key==KEY4_PRESS)
	{
		//时间设置模式
		if(sys_ctrl.set_time_mode!=0)
		{
			sys_ctrl.set_time_mode=0;
			TIM_Cmd(TIM2,ENABLE);//开启定时器	
		}
		//闹钟设置模式
		else
		{
			TIM_Cmd(TIM2,DISABLE);//关闭定时器
			if(oneflag==0)//只显示1次界面
			{
				oneflag=1;
				lcd1602_clear();
				lcd1602_show_string(0,0,"Sleep->00:00");
				lcd1602_show_string(0,1,"Alarm->00:00");	
			}
			sys_ctrl.set_alarm_mode++;
			if(sys_ctrl.set_alarm_mode>=5)sys_ctrl.set_alarm_mode=1;	
		}	
	}
}

//系统功能控制
void sys_fun_ctrl(void)
{
	//还未开启闹铃
	if(sys_ctrl.alarm_flag==0)
	{
		//正常模式下,检查时间是否达到
		if(sys_ctrl.set_time_mode==0 && sys_ctrl.set_alarm_mode==0)
		{
			//如果助眠时间达到,开启蜂鸣器提示音
			if(sys_ctrl.alarm_time[0][0]==sys_ctrl.hour)//时
			{
				if(sys_ctrl.alarm_time[0][1]==sys_ctrl.min)//分
				{
					if(sys_ctrl.sec==0)//秒
						sys_ctrl.alarm_flag=1;//闹铃	
				}		
			}
			//如果起床时间到达,开启蜂鸣器提示音
			if(sys_ctrl.alarm_time[1][0]==sys_ctrl.hour)//时
			{
				if(sys_ctrl.alarm_time[1][1]==sys_ctrl.min)//分
				{
					if(sys_ctrl.sec==0)//秒
						sys_ctrl.alarm_flag=1;//闹铃	
				}			
			}
		}		
	}
	//开始闹铃
	else 
	{
		beep_alarm(1,10000);
	}
}

//应用控制系统
void appdemo_show(void)
{
	u8 i=5;
	sys_parm_init();//系统参数初始化
	KEY_Init();
	BEEP_Init();
	pcf8591_init();
	lcd1602_init();//LCD1602初始化
	TIM2_Init(400-1,70);//定时10ms
	while(i--)
	{
		//血氧心率获取
		sys_ctrl.heart=pcf8591_read_adcvalue(1);
		sys_ctrl.heart=cal_map(sys_ctrl.heart,0,255,0,200);
		sys_ctrl.heart_lh[0]=sys_ctrl.heart;//初始值作为最小值
		sys_ctrl.heart_lh[1]=sys_ctrl.heart;//初始值作为最大值

		sys_ctrl.oxygen=pcf8591_read_adcvalue(0);
		sys_ctrl.oxygen=cal_map(sys_ctrl.oxygen,0,255,0,200);
		sys_ctrl.oxygen_lh[0]=sys_ctrl.oxygen;//初始值作为最小值
		sys_ctrl.oxygen_lh[1]=sys_ctrl.oxygen;//初始值作为最大值

		delay_ms(100);
	}
	sys_open_show();//系统开机界面显示
	TIM_Cmd(TIM2,ENABLE); //打开定时器

	while(1)
	{
		sys_data_get();//系统数据获取
		sys_data_show();//系统数据显示
		sys_data_set();//系统数据设置
		sys_fun_ctrl();//系统功能控制		
	}
}

三、实验现象

B站演示视频:https://space.bilibili.com/444388619



联系作者

视频地址:https://space.bilibili.com/444388619/video

专注于51单片机、STM32、国产32、DSP、Proteus、ardunio、ESP32、物联网软件开发,PCB设计,视频分享,技术交流。

相关推荐
yutian06066 小时前
Keil MDK下载程序后MCU自动重启设置
单片机·嵌入式硬件·keil
析木不会编程9 小时前
【小白51单片机专用教程】protues仿真独立按键控制LED
单片机·嵌入式硬件·51单片机
枯无穷肉13 小时前
stm32制作CAN适配器4--WinUsb的使用
stm32·单片机·嵌入式硬件
不过四级不改名67713 小时前
基于HAL库的stm32的can收发实验
stm32·单片机·嵌入式硬件
嵌入式科普13 小时前
十一、从0开始卷出一个新项目之瑞萨RA6M5串口DTC接收不定长
c语言·stm32·cubeide·e2studio·ra6m5·dma接收不定长
嵌入式大圣13 小时前
单片机UDP数据透传
单片机·嵌入式硬件·udp
云山工作室14 小时前
基于单片机的视力保护及身姿矫正器设计(论文+源码)
stm32·单片机·嵌入式硬件·毕业设计·毕设
嵌入式-老费14 小时前
基于海思soc的智能产品开发(mcu读保护的设置)
单片机·嵌入式硬件
qq_3975623116 小时前
MPU6050 , 设置内部低通滤波器,对于输出数据的影响。(简单实验)
单片机
艺术家天选16 小时前
STM32点亮LED灯
stm32·单片机·嵌入式硬件