一、功能介绍

项目名:基于STM32的智慧路灯设计
项目编号:dz-1197
单片机:STM32F103C8T6
功能简介:
1、通过光照检测模块检测当前环境的光照强度检测到光照小于最小值自动控制光照强度最亮,检测到光照大于最大值,照明灯关闭,检测到光照在最大值和最小值之间,光照越暗,路灯亮度越高;
2、通过另外一个光照检测模块检测当前路灯的亮度,路灯打开的时候检测到当前路灯周围光线较暗,手机端弹窗提醒路灯损坏;
3、通过噪声检测模块检测当前环境的噪声;
4、通过GP2Y10检测当前环境的粉尘浓度;
5、通过OLED显示屏显示测量数据;
6、通过WiFi模块将检测的数据上传到阿里云然后下发到手机端,手机可以设置光照强度的阈值;

二、实物演示视频

【mcu-1197】基于STM32的智慧路灯设计

三、仿真演示视频

【mcu-1197】基于STM32的智慧路灯设计

四、资料展示

实物资料

请添加图片描述

仿真资料

请添加图片描述

五、原理图

软件版本:AD2013
电路连线方式:采用网络标号连线方式,各功能模块之间通过统一的网络标号名称建立电气连接,避免大量走线交叉,使图纸层次更清晰、便于阅读与后期修改。
注意:原理图仅绘制了各模块的引脚图,并非模块的内部结构原理图,因此图中只体现模块对外的引脚定义与连接关系,模块内部的电路细节不在本图中展开。
在这里插入图片描述

六、PCB图

由原理图导出,封装很大一部分都是作者自己绘制,不提供封装库,只提供连接好的源文件,源文件可直接导入嘉立创进行打板。
板子采用两层板设计,上下两层均做了覆铜接地处理,一方面可以降低地线阻抗、提升抗干扰能力,另一方面也能减少走线难度、方便布线。PCB 上预留了各模块的接口与调试引脚,方便后续焊接与测试;中间还隐藏了一个项目编号,位于单片机底座下方,插入单片机后不会看到。
在这里插入图片描述

七、系统框图

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

八、软件设计流程图

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

九、部分程序展示

软件版本: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 "adc.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 "./ALIYUN/aliyun.h"
#include "./ESP8266/esp8266.h"
#include "./MQTT/mqtt.h"
#include "./PM25/pm25.h"


/* USER CODE END Includes */

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

/* 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;								//显示界面
uint16_t time_num = 0;									//计时值
char display_buf[16] = {0};							//显示数组

extern uint8_t esp8266_rx_buf[1024];		//esp8266接收数据数组
extern uint8_t esp8266_rx_finish;				//esp8266接收完成标志位
uint8_t *esp8266_dataPtr = NULL;				//esp8266返回的格式
uint8_t *esp8266_data = NULL;						//esp8266下发的数据
char *esp8266_result = NULL;  					//esp8266解析结果

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

uint16_t light_value = 0;								//光照值
uint16_t light_max = 300;								//光照最大值
uint16_t light_min = 100;								//光照最小值
uint8_t flag_gear = 0;                  //亮度档位
uint8_t led_speed = 0;                 	//led调节速度
uint8_t flag_mode = 0;                 	//led调节模式

uint8_t flag_light = 0;                 //光照标志位

uint16_t sound_value = 0;								//声音值

uint16_t pm25_value = 0;								//PM2.5浓度值

/* USER CODE END PV */

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

void Monitor_Function(void);						//监测函数
void Display_Function(void);						//显示函数
void Manage_Function(void);							//处理函数
void Aliyun_Send_Data(void);						//数据上报函数

/* USER CODE END PFP */

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


/**********************************
函数名:读取指定ADC通道的数据
传参值:通道
返回值:ADC值
**********************************/
uint32_t ADC_Get_Value(uint32_t Channel)
{
	ADC_ChannelConfTypeDef sConfig;
	
  sConfig.Channel = Channel;
  sConfig.Rank = 1;
  HAL_ADC_ConfigChannel(&hadc1, &sConfig);
  
  HAL_ADC_Start(&hadc1);									//启动转换并等待结束
  HAL_ADC_PollForConversion(&hadc1, 10); 	//等待转换完成,10是超时时间(单位ms)
  
  return HAL_ADC_GetValue(&hadc1);				//返回转换后的数据
}


/**********************************
函数名:监测函数
传参值:无
返回值:无
**********************************/
void Monitor_Function(void)
{
	if(time_num % 100 == 0)								//监测数据
	{
		light_value = 500 - 150 * (ADC_Get_Value(ADC_CHANNEL_4) / 4096.0 * 3.3);   //获取光照值
		
		sound_value = 30 * (ADC_Get_Value(ADC_CHANNEL_1) / 4096.0 * 3.3);               //获取声音值

		pm25_value = Pm25_Get_Value(0);					//获取PM2.5值
	}
	
	esp8266_dataPtr = ESP8266_GetIPD(0);													//获取平台返回的数据
	if(esp8266_dataPtr != NULL)
	{
		Aliyun_RevPro(esp8266_dataPtr);															//平台返回数据检测

		esp8266_result = strstr((char *)esp8266_data, "light_max");	//判断是否为改变光照最大值
		if(esp8266_result != NULL)
		{
			esp8266_result = strstr(esp8266_result, ":") + 1;
			light_max = atoi((const char *)esp8266_result);
			if(light_max <= light_min)
        light_max = light_min+10;
		}
		
		esp8266_result = strstr((char *)esp8266_data, "light_min");	//判断是否为改变光照最小值
		if(esp8266_result != NULL)
		{
			esp8266_result = strstr(esp8266_result, ":") + 1;
			light_min = atoi((const char *)esp8266_result);
			if(light_min >= light_max)
        light_min = light_max-10;
		}
		
		esp8266_result = strstr((char *)esp8266_data, "flag_mode");	//判断是否为改变光照最小值
		if(esp8266_result != NULL)
		{
			esp8266_result = strstr(esp8266_result, ":") + 1;
			flag_mode = atoi((const char *)esp8266_result);
		}
		
		esp8266_result = strstr((char *)esp8266_data, "flag_gear");	//判断是否为改变光照最小值
		if(esp8266_result != NULL)
		{
			esp8266_result = strstr(esp8266_result, ":") + 1;
			flag_gear = atoi((const char *)esp8266_result);
			flag_mode = 1;
		}
	}
	
	MQTT_FreeBuffer(esp8266_data);																//释放内存
}


/**********************************
函数名:显示函数
传参值:无
返回值:无
**********************************/
void Display_Function(void)
{
	if(time_num % 100 == 0)
	{
		Oled_ShowCHinese(1, 0, "光照:");        //显示光照值
		sprintf(display_buf, "%dLux  ", light_value);
		Oled_ShowString(1, 6, display_buf);
		
		Oled_ShowCHinese(2, 0, "噪声:");
		sprintf(display_buf, "%ddB  ", sound_value);
		Oled_ShowString(2, 6, display_buf);
		
		Oled_ShowCHinese(3, 0, "粉尘:");
		sprintf(display_buf, "%dug/m3  ", pm25_value);
		Oled_ShowString(3, 6, display_buf);
		
		Oled_ShowCHinese(1, 7,flag_mode == 0? "自": "手");

		Oled_ShowCHinese(4, 0, "路灯:");
		switch(flag_gear)											
		{
			case 0:									      			
				Oled_ShowCHinese(4, 3, "关");
			break;
			
			case 1:										
				Oled_ShowCHinese(4, 3, "暗");
			break;
			
			case 2:								
				Oled_ShowCHinese(4, 3, "中");
			break;
			
			case 3:								
				Oled_ShowCHinese(4, 3, "亮");
			break;

			default:
			break;
		}
		
		Oled_ShowCHinese(4, 6, flag_light==0? "正常":"损坏");
	}
}


/**********************************
函数名:处理函数
传参值:无
返回值:无
**********************************/
void Manage_Function(void)
{
	if(flag_mode == 0)
	{
		if(light_value > light_max)														//光照大于设置最大值,关闭灯光
		{
			flag_gear = 0;
		}
		else if(light_value > (light_min + light_max)/2)			//光照小于设置最小值,灯光最亮
		{
			flag_gear = 1;
		}
		else if(light_value > light_min)
		{
			flag_gear = 2;
		}		
		else																										//光照小于最小值自动控制光照强度最亮
		{
			flag_gear = 3;
		}
	}
	
	switch(flag_gear)											//根据不同的单位,调节LED亮度
	{
		case 0:									      			
			led_speed = 0;
		break;
		
		case 1:													
			led_speed = 3;
		break;
		
		case 2:													
			led_speed = 7;
		break;
		
		case 3:													
			led_speed = 10;
		break;

		default:
		break;
	}

	if(flag_gear != 0)                             				 	//路灯打开的时候检测到当前路灯周围光线较暗,手机端弹窗提醒路灯损坏;
	{
		if(LIGHT == 1)
		{
			if(flag_light == 0)
			{
				flag_light = 1;
			}
		}
		else
		{
			if(flag_light == 2)
			{
				flag_light = 0;
			}
		}
	}
	else                                         					//路灯关闭,不用检测
	{
		if(flag_light == 2)
		{
			flag_light = 0;
		}
	}

	if(flag_finish_5s == 1)																		//5秒上传一次数据
  {
    flag_begin_5s = 0;
    Aliyun_Send_Data();
    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_ADC1_Init();
  /* USER CODE BEGIN 2 */

	Delay_Init();													//延时初始化
	Oled_Init();													//OLED初始化
	PM25_Init();  												//PM2.5初始化函数
	
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
	
	Oled_Clear_All();											//清屏
	
	HAL_TIM_Base_Start_IT(&htim1);				//启动定时器
	
	HAL_UARTEx_ReceiveToIdle_IT(&ESP8266_HUART, esp8266_rx_buf, sizeof(esp8266_rx_buf) / sizeof(esp8266_rx_buf[0]));		//获取串口接收数据
	
	 Oled_ShowString(1,6,"WIFI ");
	 Oled_ShowCHinese(2, 2, "初始化中");
	 ESP8266_Init();											//初始化ESP8266
	 Oled_ShowString(3,4,"........");
	 while(Aliyun_DevLink())							//接入阿里云
	 Delay_ms(500);
	 Oled_ShowString(4,4,"........");
	 Aliyun_Subscribe(topics_set, 1);		//订阅主题
	 Delay_ms(500);
	 Aliyun_Send_Data();									//数据上报初始状态
   flag_begin_5s = 1;									//开启定时
   Oled_Clear_All();										//清屏

  while (1)
  {
		Monitor_Function();									//监测函数
		Display_Function();									//显示函数
		Manage_Function();									//处理函数
		
		if(time_num % 100 == 0)							//指示灯闪烁
		{
			SYSTEM_LED = !SYSTEM_LED;
		}
		
		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};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {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();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
  PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != 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;

	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;
		}

		
		time_count++;
		if(time_count >= 10)
		{
			time_count = 0;
		}
		
		if(time_count < led_speed)
		{
			RELAY_ZM = 1;
		}
		else
		{
			RELAY_ZM = 0;
		}
	}
}

/**********************************
函数名:串口事件回调函数
传参值:huart:串口号		Size:数据大小
返回值:无
**********************************/
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	if(huart->Instance == ESP8266_HUART.Instance)				//4g串口触发中断
	{
		HAL_UARTEx_ReceiveToIdle_IT(&ESP8266_HUART, esp8266_rx_buf, sizeof(esp8266_rx_buf) / sizeof(esp8266_rx_buf[0]));
		esp8266_rx_finish = 1;
	}
}

/**********************************
函数名:串口错误回调函数
传参值:huart:串口号
返回值:无
**********************************/
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
	HAL_UART_DeInit(huart);
	HAL_UART_Init(huart);
	
	if(huart->Instance == ESP8266_HUART.Instance)
	{
		HAL_UARTEx_ReceiveToIdle_IT(&ESP8266_HUART, esp8266_rx_buf, sizeof(esp8266_rx_buf) / sizeof(esp8266_rx_buf[0]));
		esp8266_rx_finish = 1;
	}
}


/**********************************
函数名:数据上报函数
传参值:无
返回值:无
**********************************/
void Aliyun_Send_Data(void)
{
	char send_data[512];								//发送数据数组

	
	sprintf(send_data,"{\"method\":\"thing/event/property/post\",\"id\":\"203302322\",\"params\":{\"light_value\":%d,\"light_max\":%d,\"light_min\":%d,\"flag_gear\":%d,\"flag_mode\":%d,\"flag_light\":%d,\"sound_value\":%d,\"pm25_value\":%d},\"version\":\"1.0.0\"}",
				light_value,light_max,light_min,flag_gear,flag_mode,flag_light,sound_value,pm25_value);

	Aliyun_Publish(topics_post, send_data);  		//添加数据,发布给服务器	
	
	if(flag_light == 1)
	{
		flag_light = 2;
	}
}


/* 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 核心人才招募,助力技术落地与开发者成长。

更多推荐