一、前言

实物项目成品:
在这里插入图片描述

仿真项目成品:
在这里插入图片描述

哔哩哔哩开源视频链接(复制浏览器打开):
https://www.bilibili.com/video/BV1VFtS6eEdz/?vd_source=10da4d04d580bd6b34f7298120737c50

(资料分享见文末)

二、项目功能简介

【开源】STM32单片机智能药盒/老人用药管理系统(代码+原理图+仿真

功能介绍:
1、 LCD1602液晶显示当前时间(DS1302模块)、温湿度(DHT11模块)、药品重量(HX711压力模块)。
2、按键可独立设置3次吃药时间、药品类目和药品数量。
3、到了吃药时间后液晶闪烁提醒吃药数量和类目,蜂鸣器进行声光报警提示。
4、该吃药时,红外感应当前药盒是否打开,药盒打开后自动取消报警和液晶显示提示。
5、药品数量、定时时间可以掉电存储,重新上电无需重新设置。
6、配备蓝牙手机APP,功能如下:
①远程显示当前温湿度、药物重量、吃药时间。
②可以远程设置三次吃药时间、药品种类、药品数量等信息。
③吃药时间到时,手机震动提醒并语音播报:“吃药时间到了,请及时吃药”,点击“已吃药”停止震动和播报。

三、PCB设计

在这里插入图片描述

四、原理图设计

在这里插入图片描述

五、程序设计

代码如下:

#include "sys.h"
#include "delay.h"
#include "lcd1602.h"
#include "timer.h"
#include "gpio.h"
#include "dht11.h"
#include "ds1302.h"
#include "usart1.h"
#include "hx711.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "stdbool.h"

#define FLASH_SAVE_ADDR  ((u32)0x0800F000)  				//设置FLASH 保存地址(必须为偶数)

#define STM32_RX1_BUF       Usart1RecBuf 
#define STM32_Rx1Counter    RxCounter
#define STM32_RX1BUFF_SIZE  USART1_RXBUFF_SIZE

#define ON   1
#define OFF  0

typedef struct {
	unsigned char  shi;	  //时
	unsigned char	 fen;		//分
	unsigned char	 state; //状态
	unsigned char  temporary;
}user;

user  Remtime1={8 ,0,1,0};   //提醒时间1
user  Remtime2={12,0,1,0};   //提醒时间2
user  Remtime3={19,0,1,0};   //提醒时间3

unsigned char  lcd_char_buf[]={0x00,0x10,0x07,0x08,0x08,0x08,0x07,0x00};
unsigned char  setn = 0;     //记录设置按键按下的次数
unsigned char display[16];
unsigned char temp,humi;  //温度湿度
bool shuaxin = 0;  
bool shanshuo = 0; 
bool tixing = 0;
bool beepflag=0;
bool SendFlag = 0;
bool SendSwitchState = 0;
bool p_r = 0;	                  //平年/润年  =0表示平年,=1表示润年
unsigned char A=1,B=2,C=3,D=4;   //4种药物数量
unsigned long weight;            //重量值

void STM32_FlashWriteData(void)  //STM32 Flash写入数据
{
		u16 temp_buf[13];
	  u8 add = 0;
	  
	  temp_buf[add ++] = Remtime1.shi;
	  temp_buf[add ++] = Remtime1.fen;
		temp_buf[add ++] = Remtime1.state;
	  
	  temp_buf[add ++] = Remtime2.shi;
	  temp_buf[add ++] = Remtime2.fen;
		temp_buf[add ++] = Remtime2.state;
	
	  temp_buf[add ++] = Remtime3.shi;
	  temp_buf[add ++] = Remtime3.fen;
		temp_buf[add ++] = Remtime3.state;
	
	  temp_buf[add ++] = A;
	  temp_buf[add ++] = B;
	  temp_buf[add ++] = C;
	  temp_buf[add ++] = D;
	
	  STMFLASH_Write(FLASH_SAVE_ADDR + 0x60,temp_buf,13); //存入数据
		delay_ms(100);
}

void STM32_FlashReadData(void)  //STM32 Flash读出数据
{
		u16 temp_buf[13];
	  u8 add = 0;
	  
	  STM32F10x_Read(FLASH_SAVE_ADDR + 0x60,temp_buf,13); //读出数据
	
	  Remtime1.shi = temp_buf[add ++];
	  Remtime1.fen = temp_buf[add ++];
		Remtime1.state = temp_buf[add ++];
	  
	  Remtime2.shi = temp_buf[add ++];
	  Remtime2.fen = temp_buf[add ++];
		Remtime2.state = temp_buf[add ++];
	
	  Remtime3.shi = temp_buf[add ++];
	  Remtime3.fen = temp_buf[add ++];
		Remtime3.state = temp_buf[add ++];
	
	  A = temp_buf[add ++];
	  B = temp_buf[add ++];
	  C = temp_buf[add ++];
	  D = temp_buf[add ++];
	
		delay_ms(100);
}

void STM32_FlashCheck(void)  // 检查是否是新的单片机,是的话清空存储区,否则保留
{
	  u8 comper_str[6];
		
	  STM32F10x_Read(FLASH_SAVE_ADDR + 0x10,(u16*)comper_str,5);
	  comper_str[5] = '\0';
	  if(strstr((char *)comper_str,"FDYDZ") == NULL)  //新的单片机
		{
			 STMFLASH_Write(FLASH_SAVE_ADDR + 0x10,(u16*)"FDYDZ",5); //写入“FDYDZ”,方便下次校验
			 delay_ms(50);
			 STM32_FlashWriteData();
	  }
		STM32_FlashReadData();

		delay_ms(100);
}

void displayInitChar(void)   //显示初始界面
{
		LCD_Write_String(0,0,"  /  /         g");//显示字符串
		LCD_Write_String(0,1,"  :  :         %");
		Lcd_Custom_Char(1,11,0,lcd_char_buf);
}

void write_week(u8 week)//写星期函数
{
    LCD_Write_Com(0x80+9);//星期字符的显示位置
    switch(week)
    {
    case 1:
        LCD_Write_Data('M');//星期数为1时,显示
        LCD_Write_Data('O');
        break;

    case 2:
        LCD_Write_Data('T');//星期数据为2时显示
        LCD_Write_Data('U');
        break;

    case 3:
        LCD_Write_Data('W');//星期数据为3时显示
        LCD_Write_Data('E');
        break;

    case 4:
        LCD_Write_Data('T');//星期数据为4是显示
        LCD_Write_Data('H');
        break;

    case 5:
        LCD_Write_Data('F');//星期数据为5时显示
        LCD_Write_Data('R');
        break;

    case 6:
        LCD_Write_Data('S');//星期数据为6时显示
        LCD_Write_Data('A');
        break;

    case 0:
        LCD_Write_Data('S');//星期数据为7时显示
        LCD_Write_Data('U');
        break;
    }

}

void displayTime(void) //显示时间
{
	 //显示时间
	 LCD_Write_Com(0x80);
	 LCD_Write_Data(SysDate.year/10+0x30);
	 LCD_Write_Data(SysDate.year%10+0x30);
	 LCD_Write_Data('/');
	 LCD_Write_Data(SysDate.mon/10+0x30);
	 LCD_Write_Data(SysDate.mon%10+0x30);
	 LCD_Write_Data('/');
	 LCD_Write_Data(SysDate.day/10+0x30);
	 LCD_Write_Data(SysDate.day%10+0x30);

	 SysDate.week=Conver_week(SysDate.year,SysDate.mon,SysDate.day);
	 write_week(SysDate.week);

	 LCD_Write_Com(0x80+0x40);
	 LCD_Write_Data(SysDate.hour/10+0x30);
	 LCD_Write_Data(SysDate.hour%10+0x30);
	 LCD_Write_Data(':');
	 LCD_Write_Data(SysDate.min/10+0x30);
	 LCD_Write_Data(SysDate.min%10+0x30);
	 LCD_Write_Data(':');
	 LCD_Write_Data(SysDate.sec/10+0x30);
	 LCD_Write_Data(SysDate.sec%10+0x30);
}

void Get_Ds1302_Time(void)//获取DS1302时间
{
		DS1302_DateRead(&SysDate);//读时间
	  if(setn == 0 && tixing==0){
			displayTime();
		}
}

void displaySetTime(const user * const time)   //显示提醒时间
{
	  if(time->state == 1)LCD_Write_String(6,1," ON");else LCD_Write_String(6,1,"OFF");
	
		LCD_Write_Char(11,1,time->shi/10+'0');
		LCD_Write_Char(12,1,time->shi%10+'0');
	
	  LCD_Write_Char(14,1,time->fen/10+'0');
		LCD_Write_Char(15,1,time->fen%10+'0');
}

void SetReminderTime(bool mode,u8 index ,user * const time)  //设置提醒时间
{
	 if(mode == 0)
	 {
			switch(index)
			{
				 case(1):
									time->state = ON; LCD_Write_String(6,1," ON");
									LCD_Write_Com(0x80+0x40+8);
									LCD_Write_Com(0x0f);//开启光标     
									break;
				case(2):  
									time->shi ++;
				          if(time->shi == 24)time->shi = 0;
				          LCD_Write_Char(11,1,time->shi/10+'0');
									LCD_Write_Char(12,1,time->shi%10+'0');
									LCD_Write_Com(0x80+0x40+12);
									LCD_Write_Com(0x0f);//开启光标     
									break;
				case(3): 
									time->fen ++;
				          if(time->fen == 60)time->fen = 0;
				          LCD_Write_Char(14,1,time->fen/10+'0');
									LCD_Write_Char(15,1,time->fen%10+'0');
									LCD_Write_Com(0x80+0x40+15);
									LCD_Write_Com(0x0f);//开启光标     
									break;
				
				default:break;
			}
	 }
	 else
	 {
			switch(index)
			{
				 case(1): 
									time->state = OFF; LCD_Write_String(6,1,"OFF");
									LCD_Write_Com(0x80+0x40+8);
									LCD_Write_Com(0x0f);//开启光标     
									break;
				case(2):
				          if(time->shi == 0)time->shi = 24;
				          time->shi --;
				          LCD_Write_Char(11,1,time->shi/10+'0');
									LCD_Write_Char(12,1,time->shi%10+'0');
									LCD_Write_Com(0x80+0x40+12);
									LCD_Write_Com(0x0f);//开启光标     
									break;
				case(3): 
				          if(time->fen == 0)time->fen = 60;
				          time->fen --;
				          LCD_Write_Char(14,1,time->fen/10+'0');
									LCD_Write_Char(15,1,time->fen%10+'0');
									LCD_Write_Com(0x80+0x40+15);
									LCD_Write_Com(0x0f);//开启光标     
									break;
				
				default:break;
			}
	 }
}

void displayMedicineNum(void)      //显示药物数量
{
	  if(setn==0 && tixing && shanshuo && A!=0)
		{
				LCD_Write_Char(5,0,' ');
				LCD_Write_Char(6,0,' ');
		}
		else
		{
			  if(A==0)
				{
						LCD_Write_Char(5,0,'-');
						LCD_Write_Char(6,0,'-');
				}
				else
				{
						LCD_Write_Char(5,0,A/10+'0');
						LCD_Write_Char(6,0,A%10+'0');
				}
		}
	  if(setn==0 && tixing && shanshuo && B!=0)
		{
				LCD_Write_Char(14,0,' ');
				LCD_Write_Char(15,0,' ');
		}
		else
		{
			  if(B==0)
				{
						LCD_Write_Char(14,0,'-');
						LCD_Write_Char(15,0,'-');
				}
				else
				{
						LCD_Write_Char(14,0,B/10+'0');
						LCD_Write_Char(15,0,B%10+'0');
				}
		}
	 
		if(setn==0 && tixing && shanshuo && C!=0)
		{
				LCD_Write_Char(5,1,' ');
				LCD_Write_Char(6,1,' ');
		}
		else
		{
			  if(C==0)
				{
						LCD_Write_Char(5,1,'-');
						LCD_Write_Char(6,1,'-');
				}
				else
				{
						LCD_Write_Char(5,1,C/10+'0');
						LCD_Write_Char(6,1,C%10+'0');
				}
		}
	
		if(setn==0 && tixing && shanshuo && D!=0)
		{
				LCD_Write_Char(14,1,' ');
				LCD_Write_Char(15,1,' ');
		}
		else
		{
			  if(D==0)
				{
						LCD_Write_Char(14,1,'-');
						LCD_Write_Char(15,1,'-');
				}
				else
				{
						LCD_Write_Char(14,1,D/10+'0');
						LCD_Write_Char(15,1,D%10+'0');
				}
		}
}

void SetMedicineNum(bool mode,u8 index)  //设置吃药数量
{
		if(mode == 0)
		{
				switch(index)
				{
						case(1): if(A < 99)A ++; displayMedicineNum();LCD_Write_Com(0x80+6);
										 LCD_Write_Com(0x0f);//开启光标
										 break;
					  case(2): if(B < 99)B ++; displayMedicineNum();LCD_Write_Com(0x80+15);
										 LCD_Write_Com(0x0f);//开启光标
										 break;
					 case(3): if(C < 99)C ++; displayMedicineNum();LCD_Write_Com(0x80+0x40+6);
										 LCD_Write_Com(0x0f);//开启光标
										 break;
					 case(4): if(D < 99)D ++; displayMedicineNum();LCD_Write_Com(0x80+0x40+15);
										 LCD_Write_Com(0x0f);//开启光标
										 break;
				}
		}
		else
		{
				switch(index)
				{
						case(1): if(A > 0)A --; displayMedicineNum();LCD_Write_Com(0x80+6);
										 LCD_Write_Com(0x0f);//开启光标
										 break;
					  case(2): if(B > 0)B --; displayMedicineNum();LCD_Write_Com(0x80+15);
										 LCD_Write_Com(0x0f);//开启光标
										 break;
					 case(3): if(C > 0)C --; displayMedicineNum();LCD_Write_Com(0x80+0x40+6);
										 LCD_Write_Com(0x0f);//开启光标
										 break;
					 case(4): if(D > 0)D --; displayMedicineNum();LCD_Write_Com(0x80+0x40+15);
										 LCD_Write_Com(0x0f);//开启光标
										 break;
				}
		}
}

bool keyLongPress=0;
unsigned int keyPressTime=0;//按键按下计数变量
unsigned int SetFlag=0;

void displayCursor1(void)
{
		if(SetFlag == 1)//设置状态
		{
			 LCD_Write_Com(0x80+0x40+8);
			 LCD_Write_Com(0x0f);//开启光标
		}
		if(SetFlag == 2)//设置时
		{
			 LCD_Write_Com(0x80+0x40+12);
			 LCD_Write_Com(0x0f);
		}
		if(SetFlag == 3)//设置分
		{
			 LCD_Write_Com(0x80+0x40+15);
			 LCD_Write_Com(0x0f);
		}
}

void displayCursor2(void)
{
		if(SetFlag == 1)//设置A
		{
			 LCD_Write_Com(0x80+6);
			 LCD_Write_Com(0x0f);//开启光标
		}
		if(SetFlag == 2)//设置B
		{
			 LCD_Write_Com(0x80+15);
			 LCD_Write_Com(0x0f);
		}
		if(SetFlag == 3)//设置C
		{
			 LCD_Write_Com(0x80+0x40+6);
			 LCD_Write_Com(0x0f);
		}
		if(SetFlag == 4)//设置D
		{
			 LCD_Write_Com(0x80+0x40+15);
			 LCD_Write_Com(0x0f);
		}
}

void keyscan(void)  //按键扫描
{
	u16 nian_temp;
	
	if(KEY1 == 0)//设置按键
	{
	 	delay_ms(50);//消抖
		if(KEY1 == 0)
		{
		 	while(KEY1 == 0)
			{
					if(keyPressTime<60000 && setn >= 7)keyPressTime++;
				  if(keyPressTime >= 500)   //长按
					{
							keyLongPress=!keyLongPress;
						  if(keyLongPress == 0)
							{				
									SetFlag=0;
								  LCD_Write_Com(0x0C);
							}
							else
							{
								  SetFlag=1;
									switch(setn)
									{
											case(7):LCD_Write_Com(0x80+0x40+8);LCD_Write_Com(0x0F);break;
											case(8):LCD_Write_Com(0x80+0x40+8);LCD_Write_Com(0x0F);break;
											case(9):LCD_Write_Com(0x80+0x40+8);LCD_Write_Com(0x0F);break;
											case(10):LCD_Write_Com(0x80+6);LCD_Write_Com(0x0F);break;
										  case(11):LCD_Write_Com(0x80+0x40+2);LCD_Write_Com(0x0F);break;
											default:break;
									}
							}
							beepflag=1;
							BEEP = 1;
							delay_ms(300);
							BEEP = 0;
							beepflag=0;
						  break;
					}
					delay_ms(1);
			}
			if(keyPressTime < 500)  //短按
			{
					if(keyLongPress == 0)
					{
							setn++;

							nian_temp=2000+SysDate.year;
							if((nian_temp%400==0)||((nian_temp%100!=0)&&(nian_temp%4==0)))  //判断是否为闰年
									p_r=1;
							else
									p_r=0;
							if(setn == 1)//设0置年
							{
								 tixing = 0;
								 LCD_Clear();
								 displayInitChar();
								
								 sprintf((char *)display,"%03dg",(int)weight);
						     LCD_Write_String(12,0,display);
								
								 LCD_Write_Char(9,1,temp/10+'0'); 
								 LCD_Write_Char(10,1,temp%10+'0'); 
								 LCD_Write_Char(13,1,humi/10+'0'); 
								 LCD_Write_Char(14,1,humi%10+'0');  
								
								 displayTime();
								
								 LCD_Write_Com(0x80+1);
								 LCD_Write_Com(0x0f);//开启光标
							}
							if(setn == 2)//设置月
							{
								 LCD_Write_Com(0x80+4);
								 LCD_Write_Com(0x0f);
							}
							if(setn == 3)//日
							{
								 LCD_Write_Com(0x80+7);
								 LCD_Write_Com(0x0f);
							}
							if(setn == 4)//时
							{
								 LCD_Write_Com(0x80+0x40+1);
								 LCD_Write_Com(0x0f);
							}
							if(setn == 5)//分
							{
								 LCD_Write_Com(0x80+0x40+4);
								 LCD_Write_Com(0x0f);
							}
							if(setn == 6)//秒
							{
								LCD_Write_Com(0x80+0x40+7);
								LCD_Write_Com(0x0f);
							}
							if(setn == 7)//设置吃药时间1
							{
								  LCD_Write_Com(0x0C);
									LCD_Write_String(0,0,"   Set Time 1   ");
									LCD_Write_String(0,1,"State:     00:00");
								
									displaySetTime(&Remtime1);
							}
							if(setn == 8)//设置吃药时间2
							{
									LCD_Write_String(0,0,"   Set Time 2   ");
									LCD_Write_String(0,1,"State:     00:00");
								
									displaySetTime(&Remtime2);
							}
							if(setn == 9)//设置吃药时间3
							{
									LCD_Write_String(0,0,"   Set Time 3   ");
									LCD_Write_String(0,1,"State:     00:00");
								
									displaySetTime(&Remtime3);
							}
							if(setn == 10)//设置吃药药量
							{
								  LCD_Write_String(0,0,"Anum:    Bnum:  ");
								  LCD_Write_String(0,1,"Cnum:    Dnum:  ");
								
								  displayMedicineNum();
							}
							if(setn >= 11)
							{
									setn = 0;
								  LCD_Write_Com(0x0C);
								  LCD_Clear();
								  displayInitChar();
								  STM32_FlashWriteData();   //退出设置之后保存一下设置值
							}
						}
						else
						{
								SetFlag ++; 
							  if(setn>=7 && setn<=9)
								{
									if(SetFlag>3)SetFlag=1;
									
									displayCursor1();
								}
								if(setn==10)
								{
									if(SetFlag>4)SetFlag=1;
									
									displayCursor2();
								}
						}
				}
				keyPressTime = 0;
				while(KEY1 == 0);
		}
	}
	if(KEY2 == 0)//加键
	{
	 	delay_ms(10);
		if(KEY2 == 0)
		{
			 while(KEY2 == 0);
			 if(keyLongPress == 0)
			 {
					 if(setn == 1)//设置年
					 {
							 SysDate.year++;
							 if(SysDate.year == 100)SysDate.year = 0;//最大到99
						 
							 DS1302_DateSet(&SysDate);//设置时间
						 
							 nian_temp=2000+SysDate.year;
							if((nian_temp%400==0)||((nian_temp%100!=0)&&(nian_temp%4==0)))  //判断是否为闰年
									p_r=1;
							else
									p_r=0;
							 displayTime();//显示
							 
							 LCD_Write_Com(0x80+1);
							 LCD_Write_Com(0x0f);//光标闪烁
					 }
					 else if(setn == 2)//设置月
					 {
							SysDate.mon++;
							if(SysDate.mon==13)//最大12个月
							SysDate.mon=1;
							if((SysDate.mon==4)||(SysDate.mon==6)||(SysDate.mon==9)||(SysDate.mon==11))//4,6,9,11月只有30天
							{
									if(SysDate.day>30)
											SysDate.day=1;
							}
							else
							{
									if(SysDate.mon==2)//2月
									{
											if(p_r==1)//闰年2月有29天
											{
													if(SysDate.day>29)
															SysDate.day=1;
											}
											else//平年2月只有28天
											{
													if(SysDate.day>28)
															SysDate.day=1;
											}
									}
							}
							DS1302_DateSet(&SysDate);//设置时间
							 
							 displayTime();//显示
							 
							 LCD_Write_Com(0x80+4);
							 LCD_Write_Com(0x0f);//光标闪烁
					 }
					 else 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))//有31天的月份
								{
										if(SysDate.day==32)
												SysDate.day=1;
								}
								else
								{
										if(SysDate.mon==2)
										{
												if(p_r==1)
												{
														if(SysDate.day==30)//闰年2月有29天
																SysDate.day=1;
												}
												else
												{
														if(SysDate.day==29)//平年2月只有28天
																SysDate.day=1;
												}
										}
										else
										{
												if(SysDate.day==31)//最大到30 
														SysDate.day=1;
										}
								}
								DS1302_DateSet(&SysDate);//设置时间
							 
							 displayTime();//显示
							 
							 LCD_Write_Com(0x80+7);
							 LCD_Write_Com(0x0f);//光标闪烁
					 }
					 else if(setn == 4)//设置时
					 {
							 SysDate.hour++;
							 if(SysDate.hour == 24)//到0点
							 SysDate.hour = 0;
							 DS1302_DateSet(&SysDate);//设置时间
							 
							 displayTime();//显示
							 
							 LCD_Write_Com(0x80+0x40+1);
							 LCD_Write_Com(0x0f);//光标闪烁
					 }
					 else  if(setn == 5)//设置分
					 {
							 SysDate.min++;
							 if(SysDate.min == 60)//60分钟
							 SysDate.min = 0;
							 DS1302_DateSet(&SysDate);//设置时间
							 
							 displayTime();//显示
							 
							 LCD_Write_Com(0x80+0x40+4);
							 LCD_Write_Com(0x0f);//光标闪烁
					 }
					 else  if(setn == 6)//设置秒
					 {
							 SysDate.sec++;
							 if(SysDate.sec == 60)//60秒
							 SysDate.sec = 0;
							 DS1302_DateSet(&SysDate);//设置时间
							 
							 displayTime();//显示
							 
							 LCD_Write_Com(0x80+0x40+7);
							 LCD_Write_Com(0x0f);//光标闪烁
					 }
				 }else
				 {
						if(setn == 7)         //设置第一个吃药时间
						{
								SetReminderTime(0,SetFlag,&Remtime1);
						}
						if(setn == 8)        //设置第二个吃药时间
						{ 
								SetReminderTime(0,SetFlag,&Remtime2);
						}
						if(setn == 9)       //设置第三个吃药时间
						{
								SetReminderTime(0,SetFlag,&Remtime3);
						}
						if(setn==10)       //设置吃药数量
						{
								SetMedicineNum(0,SetFlag);
						}
				 }
		}
	}

	if(KEY3 == 0)//减键
	{
	 	delay_ms(10);
		if(KEY3 == 0 )
		{
		 	while(KEY3 == 0);
       if(keyLongPress == 0)
			 {  
				   if(setn == 0)
					 {
						  beepflag=1;
							BEEP = 1;
							delay_ms(300);
							BEEP = 0;
							beepflag=0;
							To_Zero();
					 }
					 
					 if(setn == 1)//设置年
					 {
							 if(SysDate.year == 0)SysDate.year = 100;
							 SysDate.year--;
							 DS1302_DateSet(&SysDate);//设置时间
							 
							 nian_temp=2000+SysDate.year;
							if((nian_temp%400==0)||((nian_temp%100!=0)&&(nian_temp%4==0)))  //判断是否为闰年
									p_r=1;
							else
									p_r=0;
							 
							 displayTime();
							 
							 LCD_Write_Com(0x80+1);
							 LCD_Write_Com(0x0f);
					 }
					 else if(setn == 2)//设置月
					 {
							SysDate.mon--;
							if(SysDate.mon==0)SysDate.mon=12;
							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);//设置时间
							 
							 displayTime();
							 
							 LCD_Write_Com(0x80+4);
							 LCD_Write_Com(0x0f);
					 }
					 else 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);//设置时间
							 
							 displayTime();
							 
							 LCD_Write_Com(0x80+7);
							 LCD_Write_Com(0x0f);
					 }
						else	if(setn == 4)//设置时
						 {
								 if(SysDate.hour == 0)SysDate.hour = 24;
								 SysDate.hour--;
								 DS1302_DateSet(&SysDate);//设置时间
								 
								 displayTime();
								 
								 LCD_Write_Com(0x80+0x40+1);
								 LCD_Write_Com(0x0f);
						 }
						 else  if(setn == 5)//设置分
						 {
								 if(SysDate.min == 0)SysDate.min = 60;
								 SysDate.min--;
								 DS1302_DateSet(&SysDate);//设置时间
								 
								 displayTime();
								 
								 LCD_Write_Com(0x80+0x40+4);
								 LCD_Write_Com(0x0f);
						 }
						 else  if(setn == 6)//设置秒
						 {
								 if(SysDate.sec == 0)SysDate.sec = 60;
								 SysDate.sec--;
								 DS1302_DateSet(&SysDate);//设置时间
								 
								 displayTime();
								 
								 LCD_Write_Com(0x80+0x40+7);
								 LCD_Write_Com(0x0f);
						 }
					}else
				 {
						if(setn == 7)   //设置第一个吃药时间
						{
								SetReminderTime(1,SetFlag,&Remtime1);
						}
						if(setn == 8)  //设置第二个吃药时间
						{
								SetReminderTime(1,SetFlag,&Remtime2);
						}
						if(setn == 9) //设置第三个吃药时间
						{
								SetReminderTime(1,SetFlag,&Remtime3);
						}
						if(setn==10)  //设置吃药数量
						{
								SetMedicineNum(1,SetFlag);
						}
				 }
		}
	}
}

void UsartSendReceiveData(void)
{
		char *str1=0,*str2=0,i;
	  int  setValue=0;
	  char setvalue[5]={0};
	
		if(STM32_Rx1Counter > 0)
		{
			  delay_ms(20);
			
			  if(strstr(STM32_RX1_BUF,"CONNECTED")!=NULL)
				{
					  SendSwitchState = 1;
				}
				if(strstr(STM32_RX1_BUF,"one:")!=NULL)  //接收到设置吃药时间的指令
				{
					  beepflag=1;
					  BEEP = 1;
						delay_ms(100);
						BEEP = 0;
					  beepflag=0;					
						str1 = strstr(STM32_RX1_BUF,"one:");
					  
					  while(*str1 < '0' || *str1 > '9')        //判断是不是0到9有效数字
						{
								str1 = str1 + 1;
								delay_ms(10);
						}
						i = 0;
						while(*str1 >= '0' && *str1 <= '9')        //判断是不是0到9有效数字
						{
								setvalue[i] = *str1;
								i ++; str1 ++;
								if(*str1 == ':')break;         
								delay_ms(10);
						}
						setvalue[i] = '\0';            //加上结尾符
						setValue = atoi(setvalue);
						if(setValue>=0 && setValue<=23)
						{
								Remtime1.shi = setValue;   //吃药时间的小时
							  if(setn == 7)//设置吃药时间1
								{
										displaySetTime(&Remtime1);
									  displayCursor1();
								}
								 STM32_FlashWriteData();   //保存一下设置值
						}
						str1 = str1 + 1;
						i = 0;
						while(*str1 >= '0' && *str1 <= '9')        //判断是不是0到9有效数字
						{
								setvalue[i] = *str1;
								i ++; str1 ++;
							  if(*str1 == 't')break;         
								delay_ms(10);
						}
						setvalue[i] = '\0';            //加上结尾符

						setValue = atoi(setvalue);
						if(setValue>=0 && setValue<=59)
						{
								Remtime1.fen = setValue;   //吃药时间的小时
							  if(setn == 7)//设置吃药时间1
								{
										displaySetTime(&Remtime1);
									  displayCursor1();
								}
						}
				}
				
				if(strstr(STM32_RX1_BUF,"two:")!=NULL)  //接收到设置吃药时间的指令
				{
						str1 = strstr(STM32_RX1_BUF,"two:");
					  
					  while(*str1 < '0' || *str1 > '9')        //判断是不是0到9有效数字
						{
								str1 = str1 + 1;
								delay_ms(10);
						}
						i = 0;
						while(*str1 >= '0' && *str1 <= '9')        //判断是不是0到9有效数字
						{
								setvalue[i] = *str1;
								i ++; str1 ++;
								if(*str1 == ':')break;         
								delay_ms(10);
						}
						setvalue[i] = '\0';            //加上结尾符
						setValue = atoi(setvalue);
						if(setValue>=0 && setValue<=23)
						{
								Remtime2.shi = setValue;   //吃药时间的小时
							  if(setn == 8)//设置吃药时间2
								{
										displaySetTime(&Remtime2);
									  displayCursor1();
								}
								 STM32_FlashWriteData();   //保存一下设置值
						}
						str1 = str1 + 1;
						i = 0;
						while(*str1 >= '0' && *str1 <= '9')        //判断是不是0到9有效数字
						{
								setvalue[i] = *str1;
								i ++; str1 ++;
							  if(*str1 == 't')break;         
								delay_ms(10);
						}
						setvalue[i] = '\0';            //加上结尾符

						setValue = atoi(setvalue);
						if(setValue>=0 && setValue<=59)
						{
								Remtime2.fen = setValue;   //吃药时间的小时
							  if(setn == 8)//设置吃药时间2
								{
										displaySetTime(&Remtime2);
									  displayCursor1();
								}
								 STM32_FlashWriteData();   //保存一下设置值
						}
				}
				
				if(strstr(STM32_RX1_BUF,"three:")!=NULL)  //接收到设置吃药时间的指令
				{
						str1 = strstr(STM32_RX1_BUF,"three:");
					  
					  while(*str1 < '0' || *str1 > '9')        //判断是不是0到9有效数字
						{
								str1 = str1 + 1;
								delay_ms(10);
						}
						i = 0;
						while(*str1 >= '0' && *str1 <= '9')        //判断是不是0到9有效数字
						{
								setvalue[i] = *str1;
								i ++; str1 ++;
								if(*str1 == ':')break;         
								delay_ms(10);
						}
						setvalue[i] = '\0';            //加上结尾符
						setValue = atoi(setvalue);
						if(setValue>=0 && setValue<=23)
						{
								Remtime3.shi = setValue;   //吃药时间的小时
							  if(setn == 9)//设置吃药时间3
								{
										displaySetTime(&Remtime3);
									  displayCursor1();
								}
								 STM32_FlashWriteData();   //保存一下设置值
						}
						str1 = str1 + 1;
						i = 0;
						while(*str1 >= '0' && *str1 <= '9')        //判断是不是0到9有效数字
						{
								setvalue[i] = *str1;
								i ++; str1 ++;
							  if(*str1 == ',')break;         
								delay_ms(10);
						}
						setvalue[i] = '\0';            //加上结尾符

						setValue = atoi(setvalue);
						if(setValue>=0 && setValue<=59)
						{
								Remtime3.fen = setValue;   //吃药时间的小时
							  if(setn == 9)//设置吃药时间3
								{
										displaySetTime(&Remtime3);
									  displayCursor1();
								}
								STM32_FlashWriteData();   //保存一下设置值
						}
				}
				
				if(strstr(STM32_RX1_BUF,"MedA")!=NULL)
				{
						str2 = strstr(STM32_RX1_BUF,"MedA");
					  
					  while(*str2 < '0' || *str2 > '9')        //判断是不是0到9有效数字
						{
								str2 = str2 + 1;
								delay_ms(10);
						}
						i = 0;
						while(*str2 >= '0' && *str2 <= '9')        //判断是不是0到9有效数字
						{
								setvalue[i] = *str2;
								i ++; str2 ++;
								delay_ms(10);
						}
						setvalue[i] = '\0';            //加上结尾符
						setValue = atoi(setvalue);
						if(setValue>=0 && setValue<=99)
						{
								A = setValue;    //设置的药物数量
							  if(setn == 10)//设置吃药药量
								{
										displayMedicineNum();
									  displayCursor2();
								}
								STM32_FlashWriteData();   //保存一下设置值
						}
				}	
				if(strstr(STM32_RX1_BUF,"MedB")!=NULL)
				{
						str2 = strstr(STM32_RX1_BUF,"MedB");
					  
					  while(*str2 < '0' || *str2 > '9')        //判断是不是0到9有效数字
						{
								str2 = str2 + 1;
								delay_ms(10);
						}
						i = 0;
						while(*str2 >= '0' && *str2 <= '9')        //判断是不是0到9有效数字
						{
								setvalue[i] = *str2;
								i ++; str2 ++;
								delay_ms(10);
						}
						setvalue[i] = '\0';            //加上结尾符
						setValue = atoi(setvalue);
						if(setValue>=0 && setValue<=99)
						{
								B = setValue;    //设置的药物数量
							  if(setn == 10)//设置吃药药量
								{
										displayMedicineNum();
									  displayCursor2();
								}
								STM32_FlashWriteData();   //保存一下设置值
						}
				}
				if(strstr(STM32_RX1_BUF,"MedC")!=NULL)
				{
						str2 = strstr(STM32_RX1_BUF,"MedC");
					  
					  while(*str2 < '0' || *str2 > '9')        //判断是不是0到9有效数字
						{
								str2 = str2 + 1;
								delay_ms(10);
						}
						i = 0;
						while(*str2 >= '0' && *str2 <= '9')        //判断是不是0到9有效数字
						{
								setvalue[i] = *str2;
								i ++; str2 ++;
								delay_ms(10);
						}
						setvalue[i] = '\0';            //加上结尾符
						setValue = atoi(setvalue);
						if(setValue>=0 && setValue<=99)
						{
								C = setValue;    //设置的药物数量
							  if(setn == 10)//设置吃药药量
								{
										displayMedicineNum();
									  displayCursor2();
								}
								STM32_FlashWriteData();   //保存一下设置值
						}
				}
				if(strstr(STM32_RX1_BUF,"MedD")!=NULL)
				{
						str2 = strstr(STM32_RX1_BUF,"MedD");
					  
					  while(*str2 < '0' || *str2 > '9')        //判断是不是0到9有效数字
						{
								str2 = str2 + 1;
								delay_ms(10);
						}
						i = 0;
						while(*str2 >= '0' && *str2 <= '9')        //判断是不是0到9有效数字
						{
								setvalue[i] = *str2;
								i ++; str2 ++;
								delay_ms(10);
						}
						setvalue[i] = '\0';            //加上结尾符
						setValue = atoi(setvalue);
						if(setValue>=0 && setValue<=99)
						{
								D = setValue;    //设置的药物数量
							  if(setn == 10)//设置吃药药量
								{
										displayMedicineNum();
									  displayCursor2();
								}
								STM32_FlashWriteData();   //保存一下设置值
						}
				}
			  if(strstr(STM32_RX1_BUF,"time1Switch_on")!=NULL)
				{
					  Remtime1.state = 1;
					
					  if(setn == 7)//显示
						{
								displaySetTime(&Remtime1);
							  displayCursor1();
						}
				}
				if(strstr(STM32_RX1_BUF,"time1Switch_off")!=NULL)
				{
					  Remtime1.state = 0;
					
					  if(setn == 7)//显示
						{
								displaySetTime(&Remtime1);
							  displayCursor1();
						}
				}
				if(strstr(STM32_RX1_BUF,"time2Switch_on")!=NULL)
				{
					  Remtime2.state = 1;
					
					  if(setn == 8)//显示
						{
								displaySetTime(&Remtime2);
							  displayCursor1();
						}
				}
				if(strstr(STM32_RX1_BUF,"time2Switch_off")!=NULL)
				{
					  Remtime2.state = 0;
					
					  if(setn == 8)//显示
						{
								displaySetTime(&Remtime2);
							  displayCursor1();
						}
				}
				if(strstr(STM32_RX1_BUF,"time3Switch_on")!=NULL)
				{
					  Remtime3.state = 1;
					
					  if(setn == 9)//显示
						{
								displaySetTime(&Remtime3);
							  displayCursor1();
						}
				}
				if(strstr(STM32_RX1_BUF,"time3Switch_off")!=NULL)
				{
					  Remtime3.state = 0;
					
					  if(setn == 9)//显示
						{
								displaySetTime(&Remtime3);
							  displayCursor1();
						}
				}
				if(strstr(STM32_RX1_BUF,"closeRemind")!=NULL)
				{
					  tixing = 0;       //清除提醒标志
						displayInitChar();
				}
				memset(STM32_RX1_BUF,0,STM32_RX1BUFF_SIZE);  //清空缓存
				STM32_Rx1Counter = 0;
		}
		if(SendFlag==1)    //1秒钟上传一次数据
		{
			  SendFlag = 0;		
			   
				printf("$temp:%d#,$humi:%d#,$weight:%d#",temp,humi,(int)weight);
			
			  if(SendSwitchState)  //当状态发生变化的时候,上报一次状态
				{
					  if(Remtime1.state==1)printf(",time1_on");else printf(",time1_off");
						if(Remtime2.state==1)printf(",time2_on");else printf(",time2_off");
					  if(Remtime3.state==1)printf(",time3_on");else printf(",time3_off");
					
					  SendSwitchState = 0;
				}
			
				if(tixing==1)printf(",play"); else printf(",stop");

		}
}

int main(void)
{	
	  unsigned char timeCount=0;
	
		delay_init();	    //延时函数初始化	  
		delay_ms(500);       //上电瞬间加入一定延时在初始化
		LCD_Init();         //屏幕初始化
	  KEY_AND_BEEP_GPIO_Init();  //按键及蜂鸣器引脚初始化
	  HX711_GPIO_Init();     
	  To_Zero();
	  while(DHT11_Init()==1)
		{
				LCD_Write_String(0,0,"   DHT11 Init!  ");
				LCD_Write_String(0,1,"                ");
		}
		LCD_Write_String(0,0,"   loading...   ");//显示字符串
	  LCD_Write_String(0,1,"                ");
		uart1_Init(9600);
		To_Zero();
		STM32_FlashCheck();       
	  To_Zero();
	  displayInitChar();
		DS1302_Init(&SysDate);    //DS1302时钟初始化
		To_Zero();
		TIM3_Init(499,7199);   //定时器初始化,定时50ms
		//Tout = ((arr+1)*(psc+1))/Tclk ; 
		//Tclk:定时器输入频率(单位MHZ)
		//Tout:定时器溢出时间(单位us)
		while(1)
		{  
			 keyscan();//按键扫描
			 if(setn == 0)
			 {
					 Get_Ds1302_Time();   //显示时间
				 
				   //吃药时间到了
					 if((SysDate.hour==Remtime1.shi && SysDate.min==Remtime1.fen && SysDate.sec==0  && Remtime1.state==1)||
							 (SysDate.hour==Remtime2.shi && SysDate.min==Remtime2.fen && SysDate.sec==0 && Remtime2.state==1)||
							 (SysDate.hour==Remtime3.shi && SysDate.min==Remtime3.fen && SysDate.sec==0 && Remtime3.state==1)
							)
					 {
						   if((tixing==0)&&(A!=0 || B!=0 || C!=0 || D!=0)) //必须要有吃药量,才能提醒
							 {
									LCD_Write_String(0,0,"Anum:    Bnum:  ");
									LCD_Write_String(0,1,"Cnum:    Dnum:  ");
									tixing = 1;
						   }
					 }
				   if(HW == 0)  //红外遮挡,说明已经吃过药了
					 {
						  if(tixing==1)
							{
									tixing = 0;       //清除提醒标志
								  displayInitChar();
							}
					 }
					 if(tixing == 0)
					 {
							 timeCount ++;
							 if(timeCount >= 10)
							 {
									timeCount = 0;
									weight = get_weight();   //获取重量
									if(weight > 999)weight=999;
									sprintf((char *)display,"%03dg",(int)weight);
									if(weight == 0 && shanshuo)
									{
										LCD_Write_String(12,0,"    ");
									}
									else LCD_Write_String(12,0,display);   //显示重量
							 }
							 if(shuaxin == 1)
							 {
									 shuaxin = 0;
									 DHT11_Read_Data(&temp,&humi);     //读取温湿度
									 LCD_Write_Char(9,1,temp/10+'0'); 
									 LCD_Write_Char(10,1,temp%10+'0'); 
									 LCD_Write_Char(13,1,humi/10+'0'); 
									 LCD_Write_Char(14,1,humi%10+'0');   
							 }
					 }
					 else
					 {
							displayMedicineNum();   //吃药时间到了,显示吃药的数量
					 }
			 }
			 UsartSendReceiveData();
       delay_ms(10);
		}	
}

void TIM3_IRQHandler(void)//定时器3中断服务程序,用于记录时间
{ 
	  static u16 timeCount1=0;
	  static u16 timeCount2=0;
	  static u16 timeCount3=0;
	
		if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 
		{ 
				TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除中断标志位  

			  timeCount1 ++;
			  if(timeCount1 >= 10)
				{
						timeCount1 = 0;
					  shanshuo = !shanshuo; 
					  shuaxin = 1; 
					  if(Remtime1.temporary!=Remtime1.state)
						{
								Remtime1.temporary = Remtime1.state;
							  SendSwitchState = 1;
						}
						if(Remtime2.temporary!=Remtime2.state)
						{
								Remtime2.temporary = Remtime2.state;
							  SendSwitchState = 1;
						}
						if(Remtime3.temporary!=Remtime3.state)
						{
								Remtime3.temporary = Remtime3.state;
							  SendSwitchState = 1;
						}
				}
				
				timeCount2 ++;
				
				if(tixing == 1)   //吃药时间到了,蜂鸣器提醒
				{
						if(timeCount2==3)BEEP=1;
						if(timeCount2==6)BEEP=0; 
						if(timeCount2==9)BEEP=1;
						if(timeCount2==12)BEEP=0;
						if(timeCount2==15)BEEP=1;
						if(timeCount2==18)BEEP=0; 
					
						if(timeCount2>=40)
						{
								BEEP=0;
								timeCount2=0;
						}
				}
				else
				{
					if(timeCount2 >= 2)
					{
							timeCount2 = 0;
							if(weight == 0 && setn==0)   //重量是0,蜂鸣器响
							{
									BEEP = ~BEEP;
							}
							else
							{
									if(beepflag==0)BEEP = 0;
							}
					}
				}
				
				timeCount3 ++;
				if(timeCount3 >= 20)
				{
						timeCount3 = 0;
					  SendFlag = 1;		
				}
	  }
}

六、包含内容

在这里插入图片描述

七、资料分享

资料获取:请查看主页介绍搜索或观看开源视频获取

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐