基于单片机的太阳能热水器控制器设计原理详解

一、项目介绍

随着环保意识的逐渐增强,太阳能热水器作为一种清洁能源应用得越来越广泛。然而,传统的太阳能热水器控制器通常采用机械式或电子式温控器,存在精度低、控制不稳定等问题。为了解决这些问题,本项目基于单片机技术设计了一款太阳能热水器控制器,主控芯片采用STC89C52。该控制器可以实现对太阳能热水器的水温、水位等参数进行准确、稳定的控制,提高了太阳能热水器的能源利用效率和使用寿命,同时也符合节能环保的社会需求。

image-20230801105049392

二、系统构架

2.1 系统设计

本系统采用主从结构,由STC89C52单片机作为主控芯片,负责控制整个太阳能热水器的运行。系统包括传感器模块、驱动模块和用户界面模块。

传感器模块包括温度传感器和光照传感器,用于实时监测水温和太阳辐射强度。驱动模块包括电磁阀和水泵,用于控制水流和热水的循环。用户界面模块包括液晶显示屏和按键,用于显示当前状态和提供用户交互。

2.2 功能设计

本设计的太阳能热水器控制器功能:

  • 温度控制:通过温度传感器实时监测水温,并根据设定的阈值控制电磁阀和水泵,以保持热水器水温在设定范围内。
  • 光照控制:通过光照传感器实时监测太阳辐射强度,判断当前是否有足够的太阳能供给,若不足,则停止水泵运行,以节约能源。
  • 时间控制:设置定时计划,控制热水器在指定时间段内工作或停止工作。
  • 用户交互:通过液晶显示屏显示当前温度、工作状态等信息,并通过按键设定参数和操作热水器。
  • 2.3 硬件设计

    硬件设计包括电路连接和外围模块选择。主控芯片STC89C52与传感器模块、驱动模块和用户界面模块通过IO口进行连接。温度传感器采用DS18B20数字温度传感器,光照传感器采用光敏电阻。

    2.4 软件设计

    软件设计主要包括系统初始化、传感器数据采集、控制算法和用户交互等部分。系统初始化包括IO口配置、定时器设置等。传感器数据采集通过相应的接口获取温度和光照传感器数据。控制算法根据采集到的数据进行温度和光照控制,并控制电磁阀和水泵的开关。用户交互通过液晶显示屏和按键实现,用户可以通过按键设置参数和操作热水器。

    2.5 设计思路

    本项目的控制器主要包括传感器模块、控制模块和显示模块三部分。其中,传感器模块用于实时检测太阳能热水器的水温、水位等参数;控制模块将传感器采集到的数据进行处理,并通过控制水泵、电磁阀等执行器来实现对太阳能热水器的水温、水位等参数进行准确、稳定的控制;显示模块则用于显示当前的水温、水位等参数。

    具体的设计流程如下:

    【1】确定硬件平台:采用STC89C52单片机作为主控芯片,搭建传感器模块和执行器模块,通过串口通信与PC机连接。

    【2】确定传感器类型:选择DS18B20温度传感器和液位传感器作为检测太阳能热水器水温、水位的传感器。

    【3】确定控制策略:根据太阳能热水器的实际情况,设计PID控制算法,通过控制水泵、电磁阀等执行器来实现对太阳能热水器的水温、水位等参数进行准确、稳定的控制。

    【4】编写程序:根据硬件平台和控制策略,编写程序实现数据采集、处理和控制等功能。

    【5】调试测试:将设计好的控制器与太阳能热水器进行连接测试,检查数据采集、处理和控制等功能是否正常。

    2.6 实现效果

    本项目设计的太阳能热水器控制器实现了对太阳能热水器的水温、水位等参数进行准确、稳定的控制。

    控制器的特点:

    【1】精度高:采用PID控制算法,能够对太阳能热水器的水温、水位等参数进行精确控制。

    【2】控制稳定:通过控制水泵、电磁阀等执行器来实现对太阳能热水器的水温、水位等参数进行稳定控制。

    【3】显示直观:通过显示模块可以直观地显示当前的水温、水位等参数。

    三、代码实现

    3.1 DS18B20读取温度

    以下是基于STC89C52单片机和DS18B20温度传感器实现读取温度值并打印到串口的示例:

    #include <reg52.h>
    #include <intrins.h>
    
    #define DQ P3_7
    
    typedef unsigned char uchar;
    typedef unsigned int uint;
    
    sbit LED=P1^0;
    
    void Delay1ms(uint);
    void Delay10us(uint);
    uchar Init_DS18B20();
    void Write_DS18B20(uchar dat);
    uchar Read_DS18B20();
    int Get_Temp();
    
    void main()
    {
        uchar temp;
        int temperature;
    
        TMOD = 0x20; //定时器1工作在方式2
        TH1 = 0xfd; //波特率9600
        TL1 = 0xfd;
        PCON = 0x00; //波特率不加倍
        SCON = 0x50; //串口方式1,允许接收
        TR1 = 1; //定时器1开始计时
        ES = 1; //允许串口中断
    
        while(1)
        {
            temp = Get_Temp();
            temperature = (int)temp * 0.0625 * 100; //将温度值转换为实际温度,单位为°C
            printf("Temperature: %d.%dC \r\n", temperature / 100, temperature % 100);
            Delay1ms(500); //每隔500ms读取一次温度值并打印到串口
        }
    }
    
    void Delay1ms(uint cnt)
    {
        uint i, j;
    
        for (i = 0; i < cnt; i++)
        {
            for (j = 0; j < 110; j++);
        }
    }
    
    void Delay10us(uint cnt)
    {
        while(cnt--);
    }
    
    uchar Init_DS18B20()
    {
        uchar i;
    
        DQ = 1;
        Delay10us(5);
        DQ = 0;
        Delay10us(80);
        DQ = 1;
        Delay10us(5);
        i = DQ;
        Delay10us(20);
        return i;
    }
    
    void Write_DS18B20(uchar dat)
    {
        uchar i;
    
        for (i = 0; i < 8; i++)
        {
            DQ = 0;
            _nop_();
            DQ = dat & 0x01;
            Delay10us(5);
            DQ = 1;
            dat >>= 1;
        }
    }
    
    uchar Read_DS18B20()
    {
        uchar i, j, dat = 0;
    
        for (i = 0; i < 8; i++)
        {
            DQ = 0;
            _nop_();
            DQ = 1;
            _nop_();
            j = DQ;
            Delay10us(5);
            dat = (j << 7) | (dat >> 1);
        }
    
        return dat;
    }
    
    int Get_Temp()
    {
        uchar TL, TH;
        int temp;
    
        Init_DS18B20();
        Write_DS18B20(0xcc);
        Write_DS18B20(0x44);
        Delay1ms(750);
        Init_DS18B20();
        Write_DS18B20(0xcc);
        Write_DS18B20(0xbe);
        TL = Read_DS18B20();
        TH = Read_DS18B20();
        temp = TH;
        temp <<= 8;
        temp |= TL;
        return temp;
    }
    
    void UART_Isr() interrupt 4
    {
        if (RI == 1)
        {
            RI = 0;
        }
    
        if (TI == 1)
        {
            TI = 0;
        }
    }
    

    代码中使用了定时器和串口中断,要注意DS18B20的引脚连接和串口通信的波特率设置。

    3.2 PID算法控制温度

    以下是使用STC89C52单片机和DS18B20温度传感器通过PID算法实现热水器恒温控制的代码:

    #include <reg52.h>
    #include <intrins.h>
    
    #define uchar unsigned char
    #define uint unsigned int
    
    sbit Relay = P1^0;  // 继电器控制引脚
    
    // 温度传感器DS18B20相关宏定义
    sbit DQ = P2^7;     // DS18B20数据线引脚
    #define DQ_OUT P2 &= 0x7F
    #define DQ_IN  P2 |= 0x80
    
    // PID参数定义
    float Kp = 1.0;     // PID比例系数
    float Ki = 0.5;     // PID积分系数
    float Kd = 0.2;     // PID微分系数
    
    // 温度控制参数定义
    float setTemp = 40.0;    // 设定的目标温度
    float curTemp = 0.0;     // 当前温度
    float lastTemp = 0.0;    // 上一次的温度
    float error = 0.0;       // 温度误差
    float integral = 0.0;    // 积分项
    float derivative = 0.0;  // 微分项
    float output = 0.0;      // 控制输出
    
    // 延时函数
    void delay(uint t) {
        while (t--);
    }
    
    // DS18B20初始化
    uchar Init_DS18B20() {
        uchar presence = 0;
        
        DQ_OUT;
        DQ = 0;
        delay(480);     // 延时480us
        DQ = 1;
        delay(60);      // 延时60us
        
        DQ_IN;
        presence = DQ;
        delay(420);     // 延时420us
        
        return presence;
    }
    
    // DS18B20读取一个字节
    uchar Read_DS18B20() {
        uchar i, j, dat = 0;
        
        for (i = 8; i > 0; i--) {
            DQ_OUT;
            DQ = 0;
            dat >>= 1;
            _nop_();
            _nop_();
            _nop_();
            DQ = 1;
            DQ_IN;
            if (DQ) {
                dat |= 0x80;
            }
            delay(120);     // 延时120us
        }
        
        return dat;
    }
    
    // DS18B20写入一个字节
    void Write_DS18B20(uchar dat) {
        uchar i;
        
        for (i = 8; i > 0; i--) {
            DQ_OUT;
            DQ = 0;
            DQ = dat & 0x01;
            delay(120);     // 延时120us
            DQ = 1;
            dat >>= 1;
        }
    }
    
    // DS18B20温度转换
    void Convert_DS18B20() {
        Init_DS18B20();
        Write_DS18B20(0xCC);    // 跳过ROM操作
        Write_DS18B20(0x44);    // 启动温度转换
    }
    
    // 获取DS18B20温度值
    float Get_DS18B20_Temp() {
        uchar TL, TH;
        int temp = 0;
        
        Init_DS18B20();
        Write_DS18B20(0xCC);    // 跳过ROM操作
        Write_DS18B20(0xBE);    // 发送读取命令
        
        TL = Read_DS18B20();    // 读取温度低字节
        TH = Read_DS18B20();    // 读取温度高字节
        
        temp = TH;
        temp <<= 8;
        temp |= TL;
        
        return (float)temp / 16.0;   // 返回温度值
    }
    
    // PID控制算法
    float PID_Control(float setValue, float currentValue) {
        error = setValue - currentValue;
        integral += error;
        derivative = currentValue - lastTemp;
        
        output = Kp * error + Ki * integral + Kd * derivative;
        
        lastTemp = currentValue;
        
        return output;
    }
    
    void main() {
        while (1) {
            curTemp = Get_DS18B20_Temp();   // 获取当前温度
            
            output = PID_Control(setTemp, curTemp);   // PID控制计算
            
            if (output > 0) {
                Relay = 0;  // 继电器闭合,加热器工作
            } else {
                Relay = 1;  // 继电器断开,加热器停止工作
            }
            
            delay(1000); // 延时1s
        }
    }
    

    3.3 驱动BH1750光敏传感器

    使用STC89C52单片机读取BH1750光敏传感器值通过串口打印的代码:

    #include <reg52.h>
    #include <intrins.h>
    
    #define uchar unsigned char
    #define uint unsigned int
    
    sbit SDA = P2^7;    // IIC总线数据线引脚
    sbit SCL = P2^6;    // IIC总线时钟线引脚
    
    // BH1750光敏传感器相关宏定义
    #define BH1750_ADDR 0x23   // BH1750设备地址
    #define BH1750_ON   0x01   // BH1750上电命令
    #define BH1750_OFF  0x00   // BH1750下电命令
    #define BH1750_CONTINUOUS_HIGH_RES_MODE  0x10   // BH1750连续高分辨率模式
    
    // 延时函数
    void delay(uint t) {
        while (t--);
    }
    
    // IIC总线起始信号
    void I2C_Start() {
        SDA = 1;
        delay(1);
        SCL = 1;
        delay(1);
        SDA = 0;
        delay(1);
        SCL = 0;
        delay(1);
    }
    
    // IIC总线停止信号
    void I2C_Stop() {
        SDA = 0;
        delay(1);
        SCL = 1;
        delay(1);
        SDA = 1;
        delay(1);
    }
    
    // IIC总线发送应答信号
    void I2C_Ack() {
        SDA = 0;
        delay(1);
        SCL = 1;
        delay(1);
        SCL = 0;
        delay(1);
        SDA = 1;
        delay(1);
    }
    
    // IIC总线发送不应答信号
    void I2C_NAck() {
        SDA = 1;
        delay(1);
        SCL = 1;
        delay(1);
        SCL = 0;
        delay(1);
    }
    
    // IIC总线接收应答信号
    bit I2C_WaitAck() {
        bit ack;
        
        SDA = 1;
        delay(1);
        SCL = 1;
        delay(1);
        ack = SDA;
        SCL = 0;
        delay(1);
        
        return ack;
    }
    
    // IIC总线发送一个字节
    void I2C_WriteByte(uchar dat) {
        uchar i;
        
        for (i = 0; i < 8; i++) {
            SDA = (dat & 0x80) >> 7;
            dat <<= 1;
            delay(1);
            SCL = 1;
            delay(1);
            SCL = 0;
            delay(1);
        }
    }
    
    // IIC总线读取一个字节
    uchar I2C_ReadByte() {
        uchar i, dat = 0;
        
        SDA = 1;
        delay(1);
        
        for (i = 0; i < 8; i++) {
            SCL = 1;
            delay(1);
            dat = (dat << 1) | SDA;
            SCL = 0;
            delay(1);
        }
        
        return dat;
    }
    
    // 初始化BH1750光敏传感器
    void Init_BH1750() {
        I2C_Start();
        I2C_WriteByte(BH1750_ADDR);      // 发送设备地址
        I2C_WaitAck();
        I2C_WriteByte(BH1750_ON);        // 上电
        I2C_WaitAck();
        I2C_Stop();
        
        delay(5);
    }
    
    // 启动BH1750测量
    void Start_BH1750() {
        I2C_Start();
        I2C_WriteByte(BH1750_ADDR);                  // 发送设备地址
        I2C_WaitAck();
        I2C_WriteByte(BH1750_CONTINUOUS_HIGH_RES_MODE);   // 选择连续高分辨率模式
        I2C_WaitAck();
        I2C_Stop();
        
        delay(180);
    }
    
    // 读取BH1750测量结果
    uint Read_BH1750() {
        uint value;
        
        I2C_Start();
        I2C_WriteByte(BH1750_ADDR + 1);    // 发送设备地址,读模式
        I2C_WaitAck();
        value = ((uint)I2C_ReadByte() << 8) | (uint)I2C_ReadByte();   // 读取两个字节的数据
        I2C_NAck();
        I2C_Stop();
        
        return value;
    }
    
    // 串口发送一个字符
    void UART_SendChar(uchar chr) {
        SBUF = chr;
        while (!TI);
        TI = 0;
    }
    
    // 串口发送字符串
    void UART_SendString(const uchar *str) {
        while (*str) {
            UART_SendChar(*str++);
        }
    }
    
    // 串口发送一个无符号整数
    void UART_SendUInt(uint val) {
        uchar i, len;
        uchar buf[5];
        
        len = 0;
        do {
            buf[len++] = val % 10 + '0';
            val /= 10;
        } while (val);
        
        for (i = len; i > 0; i--) {
            UART_SendChar(buf[i-1]);
        }
    }
    
    void main() {
        uint lightValue;
    
        Init_BH1750();  // 初始化BH1750光敏传感器
        
        // 串口初始化, 波特率9600
        TMOD = 0x20;
        TH1 = 0xFD;
        TL1 = 0xFD;
        SCON = 0x50;
        TR1 = 1;
    
        while (1) {
            Start_BH1750();         // 启动测量
            lightValue = Read_BH1750();   // 读取测量结果
            
            UART_SendString("Light value: ");
            UART_SendUInt(lightValue);
            UART_SendString("\r\n");
            
            delay(1000);   // 延时1s
        }
    }
    

    在程序中,初始化了BH1750光敏传感器,使用Start_BH1750()函数启动测量,通过Read_BH1750()函数读取测量结果,在串口上打印出来。串口的初始化设置为波特率9600,发送数据时使用UART_SendString()和UART_SendUInt()函数。

    四、总结

    本设计基于STC89C52单片机实现了一个功能完善的太阳能热水器控制器。该控制器具有温度控制、光照控制、时间控制和用户交互等功能,可以提高太阳能热水器的性能和便捷程度。通过合理的硬件选型和软件设计,使得系统能够准确、稳定地实现对太阳能热水器的控制,提高能源利用效率,并为用户提供便利的操作界面。未来可以进一步优化和拓展该控制器,如增加远程控制功能、与智能家居系统的连接等,以满足不同用户的需求。

    物联沃分享整理
    物联沃-IOTWORD物联网 » 基于单片机的太阳能热水器控制器设计原理详解

    发表评论