• 基于51单片机的环境温湿度光强监测系统proteus仿真原理图PCB


    功能:
    0.本系统采用STC89C52作为单片机
    1.系统实时监测当前温湿度/土壤湿度/环境光强并显示
    2.温湿度超过设定阈值范围,蜂鸣器
    3.土壤湿度低于设定下限,开启水泵,土壤湿度高于设定上限,关闭水泵
    4.环境光强超过设定上限,启动遮阳伞,环境光强低于设定下限,停用遮阳伞
    5.四个功能按键按键可修改阈值范围
    6.采用DC002作为电源接口可直接输入5V给整个系统供电

    原理图:
    在这里插入图片描述

    PCB :
    在这里插入图片描述

    主程序:

    #include  //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
    #include 
    #include "delay.h"
    #include "pid.h"
    #include "tlc0832.h"
    #include "oled_iic.h"
    
    
    /************************* 宏定义 *************************/
    #define ON 0
    #define OFF 1
    
    #define FRAME_HEADER  0x1a
    #define FRAME_FUCTION_TEMP  0x00 //功能位,温度
    #define FRAME_FUCTION_TARGET  0x01 //功能位,目标温度
    #define FRAME_FUCTION_KP  0x02 //功能位,Kp
    #define FRAME_FUCTION_KI  0x03 //功能位,Ki
    #define FRAME_FUCTION_KD  0x04 //功能位,Kd
    #define FRAME_FUCTION_TEMP_MIN  0x05 //功能位,温度下限
    #define FRAME_FUCTION_TEMP_MAX  0x06 //功能位,温度上限
    #define FRAME_FUCTION_ADDR  0x07 //功能位,通信地址
    #define FRAME_END     0x3f
    
    /************************* 引脚定义 *************************/
    sbit BUZZER      = P3^7;
    sbit L9110_A     = P1^3;
    sbit L9110_B     = P1^4;
    
    /************************* 变量定义 *************************/
    PID_Calibration_Def xdata PID_Calibration; //PID结构体
    PID_State_Def xdata PID_State; //PID结构体
    
    float xdata temperature; //实际温度
    int xdata tempMin = 20; //温度下限
    int xdata tempMax = 50; //温度上限
    char xdata dis0[16];           //定义显示区域临时存储数组
    
    bit refreshFlag = 1;             //刷新标志
    unsigned char setIndex = 0;
    unsigned char PWMCnt = 0;
    unsigned char address = 0; //通信地址
    
    /************************* 函数声明 *************************/
    void Timer0_Init(void); //函数声明
    void KeyProcess(void); //按键处理
    void Set_PID_Parameter(void); //PID参数初始化
    
    void UART_Init(void); //串口初始化
    void UART_SendByte(unsigned char dat); //串口发送单字节数据
    // void UART_SendStr(unsigned char *s, unsigned char length); //发送定长度字符串
    void SendData(unsigned char address, float temperature); //串口发送数据
    
    void main(void)
    {
    
        /************************* 初始化 *************************/
        Timer0_Init();
        
        OLED_Init();
        UART_Init();
    
        Set_PID_Parameter();
    
        /************************* 主循环 *************************/
        while (1)
        {
            temperature = 100 * (float)ReadADC(AIN0_GND) / 255;  //温度转换 20℃/V
            PID_State.actual = temperature; //当前温度
            // PID
            PID_State = PID_Increament(PID_Calibration, PID_State);
            if (PWMCnt <= PID_State.output) //占空比调节
            {
                L9110_A = 1;
                L9110_B = 0;
            }
            else
            {
                L9110_A = 0;
                L9110_B = 1;
            }
    
            if (refreshFlag == 1) //定时刷新屏幕
            {
                refreshFlag = 0;
                sprintf(dis0,"T:%5.1f", temperature); 
                OLED_ShowString(8, 0, dis0, FONT_1608); //显示温度
                OLED_ShowWord(8*8, 0, 0); //显示摄氏度
                SendData(address, temperature*10);
    
                sprintf(dis0," S:%3d", (int)PID_State.target); //显示目标温度
                OLED_ShowString(10*8, 0, dis0, FONT_1608);
    
                sprintf(dis0," MIN:%3d MAX:%3d", tempMin, tempMax); //显示温度下限,温度上限
                OLED_ShowString(0, 2, dis0, FONT_1608);
                
                sprintf(dis0," P:%3d I:%3d %3d", (int)PID_Calibration.kp, (int)PID_Calibration.ki, (int)PID_State.output); //显示Kd,Ki,PWM输出
                OLED_ShowString(0, 4, dis0, FONT_1608);
                
                sprintf(dis0," D:%3d ADDR:%2d", (int)PID_Calibration.kd, (int)address); //显示Kd,通信地址
                OLED_ShowString(0, 6, dis0, FONT_1608);
    
                //显示设定位置
                if (setIndex == 0)
                {
                    OLED_ShowChar(10*8, 0, ' ', FONT_1608);
                    OLED_ShowChar(0, 2, ' ', FONT_1608);
                    OLED_ShowChar(8*8, 2, ' ', FONT_1608);
                    OLED_ShowChar(0, 4, ' ', FONT_1608);
                    OLED_ShowChar(6*8, 4, ' ', FONT_1608);
                    OLED_ShowChar(0, 6, ' ', FONT_1608);
                    OLED_ShowChar(6*8, 6, ' ', FONT_1608);
                }
                else if (setIndex == 1)
                {
                    OLED_ShowChar(0, 0, ' ', FONT_1608);
                    OLED_ShowChar(10*8, 0, '>', FONT_1608);
                }
                else if (setIndex == 2)
                {
                    OLED_ShowChar(10*8, 0, ' ', FONT_1608);
                    OLED_ShowChar(0, 2, '>', FONT_1608);
                }
                else if (setIndex == 3)
                {
                    OLED_ShowChar(0, 2, ' ', FONT_1608);
                    OLED_ShowChar(8*8, 2, '>', FONT_1608);
                }
                else if (setIndex == 4)
                {
                    OLED_ShowChar(8*8, 2, ' ', FONT_1608);
                    OLED_ShowChar(0, 4, '>', FONT_1608);
                }
                else if (setIndex == 5)
                {
                    OLED_ShowChar(0, 4, ' ', FONT_1608);
                    OLED_ShowChar(6*8, 4, '>', FONT_1608);
                }
                else if (setIndex == 6)
                {
                    OLED_ShowChar(6*8, 4, ' ', FONT_1608);
                    OLED_ShowChar(0, 6, '>', FONT_1608);
                }
                else if (setIndex == 7)
                {
                    OLED_ShowChar(0, 6, ' ', FONT_1608);
                    OLED_ShowChar(6*8, 6, '>', FONT_1608);
                }
    
                if (temperature < tempMin || temperature > tempMax) //高于温度上限,或低于温度下限
                {
                    BUZZER = 0; //打开蜂鸣器 
                }
                else
                {
                    BUZZER = 1; //关闭蜂鸣器
                }
            }
    
            KeyProcess();
        }
    }
    
    void Set_PID_Parameter(void)
    {
        PID_Calibration.kp = 100;
        PID_Calibration.ki = 20;
        PID_Calibration.kd = 10;
    
        PID_State.actual = 0;
        PID_State.target = 35;
        PID_State.integral = 0;
        PID_State.last_error = 0;
        PID_State.previous_error = 0;
        PID_State.output = 0;
    }  
    
    
    void Timer0_Init(void)
    {
        TMOD &= 0xF0;                //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
        TMOD |= 0x01;                //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
    	TL0 = 0x00;		//设置定时初值
    	TH0 = 0xEE;		//设置定时初值 5ms
        PT0 = 1; //设置高优先级
        EA = 1;  //总中断打开
        ET0 = 1; //定时器中断打开
        TR0 = 1; //定时器开关打开
    }
    
    void Timer0_isr(void) interrupt 1
    {
        static unsigned int numCount = 0;
    
    	TL0 = 0x66;		//设置定时初始值
    	TH0 = 0xFC;		//设置定时初始值 1ms
    
        numCount++;
    
        if (numCount > 200)
        {
            numCount = 0;
            refreshFlag = 1;
        }
    
        if (PWMCnt < 100)
        {
            PWMCnt++;
        }
        else
        {
            PWMCnt = 1; //一个周期结束
        } 
    
    }
    
    void SendData(unsigned char address, float temperature)
    {
        UART_SendByte(FRAME_HEADER); //发送帧头
        UART_SendByte(address); //发送地址
        UART_SendByte(FRAME_FUCTION_TEMP); //发送功能位,温度
        UART_SendByte(0x02); //发送数据长度位
        UART_SendByte((unsigned char)((((int)temperature)>>8) & 0x00ff)); //发送数据内容高字节
        UART_SendByte((unsigned char)(((int)temperature) & 0x00ff)); //发送数据内容低字节
        UART_SendByte(FRAME_END); //发送帧尾
    }
    
    
    /************************* 串口配置 *************************/
    void UART_Init(void)
    {
    	SCON = 0x50;
    	TH2 = 0xFF;
    	TL2 = 0xFD;
    	RCAP2H = 0xFF;  //(65536-(FOSC/32/BAUD))   BAUD = 9600 FOSC = 11059200
    	RCAP2L = 0xDC;
    //  RCAP2H = 0xFF;  //(65536-(FOSC/32/BAUD))   BAUD = 115200 FOSC = 11059200
    //	RCAP2L = 0xFD;
    
    	/*****************/
    	TCLK = 1;
    	RCLK = 1;
    	C_T2 = 0;
    	EXEN2 = 0;
    
    	/*****************/
    	TR2 = 1;
    	ES   = 1; //打开串口中断
    	EA   = 1; //打开总中断
    
    }
    
    /************************* 串口发送字节 *************************/
    void UART_SendByte(unsigned char dat) //串口发送单字节数据
    {
    	unsigned char time_out;
        
    	time_out = 0;
    	SBUF = dat;						  //将数据放入SBUF中
    	while ((!TI) && (time_out < 100)) //检测是否发送出去
    	{
    		time_out++;
    		DelayUs10x(2);
    	}		//未发送出去 进行短暂延时
    	TI = 0; //清除ti标志
    }
    
    ///************************* 串口发送字符串 *************************/
    //void UART_SendStr(unsigned char *s, unsigned char length)
    //{
    //	unsigned char num;
    //	num = 0x00;
    //	while (num < length) //发送长度对比
    //	{
    //		UART_SendByte(*s); //放松单字节数据
    //		s++;			  //指针++
    //		num++;			  //下一个++
    //	}
    //}
    
    /************************* 串口中断 *************************/
    void UART_Interrupt(void) interrupt 4 //串行中断服务程序
    {
        static unsigned char i = 0;
        static unsigned char firstBit = 0;
        static unsigned char R_buf[6];
        
        if (RI)//判断是接收中断产生
        {
            RI = 0; //标志位清零
            TR0 = 0;
            //SBUF = SBUF;
            
            if (SBUF == FRAME_HEADER) //检查到帧头
            {
                firstBit = 1; //接收标志成功
                i = 0;
                R_buf[1] = 0;
                R_buf[2] = 0;
                R_buf[3] = 0;
                R_buf[4] = 0;
                R_buf[5] = 0;
                
            }
            if (firstBit == 1)
            {
                R_buf[i] = SBUF;
                i++;
                if (i == 6)
                {
                    i = 0;
                    if (R_buf[0] == FRAME_HEADER && R_buf[5] == FRAME_END) //检测到帧头和帧尾
                    {
                        if (R_buf[1] == address) //地址对应
                        {
                            if (R_buf[2] == FRAME_FUCTION_TARGET && R_buf[3] == 0x01) //功能位和数据长度
                            {
                                if (R_buf[4] <= 100 && R_buf[4] >= 10)
                                {
                                    PID_State.target = R_buf[4];
                                }
                            }
                            else if (R_buf[2] == FRAME_FUCTION_KP && R_buf[3] == 0x01)
                            {
                                if (R_buf[4] <= 100)
                                {
                                    PID_Calibration.kp = R_buf[4];
                                }
                            }
                            else if (R_buf[2] == FRAME_FUCTION_KI && R_buf[3] == 0x01)
                            {
                                if (R_buf[4] <= 100)
                                {
                                    PID_Calibration.ki = R_buf[4];
                                }
                            }
                            else if (R_buf[2] == FRAME_FUCTION_KD && R_buf[3] == 0x01)
                            {
                                if (R_buf[4] <= 100)
                                {
                                    PID_Calibration.kd = R_buf[4];
                                }
                            }
                            else if (R_buf[2] == FRAME_FUCTION_TEMP_MIN && R_buf[3] == 0x01)
                            {
                                if (R_buf[4] < tempMax && R_buf[4] >= 0)
                                {
                                    tempMin = R_buf[4];
                                }
                            }
                            else if (R_buf[2] == FRAME_FUCTION_TEMP_MAX && R_buf[3] == 0x01)
                            {
                                if (R_buf[4] <= 100 && R_buf[4] > tempMin)
                                {
                                    tempMax = R_buf[4];
                                }
                            }
                            else if (R_buf[2] == FRAME_FUCTION_ADDR && R_buf[3] == 0x01)
                            {
                                if (R_buf[4] <= 16)
                                {
                                    address = R_buf[4];
                                }
                                
                            }
                        }
                    }
                    firstBit = 0;
                }
            }
            TR0 = 1;
        }
        if (TI)//判断是发送中断产生
        {
            TI = 0; //标志位清零
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376

    仿真演示视频:
    https://www.bilibili.com/video/BV1qW4y1v7Yq/

    实物演示视频:
    https://www.bilibili.com/video/BV16W4y1v7tL/

  • 相关阅读:
    国庆day1
    网站如何应对网络流量攻击
    Java | 学习笔记03 基础语法总结
    JavaWeb前端基础(HTML CSS JavaScript)
    http调用 采用 Basic Auth 进行请求
    新手下白对Latex下手啦!
    linux 关闭不了docker服务
    DGIOT国内首家轻量级物联网开源平台——真实ModbusRTU接入实战教程
    nacos未授权-CVE-2021-29441复现
    HBuilder X 导入git项目以及拉取和推送
  • 原文地址:https://blog.csdn.net/jimo167913/article/details/127841150