通过DS18b20来测温度,在lcd1602上显示温度和时间,时间初始值设为18:30,当温度超过26度时,直流电机打开,蜂鸣器报警,低于26关闭。也可遥控打开或关闭电机,没有使用舵机,此时直流电机不能改变方向。
当遥控器按下时,lcd1602显示turn off,无法显示温度,定时器1初始化,舵机可以使用,利用舵机对直流电机来控制方向,只有0,45,90,135,180,五个角度可以选。
将ds18b20和舵机分开使用的原因,ds18b20对时序的要求很高,如果用舵机的话就会使温度无法正常显示,
遇到的问题:
刚开始是直接在main函数里面使用舵机和温度传感器,发现温度显示不了,然后我想的在main函数用舵机,然后再用一个定时器,每隔一定时间显示温度,这样用到两个定时器,需要考虑优先级,舵机用定时器1,温度用定时器0,这样才能每隔一定时间刷新温度,但是这样发现舵机和温度都不能正常工作,我认为,因为舵机要保持一个角度话,必须持续给他该角度下的脉冲,两个定时器可能冲突了,
然后我就将两个东西分开用,在两者之间来回切换,在用完舵机,准备用18b20的时候,就令TR1=0;可是这样做温度还是显示不了,而且在关定时器的同时,我还重新初始化18b20和lcd1602,还是没用,但是如果按下复位键的话,就可以显示,在网上找了很久也提问了没有结果,我试过用串口打印ds18b20i/o的值,发现如果没切换,可以打印温度,切换后就没有值打印出来,于是我就想能不能在按下遥控上的键就执行软件复位,但是有人说,51不能软件复位,我最后居然想的是,(我看开发板原理图,发现复位键按下时,RST管脚就为高电平,RST管脚默认为低电平),我用一根杜邦线,一端接在RST上,另一端就随便接在一个管脚上P1^1,通过改变P1^1的电平,来改变RST的电压,但是给P1^1高电平的时候,并没有复位,有人说,可能是电压不够。我分别测了一下,它的对地电压只有2.4v的样子。
复位按键下两端的电压大约4.8v左右,确实是电压不不够,我想升压,我想起来有些管脚它是本身开发板就给他加了上拉电阻,看了原理图,测了一下其中一个电压,果然有4.4v,我把它接到RST的时候,就复位了,但是我这样做发现,在程序中一但执行复位后,它会一直复位,比如P3^6=1;//复位delay(1000);P3^6=0;//P3^6管脚有上拉电阻。在它复位后,P1^1=0;根本没机会执行;而P3^6默认为高电平。这种方法就不行。
我最后就打算手动复位,我准备加上ds1302,让1302和温度同时显示,发现温度又用不了,我在网上看到有一些人也是同样的问题,但是在一个论坛里面,有人说在1302读温度的时候,在最后,让CE=1;就可以了,不过他也不知道原因,百度上显示ds1302有些是CE,有些是RST,RST是CE的旧称,我试了一下,发现可以,而且把之前切换后不能显示的问题也解决了,就是不知道原因。到这里我要做的就基本完成了。
待改进:
最需要改进两个地方
1.直流电机的速度没能实现调节
2.舵机的角度不能为任意角度转动
单片机源程序如下:
- #include "reg52.h"
- #include"temp.h"
- #include"1302.h"
- sbit IRIN=P3^2; //红外
- sbit duoji=P3^5;
- uchar IrValue[6];//温度数组
- uchar zxc,count=0,flag1=1,flag2,k,m;
- uchar Disp[16]="trun off ";
- uchar push_val_left=14,pwm_val_left;
- uint timer=0,flex;
- uchar DisplayData[14]={'t'-0x30,'e'-0x30,'m'-0x30,'p'-0x30,':'-0x30,' '-0x30};
- uchar code smgduan[10]={0,1,2,3,4,5,6,7,8,9};
- void pwm_Servomoto_angle(unsigned int angle,unsigned int Servo_time)
- {
- push_val_left=5+angle*20/180; //舵机向左转90度
- // timer=0;
- while(timer<=Servo_time); //延时400MS让舵机转到其位置 4000
- delay(flex);
- }
- void pwm_Servomoto(void)
- {
-
- if(pwm_val_left<=push_val_left)
- duoji=1;
- else
- duoji=0;
- if(pwm_val_left>=200)
- pwm_val_left=0;
-
- }
- void datapros(int temp)
- {
- float tp; uint h=4000;
- if(temp< 0) //当温度值为负数
- {
- DisplayData[0] = 0x40; // -
- //因为读取的温度是实际温度的补码,所以减1,再取反求出原码
- temp=temp-1;
- temp=~temp;
- tp=temp;
- temp=tp*0.0625*100+0.5;
-
-
- }
- else
- {
- DisplayData[6] = 0x00;
- tp=temp;//因为数据处理有小数点所以将温度赋给一个浮点型变量
- //如果温度是正的那么,那么正数的原码就是补码它本身
- temp=tp*0.0625*100+0.5;
-
- }
- if(flag2==0)
- if(temp>2600)
- {dj=1;
- while(h)
- {beep=~beep;
- delay(10);
- h--;
- }
- }
- else
- dj=0;
- DisplayData[7] = smgduan[temp / 10000];
- DisplayData[8] = smgduan[temp % 10000 / 1000];
- DisplayData[9] = smgduan[temp % 1000 / 100] ;
- DisplayData[10] = -2;
- DisplayData[11] = smgduan[temp % 100 / 10];
- DisplayData[12] = smgduan[temp % 10];
- DisplayData[13] =51;
-
- }
- void test_servo(void)
- {
- int pos;
- for(pos=0;pos<180;pos+=3)
- {
-
-
- pwm_Servomoto_angle(pos,100) ;
- delay(300);
- }
- for(pos = 180; pos>=0; pos-=3) // goes from 180 degrees to 0 degrees
- {
-
- pwm_Servomoto_angle(pos,100) ;
- delay(300);
- }
- }
-
- void LcdDisplay()
- {
- lcdwrc(0x80+0X40);
- lcdwrd('t');
- lcdwrd('i');
- lcdwrd('m');
- lcdwrd('e');
- lcdwrd(':');
- lcdwrd(' ');
- lcdwrd('0'+hsp[2]/16); //时
- lcdwrd('0'+(hsp[2]&0x0f));
- lcdwrd('-');
- lcdwrd('0'+hsp[1]/16); //分
- lcdwrd('0'+(hsp[1]&0x0f));
- lcdwrd('-');
- lcdwrd('0'+hsp[0]/16); //秒
- lcdwrd('0'+(hsp[0]&0x0f));
- }
- //外部中断0初始化
- void IrInit()
- {
- IT0=1;//下降沿触发
- EX0=1;//打开中断0允许
- EA=1; //打开总中断
- IRIN=1;//初始化端口
- }
- //定时器1初始化
- void timeinit()
- {TMOD=0X10;
- TH1=(65536-100)/256; //100US定时
- TL1=(65536-100)%256;
- TR1= 1;
- ET1= 1;
- EA = 1;
- }
- //main函数
- void main()
- {uchar i,n=0;
- IrInit(); //红外初始化
- lcdinit();
- Ds1302Init();
- dj=0;
- while(1)
- {
- if(flag1==1) //关闭定时器,实现功能为超过设定温度打开电机
- {
- Ds1302ReadTime();
- datapros(Ds18b20ReadTemp()); //数据处理函数
- for(i=0;i<14;i++)
- {
- lcdwrd(DisplayData[i]+0x30);
- }
- LcdDisplay();
- lcdwrc(0x80);
- }
- else //打开定时器,(电机舵机)关闭温度传感器,和lcd1602
- { if(m==0)
- { timeinit();
- m=1;
- dj=0;
- }
- test_servo();
- for(n=0;n<16;n++)
- {
- lcdwrd(Disp[n]);
- }
- lcdwrc(0x80+0x40);
- for(n=0;n<16;n++)
- { lcdwrd(' ');
- }
-
- lcdwrc(0x80);
- }
-
- }
- }
- void ReadIr() interrupt 0
- {
- uchar j,k;
- uchar err;
- zxc=0;
- delay(700); //7ms
- if(IRIN==0) //确认是否真的接收到正确的信号
- {
-
- err=1000; //1000*10us=10ms,超过说明接收到错误的信号
-
- while((IRIN==0)&&(err>0)) //等待前面9ms的低电平过去
- {
- delay(1);
- err--;
- }
- if(IRIN==1) //如果正确等到9ms低电平
- {
- err=500;
- while((IRIN==1)&&(err>0)) //等待4.5ms的起始高电平过去
- {
- delay(1);
- err--;
- }
- for(k=0;k<4;k++) //共有4组数据
- {
- for(j=0;j<8;j++) //接收一组数据
- {
- err=60;
- while((IRIN==0)&&(err>0))//等待信号前面的560us低电平过去
- {
- delay(1);
- err--;
- }
- err=500;
- while((IRIN==1)&&(err>0)) //计算高电平的时间长度。
- {
- delay(10); //0.1ms
- zxc++;
- err--;
- if(zxc>30)
- {
- return;
- }
- }
- IrValue[k]>>=1; //k表示第几组数据
- if(zxc>=8) //如果高电平出现大于565us,那么是1
- {
- IrValue[k]|=0x80;
- }
- zxc=0; //用完时间要重新赋值
- }
- }
- }
- if(IrValue[2]!=~IrValue[3])
- {
- return;
- }
- }
- if(flag1==0)
- {
- if(IrValue[2]==0x45) //电源键 模式一 过温
- {
- flag1=1;
- TR1=0;
- }
- }
-
- if(flag1==1)
- {
- if(IrValue[2]==0x46) //mode 模式二 调整舵机
- {
- flag1=0;
- m=0;
- }
- if(IrValue[2]==0x47)
- {dj=1; // 打开电机 注意flag2的作用为设置为了控制优先级大于if(temp>25)
- flag2=1;
- }
- if(IrValue[2]==0x44) // 关闭电机
- {dj=0;
- flag2=0;
- }
- if(IrValue[2]==0x16) //按键0 舵机0度
- flex=550;
- if(IrValue[2]==0x0c) //按键1 舵机45度
- flex=1100;
- if(IrValue[2]==0x18) //按键2 舵机90度
- ;
- if(IrValue[2]==0x5e) //按键3 舵机135度
- ;
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
温控红外遥控风扇.zip
(2.55 MB, 下载次数: 22)
|