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

哔哩哔哩视频链接:
(资料分享见文末)
二、项目简介
1.功能详解
基于STM32的智能热水器
功能如下:
- 环境采集:采集环境光照强度、水位、水温
- 显示功能:屏幕显示当前时间、光照强度、热水器水位、水温;第二页显示定时开始时间和结束时间
- 模式切换:可以通过按键切换自动模式和手动模式
- 自动模式:当前时间处于定时工作时间内:光照小于光照阈值时开启照明灯,水位小于最低水位时开启进水水泵加水且此时蜂鸣器报警提醒;水位超过最大水位时开启排水水泵放水;温度低于最低温度时蜂鸣器报警并开启加热片加热水直到温度达到最高温度时停止加热; 当水位过低时加热功能不启动;当时间处于定时时间外则热水器不自动工作,只能通过手动模式控制。
- 手动模式:通过按键控制LED照明灯、加水、放水、加热
- 阈值调节:可通过按键设置当前时间、温度上限、温度下限、光照阈值、水位上限、水位下限、定时开始时间和结束时间
- 蓝牙APP:通过连接蓝牙APP,可以查看信息数据和控制指令下发,包括模式切换、手动外设控制
2.主要器件
- STM32F103C8T6最小系统板
- OLED显示屏(4针IIC协议)
- 光敏传感器
- 水位传感器
- DS18B20温度传感器
- 大功率LED灯模块
- PTC加热片
- 继电器
- 水泵模块
- 有源蜂鸣器
三、原理图设计

四、PCB硬件设计
PCB图


五、程序设计
cpp
#include "stm32f10x.h"
#include "led.h"
#include "beep.h"
#include "usart.h"
#include "usart2.h"
#include "usart3.h"
#include "delay.h"
#include "ds18b20.h"
#include "LDR.h"
#include "oled.h"
#include "key.h"
#include "Modules.h"
#include "TIM2.h"
#include "TIM3.h"
#include "adcx.h"
#include "flash.h"
#include "JDQ.h"
#include "MyRTC.h"
#include "stm32f10x_iwdg.h"
/****************异方辰电子工作室*******************
STM32
*项目 : STM32智能热水器
*版本 : V1.0
*MCU : TM32F103C8T6
*接口 : 见代码
*BILIBILI : 异方辰电子
*小红书 : 异方辰电子
*CSDN : 异方辰电子
*授权IP : 辰哥单片机设计、异方辰、YFC电子、北海单片机设计
**********************BEGIN***********************/
SensorModules sensorData; //声明传感器数据结构体变量
SensorThresholdValue Sensorthreshold; //声明传感器阈值结构体变量
DriveModules driveData; //声明驱动器状态结构体变量
uint16_t time_num = 0; //10ms计时
static uint8_t app_cmd = 0; // 0 无指令 3 开 4 关
uint8_t mode = 0; //系统模式 1自动 2手动 3设置
u8 Flag_setTime = 0;
u8 setTime_Type = 0;
// 时间设置临时变量
uint16_t tempTime[3]; // 当前时间临时变量
uint16_t tempTime_start[3]={0,0,0}; // 开始时间临时变量
uint16_t tempTime_end[3]={1,1,1}; // 结束时间临时变量
uint8_t timeFieldIndex = 0;
uint8_t lastTimeFieldIndex = 0;
extern uint8_t usart2_buf[256]; //串口2接收数组
char display_buf[16]; //显示数组
//系统静态变量
static uint8_t count_a = 1; //自动模式按键数
uint8_t count_m = 1; //手动模式按键数
static uint8_t count_s = 1; //设置模式按键数
int main(void)
{
SystemInit(); //配置系统时钟为72M
delay_init(72);
//传感器初始化
DS18B20_Init(); //ds18b20初始化
LDR_Init(); //光敏电阻初始化
//执行器初始化
LED_Init(); //大功率LED灯初始化
BUMP1_Init(); //抽水水泵初始化
BUMP2_Init(); //放水水泵初始化
JRP_Init(); //加热片初始化
BEEP_Init(); //蜂鸣器初始化
Key_Init(); //按键初始化
OLED_Init(); //OLED初始化
MyRTC_Init(); //RTC时钟初始化
USART1_Config();//串口1初始化
USART2_Config();//串口2初始化
USART3_Config();//串口3初始化
TIM2_Init(72,1000-1);
TIM3_Int_Init(1000-1,72-1); //定时1ms中断
OLED_Clear();
delay_ms(300);
FLASH_ReadThreshold();
MyRTC_SetTime();
while (1)
{
SensorScan(); //获取传感器数据
Bluetooth_Control();//蓝牙控制函数
// 将数据存入Flash
FLASH_W(FLASH_START_ADDR,Sensorthreshold.luxValue,
Sensorthreshold.tempValue_MIN ,Sensorthreshold.tmepValue_MAX ,
Sensorthreshold.waterleveVlaue_MAX,Sensorthreshold.waterleveVlaue_MIN ,
MyRTC_Time[3],MyRTC_Time[4],MyRTC_Time[5],
tempTime_start[0],tempTime_start[1],tempTime_start[2],
tempTime_end[0],tempTime_end[1],tempTime_end[2]);
MyRTC_ReadTime();
switch(mode)
{
case AUTO_MODE:
if(SetAuto() ==1)
{
OLED_autoPage1(); //显示主页面1固定信息
SensorDataDisplay1(); //显示传感器1数据
}
else
{
OLED_autoPage2(); //显示主页面2固定信息
SensorDataDisplay2(); //显示传感器2数据
}
AutoControl();
/*按键1按下时切换模式*/
if (KeyNum == KEY_1) //系统模式mode 1自动 2手动 3设置
{
KeyNum = 0;
mode = MANUAL_MODE;
count_m = 1;
OLED_Clear();
}
if (KeyNum == KEY_Long1)
{
KeyNum = 0;
mode = SETTINGS_MODE;
count_s = 1;
OLED_Clear();
}
Control_Manager();
break;
case MANUAL_MODE:
OLED_manualOption(SetManual());
ManualControl(SetManual());
OLED_manualPage1();
ManualSettingsDisplay1();
if (KeyNum == KEY_1) //系统模式mode 0手动 1自动(默认)
{
KeyNum = 0;
mode = AUTO_MODE;
count_a = 1;
OLED_Clear();
}
Control_Manager();
break;
case SETTINGS_MODE:
OLED_settingsOption(SetSelection()); //实现阈值设置页面的选择功能
ThresholdSettings(SetSelection()); //实现阈值调节功能
if(Flag_setTime == 0)
{
if (SetSelection() <= 4)
{
OLED_settingsPage1(); //显示阈值设置界面1固定信息
SettingsThresholdDisplay1(); //显示传感器阈值1数据
}
else //否则显示设置页面2
{
OLED_settingsPage2(); //显示阈值设置界面2固定信息
SettingsThresholdDisplay2(); //显示传感器阈值2数据
}
}
//判断是否退出阈值设置界面
if (KeyNum == KEY_1)
{
KeyNum = 0;
mode = AUTO_MODE; //跳转到主界面
count_a = 1;
OLED_Clear(); //清屏.
// 将修改好的阈值存入Flash中
FLASH_W(FLASH_START_ADDR,Sensorthreshold.luxValue,
Sensorthreshold.tempValue_MIN ,Sensorthreshold.tmepValue_MAX ,
Sensorthreshold.waterleveVlaue_MAX,Sensorthreshold.waterleveVlaue_MIN ,
MyRTC_Time[3],MyRTC_Time[4],MyRTC_Time[5],
tempTime_start[0],tempTime_start[1],tempTime_start[2],
tempTime_end[0],tempTime_end[1],tempTime_end[2]);
}
break;
case TIME_SET_MODE:
switch(setTime_Type)
{
case 5: // 修改当前时间
if (Flag_setTime == 1)
{
for (int i = 0; i < 3; i++)
{
tempTime[i] = MyRTC_Time[i+3];
}
Flag_setTime = 2;
timeFieldIndex = 0;
lastTimeFieldIndex = 0;
}
OLED_ShowChinese(32,0,20,16,1); //当
OLED_ShowChinese(48,0,21,16,1); //前
OLED_ShowChinese(64,0,22,16,1); //时
OLED_ShowChinese(80,0,23,16,1); //间
OLED_ShowChar(96,0,':',16,1);
OLED_TIME_SET_MODE(tempTime); // 显示时间设置模式
TimeSettings(tempTime); // 时间设置函数
break;
case 6: // 修改开始时间
OLED_ShowChinese(32,0,24,16,1); //开
OLED_ShowChinese(48,0,8,16,1); //始
OLED_ShowChinese(64,0,22,16,1); //时
OLED_ShowChinese(80,0,23,16,1); //间
OLED_ShowChar(96,0,':',16,1);
OLED_TIME_SET_MODE(tempTime_start); // 显示时间设置模式
TimeSettings(tempTime_start); // 时间设置函数
break;
case 7: // 修改结束时间
OLED_ShowChinese(32,0,12,16,1); //结
OLED_ShowChinese(48,0,13,16,1); //束
OLED_ShowChinese(64,0,22,16,1); //时
OLED_ShowChinese(80,0,23,16,1); //间
OLED_ShowChar(96,0,':',16,1);
OLED_TIME_SET_MODE(tempTime_end); // 显示时间设置模式
TimeSettings(tempTime_end); // 时间设置函数
break;
}
if (KeyNum == KEY_1)
{
KeyNum = 0;
if(Flag_setTime == 2)
{
for (int i = 0; i < 3; i++)
{
MyRTC_Time[i+3] = tempTime[i];
}
}
MyRTC_SetTime(); // RTC设置时间
mode = SETTINGS_MODE;
count_a = 1;
Flag_setTime = 0;
OLED_Clear();
}
break;
default: break;
}
}
}
六、实验效果 
七、包含内容
