找回密码
 立即注册

QQ登录

只需一步,快速开始

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

基于stc15w204s单片机的水晶倒计时牌制作 附代码

  [复制链接]
跳转到指定楼层
楼主
基于stc15f204s的水晶倒计时牌
第一次在这发帖,如有不周请指正!

以前在网上发现了一个神操作,就是把搭棚电路封装在滴胶里,美观耐用且防止氧化。与其说是电路制作,我觉得是艺术品。寒假正好没事干,就搞了一个倒计时牌,把之前学的51单片机知识用一用,顺便督促一下自己珍惜时间。
刚开始是想用 STC15F104E(因为买多了)【注意,这个单片机内部定时器是T0和T1,跟现在的新产品不一样】 ,做了几个功能发现到处出bug,而且下载器里面没有这个型号,数据手册里面也只不过提了一两次。后来一查发现这个型号早已经停产了,而且它的定时器和外部中断由BUG(怒)。于是换了个stc15w204s。工欲善其事必先利其器,计划在面包板上先做程序,调试好确定管脚分配后再搭棚。面包板接触不好(通病),所以做了个单片机转接座:





程序不是很复杂,有的地方有点啰嗦(大神勿喷),这里简单解释一下,整体思路是单片机驱动hc595,595驱动三位数码管的段,单片机用9012扩流驱动数码管的位,int0借1838b红外接收,再加上ds1302时钟芯片和ds18b20温度芯片,还剩一个管脚接了rgb自闪灯(本来可以接红外发射实现数据双向传输的,不过我懒得写程序和功能了)平时单片机就是while(1)等待,刷新、ir接收什么的全靠两个定时器T0 T1和外部中断0触发。红外接收程序是我自己想的,非常繁琐(本可以简单一些,不过我这么写可以最大程度上减少误触发)。

单片机代码如下:
  1. #include<STC15.h>
  2. #include<stdio.h>
  3. #include<INTRINS.H>
  4. sfr WDT_COUNTER = 0xc1;//【下载的时候请勾选‘上电复位由硬件启动看门狗’】
  5. //sbit CLR_WDT = WDT_COUNTER^5; //软件置1,防止误杀
  6. /*
  7. STC15w204s单片机,。数码管共阳,0亮1灭。
  8. 使用两片74hc595扩充管脚数目,连接ds1302时钟芯片和1838B红外接收头。

  9. **********IR接收程序(NEC协议)************
  10. 基于状态机,拒绝软件delay函数,只使用一个定
  11. 时器和一个中断(必须支持上升/下降沿中断),
  12. 有利于系统资源的节约。程序错误无累计,利于
  13. 长期稳定运行。使用定时器作为时间基准,如需
  14. 要移植程序,只需要按照源程序时间要求重新生
  15. 成定时器初始化函数。其中所有关键组件,均已
  16. 在其后注明【这是计划的一部分】。
  17. *******************************2020年2月20日
  18. BUG记录:
  19. int0输入信息量过大会造成程序跑飞
  20. */
  21. typedef unsigned char u8;//【这是计划的一部分】
  22. typedef unsigned int u16;

  23. //595引脚连接(待定)Q0对应低位,Q7对应高位
  24. sbit ser=P5^5;  //也叫SI
  25. sbit srclk=P1^5;  //刷新输出,上升沿有效
  26. sbit rclk=P1^4;  //内部移位,上升沿有效

  27. //1838B
  28. sbit ir=P3^2;//【这是计划的一部分】

  29. //18B20
  30. sbit DSPORT=P5^4;

  31. //DS1302
  32. sbit RST=P1^3;           //控制器复位        高电平时才能工作,其实与复位关系不大
  33. sbit DSIO=P1^2;           //数据
  34. sbit SCLK=P1^1;           //时

  35. //led
  36. sbit led=P1^0;

  37. //有关于红外接收的状态标志位,定时器用t0,中断用int0。【这是计划的一部分】
  38. bit iract=0;        //红外活动
  39. u8 irstate=0;        //红外接受状态0-6{未激活;报头低;报头升;报头高;报头降;高电平;低电平}
  40. bit started=0;        //已收到报头,请忽视报尾
  41. bit t0reset=0;        //定时器0溢出就回到等待状态
  42. bit int0reset=0;        //int0触发就回到等待状态
  43. bit int0negfall=0;        //忽视int0的下降沿(只允许上升沿中断)
  44. u8 bitamount=0;        //收到的总位数(0-32)
  45. bit irbit=0; //当前ir位数
  46. u8 ir1=0x00,ir2=0xff,ir3=0x00,ir4=0xff;//ir接受结果
  47. bit irreceived=0;//如有待处理的红外信息,此位置1
  48. u8 irresult=0;//irdecode函数解码结果

  49. //system
  50. u16 data count=1000;
  51. u8 data stat=1;//0熄屏;1正常带温度;2正常无温度;3设置界面(3set,4h十位,5h个位,6d百位,7d十位,8d个位)
  52. u8 data days=123; //倒计时应该显示的天数,同步存放于0000h
  53. u8 data wk=0x00;//上次查询到的星期,将与此次查询到的比较同步存放于0001h
  54. u8 data keynum=0;//按键输入的数字
  55. //sbit led=P1^2;

  56. //显示相关变量
  57. u8 code duan[]={0x03,0x9f,0x25,0x0d,0x99,0x49,0x41,0x1f,0x01,0x09,0x11,0xc1,0x63,0x85,0x61,0x71,//0-15
  58.                                                                 0x02,0x9e,0x24,0x0c,0x98,0x48,0x40,0x1e,0x00,0x08,0x10,0xc0,0x62,0x84,0x60,0x70,//16-31
  59.                                                                 0xff,0xef,0x91};//数码管显示,0-9,A,b,C,d,E,F,不亮,(5)(14),_,H,(13).0-34
  60. u8 data num2,num1,num0;
  61. u8 data w=2;//数码管的位号
  62. sbit wei0=P3^3;
  63. sbit wei1=P3^7;
  64. sbit wei2=P3^6;

  65. //18b20
  66. int temp;//温度*100

  67. //1302
  68. //---DS1302时钟初始化2016年5月7日星期六12点00分00秒。---//
  69. //---存储顺序是秒,分,时,  日,  月, 星期, 周年,存储格式是用BCD码---//
  70. //u8 TIME[7] = {0, 0, 0x12, 0x07, 0x05, 0x06, 0x16};
  71. u8 TIME[7]= {0x00, 0x55, 0x23, 0x15, 0x10, 0x02, 0x19}; //星期是time[5],小时是time【2】
  72. u8 timeset[7]={0x00, 0x02, 0x13, 0x07, 0x12, 0x06, 0x19};
  73. //---DS1302写入和读取时分秒的地址命令---//
  74. //---秒分时日月周年 最低位读写位;-------//
  75. u8 code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
  76. u8 code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};         //两者的区别只在于末位(发送的时候作为最先发送的)用于决定该命令是读还是写


  77. //基本函数
  78. void hc595write();
  79. void intinit();
  80. void Timer1Init();

  81. //红外相关函数
  82. void irinit();
  83. void irdecode();

  84. //温度相关函数
  85. void Ds18b20Init();
  86. void Ds18b20WriteByte(unsigned char dat);
  87. unsigned char Ds18b20ReadByte();
  88. int Ds18b20ReadTemp();

  89. //eeprom相关函数
  90. void iaperase(unsigned char addrh,unsigned char addrl);
  91. void iapwrite(unsigned char addrh,unsigned char addrl,unsigned char dat);
  92. unsigned char iapread(unsigned char addrh,unsigned char addrl);
  93. void iaprst();

  94. //ds1302相关函数
  95. void Ds1302Write(u8 addr, u8 dat);
  96. u8 Ds1302Read(u8 addr);
  97. void Ds1302set();
  98. void Ds1302ReadTime();

  99. void intinit()
  100. {
  101.         EA=1;
  102.         ET0=1;
  103.         //ET1=1;
  104.         IE2=0x04;  //T2使能,T2的优先级固定为低。IE2不可位寻址,ET2在右数第三位。
  105.         EX0=1;  //P3.2中断使能
  106.         IT0=1;  //P3.2仅接受下降沿中断【这是计划的一部分】
  107.         PX0=1;  //P3.2中断优先级高,又因为自然优先级的缘故,高于T0。
  108.         PT0=1;  //T0优先级高
  109.         //PT1=0;  //T1优先级低
  110. }

  111. void Timer2Init(void)                //5毫秒@11.0592MHz
  112. {
  113.         AUXR &= 0xFB;                //定时器时钟12T模式
  114.         T2L = 0x00;                //设置定时初值
  115.         T2H = 0xEE;                //设置定时初值
  116.         AUXR |= 0x10;                //定时器2开始计时
  117. }

  118. void irdecode()
  119. {
  120.         switch(ir3)
  121.         {
  122.                 case 0x16:
  123.                         irresult=0;
  124.                         break;
  125.                 case 0x0c:
  126.                         irresult=1;
  127.                         break;
  128.                 case 0x18:
  129.                         irresult=2;
  130.                         break;
  131.                 case 0x5e:
  132.                         irresult=3;
  133.                         break;
  134.                 case 0x08:
  135.                         irresult=4;
  136.                         break;
  137.                 case 0x1c:
  138.                         irresult=5;
  139.                         break;
  140.                 case 0x5a:
  141.                         irresult=6;
  142.                         break;
  143.                 case 0x42:
  144.                         irresult=7;
  145.                         break;
  146.                 case 0x52:
  147.                         irresult=8;
  148.                         break;
  149.                 case 0x4a:
  150.                         irresult=9;
  151.                         break;
  152.                 case 0x45:
  153.                         irresult=10;//电源键
  154.                         break;
  155.                 case 0x47:
  156.                         irresult=11;//菜单键
  157.                         break;
  158.                 case 0x15:
  159.                         irresult=12;//播放键
  160.                         break;
  161.                
  162.         }
  163. }

  164. void irinit()  //红外接受状态0的初始化函数【这是计划的一部分】,状态标志初始化,定时器初始化,int0初始化,数据接收配置初始化
  165. {
  166.         iract=0;
  167.         irstate=0;//红外接受状态0-6{未激活;报头低;报头升;报头高;报头降;高电平;低电平}
  168.         started=0;
  169.         t0reset=0;
  170.         int0reset=0;
  171.         int0negfall=0;
  172.         EX0=1;  //P3.2中断使能
  173.         IT0=1;  //P3.2仅接受下降沿中断【这是计划的一部分】
  174.         PX0=1;
  175.         
  176.         AUXR &= 0x7F;                //定时器时钟12T模式
  177.         TMOD &= 0xF0;                //设置定时器模式(先清零)
  178.         TMOD |= 0x01;                //设置定时器模式(再写入)统一规定:T0,16位不自动重装载,12T。
  179.         TF0 = 0;                //清除TF0标志
  180.         TR0 = 0;                //定时器0不计时
  181.         
  182.         EX0=1;  //P3.2中断使能
  183.         IT0=1;  //P3.2仅接受下降沿中断
  184.         PX0=1;  //P3.2中断优先级高,又因为自然优先级的缘故,高于T0。
  185.         
  186.         bitamount=0;
  187.         
  188. }

  189. void hc595write(void)          //给595输入数据c是数码管,最后送进去的那一位出现在q0
  190. {
  191.         u8 t=0,a=0,shu=0x00;//t是循环变量,a是待发送的值,先发送级联的那片,显示8段,再发送直连的
  192.         wei2=1;
  193.         wei1=1;
  194.         wei0=1;
  195.         switch(w)
  196.         {
  197.                 case 0:
  198.                         shu=duan[num0];
  199.                         break;
  200.                 case 1:
  201.                         shu=duan[num1];
  202.                         break;
  203.                 case 2:
  204.                         shu=duan[num2];
  205.                         break;
  206.         }
  207.         for(t=0;t<=7;t++)//数字区,8位
  208.         {
  209.                 if((shu&0x01)==0)
  210.                         ser=0;
  211.                 else
  212.                         ser=1;
  213.                 rclk=1;
  214.                 rclk=0;
  215.                 shu=shu>>1;
  216.         }

  217.         if(w>=2)//可以控制扫描顺序
  218.                 w=0;
  219.         else
  220.                 w++;

  221.         srclk=1;
  222.         srclk=0;
  223.         switch(w)
  224.                 {
  225.                         case 0:
  226.                                 wei0=0;
  227.                                 break;
  228.                         case 1:
  229.                                 wei1=0;
  230.                                 break;
  231.                         case 2:
  232.                                 wei2=0;
  233.                                 break;
  234.                 }
  235. }

  236. void main() //    我是main函数
  237. {
  238.         int a=3;
  239.         led=1;
  240.         srclk=0;
  241.         rclk=0;
  242.         ser=0;
  243.         wk=iapread(0x00,0x01);
  244.         days=iapread(0x00,0x00);
  245.         intinit(); //【这是计划的一部分】
  246.         Timer2Init();
  247.         WDT_COUNTER=0x37;//【这不是计划的一部分】
  248.         irinit();
  249.         num2=24;
  250.         num1=24;
  251.         num0=24;//试机
  252.         while(1)
  253.         {
  254.           //跑飞的时候while(1)里面的内容仍然正常执行
  255.         }
  256. }

  257. void timer2() interrupt 12//正常显示的扫描刷新步骤
  258. {
  259.         if(irreceived==1)//有按键刚刚按下且未处理
  260.         {
  261.                 irdecode();
  262.                 switch(irresult)
  263.                 {
  264.                         case 10://电源键
  265.                         {
  266.                                 if(stat==0)
  267.                                 {        
  268.                                         stat=1;
  269.                                         num2=days/100;
  270.                                         num1=(days%100)/10;
  271.                                         num0=days%10;
  272.                                 }
  273.                                 else
  274.                                 {
  275.                                         stat=0;
  276.                                         num2=32;
  277.                                         num1=32;
  278.                                         num0=32;
  279.                                         hc595write();
  280.                                 }
  281.                                 break;
  282.                         }
  283.                         case 11://菜单键
  284.                         {
  285.                                 if(stat<=2)
  286.                                 {
  287.                                         stat=3;//确认进入设置模式
  288.                                         num2=34;//H
  289.                                         num1=33;//_
  290.                                         num0=34;//H
  291.                                 }
  292.                                 else
  293.                                 {
  294.                                         stat=1;
  295.                                 }
  296.                                 break;
  297.                         }
  298.                         case 12://播放键
  299.                         {
  300.                                 if(stat==1)
  301.                                         stat=2;
  302.                                 if(stat==2)
  303.                                         stat=1;
  304.                                         break;
  305.                         }
  306.                         case 0:
  307.                                 led=~led;
  308.                         case 1:
  309.                         case 2:
  310.                         case 3:
  311.                         case 4:
  312.                         case 5:
  313.                         case 6:
  314.                         case 7:
  315.                         case 8:
  316.                         case 9:
  317.                                 keynum=irresult;//先记录下键值
  318.                                 switch (stat)
  319.                                 {
  320.                                         case 3:
  321.                                                 timeset[2]=keynum*16;
  322.                                         num1=keynum;
  323.                                         num0=33;//_
  324.                                         stat=4;
  325.                                         break;
  326.                                         case 4:
  327.                                                 timeset[2]=timeset[2]+keynum;
  328.                                         num2=33;//_
  329.                                         num1=13;//d
  330.                                         num0=13;//d
  331.                                         stat=5;
  332.                                         break;
  333.                                         case 5:
  334.                                                 days=keynum*100;
  335.                                         num2=keynum;
  336.                                         num1=33;//_
  337.                                         num0=13;//d
  338.                                         stat=6;
  339.                                         break;
  340.                                         case 6:
  341.                                                 days=days+keynum*10;
  342.                                         num1=keynum;
  343.                                         num0=33;//_
  344.                                         stat=7;
  345.                                         break;
  346.                                         case 7:
  347.                                                 days=days+keynum;
  348.                                         Ds1302set();//向ds1302写入小时
  349.                                         iaperase(0x00,0x00);
  350.                                         iapwrite(0x00,0x00,days);
  351.                                         Ds1302ReadTime();
  352.                                         wk=TIME[5];
  353.                                         iapwrite(0x00,0x01,wk);//向eeprom写入正确的天数和星期
  354.                                         num2=days/100;
  355.                                         num1=(days%100)/10;
  356.                                         num0=days%10;//更新显示内容
  357.                                                 stat=1;
  358.                                         break;

  359.                                 }
  360.                                 break;
  361.                 }
  362.                 irreceived=0;
  363.         }
  364.         if(count>0)
  365.         {
  366.                 count--;
  367.                 if(count==1000)
  368.                         WDT_COUNTER=WDT_COUNTER|0x10; //WDT喂狗【这是计划的一部分】
  369.         }
  370.         else
  371.         {
  372.                 count=2000;//count溢出之时,应向时钟芯片询问日期,1000->5s
  373.                 WDT_COUNTER=WDT_COUNTER|0x10; //WDT喂狗【这是计划的一部分】
  374.                 Ds1302ReadTime();
  375.                 if(wk!=TIME[5])//星期数发生变化
  376.                 {
  377.                         wk=TIME[5];//更新星期
  378.                         if(days>0)
  379.                                 days--;//更新天数
  380.                         else
  381.                                 stat=0;
  382.                         iaperase(0x00,0x00);
  383.                         iapwrite(0x00,0x00,days);
  384.                         iapwrite(0x00,0x01,wk);//向eeprom写入正确的天数和星期
  385.                 }
  386.         }
  387.         if((stat==1)&&(count==1500))//
  388.         {
  389.                 temp=Ds18b20ReadTemp();
  390.                 num2=temp % 10000 / 1000;
  391.                 num1=(temp % 1000 / 100)+16;
  392.                 num0=temp % 100 / 10;
  393.         }
  394.         else if((stat==1|stat==2)&&count==1000)
  395.         {
  396.                 num2=days/100;
  397.                 num1=(days%100)/10;
  398.                 num0=days%10;
  399.                 //num2=33;
  400.                 //num1=TIME[2]/16;
  401.                 //num0=TIME[2]%16;
  402.         }
  403.         
  404.         if(stat==0)
  405.         {
  406.                
  407.         }
  408.         else
  409.         {
  410.                 hc595write();
  411.         }
  412. }

  413. void timer0() interrupt 1
  414. {
  415.         if(t0reset==0)//定时器0溢出就回到等待状态标志位
  416.         {
  417.                 if(irstate==1)
  418.                 {
  419.                         irstate=2;        //红外接受状态0-6{未激活;报头低;报头升;报头高;报头降;高电平;低电平}
  420.                         t0reset=1;        //定时器0溢出就回到等待状态
  421.                         int0reset=0;        //int0触发就回到等待状态
  422.                         int0negfall=1;        //忽视int0的下降沿(只允许上升沿中断)
  423.                         IT0=0;  //P3.2=1仅接收下降沿中断,=0上下皆可
  424.                         
  425.                         AUXR &= 0x7F;                //定时器时钟12T模式,2ms
  426.                         TMOD &= 0xF0;                //设置定时器模式
  427.                         TMOD |= 0x01;                //设置定时器模式
  428.                         TL0 = 0xCD;                //设置定时初值
  429.                         TH0 = 0xF8;                //设置定时初值
  430.                         TF0 = 0;                //清除TF0标志
  431.                         TR0 = 1;                //定时器0开始计时
  432.                 }
  433.                 else if(irstate==3)
  434.                 {
  435.                         irstate=4;        //红外接受状态0-6{未激活;报头低;报头升;报头高;报头降;高电平;低电平}
  436.                         t0reset=1;        //定时器0溢出就回到等待状态
  437.                         int0reset=0;        //int0触发就回到等待状态
  438.                         int0negfall=1;        //忽视int0的下降沿(只允许上升沿中断)
  439.                         IT0=0;  //=1仅接收下降沿中断,=0上下皆可
  440.                         
  441.                         AUXR &= 0x7F;                //定时器时钟12T模式  2.5ms
  442.                         TMOD &= 0xF0;                //设置定时器模式
  443.                         TMOD |= 0x01;                //设置定时器模式
  444.                         TL0 = 0x00;                //设置定时初值
  445.                         TH0 = 0xF7;                //设置定时初值
  446.                         TF0 = 0;                //清除TF0标志
  447.                         TR0 = 1;                //定时器0开始计时
  448.                 }
  449.                 else if(irstate==5)//重头戏:判断逻辑值【6-long】
  450.                 {
  451.                         irstate=6;        //红外接受状态0-6{未激活;报头低;报头升;报头高;报头降;
  452.                         irbit=1;
  453.                         //out=0;
  454.                         
  455.                         t0reset=0;        //定时器0溢出就回到等待状态
  456.                         int0reset=0;        //int0触发就回到等待状态
  457.                         int0negfall=1;        //忽视int0的下降沿(只允许上升沿中断)
  458.                         IT0=0;  //=1仅接收下降沿中断,=0上下皆可
  459.                         
  460.                         AUXR &= 0x7F;                //定时器时钟12T模式 1200us
  461.                         TMOD &= 0xF0;                //设置定时器模式
  462.                         TMOD |= 0x01;                //设置定时器模式
  463.                         TL0 = 0xAE;                //设置定时初值
  464.                         TH0 = 0xFB;                //设置定时初值
  465.                         TF0 = 0;                //清除TF0标志
  466.                         TR0 = 1;                //定时器0开始计时
  467.                         
  468.                         if(bitamount<=7)  //【禁忌二重奏之一】
  469.                         {
  470.                                 ir1=ir1>>1;
  471.                                 ir1=ir1+(irbit*0x80);
  472.                         }
  473.                         else if(bitamount<=15)
  474.                         {
  475.                                 ir2=ir2>>1;
  476.                                 ir2=ir2+(irbit*0x80);
  477.                                 
  478.                         }
  479.                         else if(bitamount<=23)
  480.                         {
  481.                                 ir3=ir3>>1;
  482.                                 ir3=ir3+(irbit*0x80);
  483.                         }
  484.                         else
  485.                         {
  486.                                 ir4=ir4>>1;
  487.                                 ir4=ir4+(irbit*0x80);
  488.                         }
  489.                         
  490.                         bitamount++;
  491.                         
  492.                         if(bitamount>=32)
  493.                         {
  494.                                 irreceived=1;
  495.                                 irinit();
  496.                                 
  497.                         }
  498.                 }
  499.         }
  500.         else
  501.         {
  502.                
  503.                 irinit();
  504.         }
  505. }


  506. void int0() interrupt 0
  507. {
  508.         _nop_();
  509.         _nop_();
  510.         _nop_();
  511.         if((ir==1)|(int0negfall==0))//如果“忽视下降沿”标志位为1时(&)为下降沿(输入端=0),就不能执行下面的程序。
  512.         {
  513.                 if(int0reset==1)//如果“触发中断即复位”标志位为1,就立刻复位。
  514.                 {
  515.                         
  516.                         irinit();
  517.                         
  518.                 }
  519.                 else//好戏开始
  520.                 {
  521.                                 if(irstate==0)//报头低开始   0未激活;1报头低;2报头升;3报头高;4报头降;5高电平;6低电平
  522.                                 {
  523.                                         iract=1;        //红外活动
  524.                                         irstate=1;        //红外接受状态0-6{未激活;报头低;报头升;报头高;报头降;高电平;低电平}
  525.                                         t0reset=0;        //定时器0溢出就回到等待状态
  526.                                         int0reset=1;        //int0触发就回到等待状态
  527.                                         int0negfall=0;        //忽视int0的下降沿(只允许上升沿中断)
  528.                                         IT0=0;  //=1仅接收下降沿中断,=0上下皆可
  529.                                        
  530.                                         AUXR &= 0x7F;                //8毫秒@11.0592MHz 定时器时钟12T模式
  531.                                         TMOD &= 0xF0;                //设置定时器模式
  532.                                         TMOD |= 0x01;                //设置定时器模式
  533.                                         TL0 = 0x33;                //设置定时初值
  534.                                         TH0 = 0xE3;                //设置定时初值
  535.                                         TF0 = 0;                //清除TF0标志
  536.                                         TR0 = 1;                //定时器0开始计时
  537.                                 
  538.                                 }
  539.                                 else if(irstate==2)//报头高开始
  540.                                 {
  541.                                         irstate=3;        //红外接受状态0-7{未激活;报头低;报头升;报头高;报头降;高电平1;高电平2;低电平}
  542.                                         t0reset=0;        //定时器0溢出就回到等待状态
  543.                                         int0reset=1;        //int0触发就回到等待状态
  544.                                         int0negfall=0;        //忽视int0的下降沿(只允许上升沿中断),下降沿此时不会触发reset
  545.                                         IT0=0;  //=1仅接收下降沿中断,=0上下皆可
  546.                                        
  547.                                         AUXR &= 0x7F;                //定时器时钟12T模式 3.5ms
  548.                                         TMOD &= 0xF0;                //设置定时器模式
  549.                                         TMOD |= 0x01;                //设置定时器模式
  550.                                         TL0 = 0x66;                //设置定时初值
  551.                                         TH0 = 0xF3;                //设置定时初值
  552.                                         TF0 = 0;                //清除TF0标志
  553.                                         TR0 = 1;                //定时器0开始计时
  554.                                        
  555.                                 }
  556.                                 else if(irstate==4)//高电平开始【5-first】
  557.                                 {
  558.                                         irstate=5;        //红外接受状态0-6{未激活;报头低;报头升;报头高;报头降;高电平;低电平}
  559.                                         t0reset=0;        //定时器0溢出就回到等待状态
  560.                                         int0reset=0;        //int0触发就回到等待状态
  561.                                         int0negfall=0;        //忽视int0的下降沿(只允许上升沿中断)
  562.                                         IT0=1;  //P3.2=1仅接收下降沿中断,=0上下皆可
  563.                                        
  564.                                         AUXR &= 0x7F;                //定时器时钟12T模式  840us
  565.                                         TMOD &= 0xF0;                //设置定时器模式
  566.                                         TMOD |= 0x01;                //设置定时器模式
  567.                                         TL0 = 0xFA;                //设置定时初值
  568.                                         TH0 = 0xFC;                //设置定时初值
  569.                                         TF0 = 0;                //清除TF0标志
  570.                                         TR0 = 1;                //定时器0开始计时
  571.                                        
  572.                                         //out=1;
  573.                                        
  574.                                         if(started==0)//收到的是报头
  575.                                         {
  576.                                                 started=1;
  577.                                         }
  578.                                         else//收到的是报尾
  579.                                         {
  580.                                                 iract=0;
  581.                                                 started=0;
  582.                                                 irinit();
  583.                                         }
  584.                                 }
  585.                                 else if(irstate==5)//低电平开始【6-short】
  586.                                 {
  587.                                         irstate=6;        //红外接受状态0-6{未激活;报头低;报头升;报头高;报头降;高电平;低电平}
  588.                                         irbit=0;
  589.                                         //out=0;
  590.                                        
  591.                                         t0reset=1;        //定时器0溢出就回到等待状态
  592.                                         int0reset=0;        //int0触发就回到等待状态
  593.                                         int0negfall=1;        //忽视int0的下降沿(只允许上升沿中断)
  594.                                         IT0=0;  //P3.2=1仅接收下降沿中断,=0上下皆可
  595.                                        
  596.                                         AUXR &= 0x7F;                //定时器时钟12T模式 840us
  597.                                         TMOD &= 0xF0;                //设置定时器模式
  598.                                         TMOD |= 0x01;                //设置定时器模式
  599.                                         TL0 = 0xFA;                //设置定时初值
  600.                                         TH0 = 0xFC;                //设置定时初值
  601.                                         TF0 = 0;                //清除TF0标志
  602.                                         TR0 = 1;                //定时器0开始计时
  603.                                        
  604.                                         if(bitamount<=7)  //【禁忌二重奏之二】
  605.                                         {
  606.                                                 ir1=ir1>>1;
  607.                                                 ir1=ir1+(irbit*0x80);
  608.                                         }
  609.                                         else if(bitamount<=15)
  610.                                         {
  611.                                                 ir2=ir2>>1;
  612.                                                 ir2=ir2+(irbit*0x80);
  613.                                                 
  614.                                         }
  615.                                         else if(bitamount<=23)
  616.                                         {
  617.                                                 ir3=ir3>>1;
  618.                                                 ir3=ir3+(irbit*0x80);
  619.                                         }
  620.                                         else
  621.                                         {
  622.                                                 ir4=ir4>>1;
  623.                                                 ir4=ir4+(irbit*0x80);
  624.                                         }
  625.                                        
  626.                                         bitamount++;
  627.                                        
  628.                                         if(bitamount>=32)
  629.                                         {
  630.                                                 irreceived=1;
  631.                                                 irinit();
  632.                                                 
  633.                                         }
  634.                                 }
  635.                                 else if(irstate==6)//收到上升沿信号,由低电平转为高电平状态【5-repeat】
  636.                                 {
  637.                                         irstate=5;        //红外接受状态0-6{未激活;报头低;报头升;报头高;报头降;高电平;低电平}
  638.                                         t0reset=0;        //定时器0溢出就回到等待状态
  639.                                         int0reset=0;        //int0触发就回到等待状态
  640.                                         int0negfall=0;        //忽视int0的下降沿(只允许上升沿中断)
  641.                                         IT0=1;  //P3.2=1仅接收下降沿中断,=0上下皆可
  642.                                        
  643.                                         AUXR &= 0x7F;                //定时器时钟12T模式  840us
  644.                                         TMOD &= 0xF0;                //设置定时器模式
  645.                                         TMOD |= 0x01;                //设置定时器模式
  646.                                         TL0 = 0xFA;                //设置定时初值
  647.                                         TH0 = 0xFC;                //设置定时初值
  648.                                         TF0 = 0;                //清除TF0标志
  649.                                         TR0 = 1;                //定时器0开始计时
  650.                                        
  651.                                         //out=1;
  652.                                        
  653.                                 }
  654.                                 
  655.                 }
  656.         }
  657.         
  658. }

  659. /*
  660. 日志:在完成了数码管显示和定时
  661. 器中断的基础上,新增了状态机查
  662. 询红外信号输入的功能,在15w204
  663. s上能稳定运行。2020-2-21

  664. */

  665. void Ds18b20Init()
  666. {
  667.         unsigned char i,j;
  668.         DSPORT=1;                         //将总线拉高4us
  669.         _nop_();
  670.         _nop_();
  671.         i = 8;
  672.         while (--i);
  673.         DSPORT=0;                        //然后拉低总线480us
  674.         i = 6;
  675.         j = 38;
  676.         do
  677.         {
  678.                 while (--j);
  679.         } while (--i);
  680.         DSPORT=1;                        //然后拉高总线,如果DS18B20做出反应会将在15us~60us后总线拉低
  681.         i = 6;
  682.         j = 38;
  683.         do
  684.         {
  685.                 while (--j);
  686.         } while (--i);
  687. }

  688. void Ds18b20WriteByte(unsigned char dat)
  689. {
  690.         unsigned char i,j,e;
  691.         for(e=8;e>0;e--)
  692.         {
  693.                 DSPORT=0;                        //每写入一位数据之前先把总线拉低1us
  694.                 _nop_();
  695.                 _nop_();
  696.                 _nop_();
  697.                 DSPORT=dat&0x01; //然后写入一个数据,从最低位开始
  698.                 i = 1;//延时68us,持续时间最少60us
  699.                 j = 184;
  700.                 do
  701.                 {
  702.                         while (--j);
  703.                 } while (--i);               
  704.                 DSPORT=1;        //然后释放总线,至少1us给总线恢复时间才能接着写入第二个数值
  705.                 dat>>=1;
  706.         }
  707. }

  708. unsigned char Ds18b20ReadByte()
  709. {
  710.         unsigned char byte,i,j;
  711.         for(j=8;j>0;j--)
  712.         {
  713.                 DSPORT=0;//先将总线拉低1us
  714.                 _nop_();
  715.                 _nop_();
  716.                 _nop_();
  717.                 byte>>=1;
  718.                 DSPORT=1;//然后释放总线
  719.                 _nop_();//延时15us等待数据稳定[]
  720.                 i = 39;
  721.                 while (--i);
  722.                 if(DSPORT)
  723.                         byte|=0x80;
  724.                 i = 122;//delay45us
  725.                 while (--i);
  726.         }
  727.         return byte;
  728. }

  729. int Ds18b20ReadTemp()
  730. {
  731.         int temp=0;
  732.         int tp;
  733.         u8 i,j;
  734.         unsigned char tmh,tml;
  735.         Ds18b20Init();
  736.         Ds18b20WriteByte(0xcc);
  737.         Ds18b20WriteByte(0x44);
  738.         _nop_();//delay125us
  739.         _nop_();
  740.         i = 2;
  741.         j = 84;
  742.         do
  743.         {
  744.                 while (--j);
  745.         } while (--i);
  746.         Ds18b20Init();
  747.         Ds18b20WriteByte(0xcc);
  748.         Ds18b20WriteByte(0xbe);
  749.         tml=Ds18b20ReadByte();
  750.         tmh=Ds18b20ReadByte();
  751.         
  752.         temp=tmh;
  753.         temp<<=8;
  754.         temp|=tml;
  755.         if((temp&0xf800)==0xf800)        //*0.0625是把16进制转化位10进制所需,原始信息里的16代表1摄氏度。                        
  756.         {
  757.                 temp=temp-1;//如果温度是零下,此处未加入负温度标志位,所以显示的还是正的
  758.                 temp=~temp;
  759.                 tp=temp;
  760.                 temp=tp*0.0625*100+0.5;
  761.         }
  762.         else
  763.         {                        
  764.                 tp=temp;//如果温度是零上
  765.                 temp=tp*0.0625*100+0.5;        
  766.         }
  767.         return temp;
  768. }
  769. /*
  770. 日志 移植了某大佬的ds18b20程序,
  771. 并使之能在stc-y5内核单片机上运
  772. 行。正常情况下输出的16bit信息可
  773. 以表示12位精度的温度,但是stc单
  774. 片机不支持浮点数运算,所以temp
  775. 是乘了100的。所有延时函数(微秒
  776. 级)均已内置,无需调用,也不费
  777. 什么时间。           2020-2-24
  778. */

  779. //eeprom操作--IAP法

  780. void iaprst()  //复位
  781. {
  782.         IAP_CONTR=0;
  783.         IAP_CMD=0;
  784.         IAP_TRIG=0;
  785.         IAP_ADDRH=0x80;
  786. }

  787. unsigned char iapread(unsigned char addrh,unsigned char addrl)
  788. {
  789.         unsigned char dat;
  790.         IAP_CONTR=0x83;  //适用于12mhz以下的频率
  791.         IAP_CMD=1;
  792.         IAP_ADDRL=addrl;
  793.         IAP_ADDRH=addrh;
  794.         IAP_TRIG=0x5a;
  795.         IAP_TRIG=0xa5;
  796.         _nop_();
  797.         _nop_();
  798.         dat=IAP_DATA;
  799.         iaprst();
  800.         return dat;
  801. }

  802. void iapwrite(unsigned char addrh,unsigned char addrl,unsigned char dat)
  803. {
  804.         IAP_CONTR=0x83;//适用于12mhz以下的频率
  805.         IAP_CMD=2;
  806.         IAP_ADDRL=addrl;
  807.         IAP_ADDRH=addrh;
  808.         IAP_DATA=dat;
  809.         IAP_TRIG=0x5a;
  810.         IAP_TRIG=0xa5;
  811.         _nop_();
  812.         _nop_();
  813.         iaprst();
  814. }

  815. void iaperase(unsigned char addrh,unsigned char addrl)
  816. {
  817.         IAP_CONTR=0x83;//适用于12mhz以下的频率
  818.         IAP_CMD=3;
  819.         IAP_ADDRL=addrl;
  820.         IAP_ADDRH=addrh;
  821.         IAP_TRIG=0x5a;
  822.         IAP_TRIG=0xa5;
  823.         _nop_();
  824.         _nop_();
  825.         iaprst();
  826. }
  827. /*
  828. 日志 增加了关于eeprom的操作的函数
  829. ,现学现卖,一共就三个函数(iapinit
  830. 不需要管),204s就只有两个扇区,
  831. 0000-01ff,0200-03ff,每个地址号
  832. 都能存储一个char,一共是1024个。
  833. 使用方法:(先读出原有数据,)再
  834. 擦除扇区(擦除地址是扇区的首地址
  835. ),然后写入新值,(最后读出来)。
  836. 打算用0000存储倒计时还剩多少天,
  837. 0001存储当前的日期。程序上电先把
  838. 日期和倒数读到ram里,每隔几秒询
  839. 问1302,若有不同,则ram日期更新
  840. ,倒数减一(检测大于0),重写
  841. eeprom。           2020-2-25
  842. */


  843. /*******************************************************************************
  844. * 函 数 名         : Ds1302Write
  845. * 函数功能                   : 向DS1302命令(地址+数据)
  846. * 输    入         : addr,dat
  847. * 输    出         : 无
  848. *******************************************************************************/

  849. void Ds1302Write(u8 addr, u8 dat)
  850. {
  851.         u8 n;
  852.         RST = 0;
  853.         _nop_();

  854.         SCLK = 0;//先将SCLK置低电平。
  855.         _nop_();
  856.         RST = 1; //然后将RST(CE)置高电平。
  857.         _nop_();

  858.         for (n=0; n<8; n++)//开始传送八位地址命令
  859.         {
  860.                 DSIO = addr & 0x01;//数据从低位开始传送
  861.                 addr >>= 1;
  862.                 SCLK = 1;//数据在上升沿时,DS1302读取数据
  863.                 _nop_();  //时钟高电平时数据需要保持不动
  864.                 SCLK = 0;
  865.                 _nop_();
  866.         }
  867.         for (n=0; n<8; n++)//写入8位数据
  868.         {
  869.                 DSIO = dat & 0x01;
  870.                 dat >>= 1;
  871.                 SCLK = 1;//数据在上升沿时,DS1302读取数据
  872.                 _nop_();
  873.                 SCLK = 0;
  874.                 _nop_();        
  875.         }        
  876.                  
  877.         RST = 0;//传送数据结束
  878.         _nop_();
  879. }

  880. /*******************************************************************************
  881. * 函 数 名         : Ds1302Read
  882. * 函数功能                   : 读取一个地址的数据
  883. * 输    入         : addr
  884. * 输    出         : dat
  885. *******************************************************************************/

  886. u8 Ds1302Read(u8 addr)
  887. {
  888.         u8 n,dat,dat1;
  889.         RST = 0;
  890.         _nop_();

  891.         SCLK = 0;//先将SCLK置低电平。
  892.         _nop_();
  893.         RST = 1;//然后将RST(CE)置高电平。
  894.         _nop_();

  895.         for(n=0; n<8; n++)//开始传送八位地址命令
  896.         {
  897.                 DSIO = addr & 0x01;//数据从低位开始传送
  898.                 addr >>= 1;
  899.                 SCLK = 1;//数据在上升沿时,DS1302读取数据
  900.                 _nop_();
  901.                 SCLK = 0;//DS1302下降沿时,放置数据
  902.                 _nop_();
  903.         }
  904.         _nop_();
  905.         for(n=0; n<8; n++)//读取8位数据
  906.         {
  907.                 dat1 = DSIO;//从最低位开始接收
  908.                 dat = (dat>>1) | (dat1<<7);
  909.                 SCLK = 1;
  910.                 _nop_();
  911.                 SCLK = 0;//DS1302下降沿时,放置数据
  912.                 _nop_();
  913.         }

  914.         RST = 0;
  915.         _nop_();        //以下为DS1302复位的稳定时间,必须的。
  916.         SCLK = 1;
  917.         _nop_();
  918.         DSIO = 0;
  919.         _nop_();
  920.         DSIO = 1;
  921.         _nop_();
  922.         return dat;        
  923. }

  924. /*******************************************************************************
  925. * 函 数 名         : Ds1302Init
  926. * 函数功能                   : 初始化DS1302.
  927. * 输    入         : 无
  928. * 输    出         : 无
  929. *******************************************************************************/

  930. void Ds1302set()         
  931. {
  932.         u8 n;
  933.         Ds1302Write(0x8E,0X00);                 //关闭写保护功能
  934.         for (n=0; n<7; n++)//写入7个字节的时钟信号:分秒时日月周年          !!!此操作会破坏原有的时间数据!!!
  935.         {
  936.                 Ds1302Write(WRITE_RTC_ADDR[n],timeset[n]);        
  937.         }
  938.         Ds1302Write(0x8E,0x80);                 //打开写保护功能
  939. }

  940. /*******************************************************************************
  941. * 函 数 名         : Ds1302ReadTime
  942. * 函数功能                   : 读取时钟信息
  943. * 输    入         : 无
  944. * 输    出         : 无
  945. *******************************************************************************/

  946. void Ds1302ReadTime()
  947. {
  948.         u8 n;
  949.         for (n=0; n<7; n++)//读取7个字节的时钟信号:分秒时日月周年
  950.         {
  951.                 TIME[n] = Ds1302Read(READ_RTC_ADDR[n]);
  952.         }
  953.                
  954. }
  955. /*
  956. 添加了ds1302函数,通过全局变量传递
  957. 数据。通过每5秒钟检测一下星期并与
  958. ram里面的值比较,若有变化就日期减
  959. 一,并更新eeprom里面的值。注意ds1302
  960. 的数据格式,比如’13点’不是0x0c,
  961. 而是0x13,此之谓8421bcd码.
  962. */
复制代码
stc15.h可以用stc下载工具添加了mcu型号到keil中后再keil的文件夹里面找到,所有的函数都在里面了,帮助没黑币的小白真正实现白嫖),标有这是计划的一部分的是与ir接收相关的函数(包括看门狗设置)。说实在的,这是我首次给51单片机写这么长的代码。里面有的函数是我之前学的时候借鉴坛里大神的,在此表示感谢。


硬件制作
搭棚过程是先从数码管做起的(隔壁五家的垃圾数码管虽然便宜,可挑了半天才找到个好的)


搭棚的过程没怎么拍全,因为当时自己也没有做下去的信心

评分

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

查看全部评分

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

使用道具 举报

沙发
ID:519251 发表于 2020-3-4 00:29 | 只看该作者
刚刚不知咋的点发布了,不好意思,还没更完,
搭棚的过程没怎么拍全,因为当时自己也不确定会不会烂尾
我的设计是先用铜丝把数码管的 段 引脚引出并重新排序,放在下面一排,并接上8个限流电阻;位引脚上直接焊接上扩流三极管,三个扩流三极管共同引出一个vcc,基极接限流电阻到单片机。由于三个三极管在上面一层,所以单片机也安排在上面。单片机下面的空间自然就是74hc595了,三根引脚(ser,srclk,rclk)直接往上走连到单片机,单片机旁边再抽空安排一块ds1302,再见缝插针连上温度传感器ds18b29和一体化红外接收头和七彩自闪led。就是这一块的供电有点绕。
因为数据大多是点对点的,所以我的建议是先走数据线,后走供电线。而且电阻尽量直接连到ic的引脚上,这样可以降低ic被烫坏的概率。如果不能的话ic引脚上最好预先上锡,再把铜丝烧热后贴上去。1mm铜丝导热能力惊人,t12勉强够用,小心烫手。不建议用恒温烙铁,因为恒温烙铁容易把铜丝烧的过热,导致另一头已经焊好的焊点也脱落下来。
话不多说了,相信爱折腾的朋友自己可以解决搭棚焊的问题。上图:





下面支架上觉得太空了,就焊了个英文单词Persist(坚持)
"坚持,才是胜利!加油,奥里给!"
此时,全部的电路和程序均已经调试完毕,接下来就是准备用滴胶封起来了。

滴胶封装
封装之前还要解决一个问题,就是电源插座的问题。
如果不做任何处理的话,滴胶将流入电源孔内,导致无法接电。
我的解决办法就是用润滑脂把它填满,虽然有点浪费,但事实上很有效,且没有影响到导电性。
(鉴于我买的那管润滑脂质量太差,以至于在空气中放一会就会干燥失效,我觉得这也不算是浪费)
用美纹纸胶带盖起来顺便做个铭牌:
接下来就是激动人心的浇筑环节了:
用的模具是5*5*5的滴胶标本模具,
我用的是3:1硬胶,这次没做好消气泡的工作,留了点遗憾,如果有好的消气泡方法,望不吝赐教!

三日等待,一朝脱模:
这种模具比较深,不好弄,建议千万别加油性润滑剂(不好洗),不需要加任何液体,只需要用厚一点的纸片撑开四壁,自然就能一点点弄出来了。还有,这种硅胶模容易有划痕,别用太尖锐的东西。
小心去除电源孔的封堵:

完成!
成品图赏:

显示温度:

原创作品,转载请注明出处!
有问题或者建议的话可以加楼主QQ跤♂流:2764497627,请备注:51黑倒计时牌

P00303-130144.jpg (3.14 MB, 下载次数: 99)

P00303-130144.jpg

评分

参与人数 1黑币 +8 收起 理由
王朗的诱惑 + 8 优雅,艺术,有内味了

查看全部评分

回复

使用道具 举报

板凳
ID:519251 发表于 2020-3-4 00:30 | 只看该作者
代码一个字没改,可能有些奇怪的话,大家别在意
回复

使用道具 举报

地板
ID:214276 发表于 2020-3-15 04:24 | 只看该作者
绝对的动手达人,能出张原理图那就能学习了。
回复

使用道具 举报

5#
ID:695749 发表于 2020-3-15 19:12 | 只看该作者
动手能力强,想象力丰富,敢于实践,谢谢分享!
回复

使用道具 举报

6#
ID:377382 发表于 2020-4-5 13:27 | 只看该作者
谢谢分享!
回复

使用道具 举报

7#
ID:17204 发表于 2020-4-15 16:12 | 只看该作者
高手在人间,艺术品了!
回复

使用道具 举报

8#
ID:161785 发表于 2021-8-7 11:54 来自手机 | 只看该作者
正需要,就是不知道如何调剩余时间
回复

使用道具 举报

9#
ID:471579 发表于 2021-8-12 15:32 | 只看该作者
太厉害了,真是牛人
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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