找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2029|回复: 0
打印 上一主题 下一主题
收起左侧

单片机温控红外遥控风扇源程序 舵机对直流电机控制方向

[复制链接]
跳转到指定楼层
楼主
ID:638921 发表于 2020-11-26 22:04 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
通过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.舵机的角度不能为任意角度转动


单片机源程序如下:
  1. #include "reg52.h"                        
  2. #include"temp.h"
  3. #include"1302.h"        
  4. sbit  IRIN=P3^2;  //红外
  5. sbit  duoji=P3^5;

  6. uchar IrValue[6];//温度数组
  7. uchar zxc,count=0,flag1=1,flag2,k,m;
  8. uchar Disp[16]="trun off        ";
  9. uchar push_val_left=14,pwm_val_left;
  10. uint timer=0,flex;

  11. uchar DisplayData[14]={'t'-0x30,'e'-0x30,'m'-0x30,'p'-0x30,':'-0x30,' '-0x30};
  12. uchar code smgduan[10]={0,1,2,3,4,5,6,7,8,9};
  13. void pwm_Servomoto_angle(unsigned int angle,unsigned int Servo_time)
  14. {
  15.                   push_val_left=5+angle*20/180;          //舵机向左转90度
  16.                  // timer=0;
  17.                   while(timer<=Servo_time); //延时400MS让舵机转到其位置                 4000
  18.                   delay(flex);
  19. }
  20. void pwm_Servomoto(void)
  21. {  

  22.     if(pwm_val_left<=push_val_left)
  23.                duoji=1;
  24.         else
  25.                duoji=0;
  26.         if(pwm_val_left>=200)
  27.         pwm_val_left=0;

  28. }

  29. void datapros(int temp)         
  30. {
  31.            float tp; uint h=4000;
  32.         if(temp< 0)                                //当温度值为负数
  33.           {
  34.                 DisplayData[0] = 0x40;           //   -
  35.                 //因为读取的温度是实际温度的补码,所以减1,再取反求出原码
  36.                 temp=temp-1;
  37.                 temp=~temp;
  38.                 tp=temp;
  39.                 temp=tp*0.0625*100+0.5;        
  40.                

  41.           }
  42.          else
  43.           {                        
  44.                 DisplayData[6] = 0x00;
  45.                 tp=temp;//因为数据处理有小数点所以将温度赋给一个浮点型变量
  46.                 //如果温度是正的那么,那么正数的原码就是补码它本身
  47.                 temp=tp*0.0625*100+0.5;        
  48.                
  49.         }
  50.         if(flag2==0)
  51.         if(temp>2600)
  52.            {dj=1;
  53.            while(h)
  54.            {beep=~beep;
  55.            delay(10);
  56.                   h--;
  57.                 }
  58.            }
  59.         else
  60.            dj=0;
  61.         DisplayData[7] = smgduan[temp / 10000];
  62.         DisplayData[8] = smgduan[temp % 10000 / 1000];
  63.         DisplayData[9] = smgduan[temp % 1000 / 100] ;
  64.         DisplayData[10] = -2;
  65.         DisplayData[11] = smgduan[temp % 100 / 10];
  66.         DisplayData[12] = smgduan[temp % 10];
  67.         DisplayData[13] =51;
  68.         
  69. }
  70. void test_servo(void)
  71. {
  72. int pos;
  73.         for(pos=0;pos<180;pos+=3)
  74.         {
  75.                

  76.         
  77.                 pwm_Servomoto_angle(pos,100) ;
  78.                 delay(300);
  79.         }
  80.         for(pos = 180; pos>=0; pos-=3)     // goes from 180 degrees to 0 degrees
  81.         {
  82.         
  83.           pwm_Servomoto_angle(pos,100) ;
  84.           delay(300);
  85.         }
  86. }
  87.                                                                   
  88. void LcdDisplay()
  89. {
  90.         lcdwrc(0x80+0X40);
  91.         lcdwrd('t');
  92.         lcdwrd('i');
  93.         lcdwrd('m');
  94.         lcdwrd('e');
  95.         lcdwrd(':');
  96.         lcdwrd(' ');
  97.         lcdwrd('0'+hsp[2]/16);                                //时
  98.         lcdwrd('0'+(hsp[2]&0x0f));                                 
  99.         lcdwrd('-');
  100.         lcdwrd('0'+hsp[1]/16);                                //分
  101.         lcdwrd('0'+(hsp[1]&0x0f));        
  102.         lcdwrd('-');
  103.     lcdwrd('0'+hsp[0]/16);                                //秒
  104.         lcdwrd('0'+(hsp[0]&0x0f));
  105. }                                                                                          

  106.                                                                 //外部中断0初始化
  107. void IrInit()           
  108. {
  109.         IT0=1;//下降沿触发
  110.         EX0=1;//打开中断0允许
  111.         EA=1;        //打开总中断

  112.         IRIN=1;//初始化端口
  113. }
  114.                                 //定时器1初始化
  115. void timeinit()
  116. {TMOD=0X10;
  117.         TH1=(65536-100)/256;          //100US定时
  118.         TL1=(65536-100)%256;
  119.         TR1= 1;
  120.         ET1= 1;
  121.         EA = 1;
  122. }               

  123.                                 //main函数
  124. void main()
  125. {uchar i,n=0;
  126. IrInit(); //红外初始化
  127. lcdinit();
  128. Ds1302Init();

  129.   dj=0;
  130. while(1)
  131.   {
  132.     if(flag1==1)         //关闭定时器,实现功能为超过设定温度打开电机
  133.        {  
  134.              Ds1302ReadTime();
  135.              datapros(Ds18b20ReadTemp());         //数据处理函数
  136.          for(i=0;i<14;i++)
  137.               {               
  138.                lcdwrd(DisplayData[i]+0x30);
  139.               }
  140.                LcdDisplay();
  141.               lcdwrc(0x80);
  142.            }
  143.     else        //打开定时器,(电机舵机)关闭温度传感器,和lcd1602
  144.             {  if(m==0)
  145.                     { timeinit();
  146.                       m=1;
  147.                           dj=0;
  148.                     }
  149.                         test_servo();
  150.                  for(n=0;n<16;n++)
  151.                {
  152.                     lcdwrd(Disp[n]);        
  153.                 }
  154.                    lcdwrc(0x80+0x40);
  155.                   for(n=0;n<16;n++)
  156.                     { lcdwrd(' ');
  157.                         }
  158.                   
  159.               lcdwrc(0x80);
  160.                 }
  161.                
  162.   }
  163. }
  164. void ReadIr() interrupt 0
  165. {
  166.         uchar j,k;
  167.         uchar err;
  168.     zxc=0;                                         
  169.         delay(700);        //7ms
  170.         if(IRIN==0)                //确认是否真的接收到正确的信号
  171.         {         
  172.                
  173.                 err=1000;                                //1000*10us=10ms,超过说明接收到错误的信号
  174.                         
  175.                 while((IRIN==0)&&(err>0))        //等待前面9ms的低电平过去                  
  176.                 {                        
  177.                         delay(1);
  178.                         err--;
  179.                 }
  180.                 if(IRIN==1)                        //如果正确等到9ms低电平
  181.                 {
  182.                         err=500;
  183.                         while((IRIN==1)&&(err>0))                 //等待4.5ms的起始高电平过去
  184.                         {
  185.                                 delay(1);
  186.                                 err--;
  187.                         }
  188.                         for(k=0;k<4;k++)                //共有4组数据
  189.                         {                                
  190.                                 for(j=0;j<8;j++)        //接收一组数据
  191.                                 {

  192.                                         err=60;               
  193.                                         while((IRIN==0)&&(err>0))//等待信号前面的560us低电平过去
  194.                                         {
  195.                                                 delay(1);
  196.                                                 err--;
  197.                                         }
  198.                                         err=500;
  199.                                         while((IRIN==1)&&(err>0))         //计算高电平的时间长度。
  200.                                         {
  201.                                                 delay(10);         //0.1ms
  202.                                                 zxc++;
  203.                                                 err--;
  204.                                                 if(zxc>30)
  205.                                                 {
  206.                                                         return;
  207.                                                 }
  208.                                         }
  209.                                         IrValue[k]>>=1;         //k表示第几组数据
  210.                                         if(zxc>=8)                        //如果高电平出现大于565us,那么是1
  211.                                         {
  212.                                                 IrValue[k]|=0x80;
  213.                                         }
  214.                                         zxc=0;                //用完时间要重新赋值                                                        
  215.                                 }
  216.                         }
  217.                 }
  218.                 if(IrValue[2]!=~IrValue[3])
  219.                 {
  220.                         return;
  221.                 }
  222.         }
  223.          if(flag1==0)
  224.          {
  225.                 if(IrValue[2]==0x45)   //电源键          模式一 过温
  226.                 {
  227.                    flag1=1;
  228.                 TR1=0;
  229.                 }
  230.         }
  231.            
  232.         if(flag1==1)
  233.         {
  234.                 if(IrValue[2]==0x46)   //mode         模式二 调整舵机
  235.                 {
  236.                         flag1=0;
  237.                     m=0;
  238.                   }
  239.                 if(IrValue[2]==0x47)
  240.                    {dj=1;                                //                打开电机  注意flag2的作用为设置为了控制优先级大于if(temp>25)
  241.                     flag2=1;
  242.                         }
  243.                 if(IrValue[2]==0x44)         //      关闭电机
  244.                    {dj=0;
  245.                     flag2=0;
  246.                    }
  247.                 if(IrValue[2]==0x16)   //按键0 舵机0度
  248.                   flex=550;
  249.                 if(IrValue[2]==0x0c)  //按键1 舵机45度
  250.                   flex=1100;
  251.                 if(IrValue[2]==0x18)  //按键2 舵机90度
  252.                   ;
  253.                 if(IrValue[2]==0x5e)  //按键3 舵机135度
  254.                   ;
  255. ……………………

  256. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码

所有资料51hei提供下载:
温控红外遥控风扇.zip (2.55 MB, 下载次数: 20)


评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏3 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表