久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 6630|回復: 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 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: av色在线 | 日韩在线欧美 | 欧美综合久久久 | 国产精品久久久久一区二区三区 | 一级毛片免费完整视频 | 青青久久 | 在线中文视频 | 精品久久九九 | 国产亚洲精品美女久久久久久久久久 | 久久久久网站 | 中文字幕高清免费日韩视频在线 | 日韩精品一区二区三区免费观看 | 精品一区二区三区日本 | 免费精品 | 欧美日韩国产三级 | 中文字幕人成乱码在线观看 | 久久成人18免费网站 | 欧美在线视频二区 | 91精品久久久久久久99 | 国产精品久久国产精品久久 | 日韩中文字幕一区二区三区 | 国产成人在线免费 | 91视频导航| 91成人精品 | 在线色网址 | 中文字幕日韩专区 | 欧美在线 | 99久久久久| 欧美中文一区 | 日韩久久久久久 | 亚洲欧美在线观看 | 91香蕉| 国产1区| 毛片网站在线观看视频 | 国产精品一区二区在线 | 久久在线视频 | 伊人伊人 | 日韩av中文| 91免费小视频 | 一区二区影视 | 国产一区二区黑人欧美xxxx |