一、功能介绍

项目名:基于单片机的智能雨伞防丢及天气提醒装置设计与研究
项目编号:dz-1215
单片机类型:STM32F103C8T6
具体功能:
1、通过知心天气获取当前天气情况“温度”“下雨或晴“;
2、通过人体热释电监测当前是否有人从雨伞前经过,监测到有人经过温度大于最大值或者下雨手机弹窗震动提醒”请注意带伞“;
3、通过GPS定位模块获取当前雨伞的位置,用户可以通过手机端查看当前雨伞的位置;
4、通过OLED显示当前环境的温度、下雨或晴、当前雨伞的经纬度、是否有人;
5、通过4G模块将监测的数据传输到手机端;
6、通过按键可以设置温度阈值

二、资料总览

实物资料

请添加图片描述

仿真资料

请添加图片描述

三、部分资料展示

1、实物展示

供电接口:TYPE-C
板子类型:PCB集成板,两层板(上下层覆铜接地)
器件类型:元器件基本上为插针式,个别芯片会使用贴片式。
在这里插入图片描述

2、仿真展示

仿真软件版本:proteus8.17
电路连线方式:网络标号连线方式
注意:部分实物元器件仿真中没有,仿真中会用其他工作原理相似的元件代替,这样可能导致实物程序和仿真程序不一样
在这里插入图片描述

3、原理图展示

软件版本:AD2013
电路连线方式:网络标号连线方式
注意:原理图只是画出了模块的引脚图,而并不是模块的内部结构图
在这里插入图片描述

4、PCB图展示

由原理图导出,两层板,上下覆铜接地。
在这里插入图片描述

5、系统框图

绘制软件:VISIO
在这里插入图片描述

6、软件设计流程

绘制软件:VISIO
在这里插入图片描述

7、部分程序展示

软件版本:keil5

/* USER CODE BEGIN Header */

/**********************************
**********************************/

/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

#include "./DELAY/delay.h"
#include "./OLED/oled.h"
#include "./KEY/key.h"
#include "./4G/4g.h"


/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

uint8_t huart1_tx_buf[100];
#define Huart1_Send_Str(...)  HAL_UART_Transmit(&huart1,huart1_tx_buf,sprintf((char *)huart1_tx_buf,__VA_ARGS__),0xffff)		//重定义串口1发送函数

	
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

uint8_t key_num = 0;										//按键键值
uint8_t display_num = 0;								//显示界面
uint8_t flag_time_10ms = 0;							//计时数
uint32_t time_num = 0;									//计时值
char display_buf[32] = {0};							//显示数组

uint8_t huart1_rx_data = 0;							//串口1接收单个数据

extern uint8_t Air_4G_buf[512];					//数据接收数组
extern uint16_t Air_4G_cnt;							//数据接收数组下标
extern uint16_t Air_4G_cntPre;					//数据接收数组下标

uint8_t flag_begin_5s = 0;							//5s计时开始标志位
uint8_t flag_finish_5s = 0;							//5s计时完成标志位

uint8_t flag_begin_1m = 0;							//1m计时开始标志位
uint8_t flag_finish_1m = 0;							//1m计时标志位

uint8_t flag_bj = 0;										//报警标志位
uint8_t flag_tq = 1;										//天气标志位

int16_t temp_max = 40;									//温度最大值

Real_Weather weather;
#define	Location				"xiangyang"				//城市地区

#define HUART3_RX_SIZE	1024						//串口3接收数组最大值
uint8_t huart3_rx_buf[HUART3_RX_SIZE];	//串口3接收数组
uint8_t huart3_rx_finish = 0;						//串口3接收完成标志位

uint16_t N_du;													//纬度的度
float N_fen;														//纬度的分
uint16_t E_du;													//经度的度
float E_fen;														//经度的分
float N_num,E_num;											//解析的经纬度
char *result = NULL;  									//结果
float E_value;													//经度值
float N_value;													//维度值

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

void Key_Function(void);								//按键函数
void Monitor_Function(void);						//监测函数
void Display_Function(void);						//显示函数
void Manage_Function(void);							//处理函数

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/**********************************
函数名:按键函数
传参值:无
返回值:无
**********************************/
void Key_Function(void)
{
	key_num = Chiclet_Keyboard_Scan(0);		//按键扫描,获取键值
	if(key_num != 0)								      //有按键按下
	{
		switch(key_num)
		{
			case 1:								            //按键1:切换界面
				display_num++;
				if(display_num >= 2)
				{
					display_num = 0;
				}
				
				Oled_Clear_All();					      //清屏
			break;

			case 2:											      //按键2
				switch(display_num)
				{
					case 1:											  //界面1:温度最大值+1
						if(temp_max < 99)
						{
							temp_max++;
						}
					break;
					
					default:
					break;
				}
			break;

			case 3:														//按键3
				switch(display_num)
				{
//					case 0:											  //界面1:温度最大值-1
//						weather.temperature = 0;
//					break;

					case 1:											  //界面1:温度最大值-1
						if(temp_max > 0)
						{
							temp_max--;
						}
					break;
					
					default:
					break;
				}
			break;

			default:
			break;
		}
	}
}


/**********************************
函数名:监测函数
传参值:无
返回值:无
**********************************/
void Monitor_Function(void)
{
	if(flag_finish_1m >= 10)
	{
		flag_begin_1m = 0;
		Air_4G_Get_Weather_Once1(Location);		//获取实时天气数据
		flag_begin_1m = 1;
	}

	Air_4G_GetData();											//获取4G模块下发数据
	
	if(huart3_rx_finish == 1)										//解析GPS数据,获取经纬度
	{
		result = strstr((char *)huart3_rx_buf,"RMC");
		if(result != NULL)
		{
			result = strstr((char *)result,"A,");		//获取纬度
			if(result != NULL)
			{
				result += 2;
				
				N_num = (float)atof(result);
				N_du = (uint16_t)(N_num / 100.0);
				N_fen = N_num-N_du*100;
				N_num = N_du + N_fen/60.0;
				if(0 < N_num && N_num < 60)
					N_value = N_num;
			}
			
			result = strstr((char *)result,"N,");		//获取经度
			if(result != NULL)
			{
				result += 2;
				
				E_num = (float)atof(result);
				E_du = (uint16_t)(E_num / 100.0);
				E_fen = E_num-E_du*100;
				E_num = E_du + E_fen/60.0;
				if(70 < E_num && E_num < 150)
					E_value = E_num;
			}
		}
		
		memset(huart3_rx_buf, 0 ,HUART3_RX_SIZE);
		huart3_rx_finish = 0;
	}

}


/**********************************
函数名:显示函数
传参值:无
返回值:无
**********************************/
void Display_Function(void)
{
	if(time_num % 10 == 0)
	{
		switch(display_num)											//根据不同的显示界面,显示不同的内容
		{
			case 0:									      				//界面0:显示测量数据
				Oled_ShowCHinese(1,0,"温度:"); 	//显示温度最大值
				sprintf(display_buf,"%dC  ",weather.temperature);
				Oled_ShowString(1,6,display_buf);

				Oled_ShowCHinese(1,7,RTRSD == 0? "有": "无"); 	//有没有人在

			
				Oled_ShowCHinese(2,0,"天气:");
				switch(weather.code)
				{
					case 0:
					case 1:
					case 2:
					case 3:
						Oled_ShowCHinese(2,3,"晴");
						Oled_ShowString(2,8,"        ");
					break;
					
					case 4:
						Oled_ShowCHinese(2,3,"多云");
						Oled_ShowString(2,10,"      ");
					break;
					
					case 5:
					case 6:
						Oled_ShowCHinese(2,3,"晴间多云");
						Oled_ShowString(2,14,"  ");
					break;
					
					case 7:
					case 8:
						Oled_ShowCHinese(2,3,"大部多云");
						Oled_ShowString(2,14,"  ");
					break;
					
					case 9:
						Oled_ShowCHinese(2,3,"阴");
						Oled_ShowString(2,8,"        ");
					break;
					
					case 10:
						Oled_ShowCHinese(2,3,"阵雨");
						Oled_ShowString(2,10,"      ");
					break;
					
					case 11:
						Oled_ShowCHinese(2,3,"雷阵雨");
						Oled_ShowString(2,12,"    ");
					break;
					
					case 12:
						Oled_ShowCHinese(2,3,"雷阵雨冰雹");
					break;
					
					case 13:
						Oled_ShowCHinese(2,3,"小雨");
						Oled_ShowString(2,10,"      ");
					break;
					
					case 14:
						Oled_ShowCHinese(2,3,"中雨");
						Oled_ShowString(2,10,"      ");
					break;
					
					case 15:
						Oled_ShowCHinese(2,3,"大雨");
						Oled_ShowString(2,10,"      ");
					break;
					
					case 16:
						Oled_ShowCHinese(2,3,"暴雨");
						Oled_ShowString(2,10,"      ");
					break;
					
					case 17:
						Oled_ShowCHinese(2,3,"大暴雨");
						Oled_ShowString(2,12,"    ");
					break;
					
					case 18:
						Oled_ShowCHinese(2,3,"特大暴雨");
						Oled_ShowString(2,14,"  ");
					break;
					
					case 19:
						Oled_ShowCHinese(2,3,"冻雨");
						Oled_ShowString(2,10,"      ");
					break;
					
					case 20:
						Oled_ShowCHinese(2,3,"雨夹雪");
						Oled_ShowString(2,12,"    ");
					break;
					
					case 21:
						Oled_ShowCHinese(2,3,"阵雪");
						Oled_ShowString(2,10,"      ");
					break;
					
					case 22:
						Oled_ShowCHinese(2,3,"小雪");
						Oled_ShowString(2,10,"      ");
					break;
					
					case 23:
						Oled_ShowCHinese(2,3,"中雪");
						Oled_ShowString(2,10,"      ");
					break;
					
					case 24:
						Oled_ShowCHinese(2,3,"大雪");
						Oled_ShowString(2,10,"      ");
					break;
					
					case 25:
						Oled_ShowCHinese(2,3,"暴雪");
						Oled_ShowString(2,10,"      ");
					break;
					
					case 26:
						Oled_ShowCHinese(2,3,"浮尘");
						Oled_ShowString(2,10,"      ");
					break;
					
					case 27:
						Oled_ShowCHinese(2,3,"扬沙");
						Oled_ShowString(2,10,"      ");
					break;
					
					case 28:
						Oled_ShowCHinese(2,3,"沙尘暴");
						Oled_ShowString(2,12,"    ");
					break;
					
					case 29:
						Oled_ShowCHinese(2,3,"强沙尘暴");
						Oled_ShowString(2,14,"  ");
					break;
					
					case 30:
						Oled_ShowCHinese(2,3,"雾");
						Oled_ShowString(2,8,"        ");
					break;
					
					case 31:
						Oled_ShowCHinese(2,3,"霾");
						Oled_ShowString(2,8,"        ");
					break;
					
					case 32:
						Oled_ShowCHinese(2,3,"风");
						Oled_ShowString(2,8,"        ");
					break;
					
					case 33:
						Oled_ShowCHinese(2,3,"大风");
						Oled_ShowString(2,10,"      ");
					break;
					
					case 34:
						Oled_ShowCHinese(2,3,"飓风");
						Oled_ShowString(2,10,"      ");
					break;
					
					case 35:
						Oled_ShowCHinese(2,3,"热带风暴");
						Oled_ShowString(2,14,"  ");
					break;
					
					case 36:
						Oled_ShowCHinese(2,3,"龙卷风");
						Oled_ShowString(2,12,"    ");
					break;
					
					case 37:
						Oled_ShowCHinese(2,3,"冷");
						Oled_ShowString(2,8,"        ");
					break;
					
					case 38:
						Oled_ShowCHinese(2,3,"热");
						Oled_ShowString(2,8,"        ");
					break;
					
					case 99:
						Oled_ShowCHinese(2,3,"未知");
						Oled_ShowString(2,10,"      ");
					break;
					
					default:
					break;
				}

				Oled_ShowCHinese(3,0,"经度:");
				sprintf(display_buf,"%f",E_value);
				Oled_ShowString(3,6,display_buf);
			
				Oled_ShowCHinese(4,0,"纬度:");
				sprintf(display_buf,"%f ",N_value);
				Oled_ShowString(4,6,display_buf);
			break;
			
			case 1:																//界面1:显示设置温度最大值
				Oled_ShowCHinese(1,0,"设置温度最大值");
				if(time_num % 20 == 0)
				{
					sprintf(display_buf,"%d  ",temp_max); 
					Oled_ShowString(2,7,display_buf);
				}
				if(time_num % 40 == 0)
				{
					Oled_ShowString(2,7,"    ");
				}
			break;
			
			default:
			break;
		}
	}
}


/**********************************
函数名:处理函数
传参值:无
返回值:无
**********************************/
void Manage_Function(void)
{
	if(display_num == 0)								  										//测量界面
	{
		if(((weather.temperature > temp_max) || (9 <= weather.code && weather.code <= 25)) && RTRSD == 0)									//监测到有人经过温度大于最大值或者下雨手机弹窗震动提醒”请注意带伞“;
		{
			if(flag_bj == 0)
			{
				flag_bj = 1;
			}
		}
		else																										//温度处于设置的上下限值之间,两个继电器断开
		{
			if(flag_bj == 2)
			{
				flag_bj = 0;
			}
		}

	}

	if(flag_finish_5s == 1)																		//5秒上传一次数据
  {
    flag_begin_5s = 0;
    Air_4G_SendData();
    flag_begin_5s = 1;
  }
}

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM1_Init();
  MX_USART1_UART_Init();
  MX_USART3_UART_Init();
  /* USER CODE BEGIN 2 */

	Delay_Init();													//延时初始化
	Oled_Init();													//OLED初始化
	Key_Init();														//KEY初始化
	
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
	
	Oled_Clear_All();											//清屏
	HAL_TIM_Base_Start_IT(&htim1);				//启动定时器
	HAL_UART_Receive_IT(&huart1, &huart1_rx_data, 1);				//获取串口1接收数据
	HAL_UARTEx_ReceiveToIdle_IT(&huart3, huart3_rx_buf, HUART3_RX_SIZE);		//获取串口3接收数据
	
	Oled_ShowString(1,7,"4G");
	Oled_ShowCHinese(2, 2, "初始化中");
	Air_4G_Init();											//4G初始化
	
	Oled_ShowCHinese(2, 2, "获取天气");
	Air_4G_Get_Weather_Once("suzhou");
	

	Oled_ShowCHinese(2, 2, "初始化中");
	Oled_ShowString(3,4,"........");
	Air_4G_MQTT_Init();									//MQTT初始化
	Delay_ms(500);
	Oled_ShowString(4,4,"........");
	Delay_ms(500);
	Air_4G_SendData();									//数据上报初始状态
  flag_begin_5s = 1;									//开启定时
	flag_begin_1m = 1;									//开启1分钟定时

	Oled_Clear_All();											//清屏
	
  while (1)
  {
		Key_Function();										  //按键函数
		Monitor_Function();									//监测函数
		Display_Function();									//显示函数
		Manage_Function();									//处理函数
		
		if(time_num % 100 == 0)							//指示灯闪烁
		{
			SYSTEM_LED = !SYSTEM_LED;
		}
		
//		Delay_ms(1);												//延时1ms
		time_num++;											    //计时值+1
		if(time_num >= 10000)
		{
			time_num = 0;
		}

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */


/**********************************
函数名:定时器中断回调函数
传参值:无
返回值:无
**********************************/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	static uint32_t time_count_5s = 0;
	static uint32_t time_count_1m = 0;

	if(htim->Instance == htim1.Instance)		//定时器1触发中断
	{
		if(flag_begin_5s == 1)
		{
			time_count_5s++;
			
			if(time_count_5s >= 5000)						//5s计时
			{
				time_count_5s = 0;
				
				flag_finish_5s = 1;
			}
		}
		else
		{
			time_count_5s = 0;
			flag_finish_5s = 0;
		}

		if(flag_begin_1m == 1)
		{
			time_count_1m++;
			
			if(time_count_1m >= 60000)						//1m计时
			{
				time_count_1m = 0;
				
				flag_finish_1m ++;
			}
		}
		else
		{
			time_count_1m = 0;
			flag_finish_1m = 0;
		}
	}
}

/**********************************
函数名:串口中断回调函数
传参值:串口号
返回值:无
**********************************/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == huart1.Instance)			//串口1触发中断
	{
		if(Air_4G_cnt < sizeof(Air_4G_buf))
		{
			Air_4G_buf[Air_4G_cnt++] = huart1_rx_data;
		}
		else
		{
			Air_4G_cnt = 0;
			Air_4G_cntPre = 0;
		}
		
		HAL_UART_Receive_IT(&huart1, &huart1_rx_data, 1);
	}
}


/**********************************
函数名:串口事件回调函数
传参值:huart:串口号		Size:数据大小
返回值:无
**********************************/
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	if(huart->Instance == huart3.Instance)				//串口3触发中断
	{
		HAL_UARTEx_ReceiveToIdle_IT(&huart3, huart3_rx_buf, HUART3_RX_SIZE);
		huart3_rx_finish = 1;
	}
}

/**********************************
函数名:串口错误回调函数
传参值:huart:串口号
返回值:无
**********************************/
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
	HAL_UART_DeInit(huart);
	HAL_UART_Init(huart);
	
	if(huart->Instance == huart1.Instance)
	{
		HAL_UART_Receive_IT(&huart1, &huart1_rx_data, 1);
	}
	
	if(huart->Instance == huart3.Instance)
	{
		HAL_UARTEx_ReceiveToIdle_IT(&huart3, huart3_rx_buf, HUART3_RX_SIZE);
	}
}


/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

Logo

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

更多推荐