单片机教程网

电脑版
提示:原网页已由神马搜索转码, 内容由www.51hei.com提供.
查看:1080|回复:11
打印上一主题下一主题

单片机遥控风扇控制程序,望大师优化

[复制链接]
回帖奖励90 黑币
回复本帖可获得 3 黑币奖励! 每人限 1 次
跳转到指定楼层
楼主
ID:796012发表于 2023-5-23 14:07|只看该作者回帖奖励
  1. /*风扇遥控芯片:BA5104  红外遥控解码程序  晶振频率:11.0592MHZ  1帧12位,一次至少发2帧*//*历时8天成功调试,干扰码直接清零,只显示相关键值*/
  2. /*解码后的键值:关机 0xfd81; 开/风速 0xfd82; 风类 0xfd84; 定时 0xfd88; 摇头 0xfd90; 彩灯 0xfdc3; 无 0xfda0; 无 0xfdc6*/
  3. #include "STC8G.h"/*单片机:STC8G1K08-TSSOP20*//*红外端口:P33(包含外部中断1,改端口时要注意)*/
  4. unsigned char q,b,s,g,/*位选*/ir[13],j,c,dw;unsigned int r,m,d0,d1,ds,se,buz;bit off,on,sm,cd,gj,yt;
  5. unsigned char code dm[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x08,0x48,0x49,0x76,0x00};/*共阴段码*/
  6. void delayms(unsigned int i){while(i--);}/*延时函数*/void int1init(){PX1=1;/*设置中断优先级*/IT1=1;EX1=1;EA=1;}/*外部中断1初始化函数,设置成下降沿触发*/
  7. void d0init()/*定时器0 1微秒@11.0592MHz*/
  8. {AUXR |= 0x80;/*定时器时钟1T模式*/TMOD& = 0xF0;/*设置定时器模式*/TL0 = 0xF5;/*设置定时初始值*/TH0 = 0xFF;/*设置定时初始值*/TF0 = 0;/*清除TF0标志*/TR0 = 0;/*定时器0先不计时*/}
  9. void d1init()/*定时器1初始化函数*/{AUXR |= 0x40;/*1T*/TMOD& = 0x0F;TL1 = 0x70;/*初始值*/TH1 = 0xFF;/*初始值*/TF1 = 0;/*清除TF1标志*/TR1=0;/*先不启动*/ET1=1;/*开中断*/EA=1;}
  10. void kayscan()/*P1端口对地增加按键*/
  11. {
  12.        P1=0xff;
  13.        P34=1;P35=1;P36=1;P37=1;
  14.   if(P11==0){delayms(5);if(P11==0){m=0xfd90;buz=1;while(!P11);}} /*摇头*/
  15.        if(P12==0){delayms(5);if(P12==0){m=0xfd84;buz=1;while(!P12);}} /*风类*/
  16.   if(P13==0){delayms(5);if(P13==0){m=0xfd81;buz=1;while(!P13);}} /*关机*/
  17.        if(P14==0){delayms(5);if(P14==0){m=0xfd88;buz=1;while(!P14);}} /*定时*/
  18.        if(P15==0){delayms(5);if(P15==0){m=0xfd82;buz=1;while(!P15);}} /*开/风速*/
  19.        P1=0x00;
  20. }
  21. void display()/*数码管扫描*/
  22. {
  23.        unsigned char i;for(i=0;i<4;i++){switch(i)/*选择显示位置*/
  24.        {
  25.            case(0):P34=0;P35=1;P36=1;P37=1;break;  /*千位*/
  26.            case(1):P34=1;P35=0;P36=1;P37=1;break;  /*百位*/
  27.            case(2):P34=1;P35=1;P36=0;P37=1;break;  /*十位*/
  28.        case(3):P34=1;P35=1;P36=1;P37=0;break;  /*个位*/
  29.        }
  30.    if(i==0){P1=dm[q];}/*千位*/
  31.            if(i==0&se>0&sm==1){P1=dm[20];}
  32.        if(i==1){P1=dm[b]; /*百位*/
  33.            if(ds>999&sm==1){P1=dm[b]+0x80;}}
  34.        if(i==2){P1=dm[s];}/*十位*/
  35.        if(i==3){P1=dm[g];/*个位*/
  36.            if(yt==1){P1=dm[g]+0x80;}}
  37.        if(P33==1){delayms(50);}     /*间隔一段时间扫描*/
  38.        P1=0x00;       /*消隐*/
  39.        }
  40. }
  41. void ircl()     /*红外时间记录*/
  42. {
  43.        unsigned char c1;
  44.        if(!P33)
  45.        {
  46.    d1=0;
  47.    TR1=1;     /*启动定时器1*/
  48.    while(!P33);
  49.    TR1=0;
  50.    ir[j]=d1;
  51.        }           /*编码位置清零*/              
  52.   if(P33==1&&j>0)/*当端口高电平时,编码位置还未清零*/
  53.        {
  54.    c1++;       /*计算一下持续时间*/
  55.    if(c1>250)   /*超过一定的时间*/
  56.   {
  57.    c++;c1=0;
  58.   }
  59.        if(c>5)     /*就要再次按遥控按键*/
  60.   {
  61.        j=0;c=0;     /*如果还有干扰码就直接清零*/
  62.        }              
  63.        }
  64. }
  65. void kzhs()/*键值控制函数 包含主板按键和红外遥控按键*/
  66. {
  67.        unsigned char fl,zd;
  68.        if(on==1&cd==1){display();/*开数码管*/}
  69.        if(on==1&m==0xfd81){fl=0;on=0;dw=0;zd=0;se=0;ds=0;TR0=0;cd=0;j=0;}/*关机状态*/
  70.        if(m==0xfd82&fl==0){fl=0;off=0;on=1;dw=dw+1;if(dw>3){dw=1;}cd=1;gj=0;j=0;m=0;}/*开机状态*/
  71.   if(on==1&m==0xfd90){yt=~yt;cd=1;j=0;m=0;}/*摇头*/if(dw==0){P31=0;P32=0;P55=0;}
  72.   if(fl==0&dw==1){P31=1;P32=0;P55=0;q=16;}/*慢档*/
  73.   if(fl==0&dw==2){P31=0;P32=1;P55=0;q=17;}/*中档*/
  74.   if(fl==0&dw==3){P31=0;P32=0;P55=1;q=18;}/*快档*/
  75.        if(on==1&m==0xfd88){ds=ds+1800;d0=0;TR0=1;if(ds>28800){ds=0;}cd=1;gj=1;j=0;m=0;}
  76.        /*定时控制函数*//*8.0小时=480分钟=28800秒  999秒=16.65分钟=0.2775小时*/
  77.        if(ds>999){g=19;s=ds/60/6%10;b=ds/60/60;}/*g位显示H,s显示10进制的分钟,b显示小时加小数点*/
  78.        if(ds<999){g=ds%10;s=ds/10%10;b=ds/100%10;/*q=ds/1000%10;*/}/*显示剩余秒数*/
  79.        if(on==1&m==0xfd84){fl++;if(fl>2){fl=0;}zd=0;cd=1;j=0;m=0;}if(fl==0){se=0;}
  80.        /*A类自然风:高速运转10秒,中速运转10秒,低速运转10秒;进入循环*/
  81.        if(fl==1){q=10;if(se>1&se<11){zd=3;}if(se>10&se<21){zd=2;}if(se>20&se<31){zd=1;}if(se>30|se==0){se=1;}TR0=1;}
  82.        /*b类睡眠风:高速转10分钟,中速转30分钟;之后退出睡眠模式,返回长风1档*/
  83.   if(fl==2){q=11;if(se>1&se<600){zd=3;}if(se>600&se<1800){zd=2;}if(se>1800){m=0xfd84;}if(se==0){se=1;}TR0=1;}
  84.        if(zd==1){P31=1;P32=0;P55=0;}/*慢档*/if(zd==2){P31=0;P32=1;P55=0;}/*中档*/if(zd==3){P31=0;P32=0;P55=1;}/*快档*/
  85.        if(m==0xfdc3){cd=~cd;j=0;m=0;}/*彩灯开关,关机后单显示电压,开机后定时和电压切换显示*/
  86.        if(ds!=0&c==0){ET0=1;}/*定时打开时,检测有无红外信号*/if(se!=0&c==0){ET0=1;}/*自动风打开时,检测有无红外信号*/
  87. }
  88. void fmq()/*蜂鸣器*/
  89. {
  90.            if(off==0&buz>0)
  91.        {      
  92.          buz++;
  93.              P54=0;      
  94.        }
  95.        if(buz>800)/*延时*/
  96.        {
  97.              P54=1;      
  98.            if(m==0xfd81)
  99.            {
  100.                  off=1;
  101.                  m=0;
  102.            }
  103.              buz=0;
  104.        }
  105. }
  106. void main()
  107. {
  108.        P1M0=0xff; P1M1=0; P3M0=0x06; P3M1=0; P5M0=0x30; P5M1=0;/*端口模式*/
  109.        P31=0;P32=0;P33=1;P54=1;P55=0;cd=1;j=0;dw=0;ds=0;gj=0;yt=0;buz=0;/*初始化*/
  110.        d0init()/*定时器0初始化*/;d1init();/*定时器1初始化*/int1init();/*外部中断1初始化*/
  111.        buz=1;fmq();/*上电蜂鸣器响一声*/
  112.        while(1)
  113.        {
  114.            ircl();
  115.            kayscan();
  116.            kzhs();
  117.            fmq();
  118.        }
  119. }
  120. /*传统51单片机具有5个中断源,中断优先级从高到低依次是:外部中断0(interrupt0)、定时器0(interrupt1)、外部中断1(interrupt2)、定时器1(interrupt3)和串口中断(interrupt4)。*/
  121. void dsq0() interrupt 1
  122. {
  123.        unsigned int ms,tu,tm;
  124.        tu=965;       /*调整微秒,建议:965*/
  125.        tm=99;         /*毫秒调整,建议:99*/
  126.   d0=d0++;       /*每约1微秒加1*/
  127.        if(buz>0)
  128.        {      
  129.        buz++;
  130.            P54=0;      
  131.   }
  132.        if(buz>800)     /*延时*/
  133.        {
  134.            P54=1;
  135.            buz=0;
  136.        }
  137.        if(!P33)       /*检测到红外信号*/
  138.        {
  139.            ET0=0;       /*返回主程序*/
  140.        }
  141.        if(d0>tu)       /*受红外信号检测影响,建议199*/
  142.        {
  143.            ms++;       /*每约1000微秒=1毫秒*/
  144.            d0=0;       /*us清零*/
  145.        }
  146.        if(ms>tm/2)     /*每约0.5秒*/
  147.        {
  148.        sm=0;       /*关闭闪秒*/
  149.        }
  150.        if(ms>tm)       /*每约1000毫秒=1秒 参考值:19*/
  151.        {
  152.            if(ds>0)                
  153.      {
  154.              ds--;       /*定时秒数自减*/
  155.              }        
  156.              se++;
  157.              sm=1;       /*点亮闪秒*/
  158.            if(gj==1&ds==0)/*允许关机,定时时间到了*/
  159.            {
  160.                  m=0xfd81;   /*送出关机指令*/
  161.                  gj=0;
  162.            }
  163.            ms=0;       /*毫秒清零*/
  164.        }
  165. }
  166. void int1() interrupt 2 /*外部中断1服务函数,低电平触发*//*受遥控中断影响,不够时间处理编码,记录时间不放在这函数*/
  167. {
  168.        unsigned char i;
  169.        j++;             /*编码位置*/
  170.   if(m==0)           /*如果还没解码正确*/
  171.        {
  172.      for(i=1;i<13;i++) /*未捕获间隔码*/
  173.        {
  174.          r=r<<1;     /*从低位起左移1位*/
  175.          if(ir[i]>70&&ir[i]<125) /*编码为1*/
  176.          {
  177.                r=r|0x001;/*或1*/
  178.          }
  179.        }
  180.    }
  181.        if(j>12){r=r|0xf000;} /*表示收到符合长度的编码*/
  182.   else{r=0x0000;}     /*干扰清零*/  
  183.        if(r==0xfd81|r==0xfd82|r==0xfd84|r==0xfd88|r==0xfd90|r==0xfdc3|r==0xfda0|r==0xfdc6)
  184.        {
  185.            m=r;           /*收录合格编码*/
  186.            buz=1;           /*启动蜂鸣器*/
  187.        }
  188.        else
  189.        {
  190.            m=0;           /*干扰码清零*/
  191.        }
  192.        if(j>12&m==0){j=0;}   /*如果大于12位了,编码还不正确,就把位置清零,防止下一帧乱码*/
  193. }
  194. void dsqi() interrupt 3 /*定时器1 中断服务函数,每约13微秒中断1次*/{d1++;/*每约13微秒加1*/}
复制代码
沙发
ID:94031发表于 2023-5-23 16:09|只看该作者
你13微秒中断1次,造成cpu一直不停处理中断,根本没时间干别的,定时器1 应该有一个合理中断时间间隔。
板凳
ID:744809发表于 2023-5-23 17:06|只看该作者
1、代码没对齐,风格较差
2、中断中代码过长,可能导致下个中断进来了都没处理完
3、51的栈空间太小,不建议中断太多代码
4、函数名太短,且为拼音首字母,难以理解
5、中断间隔太短了
地板
ID:123289发表于 2023-5-24 11:23|只看该作者
不要急于写程序。先规划一下方案。
再出个程序流程图,先走通流程图而后再写程序。
如沙发提出的问题,你如果规划过方案,就不犯。
例如:列出风扇的功能,一个给出实现的方式。切换的方法,条件,检测的方式,显示的方式……。
这此都在事先做规划。至少罗列于EXCEL表中吧。

评分

黑币 +5
收起理由
+ 5
很给力!

查看全部评分

5#
ID:796012发表于 2023-5-24 12:21|只看该作者
123156fsadf 发表于 2023-5-23 17:06
1、代码没对齐,风格较差
2、中断中代码过长,可能导致下个中断进来了都没处理完
3、51的栈空间太小,不 ...

谢谢建议。我这是业余爱好的
6#
ID:796012发表于 2023-5-24 12:21|只看该作者
xuyaqi 发表于 2023-5-23 16:09
你13微秒中断1次,造成cpu一直不停处理中断,根本没时间干别的,定时器1 应该有一个合理中断时间间隔。

试了,刚好可以识别红外信号
7#
ID:796012发表于 2023-5-24 12:22|只看该作者
yzwzfyz 发表于 2023-5-24 11:23
不要急于写程序。先规划一下方案。
再出个程序流程图,先走通流程图而后再写程序。
如沙发提出的问题,你 ...

嗯嗯。专业的手法就是不一样。
8#
ID:526543发表于 2023-5-24 12:27|只看该作者
先给你来一段
#include "STC8G.h"

// 定义红外解码键值
#define KEY_POWER     0xFD81
#define KEY_MODE     0xFD82
#define KEY_WIND     0xFD84
#define KEY_TIMER     0xFD88
#define KEY_SWING     0xFD90
#define KEY_LIGHT     0xFDC3

// 定义数码管段码
unsigned char code SEGMENT[] = {
   0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07,
   0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71,
   0x08, 0x48, 0x49, 0x76
};

// 全局变量
bit fanOn = 0;         // 风扇开关状态
unsigned char fanSpeed = 0; // 风扇速度
bit fanSwing = 0;       // 风扇摇头状态
bit fanLight = 0;       // 风扇彩灯状态
unsigned int fanTimer = 0; // 风扇定时器

// 延时函数
void delayms(unsigned int ms) {
   unsigned int i, j;
   for (i = 0; i< ms; i++) {
       for (j = 0; j< 1000; j++);
   }
}

// 数码管显示函数
void display(unsigned char digit) {
   unsigned char segment = SEGMENT[digit];
   P1 = segment;
}

// 控制风扇函数
void controlFan() {
   // 根据风扇状态进行相应操作
   if (fanOn) {
       // 控制风扇开关
       P3& = 0xF8;
       P3 |= fanSpeed;
       // 控制风扇摇头
       P1& = 0xDF;
       P1 |= (fanSwing<< 5);
       // 控制风扇彩灯
       P5& = 0xDF;
       P5 |= (fanLight<< 5);
   } else {
       // 关闭风扇
       P3& = 0xF8;
   }
}

// 外部中断1中断服务函数
void int1() interrupt 2 {
   // 延时一段时间,避免按键抖动
   delayms(10);
   if (P3_2 == 0) { // 检测外部中断1触发
       // 解码键值
       unsigned int keyValue = (P1<< 8) | P0;
      
       // 根据键值执行相应操作
       switch (keyValue) {
         case KEY_POWER:
           fanOn = !fanOn; // 切换风扇开关状态
           break;
         case KEY_MODE:
           fanSpeed++; // 切换风扇速度
           if (fanSpeed > 3) {
               fanSpeed = 0;
           }
           break;
         case KEY_WIND:
           fan
9#
ID:796012发表于 2023-5-24 16:06|只看该作者
123456ZXC1 发表于 2023-5-24 12:27
先给你来一段
#include "STC8G.h"

嗯。还行,有点逻辑性
10#
ID:1079725发表于 2023-5-25 23:36|只看该作者
配合原理图调试理清,会好些吧
11#
ID:1040201发表于 2023-5-26 17:06|只看该作者
能实现功能就是一大步,其它的慢慢累积,多看、多练再过段时间会头看一下,就会发现很多问题
12#
ID:796012发表于 2023-5-28 09:54|只看该作者
liucan2020 发表于 2023-5-26 17:06
能实现功能就是一大步,其它的慢慢累积,多看、多练再过段时间会头看一下,就会发现很多问题

牛逼!这就是成功的奥秘。

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

Powered by 单片机教程网