0 前言

🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。

为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天要分享的是

🚩 基于STM32与wifi的天气预报网时钟系统

🥇学长这里给一个题目综合评分(每项满分5分)

  • 难度系数:3分
  • 工作量:3分
  • 创新点:3分

🧿 选题指导, 项目分享:

https://gitee.com/dancheng-senior/project-sharing-1/blob/master/%E6%AF%95%E8%AE%BE%E6%8C%87%E5%AF%BC/README.md

毕业设计 STM32单片机智能WiFi天气助手 - 物联网 单片机-LMLPHP


1 设计内容

该项目中学长是以实时时钟芯片DS1302和STM32F103C8T6 单片机为主要研究对象,着重进行嵌入式控制系统的设计研究和如何读取DS1302内部时钟信息的研究。以及运用18B20进行实时温度检测。

主要内容包括:

  • 1)实时温度显示;
  • 2)年月日星期时分秒显示;
  • 3)年月日星期时分秒调整;
  • 4)闹钟定时小时分钟和秒;

毕业设计 STM32单片机智能WiFi天气助手 - 物联网 单片机-LMLPHP
原理图如下
毕业设计 STM32单片机智能WiFi天气助手 - 物联网 单片机-LMLPHP

2 软件设计

主程序开始初始化,并打开中断,然后执行扫描闹钟、键盘及读取18B20值。当有S1键按下时,执行时钟设置,当有S4键按下时,则进入闹钟设置,无论是时钟还是闹钟,设置完后退出,温度、时钟恢复实时显示。主程序流程图如图

毕业设计 STM32单片机智能WiFi天气助手 - 物联网 单片机-LMLPHP

通过单片机判断S1按下的次数来设置,由s1num标志位来记录次数,用if语句判断执行命令。系统程序不断扫面键盘,当s1键按下后产生一个低电平,即s1num加一。在调节时间之前首先进行各个变量初始化,及设置起始时间,同时为读取数据作准备。当s1=1时进入秒的设置,地址指针指向miao显示位置处,通过两个if语句分别循环控制显示秒数的加和减。当s1=2时,地址指针指向fen显示位置处,变量最大值为59。当s1=3时,地址指针指向shi显示位置处,变量最大值设为23。当s1=4时,地址指针指向week显示位置处,最大值设为7,1至7分别用MON、TUE、WED、THU 、FRI、SAT、SUN字符串显示。随着s2、s3值的的变化显示不同的字符串。当s1=5时,地址指针指向day显示位置,变量最大值为31。当s1=6时,地址指针指向month显示位置,变量最大值为12。
当s1=7时,地址指针指向year显示位置,最大值为99。

毕业设计 STM32单片机智能WiFi天气助手 - 物联网 单片机-LMLPHP

时间设置程序流程图如图3-3所示。在开始时间设置之前程序会关闭全局中断,直至设置结束,中断又会重新开启,进入计时状态。
闹钟的设置时通过S1键的按下次数来判断的。当单片机检测到S4键按下一次时则进入闹钟设置界面,光标并自动跳到秒设置位置,可以对秒进行设置,当S1键依次按下1、2、3次时,则分别进入闹钟的秒、分、时关的设置。:

毕业设计 STM32单片机智能WiFi天气助手 - 物联网 单片机-LMLPHP

3 关键代码

#include "stm32f10x.h"
#include "delay.h"
#include "usart.h"
#include "sys.h"
#include "1302.h"
#include "key.h"
#include "timer.h"
#include "flash.h"
#include "ds18b20.h"
#include "time2.h"
#include "beep.h"
#include "lcd1602.h"
u8 key = 0;
u8 keyflag = 0;
u8 time[8];
int flag1 = 0;
u8 flag2 = 0;//闹钟开关状态
u8 flag3;
int beepflag1 = 0;
u8 n = ' ';
u8 memory_flag=0;
extern u8 flag4;
extern u8 flag5;
extern  my_time TIME;
extern u8 time4flag; 
u8 nolock[] = {15,30};
#define size sizeof(nolock)
u8 nolock1[size];
short temperature;					//接收读取到的温度
//#define FLASH_SAVE_ADDR  0X0800b000		//存储的地址p
//#define FLASH_SAVE_ADDR1  0X0800C000		//存储的地址
//#define FLASH_SAVE_ADDR2  0X0800CB00		//存储的地址
u8 state,s0;
u8 key1_flag=1,key2_flag=1,key3_flag=1,key4_flag=1;
u8 sec1,sec2;
u8 ms=0;
u8 read_flag=1;
u8 time_data[7];
u8 time_data_1[7];
u8 time_data_2[7];
u8 time_data_3[7];
u8 time_data_4[7];
u8 beep1=0;

void memory()
{//08002400
	STMFLASH_Write(0X0800b000,(u16*)nolock1,2);
	STMFLASH_Write(0X0800C000,(u16*)&flag2,1);
}

void read_memory()
{
	STMFLASH_Read(0X0800b000,(u16*)nolock1,2);
	STMFLASH_Read(0X0800C000,(u16*)&flag2,1);
	if(nolock1[0]>23||nolock1[1]>59||flag2>1)
	{
		nolock1[0]=6;
		nolock1[1]=30;
		flag2=1;
	}
}

void dis_play()
{
	if(state<7)
	{
		LCD1602_Set_Cursor(0,0);
		if(state==1&&s0)
		{
			LCD1602_Show_Str("    ");
		}
		else
		{
			LCD1602_Show_Str("20");
			LCD1602_Set_Cursor(2,0);
			LCD1602_Write_Dat('0'+TIME.year/10%10);
			LCD1602_Write_Dat('0'+TIME.year%10);		//年
		}
		LCD1602_Show_Str("-");
		if(state==2&&s0)
		{
			LCD1602_Show_Str("  ");
		}
		else
		{
			LCD1602_Write_Dat('0'+TIME.month/10%10);
			LCD1602_Write_Dat('0'+TIME.month%10);		//月
		}
	
		LCD1602_Show_Str("-");
		if(state==3&&s0)
		{
			LCD1602_Show_Str("  ");	
		}
		else
		{
			LCD1602_Write_Dat('0'+TIME.date/10%10);
			LCD1602_Write_Dat('0'+TIME.date%10);		//日
		}
		LCD1602_Show_Str("   ");		   
		switch(Conver_week(TIME.year,TIME.month,TIME.date))	//星期
		{
			case 0:LCD1602_Show_Str("Sun");  break;
			case 1:LCD1602_Show_Str("Mon");  break;
			case 2:LCD1602_Show_Str("Tue");  break;
			case 3:LCD1602_Show_Str("Wed"); break;
			case 4:LCD1602_Show_Str("Thu");  break;
			case 5:LCD1602_Show_Str("Fri");  break;
			case 6:LCD1602_Show_Str("Sat");  break;
		}
		LCD1602_Set_Cursor(0,1);
		if(state==4&&s0)
		{
			LCD1602_Show_Str("  ")	;
		}
		else
		{
		LCD1602_Write_Dat('0'+TIME.hour/10%10);
		LCD1602_Write_Dat('0'+TIME.hour%10);		 //时
		}
		LCD1602_Show_Str(":");
		if(state==5&&s0)
		{
			LCD1602_Show_Str("  ");	
		}
		else
		{
		LCD1602_Write_Dat('0'+TIME.minute/10%10);	 //分
		LCD1602_Write_Dat('0'+TIME.minute%10);
		}
		LCD1602_Show_Str(":");
		if(state==6&&s0)
		{
			LCD1602_Show_Str("  ");	
		}
		else
		{
		LCD1602_Write_Dat('0'+TIME.second/10%10);	//秒
		LCD1602_Write_Dat('0'+TIME.second%10);
		}
		LCD1602_Show_Str(" ");
		if(temperature<0)
		{  
			temperature=-temperature;
			LCD1602_Write_Dat('-');
			LCD1602_Write_Dat(0x30+temperature/100%10);	//取出第一位
			LCD1602_Write_Dat(0x30+temperature%100/10);	//取出第二位
			LCD1602_Write_Dat(0x2E);				
			LCD1602_Write_Dat(0x30+temperature%10);		//取出最后一位
			LCD1602_Write_Dat(0xDF);
			LCD1602_Write_Dat('C');
		}
		else if(temperature>999)
		{
			LCD1602_Write_Dat(0x30+temperature/1000%10);	//取出第一位
			LCD1602_Write_Dat(0x30+temperature%1000/100);	//取出第一位
			LCD1602_Write_Dat(0x30+temperature%1000/10%10);	//取出第二位
			LCD1602_Write_Dat(0x2E);				
			LCD1602_Write_Dat(0x30+temperature%10);		//取出最后一位
			LCD1602_Write_Dat(0xDF);
			LCD1602_Write_Dat('C');
			
		}
		else
		{
			//LCD1602_Write_Cmd(0x80+0x40+0x09);
			LCD1602_Write_Dat(' ');
			LCD1602_Write_Dat(0x30+temperature/100%10);	//取出第一位
			LCD1602_Write_Dat(0x30+temperature%100/10);	//取出第二位
			LCD1602_Write_Dat(0x2E);				
			LCD1602_Write_Dat(0x30+temperature%10);		//取出最后一位
			LCD1602_Write_Dat(0xDF);
			LCD1602_Write_Dat('C');
		}
	}
	else
	{
		LCD1602_Set_Cursor(0,0);
		LCD1602_Show_Str("     clock:     ");
		LCD1602_Set_Cursor(0,1);
		LCD1602_Show_Str("     ");
		if(state==7&&s0)
		{
			LCD1602_Show_Str("  ");
		}
		else
		{
			LCD1602_Write_Dat('0'+nolock1[0]/10%10);
			LCD1602_Write_Dat('0'+nolock1[0]%10);		//闹钟-时
		}
		LCD1602_Show_Str(":");
		if(state==8&&s0)
		{
			LCD1602_Show_Str("  ");
		}
		else
		{
			LCD1602_Write_Dat('0'+nolock1[1]/10%10);
			LCD1602_Write_Dat('0'+nolock1[1]%10);		//闹钟-分
		}
		LCD1602_Show_Str("   ");
		if(state==9&&s0)
		{
			LCD1602_Show_Str("   ");
		}
		else
		{
			if(flag2 == 0) LCD1602_Show_Str(" on");
			else if(flag2 == 1) LCD1602_Show_Str("off");
		}
		LCD1602_Show_Str("   ");
	}
}

void key_scan()	 //系统按键控制程序
{
	if(key1==0)
	{
		if(key1_flag)
		{
			key1_flag=0;
			state=(state+1)%10;
		}
	}
	else
	{
		key1_flag=1;
	}
	if(!key2)	  //手动上转动控制
	{
		if(key2_flag)
		{
			key2_flag=0;
			if(state>0&&state<7)
			{
				if(state==1)
				{
					TIME.year=(TIME.year+1)%100;
				}
				else if(state==2)
				{
					TIME.month=TIME.month%12+1;
					if(TIME.month==2)
					{
						if((TIME.year%4==0&&TIME.year%100!=0)||TIME.year==0)
						{
							if(TIME.date>29)TIME.date=29;
						}
						else
						{
							if(TIME.date>28) TIME.date=28;
						}
					}
					else if(TIME.month==4||TIME.month==6||TIME.month==9||TIME.month==11)
					{
						if(TIME.date>30) TIME.date=30;
					}
				}
				else if(state==3)
				{
					if(TIME.month==2)
					{
						if((TIME.year%4==0&&TIME.year%100!=0)||TIME.year==0)
						{
							TIME.date=TIME.date%29+1;
						}
						else
						{
							TIME.date=TIME.date%28+1;
						}
					}
					else if(TIME.month==1||TIME.month==3||TIME.month==5||TIME.month==7||TIME.month==8||TIME.month==10||TIME.month==12)
					{
						TIME.date=TIME.date%31+1;
					}
					else 
					{
						TIME.date=TIME.date%30+1;
					}
				}
				else if(state==4)
				{
					TIME.hour=(TIME.hour+1)%24;
				}
				else if(state==5)
				{
					TIME.minute=(TIME.minute+1)%60;
				}
				else if(state==6)
				{
					TIME.second=(TIME.second+1)%60;
				}
			}
			else if(state!=0)
			{
				if(state==7)
				{
					nolock1[0]=(nolock1[0]+1)%24;
				}
				else if(state==8)
				{
					nolock1[1]=(nolock1[1]+1)%60;
				}
				else if(state==9)
				{
					flag2=0;
				}
			}
		}
		if(sec1==0)	  //判断是否长按,如果长按,实现连加效果
		{
			if(state!=0&&state<7)   //设置万年历
			{
				if(state==1)
				{
					TIME.year=(TIME.year+1)%100;
				}
				else if(state==2)
				{
					TIME.month=TIME.month%12+1;
					if(TIME.month==2)
					{
						if((TIME.year%4==0&&TIME.year%100!=0)||TIME.year==0)
						{
							if(TIME.date>29)TIME.date=29;
						}
						else
						{
							if(TIME.date>28) TIME.date=28;
						}
					}
					else if(TIME.month==4||TIME.month==6||TIME.month==9||TIME.month==11)
					{
						if(TIME.date>30) TIME.date=30;
					}
				}
				else if(state==3)
				{
					if(TIME.month==2)
					{
						if((TIME.year%4==0&&TIME.year%100!=0)||TIME.year==0)
						{
							TIME.date=TIME.date%29+1;
						}
						else
						{
							TIME.date=TIME.date%28+1;
						}
					}
					else if(TIME.month==1||TIME.month==3||TIME.month==5||TIME.month==7||TIME.month==8||TIME.month==10||TIME.month==12)
					{
						TIME.date=TIME.date%31+1;
					}
					else 
					{
						TIME.date=TIME.date%30+1;
					}
				}
				else if(state==4)
				{
					TIME.hour=(TIME.hour+1)%24;
				}
				else if(state==5)
				{
					TIME.minute=(TIME.minute+1)%60;
				}
				else if(state==6)
				{
					TIME.second=(TIME.second+1)%60;
				}
			}
			else if(state!=0)
			{
				if(state==7)
				{
					nolock1[0]=(nolock1[0]+1)%24;
				}
				else if(state==8)
				{
					nolock1[1]=(nolock1[1]+1)%60;
				}
				else if(state==9)
				{
					flag2=0;
				}
			}
		}	
	}
	else 
	{
		sec1=2;
		if(key2_flag==0)
		{
			memory_flag=1;
			key2_flag=1;
		}
	}
	if(!key3)	   //手动下转动控制监测
	{
		if(key3_flag)
		{
			key3_flag=0;
			if(state!=0&&state<7)
			{
				if(state==1)
				{
					TIME.year--;
					if(TIME.year>120) TIME.year=99; 
				}
				else if(state==2)
				{
					TIME.month--;
					if(TIME.month==0) TIME.month=12; 
					if(TIME.month==2)
					{
						if((TIME.year%4==0&&TIME.year%100!=0)||TIME.year==0)
						{
							if(TIME.date>29)TIME.date=29;
						}
						else
						{
							if(TIME.date>28) TIME.date=28;
						}
					}
					else if(TIME.month==4||TIME.month==6||TIME.month==9||TIME.month==11)
					{
						if(TIME.date>30) TIME.date=30;
					}
				}
				else if(state==3)
				{
					TIME.date--;
					if(TIME.date==0)
					{
						if(TIME.month==2)
						{
							if((TIME.year%4==0&&TIME.year%100!=0)||TIME.year==0)
							{
								TIME.date=29;
							}
							else
							{
								TIME.date=28;
							}
						}
						else if(TIME.month==1||TIME.month==3||TIME.month==5||TIME.month==7||TIME.month==8||TIME.month==10||TIME.month==12)
						{
							TIME.date=31;
						}
						else 
						{
							TIME.date=30;
						}
					} 
				}
				else if(state==4)
				{
					TIME.hour--;
					if(TIME.hour>25) TIME.hour=23;
				}
				else if(state==5)
				{
					TIME.minute--;
					if(TIME.minute>60) TIME.minute=59;
				}
				else if(state==6)
				{
					TIME.second--;
					if(TIME.second>60) TIME.second=59;
				}
			}
			else if(state!=0)
			{
				if(state==7)
				{
					nolock1[0]--;
					if(nolock1[0]>25) nolock1[0]=23;
				}
				else if(state==8)
				{
					nolock1[1]--;
					if(nolock1[1]>60) nolock1[1]=59;
				}
				else if(state==9)
				{
					flag2=1;
				}
			}
		}
		if(sec2==0)		//判断是否长按,如果长按,实现连减效果
		{
			if(state!=0&&state<7)
			{
				if(state==1)
				{
					TIME.year--;
					if(TIME.year>120) TIME.year=99; 
				}
				else if(state==2)
				{
					TIME.month--;
					if(TIME.month==0) TIME.month=12; 
					if(TIME.month==2)
					{
						if((TIME.year%4==0&&TIME.year%100!=0)||TIME.year==0)
						{
							if(TIME.date>29)TIME.date=29;
						}
						else
						{
							if(TIME.date>28) TIME.date=28;
						}
					}
					else if(TIME.month==4||TIME.month==6||TIME.month==9||TIME.month==11)
					{
						if(TIME.date>30) TIME.date=30;
					}
				}
				else if(state==3)
				{
					TIME.date--;
					if(TIME.date==0)
					{
						if(TIME.month==2)
						{
							if((TIME.year%4==0&&TIME.year%100!=0)||TIME.year==0)
							{
								TIME.date=29;
							}
							else
							{
								TIME.date=28;
							}
						}
						else if(TIME.month==1||TIME.month==3||TIME.month==5||TIME.month==7||TIME.month==8||TIME.month==10||TIME.month==12)
						{
							TIME.date=31;
						}
						else 
						{
							TIME.date=30;
						}
					} 
				}
				else if(state==4)
				{
					TIME.hour--;
					if(TIME.hour>25) TIME.hour=23;
				}
				else if(state==5)
				{
					TIME.minute--;
					if(TIME.minute>60) TIME.minute=59;
				}
				else if(state==6)
				{
					TIME.second--;
					if(TIME.second>60) TIME.second=59;
				}
			}
			else if(state!=0)
			{
				if(state==7)
				{
					nolock1[0]--;
					if(nolock1[0]>25) nolock1[0]=23;
				}
				else if(state==8)
				{
					nolock1[1]--;
					if(nolock1[1]>60) nolock1[1]=59;
				}
				else if(state==9)
				{
					flag2=1;
				}
			}
		}
	}else			   //否则上下转动标志位清0
	{
		if(key3_flag==0)
		{
			memory_flag=1;
			key3_flag=1;
		}
		sec2=2;
	}
	if(key4==0)
	{
		if(key4_flag)
		{
			key4_flag=0;
			state=0;
		}
	}
	else 
	{
		key4_flag=1;
	}
}



void clock_dispose()
{
	if(state==0&&flag2==0&&nolock1[0]==TIME.hour&&nolock1[1] == TIME.minute) 
	{
		if(TIME.second==0) beep1=1;
	}
	else 
	{
		beep1=0;
	}
}

int main(void)
{   
	delay_init();
	BEEP_Init();
	 delay_ms(20); 
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	 //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    LCD1602_Init();
	KEY_Init();
	ds1302_gpio_init();
	do
	{
		temperature=DS18B20_Get_Temp();
	}while(temperature == 850);
	TIM3_Int_Init(4999, 7199);
	TIM4_Int_Init(499 ,7199);
	read_memory();
	while(1) 
	{		
		if(read_flag)
		{
			read_flag=0;
			temperature=DS18B20_Get_Temp();	//获取温度 返回的是一个三位数short型的整数
		}
		read_time1();
		clock_dispose();
		dis_play();
		if(memory_flag)
		{
			memory_flag=0;
			memory();
		}
	}	
}


void TIM4_IRQHandler(void)   //TIM4中断
{
	if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)  //检查TIM2更新中断发生与否
		{
			
			if(beep1)
			{
				if(key1==0||key2==0||key3==0||key4==0)
				{
					beep1=0;
				}
			}
			else
			{
				key_scan();
			}
			ms++;
			if(ms%5==0) 
			{
				if(beep1)
				{
					BEEP=~BEEP;
				}
				else
				{
					BEEP=0;
				}
				s0=~s0;	
			}
			if(ms%10==0)
			{
				if(sec1!=0) sec1--;
				if(sec2!=0) sec2--;
			}
			if(ms>=20)
			{
				ms=0;
				read_flag=1;
			}
		}
		TIM_ClearITPendingBit(TIM4, TIM_IT_Update  );
}

4 最后

12-09 15:03