标题:
单片机控制风扇程序
[打印本页]
作者:
杨小杨
时间:
2018-5-14 15:38
标题:
单片机控制风扇程序
单片机源程序如下:
//宏定义
#define uchar unsigned char
#define uint unsigned int
//包含头文件
#include <reg52.h>
#include <18b20.h>
#include <stdlib.h>
#include <intrins.h>
#include <eeprom52.h>
#define Imax 14000 //此处为晶振为11.0592时的取值,
#define Imin 8000 //如用其它频率的晶振时,
#define Inum1 1450 //要改变相应的取值。
#define Inum2 700
#define Inum3 3000
sbit K1=P1^1;
sbit K2=P1^2;
sbit K3=P1^3; //按键定义
sbit PWM=P3^6; //PWM输出
sbit BUZZ=P1^4; //蜂鸣器控制脚
sbit RSD=P2^0; //热释电引脚
unsigned char Im[4]={0x00,0x00,0x00,0x00};
uchar displaydata[4]; //显示暂存数组
//全局变量
char f,dang,count,count1,a_a; //档位
unsigned long m,Tc;
unsigned char IrOK; //定义红外工作变量
void jisuan(); //声明计算函数
uchar mode;
char sec_b=0;
bit flag_b=0;
uint TH,TL; //上下限变量
uchar baif,suiji;
unsigned char code duan[17]={
0x5F,0x44,0x9D,0xD5,0xC6,0xD3,0xDB,0x47,0xDF,0xD7, 0xCF,0xDA,0x98,0xDC,0x9B,0x8B}; //接线从高到低:g c dp d e b f a
//0、1、2、3、4、5、6、7、8、9、A、b、c、d、E、F的显示码 //
unsigned char code wei[8]={ //数码管的位选
0xef,0xdf,0xbf,0x7f,0xfe,0xfd,0xfb,0xf7};
uchar code zhuanhuan[4]={10,5,3,0};//转换数组
void write_eeprom() //内部eeprom写函数
{
SectorErase(0x2000); //清空
SectorErase(0x2c00);
SectorErase(0x2e00);
byte_write(0x2c00,TH/256);
byte_write(0x2c01,TH%256);
byte_write(0x2c02,TL/256);
byte_write(0x2c03,TL%256); //将上下限数据保存到eeprom
byte_write(0x2c04,dang);
byte_write(0x2c05,mode);
byte_write(0x2060,0x01);
}
/******************把数据从单片机内部eeprom中读出来*****************/
void read_eeprom()
{
mode = byte_read(0x2c05);
dang = byte_read(0x2c04);
TH = byte_read(0x2c00)*256+byte_read(0x2c01);
TL = byte_read(0x2c02)*256+byte_read(0x2c03);
a_a = byte_read(0x2060);
}
/**************开机自检eeprom初始化*****************/
void init_eeprom()
{
a_a = byte_read(0x2060);
if(a_a != 1) //新的单片机初始单片机内问eeprom
{
a_a = 1;
write_eeprom(); //保存数据
}
}
void delay(uint z) //延时函数
{
uint z1,z2;
for(z1=0;z1<z;z1++)
for(z2=0;z2<110;z2++);
}
void display() //显示函数
{
uchar i;
if(mode==0) //无极变速
{
displaydata[0]=0x00;
displaydata[1]=duan[disdata[1]];
displaydata[2]=duan[disdata[2]]|0x20;
displaydata[3]=duan[disdata[3]];
}
else if(mode==1) //上限
{
displaydata[0]=0xce; //H 11001110
displaydata[1]=duan[TH%1000/100];
displaydata[2]=duan[TH%100/10]|0x20;
displaydata[3]=duan[TH%10];
}
else if(mode==2) //下限
{
displaydata[0]=0x1a; //L 00111000
displaydata[1]=duan[TL%1000/100];
displaydata[2]=duan[TL%100/10]|0x20;
displaydata[3]=duan[TL%10];
}
else if(mode==3) //档位0到3档
{
displaydata[0]=duan[dang];
displaydata[1]=0x80; //01000000
displaydata[2]=duan[disdata[1]];
displaydata[3]=duan[disdata[2]];
}
else if(mode==4)
{
displaydata[0]=0xda; //b自然风
displaydata[1]=duan[disdata[1]];
displaydata[2]=duan[disdata[2]]|0x20;
displaydata[3]=duan[disdata[3]];
}
for(i=0;i<4;i++) //循环4次显示4位数码管
{
P2=wei[i]; //选中位
P0=displaydata[i]; //送入显示码
delay(3); //延时
P2=0xff; //关闭位
P0=0x00; //复位显示码
}
}
void key() //按键函数
{
if(K1==0||(Im[2]==0x47&&IrOK==1)) //按键1按下或者遥控器上的按键按下
{
delay(5); //延时去抖
if(K1==0||(Im[2]==0x47&&IrOK==1)) //再次判断按键按下
{
BUZZ=0;
delay(20);
BUZZ=1; //按键音
mode++; //模式加
if(mode>4) //模式加到大于4
mode=0; //模式清零
// Im[2]=0;
IrOK=0; //变量清零
write_eeprom(); //写入eeprom数据
while(!K1); //按键释放
}
}
if(K2==0||(Im[2]==0x40&&IrOK==1))
{
delay(5);
if(K2==0||(Im[2]==0x40&&IrOK==1))
{
BUZZ=0;
delay(20);
BUZZ=1;
if(mode==1) //模式等于1时
{
TH++; //上限加
if(TH>999) //上限加到大于99.9度
TH=TL+1; //上限等于下限加一
}
else if(mode==2) //模式等于2时
{
TL++; //下限加
if(TL>=TH) //下限加到大于等于上限
TL=TH-1; //下限等于上限减一
}
else if(mode==3) //模式等于3时
{
dang++; //档位加一
if(dang>3) //档位大于3时
dang=0; //档位清零
}
Im[2]=0;
IrOK=0; //红外变量清零
write_eeprom(); //写入eeprom数据
while(!K2); //按键释放
}
}
if(K3==0||(Im[2]==0x19&&IrOK==1))
{
delay(5);
if(K3==0||(Im[2]==0x19&&IrOK==1))
{
BUZZ=0;
delay(20);
BUZZ=1;
if(mode==1)
{
TH--;
if(TH<=TL)
TH=TL+1;
}
else if(mode==2)
{
TL--;
if(TL>=TH)
TL=TH-1;
}
else if(mode==3)
{
dang--;
if(dang<0)
dang=3;
}
Im[2]=0;
IrOK=0;
write_eeprom();
while(!K3);
}
}
}
void jisuan() //计算函数
{
if((mode==0||mode==1||mode==2)&&RSD==1) //模式0、1、2并且热释电有信号时
{
if(tvalue<=TL) //温度小于下限时
PWM=1; //关闭输出,占空比0%
else if(tvalue>=TH) //温度大于等于上限
PWM=0; //打开输出,占空比100%
else //其他状态时
{
baif=(((tvalue-TL)*50)/(TH-TL)); //占空比控制变量计算得到
//计算方法:当前温度减去下限值乘以5再除以上限减下限
if(count1>baif) //根据变量判断占空比大小
PWM=1; //关闭风扇
else
PWM=0; //打开风扇
}
}
else if(mode==3) //模式3时
{
if(count1>(zhuanhuan[dang]*5)) //根据档位计算出占空比
PWM=0;
else
PWM=1;
}
else if((mode==4&&flag_b==0)&&RSD==1) //模式4时,热释电有信号
{
suiji=rand(); //读随机函数
suiji=suiji%23; //随机数计算
if(10>suiji) //判断随机数是否小于10
PWM=0; //输出开
else //随机数大于等于10
PWM=1; //输出关
flag_b=1; //变量置1
}
if(RSD==0&&mode!=3) //热释电没有信号时
PWM=1; //关闭输出
}
void main() //主函数
{
uint count; //定义变量
EA=1; //打开中断总开关
EX1=1; //打开外部中断1
IT1=1; //下降沿有效
TMOD=0x11; //定时器工作方式
TR0=0; //关闭T0
TH0=0;
TL0=0; //初值0
ET1=1; //T1允许中断
TR1=1; //T1打开中断
TH1=0xfc;
TL1=0x18; //T1初值1ms
mode=0; //初始模式0
TH=300;
TL=200; //上下限初始值
init_eeprom(); //初始化eeprom
read_eeprom(); //读取eeprom数据
while(1) //进入循环
{
jisuan(); //计算函数
count++; //变量加
if(count>200) //加到大于200
{
count=0; //清零
TR1=0; //关闭定时器T1
read_wendu(); //读取温度
TR1=1; //打开定时器T1
}
jisuan(); //计算函数
display(); //显示函数
key(); //按键函数
jisuan(); //计算函数
}
}
void timer1() interrupt 3 //定时器T1工作函数
{
TH1=0xfc;
TL1=0x18; //重新赋初值
count1++; //加
if(count1>50)
{
count1=0;
if(mode==4&&flag_b==1) //模式等于4时,变量为1
{
sec_b++; //变量加
if(sec_b>=8) //加到8时
{
sec_b=0; //清零
flag_b=0; //清零
}
}
}
}
void intersvr1(void) interrupt 2 //红外工作函数
{
TR0=1;
Tc=TH0*256+TL0;//提取中断时间间隔时长
TH0=0;
TL0=0; //定时中断重新置零
if((Tc>Imin)&&(Tc<Imax))
{
m=0;
f=1;
return;
} //找到启始码
if(f==1)
{
if(Tc>Inum1&&Tc<Inum3)
{
Im[m/8]=Im[m/8]>>1|0x80; m++;
}
if(Tc>Inum2&&Tc<Inum1)
{
Im[m/8]=Im[m/8]>>1; m++; //取码
}
if(m==32)
{
m=0;
f=0;
if(Im[2]==~Im[3])
{
IrOK=1;
TR0=0;
}
else
{
IrOK=0; //取码完成后判断读码是否正确
}
}
//准备读下一码
}
}
Ds18b20
sbit DQ=P1^0;//ds18b20与单片机连接口
uchar data disdata[5];
uint tvalue;//温度值
uchar tflag;//温度正负标志
/******************************ds1820程序***************************************/
void delay_18B20(uchar k)//延时1微秒
{
while(k--);
}
void ds1820rst()/*ds1820复位*/
{
DQ = 1; //DQ复位
delay_18B20(4); //延时
DQ = 0; //DQ拉低
delay_18B20(100); //精确延时大于480us
DQ = 1; //拉高
delay_18B20(40);
}
uchar ds1820rd()/*读数据*/
{
unsigned char i=0;
unsigned char dat = 0;
for (i=8;i>0;i--)
{ DQ = 0; //给脉冲信号
dat>>=1;
DQ = 1; //给脉冲信号
if(DQ)
dat|=0x80;
delay_18B20(10);//延时106us
}
return(dat);
}
void ds1820wr(uchar wdata)/*写数据*/
{
unsigned char i=0;
for (i=8; i>0; i--)
{
DQ = 0;
DQ = wdata&0x01;
delay_18B20(10);//延时106us
DQ = 1;
wdata>>=1;
}
}
uint read_wendu()/*读取温度值并转换*/
{
uchar a,b;
ds1820rst();
ds1820wr(0xcc);//*跳过读序列号*/
ds1820wr(0x44);//*启动温度转换*/
ds1820rst();
ds1820wr(0xcc);//*跳过读序列号*/
ds1820wr(0xbe);//*读取温度*/
a=ds1820rd();
b=ds1820rd();
tvalue=b;
tvalue<<=8;
tvalue=tvalue|a;
if(tvalue<0x0fff)
tflag=0;
else
{
tvalue=~tvalue+1;
tflag=1;
}
tvalue=tvalue*(0.625);//温度值扩大10倍,精确到1位小数
disdata[1]=tvalue%1000/100;//十位数
disdata[2]=tvalue%100/10;//个位数
disdata[3]=tvalue%10;//小数位
return(tvalue);
}
eeprom
#ifndef _EEPROM52_H_
#define _EEPROM52_H_
/********STC89C51扇区分布*******
第一扇区:1000H--11FF
第二扇区:1200H--13FF
第三扇区:1400H--15FF
第四扇区:1600H--17FF
第五扇区:1800H--19FF
第六扇区:1A00H--1BFF
第七扇区:1C00H--1DFF
第八扇区:1E00H--1FFF
*****************/
/********STC89C52扇区分布*******
第一扇区:2000H--21FF
第二扇区:2200H--23FF
第三扇区:2400H--25FF
第四扇区:2600H--27FF
第五扇区:2800H--29FF
第六扇区:2A00H--2BFF
第七扇区:2C00H--2DFF
第八扇区:2E00H--2FFF
*****************/
#define RdCommand 0x01 //定义ISP的操作命令
#define PrgCommand 0x02
#define EraseCommand 0x03
#define Error 1
#define Ok 0
#define WaitTime 0x01 //定义CPU的等待时间
sfr ISP_DATA=0xe2; //寄存器申明
sfr ISP_ADDRH=0xe3;
sfr ISP_ADDRL=0xe4;
sfr ISP_CMD=0xe5;
sfr ISP_TRIG=0xe6;
sfr ISP_CONTR=0xe7;
/* ================ 打开 ISP,IAP 功能 ================= */
void ISP_IAP_enable(void)
{
EA = 0; /* 关中断 */
ISP_CONTR = ISP_CONTR & 0x18; /* 0001,1000 */
ISP_CONTR = ISP_CONTR | WaitTime; /* 写入硬件延时 */
ISP_CONTR = ISP_CONTR | 0x80; /* ISPEN=1 */
}
/* =============== 关闭 ISP,IAP 功能 ================== */
void ISP_IAP_disable(void)
{
ISP_CONTR = ISP_CONTR & 0x7f; /* ISPEN = 0 */
ISP_TRIG = 0x00;
EA = 1; /* 开中断 */
}
/* ================ 公用的触发代码 ==================== */
void ISPgoon(void)
{
ISP_IAP_enable(); /* 打开 ISP,IAP 功能 */
ISP_TRIG = 0x46; /* 触发ISP_IAP命令字节1 */
ISP_TRIG = 0xb9; /* 触发ISP_IAP命令字节2 */
_nop_();
}
/* ==================== 字节读 ======================== */
unsigned char byte_read(unsigned int byte_addr)
{
EA = 0;
ISP_ADDRH = (unsigned char)(byte_addr >> 8);/* 地址赋值 */
ISP_ADDRL = (unsigned char)(byte_addr & 0x00ff);
ISP_CMD = ISP_CMD & 0xf8; /* 清除低3位 */
ISP_CMD = ISP_CMD | RdCommand; /* 写入读命令 */
ISPgoon(); /* 触发执行 */
ISP_IAP_disable(); /* 关闭ISP,IAP功能 */
EA = 1;
return (ISP_DATA); /* 返回读到的数据 */
}
/* ================== 扇区擦除 ======================== */
void SectorErase(unsigned int sector_addr)
{
unsigned int iSectorAddr;
iSectorAddr = (sector_addr & 0xfe00); /* 取扇区地址 */
ISP_ADDRH = (unsigned char)(iSectorAddr >> 8);
ISP_ADDRL = 0x00;
ISP_CMD = ISP_CMD & 0xf8; /* 清空低3位 */
ISP_CMD = ISP_CMD | EraseCommand; /* 擦除命令3 */
ISPgoon(); /* 触发执行 */
ISP_IAP_disable(); /* 关闭ISP,IAP功能 */
}
/* ==================== 字节写 ======================== */
void byte_write(unsigned int byte_addr, unsigned char original_data)
{
EA = 0;
// SectorErase(byte_addr);
ISP_ADDRH = (unsigned char)(byte_addr >> 8); /* 取地址 */
ISP_ADDRL = (unsigned char)(byte_addr & 0x00ff);
ISP_CMD = ISP_CMD & 0xf8; /* 清低3位 */
ISP_CMD = ISP_CMD | PrgCommand; /* 写命令2 */
ISP_DATA = original_data; /* 写入数据准备 */
ISPgoon(); /* 触发执行 */
ISP_IAP_disable(); /* 关闭IAP功能 */
EA =1;
}
#endif
复制代码
chengxu.doc
2018-5-14 15:38 上传
点击文件名下载附件
下载积分: 黑币 -5
68 KB, 下载次数: 15, 下载积分: 黑币 -5
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1