开发者-导航 猿导航

基于 51 单片机 DIY 热水器控制器

发布时间:

目录

一、介绍 #

我是一个软件开发者,心血来潮想 diy 远程控制热水器烧水的控制器,热水器功率较大一直开着费电,所以我就想能不能利用我毕生所学自己实战一下。选择 51 单片机因为简单入门快。这个过程中也遇到了大量问题,在黑电子论坛各位大佬的帮助下和 AI 的加持下完成。


二、功能 #


三、元器件清单 #

序号 元件名称 型号 / 参数 数量 作用说明
1 单片机核心板 STC89C516 1 控制核心,负责逻辑控制和指令响应
2 WiFi 模块 ESP-01S 1 实现 WiFi 联网,接收远程控制指令
3 继电器 JQC-3FF-S-Z 1 控制交流电通断,用于热水器控制
4 整流二极管 1N4007 1 防止继电器回流电压损坏元件
5 降压芯片 AMS1117-3.3 1 将5V电压降为3.3V供 ESP-01S 使用
6 三极管 S8550 PNP 1 放大驱动电流控制继电器通断
7 电阻 1.2kΩ 1 用于三极管基极限流
8 指示灯 LED + 100Ω电阻 1 显示继电器工作状态(亮=加热)
9 电源 5V 电源(USB 或降压) 1 提供系统电压
10 下载器 STC UST-TTL 1 USB下载器
11 杜邦线 - 若干 连接电路

四、开发软件 #

序号 名称 描述
1 sscomV5131.exe 串口调试工具/网络调试工具,创建TCP服务和客户端
2 Keil uVision4 C51代码开发工具,编译 hex 文件
3 CH340 STC 下载器驱动程序
4 AIapp-ISP-v6.95M STC-ISP 将 hex文件下载到单片机软件

五、原理图 #

画电路图不太行,简单画了下方便大家凑合看吧!

WiFi控制器原理图

接线图

接线图

六、电路连接说明 #


七、软件设计与源代码 #

代码部分很简单,大部分内容AI生成,需要注意的时修改WiFi名称和密码。还有就是要修改 TCP 服务器地址和端口,可以现在自己电脑测试,有云服务器可以填写云服务地址+端口就可以实现远程操作。

#include <reg51.h>
#include <intrins.h>
#include <string.h>
#include <stdio.h>  

#define uchar unsigned char
#define uint unsigned int

// 引脚定义
sbit relay = P1^0;    // 继电器控制引脚

// 将大数组放到XDATA区(外部数据存储器)
uchar xdata RecBuf[50];     // 接收缓冲区,使用xdata关键字
uchar RxCounter = 0;        // 接收计数器
bit receiveFinish = 0;      // 接收完成标志


// 函数声明
void UartInit(void);        // 串口初始化
void ESP8266_Init(void);    // ESP8266初始化
void SendCmd(uchar *cmd);   // 发送AT命令
void DelayMs(uint ms);      // 毫秒延时
void ConnectWiFi(void);     // 连接WiFi
void ConnectTCP(void);      // 连接TCP服务器
void SendHeartbeat(void);
void CheckResponse(uchar *response); // 检查响应

void main() {
	
	UartInit();        // 初始化串口
    ESP8266_Init();    // 初始化ESP8266
    ConnectWiFi();     // 连接WiFi
    ConnectTCP();      // 连接TCP服务器

    
    while(1) {
	

        if(receiveFinish) { // 如果接收到数据
            receiveFinish = 0;
            
            // 检查是否接收到"1"或"0"
            if(strstr(RecBuf, "1") != NULL) {
                relay = 0;    // 低电平,打开继电器
                SendCmd("AT+CIPSEND=4\r\n"); // 准备发送数据
                DelayMs(500);
                SendCmd("0104\r\n");  // 发送确认信息
            }
            else if(strstr(RecBuf, "0") != NULL) {
                relay = 1;    // 高电平,关闭继电器
                SendCmd("AT+CIPSEND=4\r\n");
                DelayMs(500);
                SendCmd("0104\r\n");
            }
            
            memset(RecBuf, 0, sizeof(RecBuf)); // 清空缓冲区
            RxCounter = 0;
        }
		SendHeartbeat();
    }
}

// 发送心跳包
void SendHeartbeat(void) {
	DelayMs(2000);

    SendCmd("AT+CIPSEND=4\r\n"); // 发送10字节数据
    DelayMs(500);
    SendCmd("0102\r\n");     // 心跳包内容
}



// 串口初始化函数
void UartInit(void) {
    SCON = 0x50;        // 8位数据,可变波特率
    TMOD |= 0x20;       // 设置定时器1为8位自动重装方式
    TH1 = 0xFD;         // 波特率9600
    TL1 = 0xFD;
    TR1 = 1;            // 启动定时器1
    ES = 1;             // 使能串口中断
    EA = 1;             // 开总中断
}

// ESP8266初始化
void ESP8266_Init(void) {
    DelayMs(2000);      // 等待ESP8266启动
    
    SendCmd("AT\r\n");      // 测试AT命令
    DelayMs(1000);
    
    SendCmd("AT+RST\r\n");  // 重启ESP8266
    DelayMs(2000);
    
    SendCmd("AT+CWMODE=1\r\n"); // 设置为STA模式
    DelayMs(1000);
    
    SendCmd("AT+CIPMUX=0\r\n"); // 设置单连接模式
    DelayMs(1000);
}

// 连接 WiFi
void ConnectWiFi(void) {
    uchar cmd[50];
    sprintf(cmd, "AT+CWJAP=\"FAST\",\"12345678\"\r\n");
    SendCmd(cmd);
    DelayMs(5000); // 等待连接WiFi
}

// 连接TCP服务器
void ConnectTCP(void) {
    uchar cmd[50];
	sprintf(cmd, "AT+CIPSTART=\"TCP\",\"192.168.1.100\",8888\r\n");
    SendCmd(cmd);
    DelayMs(3000); // 等待连接TCP
    
    SendCmd("AT+CIPMODE=1\r\n"); // 设置为透传模式
    DelayMs(1000);
    
    SendCmd("AT+CIPSEND\r\n");   // 开始透传
    DelayMs(1000);

	SendCmd("AT+CIPSEND=4\r\n");
    DelayMs(500);
    SendCmd("0102\r\n");
}

// 发送AT命令
void SendCmd(uchar *cmd) {
    uchar i = 0;
    while(cmd[i] != '\0') {
        SBUF = cmd[i];
        while(!TI);
        TI = 0;
        i++;
    }
}

// 毫秒延时函数
void DelayMs(uint ms) {
    uint i, j;
    for(i = 0; i < ms; i++)
        for(j = 0; j < 123; j++);
}

// 串口中断服务函数
void Uart() interrupt 4 {
    if(RI) {
        RI = 0;
        RecBuf[RxCounter++] = SBUF;
        
        if(RxCounter >= 49) { // 防止缓冲区溢出
            RxCounter = 0;
        }
        
        // 判断是否接收完成
        if(SBUF == '\n') {
            receiveFinish = 1;
        }
    }
}

八、ESP-01S 通讯控制方式 #

ESP 先连接 WiFi,然后建立 TCP 连接(可使用 sscom 创建 TCP server),TCP 服务端负责下发数据控制继电器。


九、遇到的问题与解决 #

S8050 NPN 型三极管,高电平导通 #

  1. 使用 S8050(NPN) P1.0 无法驱动继电器,串联电阻无法驱动,据说是IO口驱动能力较弱。
GPIO P1.0--->1.2kΩ--->S8050(B)
  1. 在电源和P1.0口串联电阻(上拉电阻)就可以驱动了(大佬给原理图)
5v+-----|
		|
	   [电阻 R1 1.2kΩ]  
	    |
P1.0----·--->S8050(B)
  1. 又出现新的问题,第一次上电或复位时瞬间吸合一次,这个问题即使改代码也解决不了,因为51单片机IO口默认高电平。看了很多大佬的电路也是没能解决,电路是在 P1.0 加下拉电阻,P1.0 串联 1kΩ电阻到 B 基,手头也没 10kΩ 电阻没有测试成功。
GPIO P1.0--->1kΩ--->S8050(B)
			|
			|
			|
		  [10kΩ 下拉]
            |
           GND

S8550 PNP 型三极管,低电平导通 #

最终采用了 S8550 来驱动继电器,正如标题它是低电平导通,所以单片机默认高电平,复位或上电就不会出现吸合一次的情况。

问题描述 解决办法
ESP-01S 工作不稳定 / 无响应 使用 AMS1117 提供独立3.3V供电,加入电容滤波
串口通信乱码 / 无反应 确认波特率一致(9600),ESP-01S 接 RX需分压至3.3V
继电器吸合但没有动作 检查三极管是否导通、电阻设置是否合理
LED 长亮/不亮 检查LED极性、限流电阻是否连接、继电器是否正确驱动

十、三极管扩展 #

概念 #

三极管广泛用于电子电路中的开关和放大功能。其特点是价格低廉、体积小、性能稳定,常见于音频放大器、电源控制、信号处理等低功率场合。

实物 TO-92 封装 #

类型 实物图 电路符号 电流方向
NPN S8050 S8050电路符号 发射极流出,集电极流入
PNP S8550 S8050电路符号 发射极流入,集电极流出

引脚 #

正面朝你(扁平面朝前,脚朝下)

序号 引脚 引脚名称
1 E 发射器
2 B 基极
3 C 集电极

奇技淫巧(个人理解) #

第一次接触三极管感觉不太好理解,可能脑容量不够用哈哈!

十一、注意事项 #


十二、总结 #

本项目利用常见的 51 单片机 + ESP-01S 模块,完成了一个低成本的智能热水器控制器。

在完成该实践后我又发现实际上可以用 ESP-01S 作为 MCU 直接控制继电器(刷固件)而不用单独单片机也是可以的。

对于老手来说这是一个很简单的电路,于我而言涉及的内容多且复杂的,你需要懂代码,电路图,元器件作用特性等等。不过完成该案例也是受益匪浅学到了不少知识点。

十三、参考资料 #