资讯详情

写一个锅炉温控系统

1.前言

我家在东北农村,冬天很冷,买了锅炉,需要循环泵。简单地说,锅炉水热后,循环泵自动打开,然后将热水输送到加热、热水、冷水进入锅炉,温度降低,循环泵关闭,等待下一次水加热。因为需要加热的房子离锅炉很远,所以需要循环泵。如果距离近,热水加热后,热水冷水回流的原理会自动完成循环。当然,市场上有这种设备,利用温度自动控制循环泵的开启和关闭:

IMG_20220123_221152_HDR

原理是有一个热敏电阻探头(磁铁吸附,可吸附在锅炉壁上),然后由继电器控制。当温度达到设定值时,继电器打开,循环泵启动,锅炉壁温度下降,继电器关闭,循环泵关闭。

循环泵:

由于我家的循环泵功率较大,小继电器启动几次就烧坏了,所以中间又接入了一层交流接触器(我的老父亲加的)。

市场上的设备可以大致解决水循环问题,但也有一些细节无法解决。例如,当回流管的水温达到设定的温度值时,循环泵将始终打开。此时,需要手动调整旋钮温度(提高),使循环泵停止(大功率循环泵耗电量大)。又如 当炉内煤逐渐燃烧(东北称为涝)时,锅炉温度不能达到设定值。此时,需要减少旋钮,启动循环泵,以免浪费煤产生的余温。

由于上述缺点,有人需要每隔几个小时调整一次旋钮。我父亲正在做这部分工作,所以我想做一些自动的事情来减少我父亲的工作量。

2.项目结构

我最初的想法是通过手机远程调节温度,这样至少不需要手动调节旋钮。我可以在半夜起床,用手机在床上调整。基于最初的构思设计结构:

3.硬件搭建

esp01模块 继电器模块,220v转5v模块 插排 = 联网插座

esp8226 温度传感器 数码管 = 实时温度检测显示联网模块

我的控制系统都写在里面 esp8226中。

制作温度传感器探头:驱动ds18b20传感器需要在数据总线(DQ)与 VDD 在引脚之间加一个4.7k欧姆的电阻(拉电阻),这是必要的,用一个铁纽扣包裹,里面有两个小钕磁铁,最后用兄弟好胶水填充,形成一个温度传感器探头,可以吸附在锅炉壁上:

这一步我犯了一个错误,将军ds18b20传感器和上拉电阻都放入探头中。测温时发现温度升高后,温度传感器读取温度失败,因为温度升高导致电阻值增加。后来我把电阻放在尾部解决了这个问题。

包装探头:

esp8226 数码管模块:

壳子是我用3D打印机打印,放在里面esp8226模块。

4.软件编写

固件

esp8226 和 esp01 我都是烧录的固件。

通信

从通信开始,我想的是用socket实现,简单拿个HTTP协议通信,但是手机上这样控制比较麻烦。没有好的软件,我必须做一个web界面,另外socket阻塞线程。

后来发现了MQTT该协议是一种针对物联网的硬件网络通信协议,可以处理高延迟的网络环境。简单介绍一下MQTT协议,首先需要一个服务器(也叫代理服务器,在电脑上运行,我在树莓派上运行),然后你所有的物联网硬件设备(比如esp8226)都是客户端,物联网硬件设备(客户端)之间不会直接通信,都是直接与服务端通信。如果硬件设备之间需要通信,则需要发布或订阅主题。例如:如果硬件A 和硬件B 需要通信,所以首先需要连接 服务端,然后 A 发布一个名字topic如果硬件B想接受A的信息,则需要订阅主题 topic这个主题实现了 A ---> B 反向通信也是一个原则,B 发布主题,A来订阅。该协议还具有多个客户端订阅一个主题的优势,从而实现多端通信。mqtt在协议通信中,每个客户端都不知道其他客户端的存在,他们直接与服务端通信。

mqtt协议在micropython固件(不知道安信是否有默认固件)通信存在很大问题:LmacRxBlk:1举报错误。例如,如果你在一开始就订阅了一个主题,然后你使用非阻塞方法check_msg()回调函数处理 此时,如果您订阅的主题发布次数超过您的主题消息 check_msg()次数,然后就会在micropython在固件底层报错 LmacRxBlk:1,然后通信中断。简单来说,你订阅一个主题,然后进入事件循环。如果你没有时间处理订阅主题的信息,就会导致这个错误。官方解释是这个错误tcp buffer由于资源没有释放,esp8226可用资源非常有限,但在mqtt在通信中,我不能每次循环后都释放连接,然后每次都重新建立连接个错误的恶心是,try except 无法捕法捕获,则只能通过设计解决处理错误,即确保订阅主题发布的间隔远小于其循环间隔,确保订阅消息每次都能及时处理。我已经解决了这个问题很长时间了,因为try except 抓不到,不常出现,不能定位,不知道为什么通信会中断。

编写代码核心逻辑

我都写在核心控制逻辑上esp8226在模块中,循环收集温度,然后以温度为主题发布。手机可以订阅主题,实时查看锅炉温度。循环中有一个设定温度的变量 ,若采集温度高于 设定温度 然后发布一个 开关主题如果温度低于打开的主题 设定温度,那么就发布一个 开关主题关闭,每次订阅 为修改设置主题设定温度变量。

esp01 控制继电器,每次订阅 开关主题 就可以了,然后每次再把它拿走 当前开关状态 发布为主题。

这个代码逻辑最开始我是这样写的,手机上只需要发布设置温度主题就可以了,但是也是需要人一段时间用手机去调节一次,还是不能实现自动化,后来我又修改的 esp8226 中的代码逻辑,复杂了一些。

esp8226 核心逻辑与上述相同。每次检测温度高于设定温度后,开关将打开,但当检测温度低于设定温度时,开关不会立即关闭,而是等待检测温度低于设定温度,减去变量,然后发布开关关闭的主题。这是为了解决 检测温度在设定温度临界处反复跳转,导致开关在短时间内反复打开和关闭。这里引入了一个减去变量,我称之为温度步长 。这里有个问题。如果锅炉一直在加热,即使循环泵一直打开 ,锅炉温度不低于设定温度(回流管温度高于设定温度),循环泵将始终打开,因此我在这里介绍了第二个变量:最大启动时间,如果计时器的时间超过每次启动后的计时器 最大启动时间,那么无论此时的温度是否低于设定温度,循环泵将关闭并关闭设定温度提高温度,提高温度温度步长加上当前的温度,这里就实现了 自动调节 设定温度(上升方向)。还有一个问题:炉煤燃烧时,温度逐渐下降,检测到的温度肯定会远低于设定温度,循环泵永远不会打开。所以我在这里介绍了第三个变量(回调检测时间),当esp8226 上电启动时,如果计时,启动计时器 等于回调检测时间,那么将设定温度 调节到当前温度,用于调节当前温度设定温度 假设自动回调回调检测时间 为 即使是30分钟设定温度 高于 检测温度时,循环泵将在30分钟内启动,并与剩余逻辑实现闭环,从而实现 设定温度,自动上下调节。 在这里,我还添加了一个变量最低温度,若当前温度低于最低温度,那么就算 当前温度高于设定温度 循环泵不会用于燃烧煤炭燃煤时,以防止循环泵在任何时候启动30分钟,最低温度 设置高于环境温度。

这里 设定温度温度步长最大启动时间回调检测时间最低温度,可以通过手机设置,我让esp这些主题用于设置这些变量。

esp8226代码:

```python from machine import Pin,reset import onewire from ds18x20 import DS18X20 import time import tm1637 from umqtt.simple import MQTTClient

def main(): client_id = "esp_temperature" mserver = '192.168.0.99' #mserver = '192.168.3.200' #mserver = 'mq.tongxinmao.com'

tm = tm1637.TM1637(clk=Pi(14), dio=Pin(12))
ow=onewire.OneWire(Pin(4))
d = DS18X20(ow)
rom = d.scan()

def sub_callback(topic, msg):
    # print((topic, msg))
    nonlocal setTemperature
    nonlocal lowTemperature
    nonlocal startTime
    nonlocal scanTime
    nonlocal step

    nonlocal startTimeTemp
    nonlocal scanTimeTemp
    nonlocal switchStatus

    data = int(msg.decode())
    if topic == b'setTemperature':
        setTemperature = data
    elif topic == b"setLowTemperature":
        lowTemperature = data
    elif topic == b"setStartTime":
        startTime = data
        startTimeTemp = startTime

    elif topic == b"setScanTime":
        scanTime = data*60
        scanTimeTemp = scanTime

    elif topic == b"setStep":
        step = data
    elif topic == b"switchWell":
        switchStatus = data
    else:
        print("错误")

def publishInfo():
    nonlocal client
    client.publish("setTemperatureR",str(setTemperature),retain=True)
    client.publish("setLowTemperatureR",str(lowTemperature),retain=True)
    client.publish("setStartTimeR",str(startTime),retain=True)
    client.publish("setScanTimeR",str(int(scanTime/60)),retain=True)
    client.publish("setStepR",str(step),retain=True)

client = MQTTClient(client_id, mserver, 0)
client.set_callback(sub_callback)
client.connect()
client.subscribe(b'setTemperature')
client.subscribe(b'setLowTemperature')
client.subscribe(b'setStartTime')
client.subscribe(b'setScanTime')
client.subscribe(b"setStep")
client.subscribe(b"switchWell")

showSet = True
setTemperature = 40
lowTemperature = 40
startTime = 120 #启动时间
scanTime = 1800 #30分钟
step = 7

switchStatus = 0 # 0表示关闭,1表示开启

startTimeTemp = startTime
scanTimeTemp = scanTime

while True:
    try:
        d.convert_temp()
        # 显示温度和设定温度
        nowTemperature = d.read_temp(rom[0])
        if showSet:
            tm.temperature(int(setTemperature))
        else:
            tm.number(int(nowTemperature*10))

        if int(nowTemperature) >= setTemperature and (not switchStatus) and int(nowTemperature) > lowTemperature:#高于设定温度启动
            client.publish("switch",'1',retain=True)
            startTimeTemp = startTime

        if (int(nowTemperature) <= setTemperature - step) and switchStatus:
            client.publish("switch",'0',retain=True)

        if startTimeTemp <= 0: #如果时间超过3分钟,自动停止,并提高设定温度
            client.publish("switch",'0',retain=True)
            setTemperature = int(nowTemperature + step)
            startTimeTemp = startTime

        if switchStatus:
            startTimeTemp -= 1

        client.check_msg()
        client.publish("temperature",str(round(nowTemperature,2)),retain=True)
        publishInfo()

        if scanTimeTemp <= 0:
            setTemperature = int(nowTemperature - step) #回调降温
            scanTimeTemp = scanTime
        scanTimeTemp -= 1

    except Exception as e:
        reset()

    time.sleep(1)
    showSet = not showSet

```

esp01中代码:

```python from machine import Pin from umqtt.simple import MQTTClient import time

def main(): def sub_callback(topic, msg): nonlocal client nonlocal pin """ 收到订阅消息回调 """ if msg == b'0': pin.off() else: pin.on() client.publish("switchWell",str(pin.value()),retain=True)

client_id = "switch_id"
mserver = '192.168.0.99'
#mserver = 'mq.tongxinmao.com'        
pin = Pin(0,Pin.OUT)

client = MQTTClient(client_id, mserver, 0)
client.set_callback(sub_callback)
client.connect()
client.subscribe(b'switch')
while True:
    client.check_msg()
    client.publish("switchStatus",str(pin.value()),retain=True)

```

5.客户端监控调节软件

1.手机端:

MQTT Dash:

IoTMQTTPanel:

手机上我还是推荐IoTMQTTPanel,因为将一套面板的配置发布到另一台手机很方便,只需要发布一个主题,然后接收端订阅一个同名主题就可以把整个面板发布过去。MQTT Dash 也具有这个功能,但是发布过去后会卡死,不知道为什么。

2.电脑端:

电脑端我还不知道有什么好用的软件,所以我用 PyQt5 简单写了一个监控的软件,没有调节功能,因为当时设备还不是很稳定,所以我一直在监控运行状态。

6.后记

目前,整个东西已经稳定运行二周了,再也不需要人进行调节了。我反反复复弄了挺长时间,才把所有问题都解决,特别是那个LmacRxBlk:1报错,花费了我很长时间。从零开始做一个能实际有用的东西还是挺困难的,因为有些问题只能通过实际的环境才能暴露出来,例如上拉电阻升温后导致阻值变化。还有很多细节我没提及,例如烧录固件,3d建模外壳,mosquitto服务在树莓派上部署,端口转发,内容太多不便赘述,只能把主要内容和逻辑进行简单叙述。

标签: 继电器进水后会怎样

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台