找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 39498|回复: 46
收起左侧

用STC八脚单片机STC15F104E制作红外遥控灯扇

  [复制链接]
ID:224003 发表于 2018-6-7 10:33 | 显示全部楼层 |阅读模式
    餐桌顶上只有一个照明灯,天热了,就在灯的位置再装一个微风电扇,这样就不必为电扇专门拉电线了。
    往年用的是STC89C52RC芯片的最小系统板、红外接收和继电器模块组装的。
    实际上只用到了单片机3个IO口,而STC89C52RC有32个IO,大材小用,板子又大感觉挺浪费的。
    从网上查到STC有8脚的单片机芯片,后来网购时顺便就买了几个STC15F104E。
电路图.JPG

    看看图片,是不是很小巧。查了相关资料,这个芯片内部集成高精度R/C时钟的,连晶振都不用再接的,烧录时可在5M~35M之间自行设置的。
而且STC网站上还有相应的红外接收例程《STC15系列只用一个定时器中断的红外接收程序》,这样只要在此例程基础上,稍加改动就可用了。
    除了电源正负极引脚外其他六个都可以用作普通IO口的。电路很简单的,直接在洞洞板上焊接上8脚IC座和一个电阻、一个白色LED还有红外接收模块,其他就是外接引线了。这里我用P32接到红外接收数据口上,P33作为闪烁灯,P34、P35外接到继电器模块上。P33接了个闪烁灯,STC文档里面建议用3K以上电阻串联LED的,这里就用的3K的。
继电器接线图.JPG

    注意,照明灯是接到继电器的常闭触点上的,这样即使5V电源模块或单片机出故障了,墙上的开关还是能控制照明灯的。
总装.JPG

    总共是三块小板子用热熔胶粘接到PVC电线槽板上的。从左到右分别是220V转5V电源模块、自制单片机模块、5V继电器模块。
代码中需要根据自己的需要来设定频率,这里是12M。
#define MAIN_Fosc                12000000L        //定义主时钟, 模拟串口和红外接收会自动适应。5~36MHZ
还要制定设备用户代码。
#define        User_code                0xB649                //定义红外接收用户码
烧录.JPG

    如图,烧录时需要制定内置时钟频率,必须和代码里面一样的。
    安装前,先用两个LED灯泡测试一下了。

通电默认状态,亮灯是接到继电器常闭触点的

通电默认状态,亮灯是接到继电器常闭触点的


两灯全亮

两灯全亮

只开另一个

只开另一个

全关

全关


   后来,网上有文章说内置RC时钟,频率不稳定的,受外界环境影响较大。不过想来对于红外线接收这种应用来说,即使有频漂,影响应该不大的。
安装效果.JPG

   反正已经装上了,过了这个夏天,是否频漂拭目以待了。后来想到,其实可以把闪烁灯换掉,改用继电器控制一个弱光灯的,这样根据需要调节灯光亮度了。

单片机源程序如下:
  1. /*************        功能说明        **************

  2. 红外接收程序。适用于市场上用量最大的HT6121/6122及其兼容IC的编码。

  3. 对于用户码与User_code定义不同的遥控器,程序会将用户码一起从串口输出。

  4. 使用模拟串口发送监控显示编码,显示内容为ASCII码和中文。

  5. 本接收程序基于状态机的方式,占用CPU的时间非常少。

  6. HEX文件在本目录的/list里面。

  7. ******************************************/


  8. /*************        用户系统配置        **************/
  9. #define MAIN_Fosc                12000000L        //定义主时钟, 模拟串口和红外接收会自动适应。5~36MHZ
  10. #define D_TIMER0                125                        //选择定时器时间, us, 红外接收要求在60us~250us之间
  11. #define        User_code                0xB649                //定义红外接收用户码

  12. /*************        以下宏定义用户请勿修改        **************/
  13. #include        "reg51.H"
  14. #define        uchar        unsigned char
  15. #define uint        unsigned int   
  16. #define freq_base                        (MAIN_Fosc / 1200)
  17. #define Timer0_Reload                (65536 - (D_TIMER0 * freq_base / 10000))
  18. /*************        本地常量声明        **************/         
  19. /*************        本地变量声明        **************/
  20. sbit        P_TXD1 = P3^1;                //定义模拟串口发送脚,打印信息用
  21. sbit        P_IR_RX = P3^2;                //定义红外接收输入端口
  22. sbit        userLed3=P3^5;
  23. sbit         userLed4=P3^4;
  24. sbit         FlashLed=P3^3;                  //秒闪烁灯  
  25. bit                P_IR_RX_temp;                //Last sample
  26. bit                B_IR_Sync;                        //已收到同步标志
  27. uchar        IR_SampleCnt;                //采样计数
  28. uchar        IR_BitCnt;                        //编码位数
  29. uchar        IR_UserH;                        //用户码(地址)高字节
  30. uchar        IR_UserL;                        //用户码(地址)低字节
  31. uchar        IR_data;                        //数据原码
  32. uchar        IR_DataShit;                //数据反码

  33. bit                B_IrUserErr;                //User code error flag
  34. bit                B_IR_Press;                        //Key press flag,include repeat key.
  35. uchar        IR_code;                        //IR code        红外键码
  36. unsigned int Count1ms=0;        //一毫秒计数器         
  37. unsigned char   T1RH=0xFC;        //定时器时长        高位值
  38. unsigned char   T1RL=0x67;        //定时器时长        低位值

  39. /*************        本地函数声明        **************/
  40. void        Tx1Send(uchar dat);
  41. uchar        HEX2ASCII(uchar dat);
  42. void        InitTimer(void);
  43. void        PrintString(unsigned char code *puts);
  44. /*************  外部函数和变量声明 *****************/
  45. /* 配置并启动T0,ms-T0定时时间 */
  46. void ConfigTimer1(unsigned int ms)
  47. {
  48.     unsigned long tmp;  //临时变量                  
  49. //    tmp = 11059200 / 12;      //定时器计数频率
  50.         tmp = MAIN_Fosc / 12;      //定时器计数频率
  51.     tmp = (tmp * ms) / 1000;  //计算所需的计数值
  52.     tmp = 65536 - tmp;        //计算定时器重载值
  53.     tmp = tmp + 18;           //补偿中断响应延时造成的误差
  54.     T1RH = (unsigned char)(tmp>>8);  //定时器重载值拆分为高低字节
  55.     T1RL = (unsigned char)tmp;
  56.     TMOD &= 0x0F;   //清零T0的控制位
  57.     TMOD |= 0x10;   //配置T0为模式1
  58.     TH1= T1RH;     //加载T0重载值
  59.     TL1 = T1RL;
  60.     ET1 = 1;        //使能T0中断
  61.     TR1 = 1;        //启动T0
  62. }
  63. /* T0中断服务函数 */
  64. void InterruptTimer1() interrupt 3
  65. {
  66.         static unsigned char ti5=0;  
  67.     TH1 = T1RH;  //重新加载重载值
  68.     TL1 = T1RL;
  69.         ti5++;          //计数标志自加1
  70.         if(ti5==20)          //判断是否到1s
  71.         {
  72.                 ti5=0;             //将静态变量清0
  73.                 FlashLed=~FlashLed;       //LED位求反
  74.         }
  75. }
  76. /********************* 主函数 *************************/
  77. void main(void)
  78. {
  79. //        userLed3=1;
  80. //        userLed4=1;         
  81.         EA=1;        //允许总中断
  82.         ConfigTimer1(25);        
  83.         InitTimer();                //初始化Timer           
  84.         while(1)
  85.         {
  86.                 if(B_IR_Press)                //有IR键按下
  87.                 {
  88.                         switch(IR_code)
  89.                         {
  90.                                 case 0x54:
  91.                                         userLed3=~userLed3;
  92.                                         break;
  93.                                 case 0x43:
  94.                                         userLed4=~userLed4;
  95.                                         break;
  96.                         }
  97.                         B_IR_Press = 0;                //清除IR键按下标志
  98.                 }
  99.         }
  100. }   


  101. //*******************************************************************
  102. //*********************** IR Remote Module **************************
  103. //*********************** IR Remote Module **************************
  104. //this programme is used for Receive IR Remote (HT6121).                        
  105. //data format: Synchro,AddressH,AddressL,data,/data, (total 32 bit).
  106. //send a frame(85ms), pause 23ms, send synchro of another frame, pause 94ms         
  107. //data rate: 108ms/Frame   
  108. //Synchro:low=9ms,high=4.5/2.25ms,low=0.5626ms
  109. //Bit0:high=0.5626ms,low=0.5626ms
  110. //Bit1:high=1.6879ms,low=0.5626ms
  111. //frame space = 23 ms or 96 ms                  
  112. /******************** 红外采样时间宏定义, 用户不要随意修改        *******************/  
  113. #if ((D_TIMER0 <= 250) && (D_TIMER0 >= 60))
  114.         #define        D_IR_sample                        D_TIMER0                //定义采样时间,在60us~250us之间
  115. #endif        
  116. #define D_IR_SYNC_MAX                (15000/D_IR_sample)        //SYNC max time
  117. #define D_IR_SYNC_MIN                (9700 /D_IR_sample)        //SYNC min time
  118. #define D_IR_SYNC_DIVIDE        (12375/D_IR_sample)        //decide data 0 or 1
  119. #define D_IR_DATA_MAX                (3000 /D_IR_sample)        //data max time
  120. #define D_IR_DATA_MIN                (600  /D_IR_sample)        //data min time
  121. #define D_IR_DATA_DIVIDE        (1687 /D_IR_sample)        //decide data 0 or 1
  122. #define D_IR_BIT_NUMBER                32                                        //bit number

  123. //*******************************************************************************************
  124. //**************************** IR RECEIVE MODULE ********************************************
  125. void IR_RX_HT6121(void)
  126. {
  127.         uchar        SampleTime;         
  128.         IR_SampleCnt++;                                                        //Sample + 1   
  129.         F0 = P_IR_RX_temp;                                                //Save Last sample status
  130.         P_IR_RX_temp = P_IR_RX;                                        //Read current status
  131.         if(F0 && !P_IR_RX_temp)                                        //Last sample is high,and current sample is low, so is fall edge
  132.         {
  133.                 SampleTime = IR_SampleCnt;                        //get the sample time
  134.                 IR_SampleCnt = 0;                                        //Clear the sample counter
  135.                 if(SampleTime > D_IR_SYNC_MAX)                B_IR_Sync = 0;        //large the Maxim SYNC time, then error
  136.                 else if(SampleTime >= D_IR_SYNC_MIN)                                        //SYNC
  137.                 {
  138.                         if(SampleTime >= D_IR_SYNC_DIVIDE)
  139.                         {
  140.                                 B_IR_Sync = 1;                                        //has received SYNC
  141.                                 IR_BitCnt = D_IR_BIT_NUMBER;        //Load bit number
  142.                         }
  143.                 }
  144.                 else if(B_IR_Sync)                                                //has received SYNC
  145.                 {
  146.                         if(SampleTime > D_IR_DATA_MAX)        
  147.                                 B_IR_Sync=0;        //data samlpe time to large
  148.                         else
  149.                         {
  150.                                 IR_DataShit >>= 1;                                        //data shift right 1 bit
  151.                                 if(SampleTime >= D_IR_DATA_DIVIDE)        IR_DataShit |= 0x80;        //devide data 0 or 1
  152.                                 if(--IR_BitCnt == 0)                                //bit number is over?
  153.                                 {
  154.                                         B_IR_Sync = 0;                                        //Clear SYNC
  155.                                         if(~IR_DataShit == IR_data)                //判断数据正反码
  156.                                         {
  157.                                                 if((IR_UserH == (User_code / 256)) &&
  158.                                                         IR_UserL == (User_code % 256))
  159.                                                                 B_IrUserErr = 0;        //User code is righe
  160.                                                 else        B_IrUserErr = 1;        //user code is wrong
  161.                                                         
  162.                                                 IR_code      = IR_data;
  163.                                                 B_IR_Press   = 1;                        //数据有效
  164.                                         }
  165.                                 }
  166.                                 else if((IR_BitCnt & 7)== 0)                //one byte receive
  167.                                 {
  168.                                         IR_UserL = IR_UserH;                        //Save the User code high byte
  169.                                         IR_UserH = IR_data;                                //Save the User code low byte
  170.                                         IR_data  = IR_DataShit;                        //Save the IR data byte
  171.                                 }
  172.                         }
  173.                 }
  174.         }
  175. }


  176. /**************** Timer初始化函数 ******************************/
  177. void InitTimer(void)
  178. {
  179.         TMOD = 0;                //for STC15Fxxx系列        Timer0 as 16bit reload timer.
  180. ……………………

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

所有资料51hei提供下载:

红外接收1805灯扇.zip (30.92 KB, 下载次数: 496)

评分

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

查看全部评分

回复

使用道具 举报

ID:224003 发表于 2018-9-19 15:28 | 显示全部楼层
天凉了,前天把这个遥控电扇拆了。说说其中的插曲。
刚装上的头几天,发现用遥控器打开电扇的时候,有的时候单片机似乎就复位了,因为默认就是只开灯不开电扇的。
后来想到没有给单片机电源端接上0.1微法的瓷片电容,就拿下来又焊上瓷片电容了。装上再试用,接下来几天还是有这个现象。
后来,想来也许是继电器模块故障,换了,就正常了。一个夏天用着都很正常的。估计,就是负责电扇开关的那个继电器有故障了,没拆看看,具体原因就不得而知了。

频漂,看来这点用途根本是不用担心的了。

评分

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

查看全部评分

回复

使用道具 举报

ID:112693 发表于 2018-9-6 18:59 | 显示全部楼层
谢谢分享!好资料,51黑有你更精彩!!!
回复

使用道具 举报

ID:393398 发表于 2018-9-7 09:32 | 显示全部楼层
不错,
回复

使用道具 举报

ID:395350 发表于 2018-9-8 15:03 | 显示全部楼层
呵呵,牛
回复

使用道具 举报

ID:255559 发表于 2018-9-21 17:35 | 显示全部楼层
定义的红外接收用户码,是不是只能接收这个码,那遥控器上怎么知道是哪个按键?
回复

使用道具 举报

ID:320226 发表于 2018-11-28 17:28 | 显示全部楼层
楼主  你好 可以改用STC8952RC吗 如果改芯片要在那里修改程序?
回复

使用道具 举报

ID:399179 发表于 2018-11-28 19:15 来自手机 | 显示全部楼层
以前有个类似的,不太好用,不知道这个怎么样
回复

使用道具 举报

ID:225259 发表于 2018-11-30 22:10 | 显示全部楼层
另外104E外部中断有问题,触发过多程序会死机,有遇到?
回复

使用道具 举报

ID:224003 发表于 2018-12-8 15:06 | 显示全部楼层
hurbocn 发表于 2018-9-21 17:35
定义的红外接收用户码,是不是只能接收这个码,那遥控器上怎么知道是哪个按键?

提前用51实验板做个红外解码程序,显示在数码管或1602上
然后搞清楚了,再移植到这个八脚单片机
回复

使用道具 举报

ID:224003 发表于 2018-12-8 15:08 | 显示全部楼层
vbnm 发表于 2018-11-28 17:28
楼主  你好 可以改用STC8952RC吗 如果改芯片要在那里修改程序?

当然可以了。最早就是用的STC8952RC,后来移植到这个芯片上了。
论坛教程里面有现成的程序,稍加改动就可以了。
回复

使用道具 举报

ID:224003 发表于 2018-12-8 15:09 | 显示全部楼层
Nemesis_126 发表于 2018-11-30 22:10
另外104E外部中断有问题,触发过多程序会死机,有遇到?

还没有遇到过哦
回复

使用道具 举报

ID:435201 发表于 2018-12-12 14:36 来自手机 | 显示全部楼层
我也刚用这个芯片做了一个学习型的红外遥控开关,带60分钟定时,经试用还不错。
回复

使用道具 举报

ID:445163 发表于 2018-12-13 13:03 来自手机 | 显示全部楼层
兄弟能留个联系方式吗,最近在学,有问题想请教
回复

使用道具 举报

ID:151325 发表于 2019-1-14 17:41 | 显示全部楼层
创意不错,谢谢楼主分享!
回复

使用道具 举报

ID:472046 发表于 2019-1-23 14:02 | 显示全部楼层
很详细的教程,准备仿照楼主的程序做点自己的东西,谢谢了
回复

使用道具 举报

ID:440451 发表于 2019-3-11 19:50 | 显示全部楼层
非常感谢分享,谢谢,标记了!
回复

使用道具 举报

ID:43383 发表于 2019-3-14 19:48 | 显示全部楼层
谢谢分享。。。。。。。。。。。。。。。。。。。
回复

使用道具 举报

ID:423238 发表于 2019-4-2 05:06 来自手机 | 显示全部楼层
zdr833 发表于 2018-12-12 14:36
我也刚用这个芯片做了一个学习型的红外遥控开关,带60分钟定时,经试用还不错。

分享一下程序
回复

使用道具 举报

ID:128463 发表于 2019-4-16 15:13 | 显示全部楼层
谢谢楼主分享!
回复

使用道具 举报

ID:257024 发表于 2019-6-3 03:17 来自手机 | 显示全部楼层
不错。谢谢分享!
回复

使用道具 举报

ID:507712 发表于 2019-7-17 17:01 | 显示全部楼层
楼主是位活雷锋!
回复

使用道具 举报

ID:284079 发表于 2019-9-15 15:44 | 显示全部楼层
谢谢楼主分享!
回复

使用道具 举报

ID:381390 发表于 2019-9-17 11:37 | 显示全部楼层
谢谢分享!好资料
回复

使用道具 举报

ID:250717 发表于 2019-10-27 14:01 | 显示全部楼层
谢谢分享,能用到我的小车上
回复

使用道具 举报

ID:72088 发表于 2019-10-27 18:02 | 显示全部楼层
hurbocn 发表于 2018-9-21 17:35
定义的红外接收用户码,是不是只能接收这个码,那遥控器上怎么知道是哪个按键?

这个我也发表过文章,我用的是学习按键,可以学习任意一个遥控器上不常用的按键,http://www.51hei.com/bbs/dpj-144302-1.html
回复

使用道具 举报

ID:479984 发表于 2019-11-24 20:35 | 显示全部楼层
谢谢分享!好资料,51黑有你更精彩!!!
回复

使用道具 举报

ID:660892 发表于 2019-12-10 19:07 | 显示全部楼层
hzxyy 发表于 2018-12-8 15:08
当然可以了。最早就是用的STC8952RC,后来移植到这个芯片上了。
论坛教程里面有现成的程序,稍加改动就 ...

要怎么烧录进去,不太懂。
回复

使用道具 举报

ID:65286 发表于 2019-12-12 16:08 | 显示全部楼层
支持DIY!!!!
回复

使用道具 举报

ID:206067 发表于 2020-1-29 00:44 | 显示全部楼层
多谢分享 使用了你的程序在15F102W上 可以用但是有个疑问   我的遥控器用户码是01FE 跟你的不同 实际 用户码好像没起作用 只要数据码对就可以
回复

使用道具 举报

ID:697723 发表于 2020-4-4 23:01 来自手机 | 显示全部楼层
搞一个试试看效果如何
回复

使用道具 举报

ID:385168 发表于 2020-4-5 04:37 | 显示全部楼层
下载学习一下,非常感谢楼主。
回复

使用道具 举报

ID:558859 发表于 2020-5-13 18:02 | 显示全部楼层
新手,感觉程序太难了
回复

使用道具 举报

ID:756506 发表于 2020-5-20 13:57 | 显示全部楼层
感谢分享!
回复

使用道具 举报

ID:759144 发表于 2020-5-23 15:30 | 显示全部楼层
感谢分享!
回复

使用道具 举报

ID:246783 发表于 2020-6-23 21:47 来自手机 | 显示全部楼层
hzxyy 发表于 2018-9-19 15:28
天凉了,前天把这个遥控电扇拆了。说说其中的插曲。
刚装上的头几天,发现用遥控器打开电扇的时候,有的时 ...

风扇是感性负载, 启动时电压波动很大, 关闭时又要有泄放路径
回复

使用道具 举报

ID:466759 发表于 2021-5-4 20:36 | 显示全部楼层
不错,不过既然用单片机了,为什么不能加个18b20,做个pwm自动调速风扇?
回复

使用道具 举报

ID:701805 发表于 2021-5-30 21:25 来自手机 | 显示全部楼层
真是个好东西
回复

使用道具 举报

ID:701805 发表于 2021-5-30 21:31 来自手机 | 显示全部楼层
gravedigger 发表于 2020-1-29 00:44
多谢分享 使用了你的程序在15F102W上 可以用但是有个疑问   我的遥控器用户码是01FE 跟你的不同 实际 用户 ...

请问一下我有一个小红外遥控器,怎么修改程序,单片机知道我发送的是啥,控制继电器合闭呀,还是随便一个遥控器否可以用
回复

使用道具 举报

ID:701805 发表于 2021-5-31 17:26 来自手机 | 显示全部楼层
任何遥控器都可以控制吗?
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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