目录
DS18B20智能温控风扇
一、项目简介
1、介绍
本项目基于51单片机DS18B20温度传感器和直流电机,设计一款智能温控风扇,根据外界温度值来自动控制风扇风速,也可以手动调节风扇风速,实现人机交互,智能控制,应用场景非常广泛,可用于给机器散热、智能家居系统、温室大棚等领域,通过该系统监测环境温度来自动控制风扇的开关和风速。
2、实现过程
基于51单片机DS18B20温度传感器来实时监测外界温度,在LCD1602小屏幕上实时显示温度、显示风速、显示设定的温度阈值。可以通过独立按键K1、K2(按下K1阈值加1℃、按下K2阈值减1℃)来调节温度阈值,当温度高于阈值时,则自动驱动直流电机开启风扇风速为1档,当大于额定阈值2℃时,风速自动加到2档,大于额度阈值4℃时,风速自动加到3档;若人为控制风速,通过独立按键K3、K4(按下K3风速加1档、按下K4风速减1档),温控风速这会取消,防止因外界环境变化,而影响人为的体验。
3、材料准备
AT89C52芯片,直流电机,扇叶,LCD1602屏幕,供电源(充电宝)。
二、主要代码实现
-
这里我只显示该项目中的主要代码实现过程,LCD1602模块实现代码这里没有显示,整个项目代码我放在github上面,需要自取。
1、DS18B20模块(温度监测)
-
通过单总线协议(OneWire)与 DS18B20 进行通信,获取当前环境温度。
(1)、OneWire.c
#include <REGX52.H>
sbit OneWire_DQ=P3^7;
/**
*@brief OneWire初始化
*@param 无
*@retval 返回DQ总线的值
*/
unsigned char OneWire_Init()
{
unsigned char i;
unsigned char AckBit;
EA=0; //关闭定时器全部中断
OneWire_DQ=1; //先把总线拉高
OneWire_DQ=0; //再把总线拉低
i = 247;while (--i); //Delay500us
OneWire_DQ=1; //释放总线
i = 32;while (--i); //Delay70us
AckBit=OneWire_DQ;
i = 247;while (--i); //Delay500us
EA=1; //打开定时器中断
return AckBit;
}
/**
*@brief OneWire发送一位
*@param 一位
*@retval 无
*/
void OneWire_SendBit(unsigned char Bit)
{
unsigned char i;
EA=0; //关闭定时器全部中断
OneWire_DQ=0; //把总线拉低
i = 4;while (--i); //Delay10us
OneWire_DQ=Bit; //发送一位数据
i = 24;while (--i); //Delay50us
OneWire_DQ=1; //释放总线
EA=1; //打开定时器中断
}
/**
*@brief OneWire接收一位
*@param 无
*@retval 返回一位
*/
unsigned char ReceiveBit()
{
unsigned char i;
unsigned char AckBit;
EA=0; //关闭定时器全部中断
OneWire_DQ=0; //把总线拉低
i = 2;while (--i); //Delay5us
OneWire_DQ=1; //释放总线需要时间,所以释放完刚好到15us未尾
i = 2;while (--i); //Delay5us
AckBit=OneWire_DQ;
i = 24;while (--i); //Delay50us
EA=1; //打开定时器中断
return AckBit;
}
/**
*@brief OneWire发送一个字节
*@param 一个字节
*@retval 无
*/
void OneWire_SendByte(unsigned char Byte)
{
unsigned char i;
for(i=0;i<8;i++)
{
OneWire_SendBit(Byte&(0x01<<i));//逐位进行发送
}
}
/**
*@brief OneWire接收一个字节
*@param 无
*@retval 返回一个字节
*/
unsigned char OneWire_ReceiveByte()
{
unsigned char i;
unsigned char Byte=0x00;//初始化为0000 0000
for(i=0;i<8;i++)
{
if(ReceiveBit())
{
Byte=Byte|(0x01<<i);//有1,则置1
}
}
return Byte;
}
(2)、OneWire.h
#ifndef __ONEWIRE_H__
#define __ONEWIRE_H__
unsigned char OneWire_Init();
void OneWire_SendBit(unsigned char Bit);
unsigned char ReceiveBit();
void OneWire_SendByte(unsigned char Byte);
unsigned char OneWire_ReceiveByte();
#endif
(3)、DS18B20.c
#include <REGX52.H>
#include "OneWrie.h"
#define DS18B20_SKIP_ROM 0xcc //跳过ROM
#define DS18B20_CONVERT_T 0x44 //温度变换
#define DS18B20_READ_SCRATCHPAD 0xbe //读暂存器
/**
*@brief DS18B20温度转化(数字形式)
*@param 无
*@retval 无
*/
void DS18B20_ConverT()
{
OneWire_Init();//初始化
OneWire_SendByte(DS18B20_SKIP_ROM);//跳过Rom
OneWire_SendByte(DS18B20_CONVERT_T);//温度转化(数字形式)
}
/**
*@brief DS18B20温度转化(数字形式)
*@param 无
*@retval 返回温度
*/
float DS18B20_ReadT()
{
unsigned char TLSB,TMSB;//TSLB低8位 TMSB高8位
int Temp;//16位
float T;
OneWire_Init();//初始化
OneWire_SendByte(DS18B20_SKIP_ROM);//跳过Rom
OneWire_SendByte(DS18B20_READ_SCRATCHPAD);//读暂存器
TLSB=OneWire_ReceiveByte();//连续读操作
TMSB=OneWire_ReceiveByte();
Temp=(TMSB<<8)|TLSB;//转化成16位
T=Temp/16.0;
return T;
}
(4)、DS18B20.h
#ifndef __DS18B20_H__
#define __DS18B20_H__
void DS18B20_ConverT();
float DS18B20_ReadT();
#endif
2、独立按键模块(温度阈值设定、风速调节)
-
通过定时器扫描(在这里按键值获取只能通过定时器,因为在温度监测的单总线协议中有延时函数,如果使用Delay()函数,DS18B20温度监测会出现错误。当然也可以把延时函数写出定时器扫描方式,这里我就采用软件延时),来获取当前按下按键值
(1)、Key.c
#include <REGX52.H>
unsigned char Key_KeyNumer;
/**
*@brief 获取按键键码
*@param 无
*@retval 返回那个按键按下
*/
unsigned char KeyNum()
{
unsigned char Temp=0;
Temp=Key_KeyNumer;
Key_KeyNumer=0;
return Temp;
}
/**
*@brief 当有按键按下时,为Key_Loop()函数更新当前状态
*@param 无
*@retval 返回按键码
*/
unsigned char Key_GetNumer()
{
unsigned char KeyNumer=0;
if(P3_1==0){KeyNumer=1;}
if(P3_0==0){KeyNumer=2;}
if(P3_2==0){KeyNumer=3;}
if(P3_3==0){KeyNumer=4;}
return KeyNumer;
}
/**
*@brief 在定时器中断0中扫描按键状态
*@param 无
*@retval 无
*/
void Key_Loop()
{
static unsigned char NowState,LastState;
LastState=NowState; //1毫秒前的状态
NowState=Key_GetNumer(); //当前状态
//如果上个时间点按键按下,这个时间点未按下,则是松手瞬间,以此避免消抖和松手检测
if(LastState==1&&NowState==0)
{
Key_KeyNumer=1;
}
if(LastState==2&&NowState==0)
{
Key_KeyNumer=2;
}
if(LastState==3&&NowState==0)
{
Key_KeyNumer=3;
}
if(LastState==4&&NowState==0)
{
Key_KeyNumer=4;
}
}
(2)、Key.h
#ifndef __KEY_H__
#define __KEY_H__
unsigned char KeyNum();
void Key_Loop();
#endif
3、定时器0中断
-
用于扫描独立按键。
(1)、Timer0.c
#include <REGX52.H>
/**
*@brief 定时器0初始化,500微秒@12.000MHz
*@param 无
*@retval 无
*/
void Timer0_Init()
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x90; //设置定时初始值
TH0 = 0xE8; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1; //使能定时器0中断
EA=1; //全局中断使能标志(1:全局中断使能,0:全局中断失能)
PT0=1;
}
(2)、Timer0.h
#ifndef __TIMER0_H__
#define __TIMER0_H__
void Timer0_Init();
#endif
4、定时器1中断
-
PWM驱动电机实现控制风速。
(1)、Timer1.c
#include <REGX52.H>
/**
*@brief 定时器1初始化,100微秒@12.000MHz
*@param 无
*@retval 无
*/
void Timer1_Init()
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x10; //设置定时器模式
TL1 = 0x9C; //设置定时初始值
TH1 = 0xFF; //设置定时初始值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1 = 1; //使能定时器1中断
EA=1; //全局中断使能标志(1:全局中断使能,0:全局中断失能)
PT0=0; //低优先级中断
}
(2)、Timer1.h
#ifndef __TIMER1_H__
#define __TIMER1_H__
void Timer1_Init();
#endif
5、main主函数
-
主函数实现的逻辑与项目简介的实现过程一致,代码注释有具体实现步骤
#include <REGX52.H> #include "LCD1602.h" #include "Delay.h" #include "DS18B20.h" #include "Key.h" #include "Timer0.h" #include "Timer1.h" sbit Motor=P1^0; //电机驱动P1_0引脚(1:使能,0:失能) float T; unsigned char KeyNumer,Speed; unsigned char Compare,Speed_Flag=0;//风速标准位(当为0:表示没有人为调速,可智能温控风速) signed char STD=30; //设置温度阈值:30(可以根据自己的需求进行设置) /** *@brief 实时监测温度并显示(DS18B20温度范围:-55~125) *@param 无 *@retval 无 */ void Show_Temperature() { DS18B20_ConverT(); T=DS18B20_ReadT(); if(T<0) { LCD_ShowChar(1,3,'-'); T=-T; } else { LCD_ShowChar(1,3,'+'); } LCD_ShowNum(1,4,T,3); LCD_ShowChar(1,7,'.'); LCD_ShowNum(1,8,(unsigned long)(T*100)%100,2); } /** *@brief 实时控制温度阈值和风速并显示(DS18B20温度范围:-55~125,风速:0~3) *@param 无 *@retval 无 */ void Control_Value() { KeyNumer=KeyNum(); if(KeyNumer) { if(KeyNumer==1) { if(STD<=125) { STD++; } } if(KeyNumer==2) { if(STD>=-55) { STD--; } } if(KeyNumer==3){Speed++;Speed_Flag=1;} if(KeyNumer==4) { if(Speed!=0) { Speed--; Speed_Flag=1; } } Speed%=4; } LCD_ShowSignedNum(2,4,STD,3); LCD_ShowNum(2,16,Speed,1); } void main() { DS18B20_ConverT(); Delay(1000); LCD_Init(); Timer0_Init(); Timer1_Init(); LCD_ShowString(1,1,"T:"); LCD_ShowString(2,10,"Speed:"); LCD_ShowString(2,1,"STD:"); while(1) { Show_Temperature(); Control_Value(); if(T>STD) { if(Speed_Flag==0) { Speed=1; } if(Speed_Flag==0&&T-2>STD) { Speed=2; } if(Speed_Flag==0&&T-4>STD) { Speed=3; } } else { if(Speed_Flag==0) { Speed=0; } } if(Speed==0){Compare=0;} if(Speed==1){Compare=45;} if(Speed==2){Compare=60;} if(Speed==3){Compare=75;} } } void Timer0_Routine() interrupt 1 //中断函数 { static unsigned int T0Count; T0Count++; TL0 = 0x90; //设置定时初始值 TH0 = 0xE8; //设置定时初始值 if(T0Count>20) { T0Count=0; Key_Loop(); } } void Timer1_Routine() interrupt 3 //中断函数 { static unsigned int T1Count; T1Count++; T1Count%=100; TL1 = 0x9C; //设置定时初始值 TH1 = 0xFF; //设置定时初始值 if(T1Count<Compare) { Motor=1; } else { Motor=0; } }
-
三、总结
-
这个系统通过 51 单片机控制 DS18B20 温度传感器,实时监测环境温度,并根据设定的温度阈值自动控制风扇的开关,也可以通过人为需求来控制风速。这种智能温控系统能够有效地调节温度,提高环境舒适度和设备的工作效率。本文为学习笔记,欢迎大家在评论区积极讨论,一起学习,可以与我私信交流单片机学习,虽然项目能实现应有的功能,但也存在一定的不足,欢迎指出我的不足!