找回密码
 立即注册

QQ登录

只需一步,快速开始

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

单片机控制风扇程序

[复制链接]
跳转到指定楼层
楼主
ID:329632 发表于 2018-5-14 15:38 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
单片机源程序如下:
  1. //宏定义
  2. #define uchar unsigned char
  3. #define uint unsigned int

  4. //包含头文件
  5. #include <reg52.h>
  6. #include <18b20.h>
  7. #include <stdlib.h>
  8. #include <intrins.h>
  9. #include <eeprom52.h>
  10. #define Imax 14000    //此处为晶振为11.0592时的取值,
  11. #define Imin 8000    //如用其它频率的晶振时,
  12. #define Inum1 1450    //要改变相应的取值。
  13. #define Inum2 700
  14. #define Inum3 3000
  15. sbit K1=P1^1;
  16. sbit K2=P1^2;
  17. sbit K3=P1^3;                  //按键定义
  18. sbit PWM=P3^6;                  //PWM输出
  19. sbit BUZZ=P1^4;                  //蜂鸣器控制脚
  20. sbit RSD=P2^0;                  //热释电引脚
  21. unsigned char Im[4]={0x00,0x00,0x00,0x00};
  22. uchar displaydata[4]; //显示暂存数组
  23. //全局变量
  24. char f,dang,count,count1,a_a;  //档位
  25. unsigned long m,Tc;
  26. unsigned char IrOK;          //定义红外工作变量
  27. void   jisuan();          //声明计算函数
  28. uchar mode;
  29. char sec_b=0;
  30. bit flag_b=0;
  31. uint TH,TL;                          //上下限变量
  32. uchar baif,suiji;
  33. unsigned char code duan[17]={
  34. 0x5F,0x44,0x9D,0xD5,0xC6,0xD3,0xDB,0x47,0xDF,0xD7,    0xCF,0xDA,0x98,0xDC,0x9B,0x8B}; //接线从高到低:g c dp d e b f a
  35. //0、1、2、3、4、5、6、7、8、9、A、b、c、d、E、F的显示码                                                          //
  36. unsigned char code wei[8]={          //数码管的位选
  37. 0xef,0xdf,0xbf,0x7f,0xfe,0xfd,0xfb,0xf7};
  38. uchar code zhuanhuan[4]={10,5,3,0};//转换数组
  39. void write_eeprom()                           //内部eeprom写函数
  40. {

  41.         SectorErase(0x2000);                   //清空
  42.         SectorErase(0x2c00);
  43.         SectorErase(0x2e00);
  44.         byte_write(0x2c00,TH/256);       
  45.         byte_write(0x2c01,TH%256);
  46.         byte_write(0x2c02,TL/256);
  47.         byte_write(0x2c03,TL%256);           //将上下限数据保存到eeprom
  48.         byte_write(0x2c04,dang);       
  49.         byte_write(0x2c05,mode);               
  50.         byte_write(0x2060,0x01);

  51. }

  52. /******************把数据从单片机内部eeprom中读出来*****************/
  53. void read_eeprom()                                                                                                                                  
  54. {

  55.     mode = byte_read(0x2c05);
  56.         dang = byte_read(0x2c04);
  57.         TH = byte_read(0x2c00)*256+byte_read(0x2c01);
  58.         TL = byte_read(0x2c02)*256+byte_read(0x2c03);
  59.         a_a = byte_read(0x2060);
  60.          
  61. }

  62. /**************开机自检eeprom初始化*****************/
  63. void init_eeprom()
  64. {
  65.         a_a = byte_read(0x2060);
  66.         if(a_a != 1)                //新的单片机初始单片机内问eeprom
  67.         {
  68.        
  69.                 a_a = 1;
  70.                 write_eeprom();           //保存数据
  71.         }       
  72. }

  73. void delay(uint z)         //延时函数
  74. {
  75.   uint z1,z2;
  76.   for(z1=0;z1<z;z1++)
  77.   for(z2=0;z2<110;z2++);
  78. }

  79. void display()                          //显示函数
  80. {
  81.   uchar i;
  82. if(mode==0)            //无极变速
  83. {
  84.    displaydata[0]=0x00;
  85.    displaydata[1]=duan[disdata[1]];
  86.    displaydata[2]=duan[disdata[2]]|0x20;
  87.    displaydata[3]=duan[disdata[3]];
  88. }
  89.   else if(mode==1)                    //上限
  90. {
  91.    displaydata[0]=0xce;        //H                   11001110
  92.    displaydata[1]=duan[TH%1000/100];
  93.    displaydata[2]=duan[TH%100/10]|0x20;
  94.    displaydata[3]=duan[TH%10];
  95. }
  96.   else if(mode==2)                                   //下限
  97. {
  98.    displaydata[0]=0x1a;                         //L   00111000
  99.    displaydata[1]=duan[TL%1000/100];
  100.    displaydata[2]=duan[TL%100/10]|0x20;
  101.    displaydata[3]=duan[TL%10];
  102. }
  103.    else if(mode==3)          //档位0到3档
  104. {
  105.    displaydata[0]=duan[dang];
  106.    displaydata[1]=0x80;         //01000000
  107.    displaydata[2]=duan[disdata[1]];
  108.    displaydata[3]=duan[disdata[2]];
  109. }
  110.     else if(mode==4)
  111. {
  112.    displaydata[0]=0xda;        //b自然风
  113.    displaydata[1]=duan[disdata[1]];
  114.    displaydata[2]=duan[disdata[2]]|0x20;
  115.    displaydata[3]=duan[disdata[3]];
  116. }

  117.         for(i=0;i<4;i++)                //循环4次显示4位数码管
  118.         {
  119.             P2=wei[i];                        //选中位
  120.                 P0=displaydata[i];        //送入显示码
  121.             delay(3);                        //延时
  122.                 P2=0xff;                        //关闭位
  123.                 P0=0x00;                        //复位显示码
  124.         }

  125. }
  126. void key()                                                          //按键函数
  127. {
  128.   if(K1==0||(Im[2]==0x47&&IrOK==1))          //按键1按下或者遥控器上的按键按下
  129.   {
  130.    delay(5);                                                  //延时去抖

  131.     if(K1==0||(Im[2]==0x47&&IrOK==1)) //再次判断按键按下
  132.         {
  133.                 BUZZ=0;
  134.                 delay(20);
  135.                 BUZZ=1;                                                  //按键音
  136.          mode++;                                                  //模式加
  137.          if(mode>4)                                                  //模式加到大于4
  138.          mode=0;                                                  //模式清零
  139. //         Im[2]=0;
  140.          IrOK=0;                                                  //变量清零
  141.          write_eeprom();                                  //写入eeprom数据
  142.          while(!K1);                                          //按键释放
  143.         }
  144.   }
  145.   if(K2==0||(Im[2]==0x40&&IrOK==1))
  146.   {
  147.    delay(5);

  148.     if(K2==0||(Im[2]==0x40&&IrOK==1))
  149.         {
  150.                 BUZZ=0;
  151.                 delay(20);
  152.                 BUZZ=1;
  153.          if(mode==1)                                        //模式等于1时
  154.          {
  155.           TH++;                                                        //上限加
  156.           if(TH>999)                                        //上限加到大于99.9度
  157.                  
  158.           TH=TL+1;                                                //上限等于下限加一
  159.          }
  160.          else if(mode==2)                                //模式等于2时
  161.          {
  162.           TL++;                                                        //下限加
  163.           if(TL>=TH)                                        //下限加到大于等于上限
  164.           TL=TH-1;                                                //下限等于上限减一
  165.          }
  166.           else if(mode==3)                                //模式等于3时
  167.          {
  168.           dang++;                                                //档位加一
  169.           if(dang>3)                                        //档位大于3时
  170.           dang=0;                                                //档位清零
  171.          }
  172.          Im[2]=0;
  173.          IrOK=0;                                                //红外变量清零
  174.           write_eeprom();                                //写入eeprom数据
  175.          while(!K2);                                        //按键释放
  176.         }

  177.   }

  178.   if(K3==0||(Im[2]==0x19&&IrOK==1))
  179.   {
  180.    delay(5);

  181.     if(K3==0||(Im[2]==0x19&&IrOK==1))
  182.         {
  183.                 BUZZ=0;
  184.                 delay(20);
  185.                 BUZZ=1;
  186.          if(mode==1)
  187.          {
  188.           TH--;
  189.           if(TH<=TL)
  190.           TH=TL+1;
  191.          }
  192.          else if(mode==2)
  193.          {
  194.           TL--;
  195.           if(TL>=TH)
  196.           TL=TH-1;
  197.          }
  198.           else if(mode==3)
  199.          {
  200.            dang--;
  201.           if(dang<0)
  202.           dang=3;
  203.          }
  204.          Im[2]=0;
  205.          IrOK=0;
  206.           write_eeprom();
  207.          while(!K3);
  208.         }
  209.   }
  210. }
  211. void jisuan()                                                          //计算函数
  212. {
  213.   if((mode==0||mode==1||mode==2)&&RSD==1) //模式0、1、2并且热释电有信号时
  214.   {
  215.     if(tvalue<=TL)                                                 //温度小于下限时
  216.         PWM=1;                                                                 //关闭输出,占空比0%
  217.         else if(tvalue>=TH)                                         //温度大于等于上限
  218.         PWM=0;                                                                 //打开输出,占空比100%
  219.         else                                                                  //其他状态时
  220.         {
  221.           baif=(((tvalue-TL)*50)/(TH-TL));   //占空比控制变量计算得到
  222. //计算方法:当前温度减去下限值乘以5再除以上限减下限
  223.           if(count1>baif) //根据变量判断占空比大小
  224.           PWM=1;                  //关闭风扇
  225.           else
  226.           PWM=0;                  //打开风扇
  227.         }
  228.   }
  229.   else if(mode==3)                                           //模式3时
  230.   {
  231.     if(count1>(zhuanhuan[dang]*5))           //根据档位计算出占空比
  232.         PWM=0;
  233.         else
  234.         PWM=1;
  235.   }
  236.   else if((mode==4&&flag_b==0)&&RSD==1)        //模式4时,热释电有信号
  237.   {
  238.    suiji=rand();                                  //读随机函数
  239.    suiji=suiji%23;                                  //随机数计算
  240.    if(10>suiji)                                          //判断随机数是否小于10
  241.    PWM=0;                                                  //输出开
  242.    else                                                          //随机数大于等于10
  243.    PWM=1;                                                  //输出关
  244.         flag_b=1;                                          //变量置1
  245.   }
  246.   if(RSD==0&&mode!=3)                          //热释电没有信号时
  247.   PWM=1;                                                  //关闭输出
  248. }
  249. void main()                                                  //主函数
  250. {
  251.   uint count;                                          //定义变量
  252.   EA=1;                                                          //打开中断总开关
  253.   EX1=1;                                                  //打开外部中断1
  254.   IT1=1;                                                  //下降沿有效
  255.   TMOD=0x11;                                          //定时器工作方式

  256.   TR0=0;                                                  //关闭T0
  257.   TH0=0;
  258.   TL0=0;                                                  //初值0
  259.   ET1=1;                                                  //T1允许中断

  260.   TR1=1;                                                  //T1打开中断
  261.   TH1=0xfc;
  262.   TL1=0x18;                                                  //T1初值1ms
  263.   mode=0;                                                  //初始模式0
  264.   TH=300;
  265.   TL=200;                                                  //上下限初始值
  266.   init_eeprom();                                  //初始化eeprom
  267.   read_eeprom();                                  //读取eeprom数据
  268. while(1)                                                  //进入循环
  269.         {            
  270.                 jisuan();                                  //计算函数
  271.                 count++;                                  //变量加
  272.                 if(count>200)                          //加到大于200
  273.                 {
  274.                         count=0;                          //清零
  275.                         TR1=0;                                  //关闭定时器T1
  276.                         read_wendu();                  //读取温度
  277.                         TR1=1;                                  //打开定时器T1
  278.                 }
  279.                 jisuan();                                  //计算函数
  280.                 display();                                  //显示函数
  281.                 key();                                          //按键函数
  282.                 jisuan();                                  //计算函数
  283.         }
  284. }
  285. void timer1() interrupt 3                  //定时器T1工作函数
  286. {
  287. TH1=0xfc;
  288. TL1=0x18;                                                  //重新赋初值

  289.   count1++;                                                  //加
  290.   if(count1>50)
  291.   {
  292.           count1=0;
  293.         if(mode==4&&flag_b==1)                 //模式等于4时,变量为1
  294.         {
  295.                 sec_b++;                                 //变量加
  296.                 if(sec_b>=8)                         //加到8时
  297.                 {
  298.                         sec_b=0;                         //清零
  299.                         flag_b=0;                         //清零
  300.                 }
  301.         }
  302.   }
  303. }

  304. void intersvr1(void) interrupt 2                 //红外工作函数
  305. {
  306. TR0=1;
  307. Tc=TH0*256+TL0;//提取中断时间间隔时长
  308. TH0=0;
  309. TL0=0;         //定时中断重新置零
  310. if((Tc>Imin)&&(Tc<Imax))
  311. {
  312.         m=0;
  313.         f=1;

  314.         return;
  315. }       //找到启始码
  316. if(f==1)
  317. {
  318.     if(Tc>Inum1&&Tc<Inum3)
  319.     {
  320.            Im[m/8]=Im[m/8]>>1|0x80; m++;
  321.     }
  322.     if(Tc>Inum2&&Tc<Inum1)
  323.     {
  324.       Im[m/8]=Im[m/8]>>1; m++; //取码
  325.            }
  326.            if(m==32)
  327.     {
  328.       m=0;  
  329.       f=0;
  330.        
  331.       if(Im[2]==~Im[3])
  332.       {
  333.            IrOK=1;
  334.                           TR0=0;
  335.            }
  336.       else
  337.           {
  338.            IrOK=0;   //取码完成后判断读码是否正确

  339.            }
  340.     }
  341.                //准备读下一码
  342. }


  343. }


  344. Ds18b20
  345. sbit DQ=P1^0;//ds18b20与单片机连接口

  346. uchar data disdata[5];
  347. uint tvalue;//温度值
  348. uchar tflag;//温度正负标志

  349. /******************************ds1820程序***************************************/
  350. void delay_18B20(uchar k)//延时1微秒
  351. {
  352.         while(k--);
  353. }

  354. void ds1820rst()/*ds1820复位*/
  355. {  
  356.      
  357.          DQ = 1;          //DQ复位
  358.          delay_18B20(4);  //延时
  359.          DQ = 0;          //DQ拉低
  360.          delay_18B20(100); //精确延时大于480us
  361.          DQ = 1;          //拉高
  362.          delay_18B20(40);         
  363. }  
  364.   
  365. uchar ds1820rd()/*读数据*/
  366. {   
  367.      unsigned char i=0;
  368.          unsigned char dat = 0;
  369.          for (i=8;i>0;i--)
  370.          {   DQ = 0; //给脉冲信号
  371.                   dat>>=1;
  372.                   DQ = 1; //给脉冲信号
  373.                   if(DQ)
  374.                   dat|=0x80;
  375.                   delay_18B20(10);//延时106us
  376.          }
  377.         return(dat);
  378. }

  379. void ds1820wr(uchar wdata)/*写数据*/
  380. {
  381.     unsigned char i=0;
  382.     for (i=8; i>0; i--)
  383.    {
  384.      DQ = 0;
  385.      DQ = wdata&0x01;
  386.      delay_18B20(10);//延时106us
  387.      DQ = 1;
  388.      wdata>>=1;
  389.    }
  390. }
  391.   


  392. uint read_wendu()/*读取温度值并转换*/
  393. {
  394.   uchar a,b;
  395.   ds1820rst();   
  396.   ds1820wr(0xcc);//*跳过读序列号*/
  397.   ds1820wr(0x44);//*启动温度转换*/
  398.   ds1820rst();   
  399.   ds1820wr(0xcc);//*跳过读序列号*/
  400.   ds1820wr(0xbe);//*读取温度*/
  401.   a=ds1820rd();
  402.   b=ds1820rd();
  403.   tvalue=b;
  404.   tvalue<<=8;
  405.   tvalue=tvalue|a;
  406.   if(tvalue<0x0fff)
  407.   tflag=0;
  408.   else
  409.   {
  410.     tvalue=~tvalue+1;
  411.         tflag=1;
  412.   }
  413.   tvalue=tvalue*(0.625);//温度值扩大10倍,精确到1位小数
  414.      disdata[1]=tvalue%1000/100;//十位数
  415.     disdata[2]=tvalue%100/10;//个位数
  416.     disdata[3]=tvalue%10;//小数位
  417.   return(tvalue);
  418. }

  419. eeprom
  420. #ifndef _EEPROM52_H_
  421. #define _EEPROM52_H_


  422. /********STC89C51扇区分布*******
  423. 第一扇区:1000H--11FF
  424. 第二扇区:1200H--13FF
  425. 第三扇区:1400H--15FF
  426. 第四扇区:1600H--17FF
  427. 第五扇区:1800H--19FF
  428. 第六扇区:1A00H--1BFF
  429. 第七扇区:1C00H--1DFF
  430. 第八扇区:1E00H--1FFF
  431. *****************/

  432. /********STC89C52扇区分布*******
  433. 第一扇区:2000H--21FF
  434. 第二扇区:2200H--23FF
  435. 第三扇区:2400H--25FF
  436. 第四扇区:2600H--27FF
  437. 第五扇区:2800H--29FF
  438. 第六扇区:2A00H--2BFF
  439. 第七扇区:2C00H--2DFF
  440. 第八扇区:2E00H--2FFF
  441. *****************/


  442. #define RdCommand 0x01 //定义ISP的操作命令
  443. #define PrgCommand 0x02
  444. #define EraseCommand 0x03
  445. #define Error 1
  446. #define Ok 0
  447. #define WaitTime 0x01 //定义CPU的等待时间
  448. sfr ISP_DATA=0xe2;  //寄存器申明
  449. sfr ISP_ADDRH=0xe3;
  450. sfr ISP_ADDRL=0xe4;
  451. sfr ISP_CMD=0xe5;
  452. sfr ISP_TRIG=0xe6;
  453. sfr ISP_CONTR=0xe7;

  454. /* ================ 打开 ISP,IAP 功能 ================= */
  455. void ISP_IAP_enable(void)
  456. {
  457.          EA = 0;       /* 关中断   */
  458.          ISP_CONTR = ISP_CONTR & 0x18;       /* 0001,1000 */
  459.          ISP_CONTR = ISP_CONTR | WaitTime; /* 写入硬件延时 */
  460.          ISP_CONTR = ISP_CONTR | 0x80;       /* ISPEN=1  */
  461. }
  462. /* =============== 关闭 ISP,IAP 功能 ================== */
  463. void ISP_IAP_disable(void)
  464. {
  465.          ISP_CONTR = ISP_CONTR & 0x7f; /* ISPEN = 0 */
  466.          ISP_TRIG = 0x00;
  467.          EA   =   1;   /* 开中断 */
  468. }
  469. /* ================ 公用的触发代码 ==================== */
  470. void ISPgoon(void)
  471. {
  472.          ISP_IAP_enable();   /* 打开 ISP,IAP 功能 */
  473.          ISP_TRIG = 0x46;  /* 触发ISP_IAP命令字节1 */
  474.          ISP_TRIG = 0xb9;  /* 触发ISP_IAP命令字节2 */
  475.          _nop_();
  476. }
  477. /* ==================== 字节读 ======================== */
  478. unsigned char byte_read(unsigned int byte_addr)
  479. {
  480.         EA = 0;
  481.          ISP_ADDRH = (unsigned char)(byte_addr >> 8);/* 地址赋值 */
  482.          ISP_ADDRL = (unsigned char)(byte_addr & 0x00ff);
  483.          ISP_CMD   = ISP_CMD & 0xf8;   /* 清除低3位  */
  484.          ISP_CMD   = ISP_CMD | RdCommand; /* 写入读命令 */
  485.          ISPgoon();       /* 触发执行  */
  486.          ISP_IAP_disable();    /* 关闭ISP,IAP功能 */
  487.          EA  = 1;
  488.          return (ISP_DATA);    /* 返回读到的数据 */
  489. }
  490. /* ================== 扇区擦除 ======================== */
  491. void SectorErase(unsigned int sector_addr)
  492. {
  493.          unsigned int iSectorAddr;
  494.          iSectorAddr = (sector_addr & 0xfe00); /* 取扇区地址 */
  495.          ISP_ADDRH = (unsigned char)(iSectorAddr >> 8);
  496.          ISP_ADDRL = 0x00;
  497.          ISP_CMD = ISP_CMD & 0xf8;   /* 清空低3位  */
  498.          ISP_CMD = ISP_CMD | EraseCommand; /* 擦除命令3  */
  499.          ISPgoon();       /* 触发执行  */
  500.          ISP_IAP_disable();    /* 关闭ISP,IAP功能 */
  501. }
  502. /* ==================== 字节写 ======================== */
  503. void byte_write(unsigned int byte_addr, unsigned char original_data)
  504. {
  505.          EA  = 0;
  506. //         SectorErase(byte_addr);
  507.          ISP_ADDRH = (unsigned char)(byte_addr >> 8);  /* 取地址  */
  508.          ISP_ADDRL = (unsigned char)(byte_addr & 0x00ff);
  509.          ISP_CMD  = ISP_CMD & 0xf8;    /* 清低3位 */
  510.          ISP_CMD  = ISP_CMD | PrgCommand;  /* 写命令2 */
  511.          ISP_DATA = original_data;   /* 写入数据准备 */
  512.          ISPgoon();       /* 触发执行  */
  513.          ISP_IAP_disable();     /* 关闭IAP功能 */
  514.          EA =1;
  515. }
  516. #endif

复制代码



chengxu.doc

68 KB, 下载次数: 15, 下载积分: 黑币 -5

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

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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