回顧 這是樓主在高三時(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)試。 圖片展示
DSC_0093-300x199.jpg (9.89 KB, 下載次數(shù): 73)
下載附件
2018-5-7 17:49 上傳
DSC_0072-min-300x199.jpg (14.98 KB, 下載次數(shù): 69)
下載附件
2018-5-7 17:49 上傳
DSC_0088-min-300x199.jpg (12.15 KB, 下載次數(shù): 73)
下載附件
2018-5-7 17:49 上傳
結(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的引腳置高
timg-215x300.jpg (12.57 KB, 下載次數(shù): 80)
下載附件
2018-5-7 17:49 上傳
這樣問(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ì)好的自模): - void convertShow(char hour_s1,hour_s2,min_s1,min_s2)
- {
- E1 = 0;
- P1 = chart[hour_s1];
- delayMS(5);
- P1 = allclear;
- E1 = 1;
- E2 = 0;
- P1 = chart[hour_s2];
- delayMS(5);
- P1 = allclear;
- E2 = 1;
- E3 = 0;
- P1 = chart[min_s1];
- delayMS(5);
- P1 = allclear;
- E3 = 1;
- E4 = 0;
- P1 = chart[min_s2];
- delayMS(5);
- P1 = allclear;
- E4 = 1;
- if(sec_2%0x02==0x01)
- {
- MDLIGHT = 0;
- }
- else
- 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)象而作的措施就是按鍵消抖,如下圖。
20150722113229813.jpg (8.17 KB, 下載次數(shù): 70)
下載附件
2018-5-7 17:49 上傳
看來(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)入該鍵的處理程序。程序如下: - if (KEY_1==0 || KEY_2==0 || KEY_3==0)
- {
- delayMS(20); //20毫秒軟件防抖
- if (KEY_1 == 0)
- {
- keyValue = 1;
- while(KEY_1==0)
- {
- modifyTime(status+8);
- delayShow(500);
- }
- }
- if (KEY_2 == 0)
- {
- keyValue = 2;
- while(KEY_2==0)
- {
- modifyTime(status+16);
- delayShow(500);
- }
- }
- if (KEY_3 == 0)
- {
- keyValue = 3;
- }
- }
- }
復(fù)制代碼
下面是按鈕修改的代碼:- /*************按鈕掃描函數(shù)******************************/
- void keyScan()
- {
- if (KEY_1==0 || KEY_2==0 || KEY_3==0)
- {
- delayMS(20); //20毫秒軟件防抖
- if (KEY_1 == 0)
- {
- keyValue = 1;
- while(KEY_1==0)
- {
- modifyTime(status+8);
- delayShow(500);
- }
- }
- if (KEY_2 == 0)
- {
- keyValue = 2;
- while(KEY_2==0)
- {
- modifyTime(status+16);
- delayShow(500);
- }
- }
- if (KEY_3 == 0)
- {
- keyValue = 3;
- }
- }
- }
- /*************按鈕響應(yīng)處理函數(shù)******************************/
- void keyHandle()
- {
- if(keyValue==1)
- {
- DS1302_Write(sec,min,hour,day,month,week,year);
- keyValue = 0;
- }
- else if(keyValue==2)
- {
- DS1302_Write(sec,min,hour,day,month,week,year);
- keyValue = 0;
- }
- else if(keyValue==3)
- {
- if (status==1)
- {
- status = 2;
- }
- else if(status==2)
- {
- status = 3;
- }
- else if(status==3)
- {
- status = 1;
- }
- keyValue = 0;
- }
- }
復(fù)制代碼
還有修改時(shí)間的一些詭異邏輯代碼,涉及到一些標(biāo)志變量,請(qǐng)仔細(xì)研讀體會(huì):- /*************修改時(shí)間函數(shù)******************************/
- void modifyTime(int mode) //mode指明修改小時(shí)或分鐘 1:小時(shí) 2:分鐘
- {
- //修改小時(shí)(1)+遞增(8)
- if(mode == 9)
- {
- if(hour==0x23)
- {
- hour = 0x00;
- }
- else if(hour==0x09)
- {
- hour=0x10;
- }
- else if(hour==0x19)
- {
- hour=0x20;
- }
- else
- {
- hour=hour+0x01;
- }
- timeConvert();
- convertShow(hour_1,hour_2,min_1,min_2);
- }
- //修改小時(shí)(1)+遞減(16)
- if(mode == 17)
- {
- if(hour==0x00)
- {
- hour = 0x23;
- }
- else if(hour==0x10)
- {
- hour = 0x09;
- }
- else if(hour==0x20)
- {
- hour = 0x19;
- }
- else
- {
- hour = hour-0x01;
- }
- timeConvert();
- convertShow(hour_1,hour_2,min_1,min_2);
- }
- //修改分鐘(2)+遞增(8)
- if(mode == 10)
- {
- if(min==0x59)
- {
- min=0x00;
- }
- else if(min-(min_1<<4)==0x09)
- {
- min=(min_1+0x01)<<4;
- }
- else
- {
- min=min+0x01;
- }
- timeConvert();
- convertShow(hour_1,hour_2,min_1,min_2);
- }
- //修改分鐘(2)+遞減(16)
- if(mode == 18)
- {
- if(min==0x00)
- {
- min=0x59;
- }
- else if(min_2==0x00)
- {
- min=min-0x10;
- min=min+0x09;
- }
- else
- {
- min=min-0x01;
- }
- timeConvert();
- convertShow(hour_1,hour_2,min_1,min_2);
- }
- }
復(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ù)代碼: - void main()
- {
- init();
- while(1)
- {
- if(status==3)
- {
- temp = DS18B20_ReadTemp();
- tempHandle();
- tempshow(temp_1,temp_2);
- }
- else
- {
- DS1302_readtime();
- convertShow(hour_1,hour_2,min_1,min_2);
- }
- keyScan();
- if(keyValue!=0&&KEY_1==1&&KEY_2==1&&KEY_3==1)
- {
- keyHandle();
- }
- }
- }
復(fù)制代碼
下面是初始化函數(shù):- void init()
- {
- //關(guān)閉所有小燈
- E1=1;
- E2=1;
- E3=1;
- E4=1;
- MDLIGHT = 1;
- P1 = allclear;
- T_CE = 0;
- T_SCLK = 0;
- //默認(rèn)初始化時(shí)間12:00
- sec = 0x00;
- min = 0x00;
- hour = 0x16;
- year = 0x01;
- month = 0x01;
- week = 0x01;
- day = 0x01;
- status = 1;
- keyValue = 0;
- delayMS(1000);
- //DS1302初始化判斷是否存在后備電源
- if(DS1302_Read(0x81)&0x80==0x80)
- {
- DS1302_Write_one(0x8e,0x00);
- DS1302_Write_one(0x80,sec); //起振
- DS1302_Write_one(0x8e,0x80);
- }
- else
- {
- }
- }
復(fù)制代碼
下面附上DS1302類庫(kù),親測(cè)好用:- /*************寫入一字節(jié)****************/
- void DS1302_Input_Byte(char Input) //向時(shí)鐘IC寫入一字節(jié)
- {
- char i;
- T_SCLK = 0;
- delay2us();
- ACC =Input;
- for(i=8; i>0; i--)
- {
- T_DIO = ACC_0; //相當(dāng)于匯編中的 RRC
- delay2us();
- T_SCLK = 1;
- delay2us();
- T_SCLK = 0;
- ACC = ACC >> 1;
- }
- }
-
- /*************讀取一字節(jié)****************/
- char DS1302_Output_Byte(void) //從時(shí)鐘IC讀取一字節(jié)()
- {
- char i;
- for(i=8; i>0; i--)
- {
- ACC>>=1;
- T_DIO= 1;
- delay2us();
- ACC_7 = T_DIO;
- T_SCLK = 1; //相當(dāng)于匯編中的 RRC
- delay2us();
- T_SCLK = 0;
- delay2us();
- }
- T_DIO = 0;
- delay2us();
- return(ACC);
- }
-
- /*************寫一字節(jié)數(shù)據(jù)****************/
- void DS1302_Write_one( char addr,dat ) // 寫入地址、數(shù)據(jù)子程序
- {
- T_CE=0; //T_CE引腳為低,數(shù)據(jù)傳送中止
- T_SCLK=0; //清零時(shí)鐘總線
- T_CE = 1; //T_CE引腳為高,邏輯控制有效
- DS1302_Input_Byte(addr); // 地址,命令
- DS1302_Input_Byte(dat); // 寫1Byte數(shù)據(jù)
- T_SCLK = 1;
- T_CE = 0;
- }
-
- /*************讀一字節(jié)數(shù)據(jù)****************/
- char DS1302_Read ( char addr ) //數(shù)據(jù)讀取子程序
- {
- char date;
- T_CE=0;
- T_SCLK=0;
- T_CE = 1;
- DS1302_Input_Byte(addr); // 地址,命令
- date = DS1302_Output_Byte(); // 讀1Byte數(shù)據(jù)
- T_SCLK = 1;
- T_CE = 0;
- return(date);
- }
-
-
- /*************寫入時(shí)間數(shù)據(jù)****************/
- void DS1302_Write(char sec_w,min_w,hour_w,day_w,month_w,week_w,year_w)
- {
- DS1302_Write_one(0x8e,0x00);
- DS1302_Write_one(0x82,min_w);
- DS1302_Write_one(0x84,hour_w);
- DS1302_Write_one(0x86,day_w);
- DS1302_Write_one(0x88,month_w);
- DS1302_Write_one(0x8a,week_w);
- DS1302_Write_one(0x8c,year_w);
- DS1302_Write_one(0x80,sec_w);
- DS1302_Write_one(0x8e,0x80);
-
- }
-
- /*************時(shí)間轉(zhuǎn)換為顯示格式****************/
- void timeConvert()
- {
- sec_1 = sec>>4;
- sec_2 = sec&0x0f;
- min_1 = min>>4;
- min_2 = min&0x0f;
- hour_1 = hour>>4;
- hour_2 = hour&0x0f;
-
- }
-
- /*************從芯片讀取時(shí)間****************/
- void DS1302_readtime()
- {
- sec=DS1302_Read(0x81); //讀秒
- min=DS1302_Read(0x83); //讀分
- hour=DS1302_Read(0x85); //讀時(shí)
- day=DS1302_Read(0x87); //讀日
- month=DS1302_Read(0x89); //讀月
- year=DS1302_Read(0x8d); //讀年
- week=DS1302_Read(0x8b); //讀星期
- timeConvert();
-
- }
復(fù)制代碼
DIY教程Windows1.克隆或下載本倉(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:
0.png (46.17 KB, 下載次數(shù): 71)
下載附件
2018-5-7 17:44 上傳
0.png (5.37 KB, 下載次數(shù): 84)
下載附件
2018-5-7 17:45 上傳
全部資料51hei下載地址:
ds1302-stc15-clock-master.zip
(184.78 KB, 下載次數(shù): 73)
2018-5-7 17:39 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
|