温度控制风扇转速
代码中LCD和18B20完全是照搬的百度上网友的代码,但不记得具体搬的是哪里了。…对不起原作者。
DIY的2.1音响,由于作的功放箱子体积有限,芯片温度较高,底噪时能到60度,须要加风扇,心太大,买的风扇转速太高,太吵,为了使温度受控而风扇不要太吵,百度到处找,终于搞出这个小程序;
使用芯片: STC89C52RC
显示硬件: LCD1602;
温度硬件:18B20
风扇硬件: 台达,12V0.4A 4线的,即±两线,方波输出线,PWM转速控制线;
运行效果:PWM频率81Hz,PWM Duty 宽度可调,风扇转速随便温度上升而上升,当然风扇噪声也跟着变大,全速的时候,即Duty为10的时候,占空比用示波器看是90%样子。应选用不那么暴力的风扇。12V0.4A左右即可。电流越大,噪声越大。
程序代码如下,可直接使用。
#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
typedef unsigned char uint8;
typedef unsigned int uint16;
typedef unsigned long uint32;
sfr P4 = 0xe8;
sbit led1 = P4^0;
sbit led2 = P3^7;
sbit rs=P2^4;
sbit rw=P2^5;
sbit e=P2^6;
sbit dq=P1^0;
sbit pwm=P1^2;
uint8 d[16]=" Internal Temp ";
uint8 num[10]="0123456789";
uint8 a,c,temp;
char time,RDD,speed;
void delay(uint16 i)
{
while(i--);
}
void wrc(uint8 c)
{
delay(1000);
rs=0;
rw=0;
e=0;
P0=c;
e=1;
delay(10);
e=0;
}
void wrd(uint8 dat)
{
delay(1000);
rs=1;
rw=0;
e=0;
P0=dat;
e=1;
delay(10);
e=0;
rs=0;
}
void lcdinit()
{
delay(10);
wrc(0x38);
wrc(0x38);
wrc(0x38);
wrc(0x06);
wrc(0x0c);
wrc(0x01);
}
void ds18b20init() //18b20的初始化
{
dq=1;
delay(1);
dq=0;
delay(80);
dq=1;
delay(5);
dq=0;
delay(20);
dq=1;
delay(35);
}
void ds18b20wr(uint8 dat) //18b20写数据
{
uint8 i;
for(i=0;i<8;i++)
{
dq=0;
dq=dat&0x01;
dat>>=1;
delay(8);//在时序上只有这一块对时序要求最准确,他的时间必须大于15us
dq=1;
delay(1);
}
}
uint8 ds18b20rd() //18b20读数据
{
uint8 value,i;
for(i=0;i<8;i++)
{
dq=0;
value>>=1;
dq=1;
if(dq==1)value|=0x80;
delay(8);//在这一块也对时间要求特别准确,整段程序必须大于60us
}
return value;
}
uint8 readtemp() //读取温度内需要复位的
{
uint8 b;
ds18b20init(); //初始化
ds18b20wr(0xcc); //发送忽略ROM指令
ds18b20wr(0x44); //发送温度转换指令
delay(100);
ds18b20init(); //初始化
ds18b20wr(0xcc); //发送忽略ROM指令
ds18b20wr(0xbe); //发读暂存器指令
a=ds18b20rd(); //温度的低八位
b=ds18b20rd(); //温度的高八位
b<<=4; //ssss s***;s为标志位s=0表示温度值为正数,s=1温度值为负数
c=b&0x80; //温度正负标志位确认
b+=(a&0xf0)>>4;
a=a&0x0f; //温度的小数部分
return b;
}
void display()
{
uint16 i,k;
float dio;
dio=a*0.0625;
k=dio*10000;//取小数点后两位有效数字
wrc(0x80);//+0x00);
for(i=0;i<16;i++)
{
wrd(d[i]);
}
wrc(0x80+0x43);
if(c==0x80) //读取到负温度即为补码,要将其转换成源码
{
wrd('-');
temp=temp-1;
temp=(~temp)|0x80;//负数的补码即为反码+1;而负数的反码为其源码取反,除了符号位;正数的补码等于正数的反码等于正数的源码
}
else
{
wrd('+');
temp=(temp);
}
wrd(num[temp/100]);
wrd(num[temp%100/10]);
wrd(num[temp%100%10]);
wrd('.');
wrd(num[k/1000]);
wrd(num[k%1000/100]);
wrd(0xdf);
wrd('C');
}
void time0init() //定时器0初始化
{
TMOD=0x02;
TH0=0xFC;
TL0=0x18; //1ms
TR0=1;
EA=1;
ET0=1;
}
void time1init() //定时器0初始化
{
TMOD=0x01;
TH1=0xFB;
TL1=0xAE; //1ms
TR1=1;
EA=1;
ET1=1;
}
void TempSpeed() //根据温度,设定风扇转速;
{
if(28>temp && temp>=20){speed=1;} //比如:当温度大于等于20度,同时,小于28度时,风扇仅10%全速;
else if(30>temp && temp>=28){speed=2;}
else if(31>temp && temp>=30){speed=4;}
else if(32>temp && temp>=31){speed=6;}
else if(50>temp && temp>=32){speed=8;}
else if(temp>=50){speed=10;}
}
void main()
{
time0init();
time1init();
lcdinit();
PT0 = 1;
speed=1;
while(1);
}
void time0()interrupt 1
{
EA = 0;//关闭定时器0;
TR1 = 1;//开启定时器1;
TH0 = 0xFC;
TL0 = 0x18;
TR1 = 0;//关闭定时器1;
EA = 1;//开启定时器0;
time++;
if(time>10){time = 0;}
if(time<(speed)){pwm = 1;led1 = 1;led2 = 1;}
else{pwm = 0;led1 = 0;led2 = 0;}
}
void time1()interrupt 3
{
EA = 0;
TH1 = 0Xfb;
TL1 = 0Xae;
EA = 1;
RDD++;
if(RDD>=10){RDD=0;}
if(RDD<5)
{
temp=readtemp();
}
else
{
display();
TempSpeed();
}
}