最近为了练习51单片机,便做了一个温控风扇的项目。
先说一下温控风扇的功能吧,对于我来说,已经接触51单片机已经有一年的时间了,可是真正的开始做东西,却没有多长时间。我之前只是用51做过一个光立方。而光立方的代码却十分的简单(只是简单的光立方,,没有涉及更加复杂的原理,,,像神马傅里叶变换,,神马高大上的东西,,,我还是先学好高数吧),只是用了个74HC573进行锁存进而位控制。。。。。从这说起来,光立方基本都是队友焊接的,,我只是一个编程者(苦逼的程序员),而光立方也没有做的多么完美,但是已经尽力了,当时只接触51一个月便做完了光立方。
最近因为一个比赛而接触了温控风扇,当时,,比赛没做出来(我实在是还太水),于是把未完成品带回去继续做,把上面的基本要求加拓展要求基本都做了出来,,唉 ,硬件调试的例程可真是艰辛啊,,代码更不用提 唉 ,说多了鼻子一把泪一把的。。好了,不扯太多东西,进入正题。
此温控风扇的功能:大体来说,分为以下几类:1,电机驱动(不用多说)2,LCD1602(咦,这是做神马的?不用急,下面会提到)3,DS18B20(哎呀,温控啊温控,说实话,这个时序图到现在还没记住,哎呀,只能靠现查了,再copy一下别人的例程修改一下啦),,,,,,有点懒,,但是都看懂啦,也会修改啦。4,红外遥控器加发射器。。。唉,这个红外遥控从一开始到明白可是耗费了我一年的时间啊。5,蜂鸣器,,额外功能,没打算加了。
好了,开始贴贴代码啦啦啦~~~~~~~~~~~~~~~~~~~~~~~~~~·
#include
#include "18B20.h"
#define e P0 //LCD1602的D0~D7
/*****************************************************************************
* TH0和TL0是计数器0的高8位和低8位计数器,计算办法:TL0=(65536-C)%256; *
* TH0=(65536-C)/256,其中C为所要计数的次数即多长时间产生一次中断;TMOD是计数器*
* 工作模式选择,0X01表示选用模式1,它有16位计数器,最大计数脉冲为65536,最长时 *
* 间为1ms*65536=65.536ms *
******************************************************************************/
#define V_TH0 0x0FC
#define V_TL0 0x18
#define V_TMOD 0X01
#define T25 250
#define T30 300
#define T35 350
#define T40 400
sbit lcden=P1^4;//使能端
sbit lcdrs=P1^2;//读写选择端
sbit lcdrw=P1^5;//读写选择端
uchar num;
int result;
bit IrOK;
unsigned char IrValue[6];
unsigned char Time;
void IrInit();
void hongwai();
void deal(uint);
unsigned char ZKB1,ZKB2,ZKB3;
sbit K1=P2^3;
sbit K2=P2^7;
sbit K3=P2^6;
sbit K4=P2^5;
void init_sys(void); /*系统初始化函数*/
void delay(uint z);
sbit IRIN = P3^2;
//--定义全局变量--//
void jiema();
//--声明全局函数--//
extern void DelayMs(unsigned int );
sbit dianji=P1^1;
/*******************************************************************************
* 函数名 : main
* 函数功能 : 主函数
* 输入 : 无
* 输出 : 无
*******************************************************************************/
/*******************************************************************************
* 函数名 : LCD延时
* 函数功能 : 延时
* 输入 : z
* 输出 : 无
*******************************************************************************/
void delay_lcd(uchar z)
{
uint x,y;
for(x=z;x>0;x--)
{
for(y=110;y>0;y--);
}
}
void write_com(uint com)//写命令
{
lcden=0;
lcdrw=0;
lcdrs=0;
e=com;
delay_lcd(5);
lcden=1;
delay_lcd(5);
lcden=0;
}
void init()//进行初始化
{
lcden=0;
write_com(0x3c);
write_com(0x0c);
write_com(0x06);
write_com(0x01);
}
void write_data(uint date)//写数据
{
lcden=0;
lcdrw=0;
lcdrs=1;
e=date;
delay_lcd(15);
lcden=1;
delay_lcd(15);
lcden=0;
}
/*******************************************************************************
*函数名 :红外遥控
*函数功能 :红外遥控
*输入 ;无
*输出 ; 无
**********************************************************************************/
void hongwai()
{
dianji=0;
// unsigned char i;
IrInit();
}
/*******************************************************************************
* 函数名 : DelayMs()
* 函数功能 : 延时
* 输入 : x
* 输出 : 无
*******************************************************************************/
void DelayMs(unsigned int x) //0.14ms误差 0us
{
unsigned char i;
while(x--)
{
for (i = 0; i<13; i++)
{}
}
}
/*******************************************************************************
* 函数名 : IrInit()
* 函数功能 : 初始化红外线接收
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void IrInit()
{
IT0=1;//下降沿触发
EX0=1;//打开中断0允许
EA=1; //打开总中断
IRIN=1;//初始化端口
}
/*******************************************************************************
* 函数名 : ReadIr()
* 函数功能 : 读取红外数值的中断函数
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void ReadIr() interrupt 0
{
unsigned char j,k;
unsigned int err;
uchar code LCD_hongwai[]="B 0123456789";//hongwai
Time=0;
DelayMs(70);
if(IRIN==0) //确认是否真的接收到正确的信号
{
err=1000; //1000*10us=10ms,超过说明接收到错误的信号
/*当两个条件都为真是循环,如果有一个条件为假的时候跳出循环,免得程序出错的时
侯,程序死在这里*/
while((IRIN==0)&&(err>0)) //等待前面9ms的低电平过去
{
DelayMs(1);
err--;
}
if(IRIN==1) //如果正确等到9ms低电平
{
err=500;
while((IRIN==1)&&(err>0)) //等待4.5ms的起始高电平过去
{
DelayMs(1);
err--;
}
for(k=0;k<4;k++) //共有4组数据
{
for(j=0;j<8;j++) //接收一组数据
{
err=60;
while((IRIN==0)&&(err>0))//等待信号前面的560us低电平过去
{
DelayMs(1);
err--;
}
err=500;
while((IRIN==1)&&(err>0)) //计算高电平的时间长度。
{
DelayMs(1);//0.14ms
Time++;
err--;
if(Time>30)
{
EX0=1;
return;
}
}
IrValue[k]>>=1; //k表示第几组数据
if(Time>=8) //如果高电平出现大于565us,那么是1
{
IrValue[k]|=0x80;
}
Time=0; //用完时间要重新赋值
}
}
}
if(IrValue[2]!=~IrValue[3])
{
IrOK=0;
return;
}
else
{
IrOK=1;
if (IrValue[2]==0x08)
{
write_com(0x80);
write_data(LCD_hongwai[0]);
delay(5);
write_data(LCD_hongwai[1]);
delay(5);
write_data(LCD_hongwai[2+temp_bai]);
delay(5);
write_data(LCD_hongwai[2+temp_shi]);
delay(5);
write_data(LCD_hongwai[2+temp_ge]);
delay(5);
result=ZKB1;
}
else if(IrValue[2]==0x18)
{
write_com(0x80);
write_data(LCD_hongwai[0]);
delay(5);
write_data(LCD_hongwai[1]);
delay(5);
write_data(LCD_hongwai[2+temp_bai]);
delay(5);
write_data(LCD_hongwai[2+temp_shi]);
delay(5);
write_data(LCD_hongwai[2+temp_ge]);
delay(5);
result=ZKB2;
}
else if(IrValue[2]==0x0C)
{
write_com(0x80);
write_data(LCD_hongwai[0]);
delay(5);
write_data(LCD_hongwai[1]);
delay(5);
write_data(LCD_hongwai[2+temp_bai]);
delay(5);
write_data(LCD_hongwai[2+temp_shi]);
delay(5);
write_data(LCD_hongwai[2+temp_ge]);
delay(5);
result=ZKB3;
}
else
{
dianji=0;
}
}
IrOK=0;
}
}
void main (void)
{
uchar code LCD[]="0123456789";
uchar code LCD_anjian1[]="A1 0123456789";//ZKB1
uchar code LCD_anjian2[]="A2 0123456789";//ZKB2
uchar code LCD_anjian3[]="A3 0123456789";//ZKB3
uchar code LCD_anjian4[]="A4 0123456789";//稳控
uchar code LCD_hongwai[]="B 0123456789";//hongwai
init();
hongwai();
Init_DS18B20();
ReadOneChar();
WriteOneChar(dat);
ReadTemperature();
ZKB1=30; /*占空比初始值设定*/
ZKB2=0;
ZKB3=90;
init_sys();
temp_broken();
while(1)
{
if(K1==0)
delay(20);
if(K1==0)
{
result=ZKB1;
write_com(0x80);
write_data(LCD_anjian1[0]);
delay(5);
write_data(LCD_anjian1[1]);
delay(5);
write_data(LCD_anjian1[2]);
delay(5);
write_data(LCD_anjian1[3+temp_bai]);
delay(5);
write_data(LCD_anjian1[3+temp_shi]);
delay(5);
write_data(LCD_anjian1[3+temp_ge]);
delay(5);
}
if(K2==0)
delay(20);
if(K2==0)
{
result=ZKB2;
write_com(0x80);
write_data(LCD_anjian2[0]);
delay(5);
write_data(LCD_anjian2[1]);
delay(5);
write_data(LCD_anjian2[2]);
delay(5);
write_data(LCD_anjian2[3+temp_bai]);
delay(5);
write_data(LCD_anjian2[3+temp_shi]);
delay(5);
write_data(LCD_anjian2[3+temp_ge]);
delay(5);
}
if(K3==0)
delay(20);
if(K3==0)
{
result=ZKB3;
write_com(0x80);
write_data(LCD_anjian3[0]);
delay(5);
write_data(LCD_anjian3[1]);
delay(5);
write_data(LCD_anjian3[2]);
delay(5);
write_data(LCD_anjian3[3+temp_bai]);
delay(5);
write_data(LCD_anjian3[3+temp_shi]);
delay(5);
write_data(LCD_anjian3[3+temp_ge]);
delay(5);
}
delay(20);
if(K4==0)
delay(20);
if(K4==0)
{
deal(temp);
write_com(0x80);
write_data(LCD_anjian4[0]);
delay(5);
write_data(LCD_anjian4[1]);
delay(5);
write_data(LCD_anjian4[2]);
delay(5);
write_data(LCD_anjian4[3+temp_bai]);
delay(5);
write_data(LCD_anjian4[3+temp_shi]);
delay(5);
write_data(LCD_anjian4[3+temp_ge]);
delay(5);
}
}
/*占空比初始值设定*/
/*对占空比值限定范围*/
}
/******************************************************
*函数功能:对系统进行初始化,包括定时器初始化和变量初始化*/
void init_sys(void) /*系统初始化函数*/
{
/*定时器初始化*/
TMOD=V_TMOD;
TH0=V_TH0;
TL0=V_TL0;
TR0=1;//开启定时器计数
ET0=1;// 开启定时器中断
EA=1;//开启总中断
}
/*中断函数*/
void timer0(void) interrupt 1 using 2
{
uchar click=0; /*中断次数计数器变量*/
TH0=V_TH0; /*恢复定时器初始值*/
TL0=V_TL0;
++click;
if (click>=100)
click=0;
if (click
if(click>=result)
dianji=0;
}
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void deal(uint t)
{
if((t>T25)&&(t
result=ZKB1;
}
if((t>T30)&&(t
result=ZKB3;
}
if((t>T35)&&(t
result=ZKB3;
}
else
dianji=0;
}
也许你会说,,,,咦,,,,18B20.H呢???????????哎呀 别急 继续贴啦啦~~~~~~~~
#ifndef _18B20_H_
#define _18B20_H_
#define uchar unsigned char
#define uint unsigned int
int readdata[2];
uint temp_shi,temp_ge,temp_bai;
uint temp,dat;
float f_temp;
sbit DQ=P3^4;
void delay_18B20(uint i)
{
while(i--);
}
/**********ds18b20初始化函数**********************/
void Init_DS18B20(void)
{
unsigned char x=0;
DQ = 1; //DQ复位
delay_18B20(2); //稍做延时
DQ = 0; //单片机将DQ拉低
delay_18B20(60); //精确延时 大于 480us
DQ = 1; //拉高总线
delay_18B20(2);
x=DQ; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
delay_18B20(15);
}
/***********ds18b20读一个字节**************/
unsigned char ReadOneChar(void)
{
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(4);
}
return(dat);
}
/*************ds18b20写一个字节****************/
void WriteOneChar(unsigned char dat)
{
unsigned char i=0;
for (i=8; i>0; i--)
{
DQ = 0;
DQ = dat&0x01;
delay_18B20(2);
DQ = 1;
dat>>=1;
}
}
ReadTemperature(void)
{
delay_18B20(40); // this message is very important
Init_DS18B20();
delay_18B20(1);
WriteOneChar(0xCC); // 跳过读序号列号的操作
WriteOneChar(0x44); // 启动温度转换
delay_18B20(40); // this message is very important
Init_DS18B20();
WriteOneChar(0xCC); //跳过读序号列号的操作
WriteOneChar(0xBE); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
delay_18B20(40);
readdata[0]=ReadOneChar(); //读取温度值低位
readdata[1]=ReadOneChar(); //读取温度值高位
temp=readdata[1];
temp<<=8;
temp=temp|readdata[0];
f_temp=temp*0.0625;
temp=f_temp*10+0.5;
f_temp=f_temp+0.05;
return temp;
}
void temp_broken() //将temp分成个位和十位还有百位
{
temp_bai=temp/100;
temp_shi=temp%100/10;
temp_ge=temp%100%10;
}
#endif
这些程序中存在有一些问题,就是代码的效率问题,代码的效率不够高,数据结构没怎么学,没怎么分配好内存,不知道如何提速,如何更快的完成一个程序,导致了两个问题:一:导致了LCD1602的显示不是瞬间就显示,而是缓慢的显示出来。二:红外遥控不够灵敏,导致红外遥控有时要按好多下才可以。
温控风扇基本搞定,但是却存在有一些不足之处,还有需要改进的地方,比如说PID模糊控制没有添加进去,直到现在还在认真学习PID模糊控制。
然后接下来,我要做的就是两个项目:一个是基于51单片机的GPRS模块的一个项目。第二个便是最近挺火热的ARDUINO的项目,也是用GPRS来做
做完这两个项目,还有一个,打算开学再做的用ARDUINO做的四轴飞行器。
期间还要学习模电的知识,确实任务量很大,任务量很是艰巨,但是,我要做到这一些,加油!!!!!!!