基于51单片机的温控系统
本文是基于STC89C52单片机的温度控制系统,主要由主控模块、显示模块及外围电路几个部分组成。
通过DS18B20检测外部温度,通过LCD1602显示,按键可调节上下限。当温度超过上限或低于下限,蜂鸣器均会报警。当温度超过上限时,电机会开始工作,模拟风扇,起到降温作用。LED灯电路模拟家用电灯,由两个开关对其进行控制。
删除线格式 该温控系统可以模拟简易智能家居系统。
系统硬件设计
整体电路原理图设计
该系统由51单片机作为主控模块,通过DS18B20检测温度,由LCD1602显示,并加外围电路组成。
测温显示模块
蜂鸣器报警及电机模块
系统软件设计
单片机IO口定义
sbit beep = P1^7; //定义蜂鸣器IO口
sbit LED1 = P1^0; //定义灯IO口
sbit LED2 = P1^1;
sbit k1 = P1^2; //定义灯开关IO口
sbit k2 = P1^3;
sbit MOTOR = P1^4; //定义电机
sbit BUTTON_RUN = P1^5; //定义电机启动按钮
sbit BUTTON_STOP = P1^6; //定义电机关闭按钮
sbit RS = P2^7;
sbit RW = P2^6;
sbit EN = P2^5;
sbit K1 = P2^0;
sbit K2 = P2^1; //上限加
sbit K3 = P2^2; //下限减
sbit DQ = P2^3; //DS18B20数据端
LCD1602初始化及读/写数据
void lcd_init()
{
uint8 i;
RW = 0;
lcd_order(0x38); //设置显示光标功能
delay(100);
lcd_order(0x0e); //显示开及光标设置
delay(100);
lcd_order(0x06); //显示光标移动设置
delay(100);
lcd_order(0x01); //显示清屏
delay(100);
lcd_order(0x80);
for(i=0;i<16;i++)
lcd_data(hodometer[i]);
}
void write_1602(uint8 add,uint8 daa)
{
lcd_order(0x80+add);
lcd_data(0x30+daa/10);
lcd_data(0x30+daa%10);
}
void lcd_order(uint8 date) //LCD1602写指令
{
RS = 0; //选择写指令
RW = 0; //使能初始化
P0 = date; //发送指令
EN = 1; //开使能
delay(100); //延时
EN = 0; //关使能
}
void lcd_data(uint8 date) //LCD1602写数据
{
RS = 1; //选择写数据
RW = 0; //使能初始化
P0 = date; //发送指令
EN = 1; //开使能
delay(100); //延时
EN = 0; //关使能
}
DS18B20初始化及读/写数据
uint8 DS18B20_init()
{
uint8 ans;
DQ = 1;
delay(1);
DQ = 0;
delay(100);
DQ = 1;
delay(6);
ans = DQ;
delay(100);
if(!ans)
return 1;
else
return 0;
}
void DS18B20_write(uint8 date)
{
uint8 i;
DQ = 1;
delay(1);
for(i=0;i<8;i++) //根据时序将数据从低到高一位一位发送出来
{
DQ = 0;
if(date&0x01) //从低到高取出数据的每位
DQ = 1;
else
DQ = 0;
delay(10);
DQ = 1;
date >>= 1;
delay(1);
}
}
uint8 DS18B20_read()
{
uint8 i,date = 0;
DQ = 1; //释放总线
delay(1);
for(i=0;i<8;i++) //根据时序将数据从低到高一位一位接收
{
DQ = 0;
date >>= 1;
DQ = 1;
if(DQ)
date |= 0x80; //将data的一位置1
delay(8);
DQ = 1;
delay(1);
}
return date; //返回读出的数
}
void DS18B20_check()
{
uint8 date1,date2;
float ta;
if(DS18B20_init())
{
DS18B20_write(0xcc); //跳过序列号
DS18B20_write(0x44); //启动温度转换
DS18B20_init(); //复位
DS18B20_write(0xcc); //跳过序列号
DS18B20_write(0xbe); //启动读取温度
date1 = DS18B20_read(); //读取两个温度字节
date2 = DS18B20_read();
tmp = date2;
tmp <<= 8;
tmp = tmp|date1;
ta = tmp*0.0625;
tmp = ta*1000;
}
}
温度上下限调节函数
void KEY()
{
uint8 jj;
uint8 i = 0;
beep = 1;
if(K1==0)
{
while(!K1);
while(1)
{
lcd_order(0x0f); //开启光标显示
lcd_order(0x80+5); //光标显示位置
if(K2==0) //判断加按键按下
{
while(K2==0); //等待按键释放
t_h++; //温度上限加1
write_1602(4,t_h); //显示温度上限
}
if(K3==0) //判断减按键按下
{
while(K3==0); //等待按键释放
if(t_h>t_l) //判断温度上限大于温度下限
t_h--;
write_1602(4,t_h); //显示温度上限
}
if(K1==0)
{
while(K1==0);
while(1)
{
lcd_order(0x0f);
lcd_order(0x80+13);
if(K2==0)
{
while(K2==0);
if(t_l<t_h&&t_l>=0)
{
lcd_order(0x80+11);
lcd_data(' ');
t_l++;
write_1602(12,t_l);
}
else
{
t_l++;
jj =~ t_l;
write_1602(12,jj);
}
}
if(K3==0)
{
while(K3==0);
if(t_l>(-50))
{
t_l--;
if(t_l<0)
jj =~ t_l;
}
if(t_l>=0)
{
lcd_order(0x80+11);
lcd_data(' ');
write_1602(12,t_l);
}
if(t_l<0)
{
write_1602(12,jj);
lcd_order(0x80+11);
lcd_data('-');
}
}
if(K1==0)
{
while(K1==0);
goto loop;
}
}
}
}
}
loop:beep = 1;
}
完整程序展示
#include<reg52.h>
#include"stdio.h"
#define uint unsigned int
#define uchar unsigned char
typedef unsigned char uint8;
typedef unsigned int uint16;
sbit beep = P1^7; //定义蜂鸣器IO口
sbit LED1 = P1^0; //定义灯IO口
sbit LED2 = P1^1;
sbit k1 = P1^2; //定义灯开关IO口
sbit k2 = P1^3;
sbit MOTOR = P1^4; //定义电机
sbit BUTTON_RUN = P1^5; //定义电机启动按钮
sbit BUTTON_STOP = P1^6; //定义电机关闭按钮
sbit RS = P2^7;
sbit RW = P2^6;
sbit EN = P2^5;
sbit K1 = P2^0;
sbit K2 = P2^1; //加
sbit K3 = P2^2; //减
sbit DQ = P2^3; //DS18B20数据端
//void delay(uint xms);
void motor_run();
void motor_stop();
void LED1_SWITCH();
void LED2_SWITCH();
void init();
void delay(uint16 time);
void lcd_init(); //LCD1602初始化
void lcd_order(uint8 date); //向LCD1602写一个指令
void lcd_data(uint8 date); //向LCD1602写一个指令
void write_1602(uint8 add,uint8 daa); //写数据
void display(); //显示温度
uint8 DS18B20_init(); //DS18B20初始化
void DS18B20_write(uint8 date); //向DS18B20中写入一个数据
uint8 DS18B20_read(); //从DS18B20中读一个数据并返回
void DS18B20_check(); //启动DS18B20进行温度采集,并返回当前温度
void KEY(); //修改报警范围
long tmp = 0; //存储温度值
long t_h = 37,t_l = 10; //温度上限 温度下限
bit tmp_hb = 0; tmp_lb = 0; //温度上下限调节指示变量
void judge(); //判断报警
uint8 hodometer[] = " H:00 L:00 ";
uint8 temp[]= " wendu:00.00 ";
uint16 ji = 0;
uint8 ku = 0; //标志位
void main()
{
init();
lcd_init(); //LCD1602初始化
DS18B20_init(); //DS18B20初始化
DS18B20_write(0xcc); //跳过序列号
DS18B20_write(0x44); //启动温度转换
write_1602(4,t_h);
write_1602(12,t_l);
while(1)
{
LED1_SWITCH();
LED2_SWITCH();
motor_run();
motor_stop();
DS18B20_check(); //从DS18B20中读取温度
display();
KEY();
judge();
}
}
void write_1602(uint8 add,uint8 daa)
{
lcd_order(0x80+add);
lcd_data(0x30+daa/10);
lcd_data(0x30+daa%10);
}
void judge() //判断是否在报警范围
{
if(tmp<(t_l*1000)||tmp>(t_h*1000)&&t_l>=0)
{
beep = 0;
delay(10);
MOTOR = 1;
}
else if(t_l<0&&tmp>(t_h*1000))
{
beep = 1;
MOTOR = 0;
}
else
{
beep = 1;
MOTOR = 0;
}
}
void KEY()
{
uint8 jj;
uint8 i = 0;
beep = 1;
if(K1==0)
{
while(!K1);
while(1)
{
lcd_order(0x0f); //开启光标显示
lcd_order(0x80+5); //光标显示位置
if(K2==0) //判断加按键按下
{
while(K2==0); //等待按键释放
t_h++; //温度上限加1
write_1602(4,t_h); //显示温度上限
}
if(K3==0) //判断减按键按下
{
while(K3==0); //等待按键释放
if(t_h>t_l) //判断温度上限大于温度下限
t_h--;
write_1602(4,t_h); //显示温度上限
}
if(K1==0)
{
while(K1==0);
while(1)
{
lcd_order(0x0f);
lcd_order(0x80+13);
if(K2==0)
{
while(K2==0);
if(t_l<t_h&&t_l>=0)
{
lcd_order(0x80+11);
lcd_data(' ');
t_l++;
write_1602(12,t_l);
}
else
{
t_l++;
jj =~ t_l;
write_1602(12,jj);
}
}
if(K3==0)
{
while(K3==0);
if(t_l>(-50))
{
t_l--;
if(t_l<0)
jj =~ t_l;
}
if(t_l>=0)
{
lcd_order(0x80+11);
lcd_data(' ');
write_1602(12,t_l);
}
if(t_l<0)
{
write_1602(12,jj);
lcd_order(0x80+11);
lcd_data('-');
}
}
if(K1==0)
{
while(K1==0);
goto loop;
}
}
}
}
}
loop:beep = 1;
}
//void delay(uint xms) //延时
//{
// uint i,j;
// for(i=xms;i>0;i--)
// for(j=110;j>0;j--) ;
//}
void delay(uint16 time)
{
while(time--);
}
void lcd_init()
{
uint8 i;
RW = 0;
lcd_order(0x38); //设置显示光标功能
delay(100);
lcd_order(0x0e); //显示开及光标设置
delay(100);
lcd_order(0x06); //显示光标移动设置
delay(100);
lcd_order(0x01); //显示清屏
delay(100);
lcd_order(0x80);
for(i=0;i<16;i++)
lcd_data(hodometer[i]);
}
void lcd_order(uint8 date) //LCD1602写指令
{
RS = 0; //选择写指令
RW = 0; //使能初始化
P0 = date; //发送指令
EN = 1; //开使能
delay(100); //延时
EN = 0; //关使能
}
void lcd_data(uint8 date) //LCD1602写数据
{
RS = 1; //选择写数据
RW = 0; //使能初始化
P0 = date; //发送指令
EN = 1; //开使能
delay(100); //延时
EN = 0; //关使能
}
uint8 DS18B20_init()
{
uint8 ans;
DQ = 1;
delay(1);
DQ = 0;
delay(100);
DQ = 1;
delay(6);
ans = DQ;
delay(100);
if(!ans)
return 1;
else
return 0;
}
void DS18B20_write(uint8 date)
{
uint8 i;
DQ = 1;
delay(1);
for(i=0;i<8;i++) //根据时序将数据从低到高一位一位发送出来
{
DQ = 0;
if(date&0x01) //从低到高取出数据的每位
DQ = 1;
else
DQ = 0;
delay(10);
DQ = 1;
date >>= 1;
delay(1);
}
}
uint8 DS18B20_read()
{
uint8 i,date = 0;
DQ = 1; //释放总线
delay(1);
for(i=0;i<8;i++) //根据时序将数据从低到高一位一位接收
{
DQ = 0;
date >>= 1;
DQ = 1;
if(DQ)
date |= 0x80; //将data的一位置1
delay(8);
DQ = 1;
delay(1);
}
return date; //返回读出的数
}
void DS18B20_check()
{
uint8 date1,date2;
float ta;
if(DS18B20_init())
{
DS18B20_write(0xcc); //跳过序列号
DS18B20_write(0x44); //启动温度转换
DS18B20_init(); //复位
DS18B20_write(0xcc); //跳过序列号
DS18B20_write(0xbe); //启动读取温度
date1 = DS18B20_read(); //读取两个温度字节
date2 = DS18B20_read();
tmp = date2;
tmp <<= 8;
tmp = tmp|date1;
ta = tmp*0.0625;
tmp = ta*1000;
}
}
void display()
{
uint8 i;
temp[8] = 0x30+tmp/10000;
temp[9] = 0x30+tmp/1000%10;
temp[11] = 0x30+tmp/100%10;
temp[12] = 0x30+tmp/10%10;
temp[13] = 0x30+tmp%10;
lcd_order(0x80+0x40);
for(i=0;i<16;i++)
lcd_data(temp[i]) ;
}
void init() //初始化函数
{
BUTTON_RUN = 1;
BUTTON_STOP = 1;
MOTOR = 0;
beep = 0;
delay(50);
}
void motor_run() //打开电机
{
if(BUTTON_RUN==0)
{
delay(10);
if(BUTTON_RUN==0)
{
while(1)
{
MOTOR = 1;
if(BUTTON_STOP==0)
{
delay(5);
if(BUTTON_STOP==0)
{
break;
}
}
}
}
}
}
void motor_stop() //关闭电机
{
if(BUTTON_STOP==0)
{
delay(10);
if(BUTTON_STOP==0)
{
MOTOR = 0;
}
}
}
void LED1_SWITCH() //LED1开关
{
if(k1==0)
LED1 = 0;
else if(k1==1)
LED1 = 1;
}
void LED2_SWITCH() //LED2开关
{
if(k2==0)
LED2 = 0;
else if(k2==1)
LED2 = 1;
}
使用Proteus仿真
整体电路PCB设计
51单片机温控系统程序(电机模拟风扇 可调上下限)Proteus仿真 DS18B20+LCD1602显示
原理图+程序+仿真图
HappyFrankie的公众号