基于51单片机智能温控风扇设计—数码管显示
基于51单片机智能温控风扇设计
(仿真+程序+原理图+设计报告)
功能介绍
具体功能:
1.数码管实时显示当前温度
2.可以设置温度上下限
3.当温度低于下限温度,降温电机不运行
当温度在上下温度之间,降温电机50%运行
当温度高于上限温度,降温电机全速运行
演示视频:
基于51单片机智能温控风扇设计
/***********51单片机智能温控风扇 设计***********
*********************原创设计*******************
*************测量范围-55℃-+125℃***************
******上下限温度设定范围-55℃-+125℃********
******当温度低于下限温度,降温电机不运行*********
******当温度高于上限温度,降温电机全速运行*******
******当温度在上下温度之间,降温电机50%运行******
说明:计算机仿真运行平台和实物硬件运行平台的差异,
在实物上可运行但是仿真却不理想,为了使仿真功能体现出来,
我这边给出两组参数:0:实物运行参数 1:仿真运行参数,
他们的原理是一模一样,只是运行的平台不一样,
0、是实物硬件平台 1、 protues平台)
程序里定义了两个运行参数:
0: 实物运行参数 t=2
温度处理函数里的i(0-3000)
定时器中断定时时间0.25ms 0xff06
1: 仿真运行参数 t=300
温度处理函数里的i(0-400)
定时器中断定时时间 10ms 0xd8f0
************************************************/
#include <REGX52.H>
#define uchar unsigned char //uchar 代替 unsigned char
#define uint unsigned int //uint 代替 unsigned int
uchar display[4]={0x00,0x00,0x00,0x00}; //定义显示缓冲区(初始化为0x00 表示显示0000)
uchar code table[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xBF,0x89,0xC7};
//共阳数码管 0 1 2 3 4 5 6 7 8 9 - H L
//引脚定义:
#define SMG_XS P0 //定义数码管显示
#define IA P2_1 //电机控制接口
#define IB P2_0
#define LED1 P1_5 //指示灯1
#define LED2 P3_5 //指示灯2
#define q_kz P2_3 //(千位)数码管位选控制(第1个数码管)
#define b_kz P2_4 //(白位)数码管位选控制(第2个数码管)
#define s_kz P2_5 //(十位)数码管位选控制(第3个数码管)
#define g_kz P2_6 //(个位)数码管位选控制(第4个数码管)
#define IO_18b20 P1_0//定义DS18B20接口
#define Key1 P1_1 //温度上下限设置 按键
#define Key2 P1_6 //上下限温度加 按键
#define Key3 P3_2 //上下限温度减 按键
#define Key4 P3_7 //实物/仿真运行切换按键(上电默认为:实物运行参数)
float wendu; //定义真实的十进制温度变量
int big_wendu; //放大10倍后的十进制温度变量(主要方便温度显示精确到小数点后一位)
int high=35; //定义上限温度变量
int low=25; //定义下限温度变量
uchar flag=0; //定义按键温度设置标志位(0:正常显示温度 1:显示上限温度值 2:显示下限温度值)
bit jw_flag; //定义降温风扇运行指示灯标志位
//(0:指示灯1闪烁,电机50%运行 1:指示灯1和指示灯2 都闪烁,电机全速运行)
int num=0; //定义指示灯1、2的闪烁频率变量
uint t=2; //数码管动态扫描基数为2(t=2为实物运行参数),另外(t=300为仿真运行参数)
bit ts=0; //定义临时调试标志位为0(0:实物运行参数 1:仿真运行参数)
/********************DS18B20部分******************/
void delay_ms(uint count) //延时函数(keil软件测试此函数运行时间约1ms)
{
uint i;
while(count)
{
i=125;
while(i>0) {i--;} //当i>0,执行i自减1,达到延时效果
count--;
}
}
void ds18b20_init() //DS18B20初始化(根据DS18B20初始化时序编写)
{
uint i;
IO_18b20=0; //先将IO_18b20拉低
i=100;
while(i>0){i--;} //延时一段时间803us(延时持续时间在480-960us之间即可)
IO_18b20=1; //再将IO_18b20拉高
i=7; //由于DS18B20需要等待15-60US之后会自动响应拉低这个引脚
while(i>0){i--;} //所以这边需要延时一小段时间(程序中延时59us)等待DS18B20响应
}
bit ds18b20_read_bit() //读一位函数并返回"dat"(根据DS18B20读一位字节时序编写)
{
uint i;
bit dat; //定义位变量dat
EA=0; //要操作DS18b20时先关闭定时器中断(防止定时器中断对操作DS18b20有影响,导致出错)
IO_18b20=0; //先将IO_18b20拉低***(从IO_18b20拉低到读取IO_18b20上的数据状态,过程不能超过15us)
i++; //小延时一下 ↑
IO_18b20=1; //再将IO_18b20拉高(释放改引脚) 不能超过15us
i++; //小延时一下
EA=1; //再打开定时器中断 ↓
dat=IO_18b20; //读到的数据送到dat**(从IO_18b20拉低到读取IO_18b20上的数据状态,过程不能超过15us)
i=8;
while(i>0) {i--;} //延时一下
return (dat); //返回读出来的数据dat
}
uchar ds18b20_read_byte() //读一个字节
{
uchar i,j,dat; //定义i,j,dat变量
dat=0; //dat初始化为0
for(i=0;i<8;i++) //for循环传递8位数据(即一个字节)
{
j=ds18b20_read_bit(); //将读一位函数并返回"dat",传送到j
dat=(j<<7)|(dat>>1); //读出的数据最低位在最前面,这样刚好一个字节在dat里
}
return(dat); //将一个字节数据返回
}
void ds18b20_write_byte(uchar dat)//写一个字节
{
uint i;
uchar j;
bit test; //定义临时位变量test
for(j=0;j<8;j++) //for循环传递8位数据(即一个字节)
{
test=dat&0x01; //将dat的最低位取出来放在test
dat=dat>>1; //再将dat向右移一位
if(test) //如果test为1,"写1部分(根据DS18B20写"1"时序编写)"
{
EA=0; //要操作DS18b20时先关闭定时器中断(防止定时器中断对操作DS18b20有影响,导致出错)
IO_18b20=0; //先将IO_18b20拉低
i++; //小延时一下,(时序时间要求大于1us)
EA=1; //再打开定时器中断
IO_18b20=1; //再将IO_18b20拉高(释放总线)
i=8;
while(i>0) {i--;}//延时一下69us(时序时间要求大于60us)
}
else //否则test为0,"写0部分(根据DS18B20写"0"时序编写)"
{
EA=0; //要操作DS18b20时先关闭定时器中断(防止定时器中断对操作DS18b20有影响,导致出错)
IO_18b20=0; //先将IO_18b20拉低
i=8;
EA=1; //再打开定时器中断
while(i>0) {i--;}//延时一下69us(时序时间要求大于60us小于120us即可)
IO_18b20=1; //再将IO_18b20拉高
i++;i++; //小延时一下
}
}
}
/**********************************************************/
void temp_change() //发送温度转换命令函数
{
ds18b20_init(); //初始化DS18B20
delay_ms(1); //延时等待1ms,时间上留有一些余地,因为DS18B20器件响应后会主动
//拉低60-240us,然后DS18B20自己会主动释放总线,即主动拉高IO口
ds18b20_write_byte(0xcc); //跳过序列号命令
ds18b20_write_byte(0x44); //发送温度转换命令
}
/******************************************************************/
int temperature() //获得温度函数
{
int temp; //定义温度值变量(整型变量)
uchar a,b; //定义变量a,b用来存放温度值的低8位和高8位
ds18b20_init(); //初始化DS18B20
delay_ms(1); //延时等待1ms,时间上留有一些余地,因为DS18B20器件响应后会主动
//拉低60-240us,然后DS18B20自己会主动释放总线,即主动拉高IO口
ds18b20_write_byte(0xcc); //跳过序列号命令
ds18b20_write_byte(0xbe); //发送读取数据命令
a=ds18b20_read_byte(); //连续读两个字节数据 (a为低8位数据)
b=ds18b20_read_byte(); //b为高8位数据
temp=b; //将高8位数据送到temp中
temp<<=8; //再将temp左移8位,这样高8位数据就存在temp的高8位上了
temp=temp|a;//两字节合成一个整型变量(temp是高8位"按位或"a是低8位)
return temp;//返回温度值
}
/****************以上为DS18B20部分****************/
void delay(uint time) //数码管扫描延时函数
{
uint i,j;
for(i=time;i>0;i--)
for(j=3;j>0;j--);
}
void delay_anjian(uint time) //按键延时去抖函数
{
uint i,j;
for(i=time;i>0;i--)
for(j=110;j>0;j--);
}
void disp0() //正常显示当前温度函数(显示缓冲区内容)
{
if(wendu>0) //如果温度大于0,为正数
{
SMG_XS=table[display[0]]; //显示温度数据百位值
q_kz=0;b_kz=s_kz=g_kz=1; //允许(千位)数码管位(第1个数码管)点亮
delay(t); //延时一下(消隐)
q_kz=1;
}
else //否则温度小于0,为负数
{
SMG_XS=table[10]; //显示负号"-"
q_kz=0;b_kz=s_kz=g_kz=1; //允许(千位)数码管位(第1个数码管)点亮
delay(t); //延时一下(消隐)
q_kz=1;
}
SMG_XS=table[display[1]]; //显示温度数据十位值
b_kz=0;q_kz=s_kz=g_kz=1; //允许(百位)数码管位(第2个数码管)点亮
delay(t); //延时一下(消隐)
b_kz=1;
SMG_XS=table[display[2]]&0x7f; //显示温度数据个位值,并加入小数点
s_kz=0;q_kz=b_kz=g_kz=1; //允许(十位)数码管位(第3个数码管)点亮
delay(t); //延时一下(消隐)
s_kz=1;
SMG_XS=table[display[3]]; //显示温度数据小数点后一位
g_kz=0;q_kz=b_kz=s_kz=1; //允许(个位)数码管位(第4个数码管)点亮
delay(t); //延时一下(消隐)
g_kz=1;
}
void disp1(high) //显示上限温度函数
{
SMG_XS=table[11]; //显示"H"
q_kz=0;b_kz=s_kz=g_kz=1; //允许(千位)数码管位(第1个数码管)点亮
delay(t); //延时一下(消隐)
q_kz=1;
if(high/100!=0) //如果上限温度百位不为0(表示上限温度值超过100)
{
SMG_XS=table[high/100]; //显示上限温度的百位
b_kz=0;q_kz=s_kz=g_kz=1; //允许(百位)数码管位(第2个数码管)点亮
delay(t); //延时一下(消隐)
b_kz=1;
SMG_XS=table[high%100/10]; //显示上限温度的十位
s_kz=0;q_kz=b_kz=g_kz=1; //允许(十位)数码管位(第3个数码管)点亮
delay(t); //延时一下(消隐)
s_kz=1;
SMG_XS=table[high%10]; //显示上限温度的个位
g_kz=0;q_kz=b_kz=s_kz=1; //允许(个位)数码管位(第4个数码管)点亮
delay(t); //延时一下(消隐)
g_kz=1;
}
else if(high>=0) //再如果上限温度值大于等于0(说明温度值是正数)
{
SMG_XS=table[high/10]; //显示上限温度的十位
s_kz=0;q_kz=b_kz=g_kz=1; //允许(十位)数码管位(第3个数码管)点亮
delay(t); //延时一下(消隐)
s_kz=1;
SMG_XS=table[high%10]; //显示上限温度的个位
g_kz=0;q_kz=b_kz=s_kz=1; //允许(个位)数码管位(第4个数码管)点亮
delay(t); //延时一下(消隐)
g_kz=1;
}
else //否则上限温度值是负数(即零下温度值)
{
SMG_XS=table[10]; //显示"-"(因为是负数,所以要加"-"号)
b_kz=0;q_kz=s_kz=g_kz=1; //允许(百位)数码管位(第2个数码管)点亮
delay(t); //延时一下(消隐)
b_kz=1;
high=0-high; //把上限温度值取正
SMG_XS=table[high/10]; //显示上限温度的十位
s_kz=0;q_kz=b_kz=g_kz=1; //允许(十位)数码管位(第3个数码管)点亮
delay(t); //延时一下(消隐)
s_kz=1;
SMG_XS=table[high%10]; //显示上限温度的个位
g_kz=0;q_kz=b_kz=s_kz=1; //允许(个位)数码管位(第4个数码管)点亮
delay(t); //延时一下(消隐)
g_kz=1;
}
}
void disp2(low) //显示下限温度函数
{
SMG_XS=table[12]; //显示"L"
q_kz=0;b_kz=s_kz=g_kz=1; //允许(千位)数码管位(第1个数码管)点亮
delay(t); //延时一下(消隐)
q_kz=1;
if(low/100!=0) //如果下限温度百位不为0(表示上限温度值超过100)
{
SMG_XS=table[low/100]; //显示下限温度的百位
b_kz=0;q_kz=s_kz=g_kz=1; //允许(百位)数码管位(第2个数码管)点亮
delay(t); //延时一下(消隐)
b_kz=1;
SMG_XS=table[low%100/10]; //显示下限温度的十位
s_kz=0;q_kz=b_kz=g_kz=1; //允许(十位)数码管位(第3个数码管)点亮
delay(t); //延时一下(消隐)
s_kz=1;
SMG_XS=table[low%10]; //显示下限温度的个位
g_kz=0;q_kz=b_kz=s_kz=1; //允许(个位)数码管位(第4个数码管)点亮
delay(t); //延时一下(消隐)
g_kz=1;
}
else if(low>=0) //再如果下限温度值大于等于0(说明温度值是正数)
{
SMG_XS=table[low/10]; //显示下限温度的十位
s_kz=0;q_kz=b_kz=g_kz=1; //允许(十位)数码管位(第3个数码管)点亮
delay(t); //延时一下(消隐)
s_kz=1;
SMG_XS=table[low%10]; //显示下限温度的个位
g_kz=0;q_kz=b_kz=s_kz=1; //允许(个位)数码管位(第4个数码管)点亮
delay(t); //延时一下(消隐)
g_kz=1;
}
else //否则下限温度值是负数(即零下温度值)
{
SMG_XS=table[10]; //显示"-"(因为是负数,所以要加"-"号)
b_kz=0;q_kz=s_kz=g_kz=1; //允许(百位)数码管位(第2个数码管)点亮
delay(t); //延时一下(消隐)
b_kz=1;
low=0-low; //把下限温度值取正
SMG_XS=table[low/10]; //显示下限温度的十位
s_kz=0;q_kz=b_kz=g_kz=1; //允许(十位)数码管位(第3个数码管)点亮
delay(t); //延时一下(消隐)
s_kz=1;
SMG_XS=table[low%10]; //显示下限温度的个位
g_kz=0;q_kz=b_kz=s_kz=1; //允许(个位)数码管位(第4个数码管)点亮
delay(t); //延时一下(消隐)
g_kz=1;
}
}
void SMG_disp() //数码管显示函数
{
if(flag==0) //如果flag=0
{
disp0(); //正常显示当前温度函数(显示缓冲区内容)
}
if(flag==1) //如果flag=1
{
disp1(high); //显示上限温度函数
}
if(flag==2) //如果flag=2
{
disp2(low); //显示下限温度函数
}
}
void xitong_init() //系统初始化等待DS18b20彻底转换完成,未完成之前数码管显示"----"
{
EA=1; //开总中断
TMOD=0x01; //定时器0为方式1
TH0=0xff; //12M晶振 定时时间0.25ms 0xff06
TL0=0x06;
ET0=1; //开定时器0中断
TR0=0; //先不启动定时器0
SMG_XS=table[10]; //数码管显示"----"
q_kz=b_kz=s_kz=g_kz=0; //允许4位数码管显示
temp_change(); //发送温度转换命令函数
delay_ms(980); //等待延时980ms>750ms,时间上留有一些余地;
//(因为DS18b20出厂默认最大的温度转换时间为750ms,
//为了防止第一次读出来的温度值是错误的值(典型错误值一般是85℃
//程序中的延时时间需要至少为750ms)*/
}
void wendu_data_cl() //温度数据处理
{
static uint i=0; //定义循环变量
i++; //i自加1(i开始从零开始自加1)
if(ts==0) //0:实物运行参数
{
if(i==3000) {i=0;}//如果i=3000,i清0(使i控制在0-3000之间),i的范围决定温度数据刷新的快慢
}
else //1:仿真运行参数
{
if(i>=400) {i=0;}
}
if(i==0) //如果i=0,执行温度转换
{
temp_change();//发送温度转换命令函数
}
if(i==100) //如果i=100,处理DS18B20送过来的数据,同时加以处理
{ //为了显示精确小数点后一位的温度值
wendu=temperature()*0.0625; //得到真实十进制温度值,因为DS18B20
//可以精确到0.0625度,所以读回数据的最低位代表的是0.0625度
if(wendu<=low) //温度值低于下限温度(表示温度过低,不能降温,则降温电机风扇不运行)
{
TR0=0; //关闭TR0
LED1=LED2=1; //指示灯1 指示灯2都不亮
IA=IB=0; //降温电机风扇不转
}
else if(wendu>=high)//温度值高于上限温度(表示温度过高,需降温,则降温电机风扇全速运行)
{
jw_flag=1; //1:指示灯1和指示灯2 都闪烁
IA=1;IB=0; //降温电机风扇全速运行
TR0=1; //打开TR0
}
else //否则温度在正常温度范围(表示温度适当,需维持温度,则降温电机风扇50%运行)
{
jw_flag=0; //0:指示灯1闪烁
TR0=1; //打开TR0
}
big_wendu=wendu*10; //放大十倍,这样做的目的将小数点后第一位也转换为可显示数字
if(wendu<0) //(如果温度数据是负数)判断第一位显示正数还是负数
{
big_wendu=0-big_wendu; //再把数据转换成正数,方便数据显示
}
else //否则温度数据是正数
{
display[0]=big_wendu/1000;//显示温度数据百位值
}
big_wendu=big_wendu%1000;
display[1]=big_wendu/100; //显示温度数据十位值
big_wendu=big_wendu%100;
display[2]=big_wendu/10; //显示温度数据个位值
display[3]=big_wendu%10; //显示温度数据小数点后一位
}
}
void anjian_cl() //按键处理函数
{
if(Key1==0) //温度上下限设置 按键 按下
{
delay_anjian(5); //延时去抖
if(Key1==0) //再判断温度上下限设置 按键 是否按下
{
flag++; //按键温度设置标志位 加1
while(flag==3) {flag=0;}//当flag=3.flag清0(让0<=flag<=2)
q_kz=b_kz=s_kz=g_kz=1; //关闭数码管显示
TR0=0; //关闭TR0(关闭定时器0)
LED1=LED2=1; //指示灯LED1、2灯关闭
IA=IB=0; //关闭降温电机
}
while(Key1==0); //等待按键松开
}
if(flag==1) //允许调整上限温度值
{
if(Key2==0) //上下限温度加 按键 按下
{
delay_anjian(5); //延时去抖
if(Key2==0) //再判断上下限温度加 按键 是否按下
{
if(high>low) //如果上限温度>下限温度
{
high++; //上限温度自加 1
while(high==126) {high=low+1;}//当上限温度加到126℃时,上限温度设定为比下限温度高1℃
//原因是上限温度值一定需要比下限温度值高。
q_kz=b_kz=s_kz=g_kz=1; //关闭数码管显示
}
}
while(Key2==0); //等待按键松开
}
if(Key3==0) //上下限温度减 按键 按下
{
delay_anjian(5); //延时去抖
if(Key3==0) //再判断上下限温度减 按键 是否按下
{
if(high-low>1) //如果上限温度值减去下限温度值大于1
{ //(这个条件判断确保上限温度不能低于下限温度)
high--; //上限温度自减 1
while(high==-56) {high=low+1;}//当上限温度自减到-56℃时,上限温度设定为比下限温度高1℃
//原因是上限温度值一定需要比下限温度值高。
q_kz=b_kz=s_kz=g_kz=1; //关闭数码管显示
}
else //否则上限温度不能再自减1
{
high=high; //上限温度保持不变
q_kz=b_kz=s_kz=g_kz=1; //关闭数码管显示
}
}
while(Key3==0); //等待按键松开
}
}
if(flag==2) //允许调整下限温度值
{
if(Key2==0) //上下限温度加 按键 按下
{
delay_anjian(5); //延时去抖
if(Key2==0) //再判断上下限温度加 按键 是否按下
{
if(low-high<-1) //如果下限温度减去上限温度小于-1
{ //(这个条件判断确保下限温度不能超过上限温度)
low++; //下限温度自加 1
while(low==126) {low=high-1;}//当下限温度自加到126℃,下限温度设置为比上限温度低1℃
//(说明:这个情况不存在,考虑到系统的更加稳定,加上这个判断)
q_kz=b_kz=s_kz=g_kz=1; //关闭数码管显示
}
else //否则下限温度不能再自加1
{
low=low; //下限温度保持不变
q_kz=b_kz=s_kz=g_kz=1; //关闭数码管显示
}
}
while(Key2==0); //等待按键松开
}
if(Key3==0) //上下限温度减按键 按下
{
delay_anjian(5); //延时去抖
if(Key3==0) //再判断上下限温度减按键 是否按下
{
if(low<high) //如果下限温度低于上限温度(说明上下限温度值正常)
{
low--; //下限温度自减 1
while(low==-56) {low=high-1;}//当下限温度减到-56℃时,下限温度设定比上限温度小1℃
//原因是下限温度值要比上限温度值要低
q_kz=b_kz=s_kz=g_kz=1; //关闭数码管显示
}
}
while(Key3==0); //等待按键松开
}
}
}
void anjian_ts() //按键调试函数
{
if(Key4==0) //实物/仿真运行切换按键 按下
{
delay_anjian(5); //延时去抖
if(Key4==0) //再判断实物/仿真运行切换按键 是否按下
{
ts=~ts; //调试标志位取反(0:实物运行参数 1:仿真运行参数)
q_kz=b_kz=s_kz=g_kz=1; //关闭数码管显示
}
}
while(Key4==0); //等待按键松开
if(ts==0) {t=2;} //0:实物运行参数 t=2
else {t=300;} //1:仿真运行参数 t=300
}
硬件设计
使用元器件:
单片机:STC89C52;
(注意:单片机是通用的,无论51还是52、无论stc还是at都一样,引脚功能都一样。程序也是一样的。)
USB接头(母头);自锁开关;
电解电容10u;电阻10K;
瓷片电容30P;晶振12M;
电阻470(贴片);按键;
电解电容470uF;瓷片电容104;
LED(红发红);电阻4.7K;
三极管8550;4位共阳数码管;
DIP40;DS18B20;
芯片座DIP8;L9110;
直流电机;9*15CM万能板;
USB公对公线 ;方柱;
铁架;M2螺丝配螺母;
风扇叶;扎带 ;
铜柱子配螺丝;2P排针;
导线:若干;
流程图:
设计资料
01 仿真图
本设计使用proteus7.8和proteus8.7两个版本设计,向下兼容,无需担心!具体如图!
监控模式
设置温度上限值
设置温度下限值
02 原理图
本系统原理图采用Altium Designer19设计,具体如图!
03 程序
本设计使用软件keil4和keil5两个版本编程设计,无需担心!具体如图!
04 设计报告
一万两千字设计报告,具体如下!
05 设计资料
全部资料包括仿真源文件 、程序(含注释)、AD原理图、参考论文、流程图等。具体内容如下,全网最全! !
资料获取请观看前面演示视频!
点赞分享一起学习成长。