目录
一、前言
项目成品图片:

哔哩哔哩视频链接:
STM32室内环境监测系统
(资料分享见文末)
二、项目简介
1.功能详解
基于STM32的室内环境监测系统
功能如下:
- 使用STM32F103C8T6单片机作为主控单元
- 光敏电阻采集环境光强度,温度传感器采集温度,光电红外传感器采集人体有无
- OLED显示屏实时显示当前环境信息
- 光电红外检测到有人,可根据环境光照强度控制照明灯开关,根据环境温度情况控制风扇风速(低/高风速)和加热/制冷的操作
- 按键可设置阈值
- 可以通过蓝牙接入APP,APP实现数据上传与控制下发的功能
2.主要器件
- STM32F103C8T6单片机
- OLED 屏幕
- DS18B20温度传感器
- 光电红外传感器
- 光敏传感器
- BT04A蓝牙模块
- TB6612电机调速模块
- 继电器
- 风扇模块
- PTC加热片
三、原理图设计
四、PCB硬件设计
PCB图

五、程序设计
#include "sys.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "math.h"
#include "delay.h"
#include "gpio.h"
#include "key.h"
#include "oled.h"
#include "usart.h"
#include "adc.h"
#include "ds18b20.h"
#include "timer.h"
#include "motor_dianji.h"
/**********************************
变量定义
**********************************/
uint8_t key_num = 0; //按键扫描标志位
uint8_t flag_display = 0; //显示界面标志位
uint32_t time_num = 0; //10ms计时
uint32_t light_value = 0; //光照数值
uint32_t light_min = 40; //光照数值
u16 temp_value = 0; //温度值
u16 temp_min = 15; //温度最小值
u16 temp_zj = 25; //温度中间值
u16 temp_max = 30; //温度最大值
extern uint8_t usart1_buf[256]; //串口1接收数组
char display_buf[32]; //显示缓存区
_Bool flag_mode = 0; //模式标志位
uint8_t flag_motor_speed = 0; //电机速度标志位
uint32_t speed_value = 0; //速度值
_Bool flag_mode_r = 0; //模式标志位
/**********************************
函数声明
**********************************/
void Key_function(void); //按键函数
void Monitor_function(void); //监测函数
void Display_function(void); //显示函数
void Manage_function(void); //处理函数
/****
******* 主函数
*****/
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置中断优先分组
Delay_Init(); //延时初始化
Gpio_Init(); //IO初始化
Key_Init(); //按键初始化
Oled_Init(); //OLED初始化
Oled_Clear_All(); //清屏
Usart1_Init(9600); //串口1初始化
// TIM3_Init(99,7199); //定时器初始化函数
DS18B20_Init();
Adc_Init();
Motor_Dianji_Init(); //直流电机初始化
TIM_SetCompare1(MOTOR_DIANJI_TIM,0);
Delay_ms(1000);
Delay_ms(1000);
while(1)
{
Key_function(); //按键函数
Monitor_function(); //监测函数
Display_function(); //显示函数
Manage_function(); //处理函数
time_num++; //计时变量+1
Delay_ms(10);
if(time_num %10 == 0)
LED_SYS = ~LED_SYS;
if(time_num >= 5000)
{
time_num = 0;
}
}
}
/****
*******按键函数
*****/
void Key_function(void)
{
key_num = Chiclet_Keyboard_Scan(0); //按键扫描
if(key_num != 0) //有按键按下
{
switch(key_num)
{
case 1: //按键1,切换设置界面
flag_display++;
if(flag_display >= 5)
flag_display = 0;
Oled_Clear_All(); //清屏
break;
case 2: //按键2 各个阈值+1
switch(flag_display)
{
case 1: //界面1:
if(temp_max < 99)
temp_max++;
break;
case 2: //界面2:
if(temp_min < temp_zj)
temp_min++;
break;
case 3: //界面3:
if(temp_zj < temp_max)
temp_zj++;
break;
case 4: //界面4:
if(light_min < 70)
light_min ++ ;
break;
default:
break;
}
break;
case 3: //按键3 各个阈值-1
switch(flag_display)
{
case 1: //界面1:
if(temp_max > temp_zj)
temp_max --;
break;
case 2: //界面2:
if(temp_min > 0)
temp_min --;
break;
case 3: //界面3:
if(temp_zj > temp_min)
temp_zj --;
break;
case 4: //界面4:
if(light_min > 0)
light_min --;
break;
default:
break;
}
break;
default:
break;
}
}
}
/****
*******监测函数
*****/
void Monitor_function(void)
{
if(flag_display == 0) //测量界面
{
if(time_num % 10 == 0) //获取数据
{
light_value = 99-30*(Get_Adc_Average(0,3)*3.3/4096.0); //获取光照强度
temp_value = DS18B20_Get_Temp();
}
if(time_num % 20 == 0) //发送数据
{
UsartPrintf(USART1,"温度:%d.%dC\r\n",temp_value/10,temp_value%10);
UsartPrintf(USART1,"光照:%dlux\r\n",light_value);
if(IRED == 0)
UsartPrintf(USART1,"人体热释电:有人\r\n");
else
UsartPrintf(USART1,"人体热释电:无人\r\n");
}
if(USART1_WaitRecive() == 0) //如果接收到蓝牙数据
{
switch(usart1_buf[0])
{
case('A'): //A:切换自动模式
flag_mode_r = 0;
// flag_mode = 0;
break;
case('B'): //B: 风扇低速
flag_mode_r = 1;
flag_motor_speed = 1;
break;
case('C'): //C:风扇高速
flag_mode_r = 1;
flag_motor_speed = 2;
break;
case('D'): //D:照明灯
flag_mode_r = 1;
RELAY_ZM = ~RELAY_ZM;
break;
case('E'): //E:加热
flag_mode_r = 1;
RELAY_JR = ~RELAY_JR;
break;
case('F'): //F:制冷
flag_mode_r = 1;
RELAY_ZL = ~RELAY_ZL;
break;
default:
break;
}
USART1_Clear();
}
if(flag_mode_r == 0)
{
if(IRED == 0)
{
flag_mode =0;
}
else
{
flag_mode = 1;
RELAY_JR = 0;
RELAY_ZL = 0;
RELAY_ZM = 0;
flag_motor_speed = 0;
}
}
}
}
/****
*******显示函数
*****/
void Display_function(void)
{
switch(flag_display) //根据不同的显示模式标志位,显示不同的界面
{
case 0: //界面0:
Oled_ShowCHinese(1, 0, "温度:");
sprintf(display_buf,"%d.%dC ",temp_value/10,temp_value%10); //显示温度的值
Oled_ShowString(1, 6, display_buf);
Oled_ShowCHinese(2, 0, "光照:");
sprintf(display_buf,"%dlux ",light_value); //显示温度的值
Oled_ShowString(2, 6, display_buf);
Oled_ShowCHinese(3, 0, "人体:");
if(IRED == 0)
Oled_ShowCHinese(3, 3, "有人");
else
Oled_ShowCHinese(3, 3, "无人");
Oled_ShowCHinese(4, 0, "蓝牙模式:");
if(flag_mode_r == 1)
Oled_ShowCHinese(4, 5, "开启");
else
Oled_ShowCHinese(4, 5, "关闭");
break;
case 1: //界面1:
Oled_ShowCHinese(1,0,"设置温度最大值");
if(time_num % 5 == 0)
{
sprintf(display_buf,"%d ",temp_max);
Oled_ShowString(2, 7, display_buf);
}
if(time_num % 10 == 0)
{
Oled_ShowString(2, 7, " ");
}
break;
case 2: //界面2:
Oled_ShowCHinese(1,0,"设置温度最小值");
if(time_num % 5 == 0)
{
sprintf(display_buf,"%d ",temp_min);
Oled_ShowString(2, 7, display_buf);
}
if(time_num % 10 == 0)
{
Oled_ShowString(2, 7, " ");
}
break;
case 3: //界面3:
Oled_ShowCHinese(1,0,"设置温度中间值");
if(time_num % 5 == 0)
{
sprintf(display_buf,"%d ",temp_zj);
Oled_ShowString(2, 7, display_buf);
}
if(time_num % 10 == 0)
{
Oled_ShowString(2, 7, " ");
}
break;
case 4: //界面4:
Oled_ShowCHinese(1,0,"设置光照最小值");
if(time_num % 5 == 0)
{
sprintf(display_buf,"%d ",light_min);
Oled_ShowString(2, 7, display_buf);
}
if(time_num % 10 == 0)
{
Oled_ShowString(2, 7, " ");
}
break;
default:
break;
}
}
/****
*******处理函数
*****/
void Manage_function(void)
{
if(flag_mode == 0 && flag_mode_r == 0)
{
if(flag_display == 0) //测量界面
{
if(temp_value > temp_max*10)
{
RELAY_ZL = 1;
RELAY_JR = 0;
flag_motor_speed = 0;
}
else if(temp_value > temp_zj*10)
{
flag_motor_speed = 2;
RELAY_ZL = 0;
RELAY_JR = 0;
}
else if(temp_value > temp_min*10)
{
flag_motor_speed = 1;
RELAY_ZL = 0;
RELAY_JR = 0;
}
else
{
flag_motor_speed = 0;
RELAY_ZL = 0;
RELAY_JR = 1;
}
if(light_value < light_min)
{
RELAY_ZM = 1;
}
else
{
RELAY_ZM = 0;
}
}
else //设置界面
{
RELAY_ZM = 0;
RELAY_JR = 0;
RELAY_ZL = 0;
flag_motor_speed = 0;
}
}
switch(flag_motor_speed) //根据不同的电机速度标志位,控制电机转速
{
case 0:
speed_value = 0; //停止
break;
case 1:
speed_value = 860; //低速
break;
case 2:
speed_value = 980; //高速
break;
default:
break;
}
TIM_SetCompare1(MOTOR_DIANJI_TIM,speed_value);
}
六、实验效果


七、资料内容
1万+

被折叠的 条评论
为什么被折叠?



