找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 9248|回復(fù): 0
打印 上一主題 下一主題
收起左側(cè)

簡(jiǎn)明DS1302溫度LED時(shí)鐘制作詳解(附單片機(jī)源碼與PCB)

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
回顧
這是樓主在高三時(shí)候做的一個(gè)項(xiàng)目,我和我的組員們共同完成了這個(gè)小鐘從電路設(shè)計(jì),焊接,再到編程調(diào)試的過(guò)程。我們將之前學(xué)習(xí)到的單片機(jī)和電路知識(shí)運(yùn)用起來(lái),雖然經(jīng)歷了不計(jì)其數(shù)的Bug和坎坷,可是就是在這樣痛苦的過(guò)程中我們不知不覺(jué)中成長(zhǎng)了許多,收獲了更多的實(shí)戰(zhàn)經(jīng)驗(yàn)。
提出
一直以來(lái),我多數(shù)在開發(fā)軟件,偶爾碰碰Arduino實(shí)現(xiàn)點(diǎn)小功能,幸運(yùn)的是我的高中有機(jī)器人實(shí)驗(yàn)室,于是我們就在龔鵬老師的帶領(lǐng)下,系統(tǒng)的學(xué)習(xí)STC單片機(jī)開發(fā)和基礎(chǔ)硬件知識(shí)。上個(gè)學(xué)期,課程已經(jīng)基本學(xué)完,在7*5點(diǎn)陣的基礎(chǔ)下,我們幾個(gè)都想獨(dú)立自主的完成一個(gè)有規(guī)模的項(xiàng)目,在大家的提議下,我們選擇去做一個(gè)可以顯示溫度的LED時(shí)鐘,而且顯示要用LED才大氣,于是我們開始了有序的準(zhǔn)備工作。
實(shí)現(xiàn)
為了實(shí)現(xiàn)這個(gè)小鐘的預(yù)期功能,我們聽取了老師的意見。使用STC15W402AS芯片(宏晶科技生產(chǎn))作為主控芯片,利用LED小燈組成的4個(gè)“8”作為顯示部分,同時(shí)使用DS1302(Maxim生產(chǎn))作為系統(tǒng)時(shí)鐘芯片,使用DS18B20(Maxim生產(chǎn))作為溫度傳感器芯片。電源使用MicroUSB+5V供電。電路圖為自行設(shè)計(jì),使用Protel繪制,再有工廠加工,隨后按電路圖焊接原件,最后進(jìn)行編程調(diào)試。
圖片展示

結(jié)構(gòu)
使用STC15W402AS芯片(宏晶科技生產(chǎn))作為主控芯片,利用LED小燈組成的4個(gè)“8”作為顯示部分,同時(shí)使用DS1302(Maxim生產(chǎn))作為系統(tǒng)時(shí)鐘芯片,使用DS18B20(Maxim生產(chǎn))作為溫度傳感器芯片。電源使用MicroUSB+5V供電。電路圖為自行設(shè)計(jì)。
重要邏輯顯示原理 - 視覺(jué)暫留掃描
由于我們使用了類似于放大版“數(shù)碼管”的顯示方式,限于單片機(jī)引腳數(shù)量限制,我們不能把每個(gè)8的每個(gè)部分都和單片機(jī)相連。于是我們采用了現(xiàn)在LED顯示屏的顯示原理--掃描點(diǎn)亮的原理。在我們的電路中,我們將4個(gè)“8”的8個(gè)組成部分(a,b,c,d,e,f,g)的正極和單片機(jī)P1端口(恰好8個(gè)端口)連接(也就是把每個(gè)“8”的a并連起來(lái)接到一個(gè)單片機(jī)引腳,把每個(gè)“8”的b并連起來(lái)接到另一個(gè)單片機(jī)引腳,以此類推),再將每個(gè)“8”的所有組成部分的所有負(fù)極并聯(lián),分別和單片機(jī)上P2端口上的4個(gè)引腳相連,組成顯示控制電路。需要點(diǎn)亮第1個(gè)“8”時(shí)就先將這個(gè)“8”的負(fù)極引腳置低,再將需要點(diǎn)亮的部分引腳同時(shí)置高。例如下圖所示想要顯示“1”,就將b,c的引腳置高


這樣問(wèn)題就來(lái)了:現(xiàn)在我們能一個(gè)一個(gè)點(diǎn)亮了,如果我讓這4個(gè)“8”一起亮怎么辦?
這就需要視覺(jué)暫留原理了,大家都知道電影之所以能動(dòng)起來(lái)就是因?yàn)槲覀內(nèi)搜塾?.1秒的視覺(jué)暫留。我們點(diǎn)亮小燈也如此,先點(diǎn)亮第一個(gè),延遲5ms,再點(diǎn)亮第二個(gè),延遲5ms,以此類推。5ms這樣短的時(shí)間人根本看不出閃動(dòng)感,于是完整的圖像顯示出來(lái)。
下面是時(shí)間送顯的代碼(chart數(shù)組里是預(yù)先設(shè)計(jì)好的自模):
  1. void convertShow(char hour_s1,hour_s2,min_s1,min_s2)
  2. {

  3.     E1 = 0;
  4.     P1 = chart[hour_s1];
  5.     delayMS(5);
  6.     P1 = allclear;
  7.     E1 = 1;

  8.     E2 = 0;
  9.     P1 = chart[hour_s2];
  10.     delayMS(5);
  11.     P1 = allclear;
  12.     E2 = 1;

  13.     E3 = 0;
  14.     P1 = chart[min_s1];
  15.     delayMS(5);
  16.     P1 = allclear;
  17.     E3 = 1;

  18.     E4 = 0;
  19.     P1 = chart[min_s2];
  20.     delayMS(5);
  21.     P1 = allclear;
  22.     E4 = 1;
  23.     if(sec_2%0x02==0x01)
  24.     {
  25.         MDLIGHT = 0;
  26.     }
  27.     else
  28.     MDLIGHT = 1;
復(fù)制代碼

讀取時(shí)間和溫度
這個(gè)想起來(lái)很簡(jiǎn)單,無(wú)非是單片機(jī)一邊顯示,一邊不斷向時(shí)鐘芯片或者溫度芯片詢問(wèn)數(shù)據(jù),至于芯片如何驅(qū)動(dòng),則是后面要講的重頭戲
時(shí)間修改/模式切換 - 按鈕的使用
誰(shuí)家的鐘不能改時(shí)間啊,所以我們要支持時(shí)間修改功能,于是我們決定用傳統(tǒng)的按鈕來(lái)修改時(shí)間。使用三個(gè)按鈕(稱呼他們?yōu)锽tn1,Btn2,Btn3)。Btn1負(fù)責(zé)加時(shí)間,短按是加1,長(zhǎng)按遞加,直到松開。Btn2和Btn1相反,而Btn3則是模式切換(一共三種:修改小時(shí),修改分鐘,顯示溫度)。
可是在實(shí)際編程時(shí)我們發(fā)現(xiàn),按鈕只要收到輕微擾動(dòng)就響應(yīng),并不是按下才響應(yīng),這是為何?
原來(lái)通常的按鍵所用開關(guān)為機(jī)械彈性開關(guān),當(dāng)機(jī)械觸點(diǎn)斷開、閉合時(shí),由于機(jī)械觸點(diǎn)的彈性作用,一個(gè)按鍵開關(guān)在閉合時(shí)不會(huì)馬上穩(wěn)定地接通,在斷開時(shí)也不會(huì)一下子斷開。因而在閉合及斷開的瞬間均伴隨有一連串的抖動(dòng),為了不產(chǎn)生這種現(xiàn)象而作的措施就是按鍵消抖,如下圖。

看來(lái)我們需要軟件軟件消抖(硬件消抖效果好可是我們的電路圖已經(jīng)印刷了。\浖都礄z測(cè)出鍵閉合后執(zhí)行一個(gè)延時(shí)程序,5ms~10ms的延時(shí),讓前沿抖動(dòng)消失后再一次檢測(cè)鍵的狀態(tài),如果仍保持閉合狀態(tài)電平,則確認(rèn)為真正有鍵按下。當(dāng)檢測(cè)到按鍵釋放后,也要給5ms~10ms的延時(shí),待后沿抖動(dòng)消失后才能轉(zhuǎn)入該鍵的處理程序。程序如下:
  1. if (KEY_1==0 || KEY_2==0 || KEY_3==0)
  2.     {
  3.         delayMS(20);        //20毫秒軟件防抖
  4.         if (KEY_1 == 0)
  5.         {
  6.             keyValue = 1;
  7.             while(KEY_1==0)
  8.             {
  9.                 modifyTime(status+8);
  10.                 delayShow(500);
  11.             }
  12.         }
  13.         if (KEY_2 == 0)
  14.         {
  15.             keyValue = 2;
  16.             while(KEY_2==0)
  17.             {
  18.                 modifyTime(status+16);
  19.                 delayShow(500);
  20.             }
  21.         }
  22.         if (KEY_3 == 0)
  23.         {
  24.             keyValue = 3;
  25.         }
  26.     }
  27. }
復(fù)制代碼

下面是按鈕修改的代碼:
  1. /*************按鈕掃描函數(shù)******************************/
  2. void keyScan()
  3. {
  4.     if (KEY_1==0 || KEY_2==0 || KEY_3==0)
  5.     {
  6.         delayMS(20);        //20毫秒軟件防抖
  7.         if (KEY_1 == 0)
  8.         {
  9.             keyValue = 1;
  10.             while(KEY_1==0)
  11.             {
  12.                 modifyTime(status+8);
  13.                 delayShow(500);
  14.             }
  15.         }
  16.         if (KEY_2 == 0)
  17.         {
  18.             keyValue = 2;
  19.             while(KEY_2==0)
  20.             {
  21.                 modifyTime(status+16);
  22.                 delayShow(500);
  23.             }
  24.         }
  25.         if (KEY_3 == 0)
  26.         {
  27.             keyValue = 3;
  28.         }
  29.     }
  30. }

  31. /*************按鈕響應(yīng)處理函數(shù)******************************/
  32. void keyHandle()
  33. {
  34.     if(keyValue==1)
  35.     {
  36.         DS1302_Write(sec,min,hour,day,month,week,year);
  37.         keyValue = 0;
  38.     }
  39.     else if(keyValue==2)
  40.     {
  41.         DS1302_Write(sec,min,hour,day,month,week,year);
  42.         keyValue = 0;
  43.     }
  44.     else if(keyValue==3)
  45.     {
  46.         if (status==1)
  47.         {
  48.             status = 2;
  49.         }
  50.         else if(status==2)
  51.         {
  52.             status = 3;
  53.         }
  54.         else if(status==3)
  55.         {
  56.             status = 1;
  57.         }
  58.         keyValue = 0;

  59.     }
  60. }
復(fù)制代碼

還有修改時(shí)間的一些詭異邏輯代碼,涉及到一些標(biāo)志變量,請(qǐng)仔細(xì)研讀體會(huì):
  1. /*************修改時(shí)間函數(shù)******************************/
  2. void modifyTime(int mode)  //mode指明修改小時(shí)或分鐘   1:小時(shí)   2:分鐘
  3. {

  4.     //修改小時(shí)(1)+遞增(8)
  5.     if(mode == 9)
  6.     {
  7.         if(hour==0x23)
  8.         {
  9.             hour = 0x00;
  10.         }
  11.         else if(hour==0x09)
  12.         {
  13.             hour=0x10;
  14.         }
  15.         else if(hour==0x19)
  16.         {
  17.             hour=0x20;
  18.         }
  19.         else
  20.         {
  21.             hour=hour+0x01;
  22.         }

  23.         timeConvert();
  24.         convertShow(hour_1,hour_2,min_1,min_2);
  25.     }

  26.     //修改小時(shí)(1)+遞減(16)
  27.     if(mode == 17)
  28.     {
  29.         if(hour==0x00)
  30.         {
  31.             hour = 0x23;
  32.         }
  33.         else if(hour==0x10)
  34.         {
  35.             hour = 0x09;
  36.         }
  37.         else if(hour==0x20)
  38.         {
  39.             hour = 0x19;
  40.         }
  41.         else
  42.         {
  43.             hour = hour-0x01;
  44.         }

  45.         timeConvert();
  46.         convertShow(hour_1,hour_2,min_1,min_2);
  47.     }

  48.     //修改分鐘(2)+遞增(8)
  49.     if(mode == 10)
  50.     {

  51.         if(min==0x59)
  52.         {
  53.             min=0x00;
  54.         }
  55.         else if(min-(min_1<<4)==0x09)
  56.         {
  57.             min=(min_1+0x01)<<4;
  58.         }
  59.         else
  60.         {
  61.             min=min+0x01;
  62.         }

  63.         timeConvert();
  64.         convertShow(hour_1,hour_2,min_1,min_2);
  65.     }

  66.     //修改分鐘(2)+遞減(16)
  67.     if(mode == 18)
  68.     {
  69.         if(min==0x00)
  70.         {
  71.             min=0x59;
  72.         }
  73.         else if(min_2==0x00)
  74.         {
  75.             min=min-0x10;
  76.             min=min+0x09;
  77.         }
  78.         else
  79.         {
  80.             min=min-0x01;
  81.         }

  82.         timeConvert();
  83.         convertShow(hour_1,hour_2,min_1,min_2);
  84.     }
  85. }
復(fù)制代碼

整體邏輯
各部分的邏輯設(shè)計(jì)都完成了,我們現(xiàn)在開始設(shè)計(jì)整個(gè)程序的主函數(shù)部分。單片機(jī)上電后首先初始化(包括引腳置低什么的不再贅述)檢測(cè)DS1302是否在運(yùn)行(內(nèi)置電池可以掉電走時(shí)),如果在運(yùn)行就讀取時(shí)間送顯,不在運(yùn)行就起振(開始走時(shí))。然后在每個(gè)顯示函數(shù)過(guò)后偵測(cè)按鈕操作,如果發(fā)現(xiàn)有效按鈕操作就進(jìn)行處理按鈕的邏輯,該修改時(shí)間就修改時(shí)間,該顯示溫度就顯示溫度。這個(gè)流程用死循環(huán)加以嵌套,就可以無(wú)止無(wú)休的運(yùn)行下去(不斷電的話)。下面是主函數(shù)代碼:
  1. void main()
  2. {
  3.     init();

  4.     while(1)
  5.     {
  6.         if(status==3)
  7.         {
  8.             temp = DS18B20_ReadTemp();
  9.             tempHandle();
  10.             tempshow(temp_1,temp_2);
  11.         }
  12.         else
  13.         {
  14.             DS1302_readtime();
  15.             convertShow(hour_1,hour_2,min_1,min_2);
  16.         }
  17.         keyScan();
  18.         if(keyValue!=0&&KEY_1==1&&KEY_2==1&&KEY_3==1)
  19.         {
  20.             keyHandle();
  21.         }
  22.     }
  23. }
復(fù)制代碼

下面是初始化函數(shù):
  1. void init()
  2. {
  3.     //關(guān)閉所有小燈
  4.     E1=1;
  5.     E2=1;
  6.     E3=1;
  7.     E4=1;
  8.     MDLIGHT = 1;
  9.     P1 = allclear;
  10.     T_CE = 0;
  11.     T_SCLK = 0;

  12.     //默認(rèn)初始化時(shí)間12:00
  13.     sec = 0x00;
  14.     min = 0x00;
  15.     hour = 0x16;
  16.     year = 0x01;
  17.     month = 0x01;
  18.     week = 0x01;
  19.     day = 0x01;
  20.     status = 1;
  21.     keyValue = 0;
  22.     delayMS(1000);
  23.     //DS1302初始化判斷是否存在后備電源

  24.     if(DS1302_Read(0x81)&0x80==0x80)
  25.     {
  26.         DS1302_Write_one(0x8e,0x00);
  27.         DS1302_Write_one(0x80,sec);  //起振
  28.         DS1302_Write_one(0x8e,0x80);
  29.     }
  30.     else
  31.     {

  32.     }
  33. }
復(fù)制代碼

下面附上DS1302類庫(kù),親測(cè)好用:
  1. /*************寫入一字節(jié)****************/
  2. void DS1302_Input_Byte(char Input)  //向時(shí)鐘IC寫入一字節(jié)
  3. {
  4.     char i;
  5.     T_SCLK = 0;
  6.     delay2us();
  7.     ACC =Input;
  8.     for(i=8; i>0; i--)
  9.     {
  10.         T_DIO = ACC_0;            //相當(dāng)于匯編中的 RRC
  11.         delay2us();
  12.         T_SCLK = 1;
  13.         delay2us();
  14.         T_SCLK = 0;
  15.         ACC = ACC >> 1;
  16.     }
  17. }

  18. /*************讀取一字節(jié)****************/
  19. char DS1302_Output_Byte(void)      //從時(shí)鐘IC讀取一字節(jié)()
  20. {
  21.     char i;
  22.     for(i=8; i>0; i--)
  23.     {
  24.         ACC>>=1;
  25.         T_DIO= 1;
  26.         delay2us();
  27.         ACC_7 = T_DIO;
  28.         T_SCLK = 1;                 //相當(dāng)于匯編中的 RRC
  29.         delay2us();
  30.         T_SCLK = 0;
  31.         delay2us();
  32.     }
  33.     T_DIO = 0;
  34.     delay2us();
  35.     return(ACC);
  36. }

  37. /*************寫一字節(jié)數(shù)據(jù)****************/
  38. void DS1302_Write_one( char addr,dat )       // 寫入地址、數(shù)據(jù)子程序
  39. {
  40.     T_CE=0;                             //T_CE引腳為低,數(shù)據(jù)傳送中止
  41.     T_SCLK=0;                          //清零時(shí)鐘總線
  42.     T_CE = 1;                          //T_CE引腳為高,邏輯控制有效
  43.     DS1302_Input_Byte(addr);           // 地址,命令
  44.     DS1302_Input_Byte(dat);          // 寫1Byte數(shù)據(jù)
  45.     T_SCLK = 1;
  46.     T_CE = 0;
  47. }

  48. /*************讀一字節(jié)數(shù)據(jù)****************/
  49. char DS1302_Read ( char addr )    //數(shù)據(jù)讀取子程序
  50. {
  51.     char date;
  52.     T_CE=0;
  53.     T_SCLK=0;
  54.     T_CE = 1;
  55.     DS1302_Input_Byte(addr);        // 地址,命令
  56.     date = DS1302_Output_Byte();         // 讀1Byte數(shù)據(jù)
  57.     T_SCLK = 1;
  58.     T_CE = 0;
  59.     return(date);
  60. }


  61. /*************寫入時(shí)間數(shù)據(jù)****************/
  62. void DS1302_Write(char sec_w,min_w,hour_w,day_w,month_w,week_w,year_w)
  63. {
  64.     DS1302_Write_one(0x8e,0x00);
  65.     DS1302_Write_one(0x82,min_w);
  66.     DS1302_Write_one(0x84,hour_w);
  67.     DS1302_Write_one(0x86,day_w);
  68.     DS1302_Write_one(0x88,month_w);
  69.     DS1302_Write_one(0x8a,week_w);
  70.     DS1302_Write_one(0x8c,year_w);
  71.     DS1302_Write_one(0x80,sec_w);
  72.     DS1302_Write_one(0x8e,0x80);

  73. }

  74. /*************時(shí)間轉(zhuǎn)換為顯示格式****************/
  75. void timeConvert()
  76. {
  77.     sec_1 = sec>>4;
  78.     sec_2 = sec&0x0f;
  79.     min_1 = min>>4;
  80.     min_2 = min&0x0f;
  81.     hour_1 = hour>>4;
  82.     hour_2 = hour&0x0f;

  83. }

  84. /*************從芯片讀取時(shí)間****************/
  85. void DS1302_readtime()
  86. {
  87.     sec=DS1302_Read(0x81);                    //讀秒
  88.     min=DS1302_Read(0x83);                    //讀分
  89.     hour=DS1302_Read(0x85);                   //讀時(shí)
  90.     day=DS1302_Read(0x87);                    //讀日
  91.     month=DS1302_Read(0x89);                  //讀月
  92.     year=DS1302_Read(0x8d);                   //讀年
  93.     week=DS1302_Read(0x8b);                   //讀星期
  94.     timeConvert();

  95. }
復(fù)制代碼

DIY教程Windows
1.克隆或下載本倉(cāng)庫(kù),PCB電路圖在倉(cāng)庫(kù)內(nèi),印刷后按照引腳焊接元件。
2.下載宏晶科技官網(wǎng)所提供的相關(guān)燒錄軟件與教程,并安裝。
3.下載KeilC51開發(fā)工具,并安裝。
4.下載TKStudio,并安裝(可選)。
5.使用USB轉(zhuǎn)TTl燒錄器連接板載串口與計(jì)算機(jī)(如果需要驅(qū)動(dòng)請(qǐng)自行安裝)
6.使用STC燒錄軟件,選擇STC15W402AS型號(hào),使用默認(rèn)配置(單片機(jī)震蕩頻率11.0592MHz),載入想要燒錄的二進(jìn)制文件,上電燒錄。
7.如果需要增加修改邏輯代碼,可以使用TKStudio打開main-code/Clock.xmp進(jìn)行二次開發(fā),其他IDE也可。
最后附上代碼以及PCB:



全部資料51hei下載地址:
ds1302-stc15-clock-master.zip (184.78 KB, 下載次數(shù): 73)

評(píng)分

參與人數(shù) 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏3 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表