單片機(jī)綜合練習(xí)
結(jié)合前幾天來(lái)寫過(guò)的文章, 今天總算寫了一個(gè)功能較多的應(yīng)用 - 多功能時(shí)鐘, 集時(shí)鐘, 秒表, 溫度計(jì)一體.
基礎(chǔ)文章:
1.單片機(jī)練習(xí) - DS18B20溫度轉(zhuǎn)換與顯示
2.用C51編寫單片機(jī)延時(shí)函數(shù)
3.單片機(jī)練習(xí) - 定時(shí)器
4.單片機(jī)練習(xí) - 計(jì)時(shí)器
實(shí)驗(yàn)板:TX-1B實(shí)驗(yàn)板
6位數(shù)碼管與單片機(jī)的連接電路圖
按鍵S2, S3與單片機(jī)的連接電路圖: 其中S2與P3.4連, S3與P3.5連接...
DS18B20與單片機(jī)連接電路圖:
具體按鍵功能分配請(qǐng)看源代碼注釋部分:
1//多功能時(shí)鐘,精確到小數(shù)0.01秒,即10ms
2//功能:時(shí)鐘,秒表,溫度計(jì)
3
4/*
5S5鍵為功能選擇鍵,上電默認(rèn)使用時(shí)鐘功能
6功能順序?yàn)?時(shí)鐘,溫度計(jì),秒表
7
8mode=1.時(shí)鐘(每次掉電后都要重新設(shè)置時(shí)間)
91)當(dāng)選中時(shí)鐘功能時(shí),具體按鍵功能如下:
10
112)可設(shè)置時(shí)分秒,時(shí)利用發(fā)光二極管顯示,分秒用數(shù)碼管顯示
12
133)時(shí)鐘:采用定時(shí)器0計(jì)時(shí),工作方式1
14
15mode=2.時(shí)鐘設(shè)置模式
16當(dāng)選中時(shí)鐘設(shè)置模式
17S2為位選,S3為增加選中位的值
18S4確定更改,S5放棄更改,進(jìn)入秒表模式
19
20mode=3.秒表
211)當(dāng)選中秒表功能時(shí),具體按鍵功能如下:
22S2為開(kāi)始/暫停,S3為清零
23
242)采用定時(shí)器1計(jì)時(shí),工作方式1
25
26mode=4.溫度計(jì)
271)利用DS18B20檢測(cè)環(huán)境溫度;
282)最小溫度值為0.01℃,可表示溫度范圍:-55℃~+125℃
29
30*/
31
32#include
33#include
34#include
35
36//0-F數(shù)碼管的編碼(共陰極)
37unsignedcharcodetable[]={0x3f,0x06,0x5b,0x4f,0x66,
380x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
39//0-9數(shù)碼管的編碼(共陰極),帶小數(shù)點(diǎn)
40unsignedcharcodetableWidthDot[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,
410x87,0xff,0xef};
42
43sbitwela=P2^7;//數(shù)碼管位選
44sbitdula=P2^6;//數(shù)碼管段選
45sbitds=P2^2;
46unsignedcharth,tl,mode=1;//mode存放功能模式,默認(rèn)在模式1時(shí)鐘
47unsignedcharclockPosition=0;//時(shí)鐘設(shè)置模式下,光標(biāo)所在的位置;默認(rèn)在0
48unsignedcharclockTmp=0;//用于時(shí)鐘模式下臨時(shí)計(jì)數(shù)
49bitclockTmpBit=0;//用于時(shí)鐘模式下臨時(shí)標(biāo)志位
50
51//秒4字節(jié),分2字節(jié),時(shí)1字節(jié)
52unsignedchardatas[]={0,0,0,0,0,0,0};//保存計(jì)時(shí)器數(shù)據(jù)
53unsignedcharclockDatas[]={0,0,0,0,0,0,0};//保存時(shí)鐘數(shù)據(jù)
54unsignedchar*values=clockDatas;//根據(jù)mode選擇適當(dāng)?shù)臄?shù)據(jù)數(shù)組指針
55inttempValue;//存放溫度值
56unsignedchartempCount=0;//用于記錄顯示了多少次溫度值,用于定時(shí)
57
58sbitS2=P3^4;//鍵S2,作開(kāi)始/暫停
59sbitS3=P3^5;//鍵S3,清零
60sbitS4=P3^6;//鍵S4
61sbitS5=P3^7;//鍵S5
62unsignedchartmpDatas[]={0,0,0,0,0,0,0};//存放臨時(shí)設(shè)置值
63unsignedcharicount;
64
65//延時(shí)函數(shù),對(duì)于11.0592MHz時(shí)鐘,例i=5,則大概延時(shí)5ms.
66voiddelay(unsignedinti)
67{
68unsignedintj;
69while(i--)
70{
71for(j=0;j<125;j++);
72}
73}
74
75/***********************溫度計(jì)模式******************************/
76
77//初始化DS18B20
78//讓DS18B20一段相對(duì)長(zhǎng)時(shí)間低電平,然后一段相對(duì)非常短時(shí)間高電平,即可啟動(dòng)
79voiddsInit()
80{
81//對(duì)于11.0592MHz時(shí)鐘,unsignedint型的i,作一個(gè)i++操作的時(shí)間大于為8us
82unsignedinti;
83ds=0;
84i=100;//拉低約800us,符合協(xié)議要求的480us以上
85while(i>0)i--;
86ds=1;//產(chǎn)生一個(gè)上升沿,進(jìn)入等待應(yīng)答狀態(tài)
87i=4;
88while(i>0)i--;
89}
90
91voiddsWait()
92{
93unsignedinti;
94while(ds);
95while(~ds);//檢測(cè)到應(yīng)答脈沖
96i=4;
97while(i>0)i--;
98}
99
100//向DS18B20讀取一位數(shù)據(jù)
101//讀一位,讓DS18B20一小周期低電平,然后兩小周期高電平,
102//之后DS18B20則會(huì)輸出持續(xù)一段時(shí)間的一位數(shù)據(jù)
103bitreadBit()
104{
105unsignedinti;
106bitb;
107ds=0;
108i++;//延時(shí)約8us,符合協(xié)議要求至少保持1us
109ds=1;
110i++;i++;//延時(shí)約16us,符合協(xié)議要求的至少延時(shí)15us以上
111b=ds;
112i=8;
113while(i>0)i--;//延時(shí)約64us,符合讀時(shí)隙不低于60us要求
114returnb;
115}
116
117//讀取一字節(jié)數(shù)據(jù),通過(guò)調(diào)用readBit()來(lái)實(shí)現(xiàn)
118unsignedcharreadByte()
119{
120unsignedinti;
121unsignedcharj,dat;
122dat=0;
123for(i=0;i<8;i++)
124{
125j=readBit();
126//最先讀出的是最低位數(shù)據(jù)
127dat=(j<<7)|(dat>>1);
128}
129returndat;
130}
131
132//向DS18B20寫入一字節(jié)數(shù)據(jù)
133voidwriteByte(unsignedchardat)
134{
135unsignedinti;
136unsignedcharj;
137bitb;
138for(j=0;j<8;j++)
139{
140b=dat&0x01;
141dat>>=1;
142//寫"1",將DQ拉低15us后,在15us~60us內(nèi)將DQ拉高,即完成寫1
143if(b)
144{
145ds=0;
146i++;i++;//拉低約16us,符號(hào)要求15~60us內(nèi)
147ds=1;
148i=8;while(i>0)i--;//延時(shí)約64us,符合寫時(shí)隙不低于60us要求
149}
150else//寫"0",將DQ拉低60us~120us
151{
152ds=0;
153i=8;while(i>0)i--;//拉低約64us,符號(hào)要求
154ds=1;
155i++;i++;//整個(gè)寫0時(shí)隙過(guò)程已經(jīng)超過(guò)60us,這里就不用像寫1那樣,再延時(shí)64us了
156}
157}
158}
159
160//向DS18B20發(fā)送溫度轉(zhuǎn)換命令
161voidsendChangeCmd()
162{
163dsInit();//初始化DS18B20,無(wú)論什么命令,首先都要發(fā)起初始化
164dsWait();//等待DS18B20應(yīng)答
165delay(1);//延時(shí)1ms,因?yàn)镈S18B20會(huì)拉低DQ60~240us作為應(yīng)答信號(hào)
166writeByte(0xcc);//寫入跳過(guò)序列號(hào)命令字SkipRom
167writeByte(0x44);//寫入溫度轉(zhuǎn)換命令字ConvertT
168}
169
170//向DS18B20發(fā)送讀取數(shù)據(jù)命令
171voidsendReadCmd()
172{
173dsInit();
174dsWait();
175delay(1);
176writeByte(0xcc);//寫入跳過(guò)序列號(hào)命令字SkipRom
177writeByte(0xbe);//寫入讀取數(shù)據(jù)令字ReadScratchpad
178}
179
180//獲取當(dāng)前溫度值
181voidgetTempValue()
182{
183unsignedinttmpvalue;
184floatt;
185unsignedcharlow,high;
186sendReadCmd();
187//連續(xù)讀取兩個(gè)字節(jié)數(shù)據(jù)
188low=readByte();
189high=readByte();
190//將高低兩個(gè)字節(jié)合成一個(gè)整形變量
191//計(jì)算機(jī)中對(duì)于負(fù)數(shù)是利用補(bǔ)碼來(lái)表示的
192//若是負(fù)值,讀取出來(lái)的數(shù)值是用補(bǔ)碼表示的,可直接賦值給int型的value
193tmpvalue=high;
194tmpvalue<<=8;
195tmpvalue|=low;
196tempValue=tmpvalue;
197
198//使用DS18B20的默認(rèn)分辨率12位,精確度為0.0625度,即讀回?cái)?shù)據(jù)的最低位代表0.0625度
199t=tempValue*0.0625;
200//將它放大100倍,使顯示時(shí)可顯示小數(shù)點(diǎn)后兩位,并對(duì)小數(shù)點(diǎn)后第三進(jìn)行4舍5入
201//如t=11.0625,進(jìn)行計(jì)數(shù)后,得到value=1106,即11.06度
202//如t=-11.0625,進(jìn)行計(jì)數(shù)后,得到value=-1106,即-11.06度
203tempValue=t*100+(tempValue>0?0.5:-0.5);//大于0加0.5,小于0減0.5
204}
205
206//顯示當(dāng)前溫度值,精確到小數(shù)點(diǎn)后一位
207//若先位選再段選,由于IO口默認(rèn)輸出高電平,所以當(dāng)先位選會(huì)使數(shù)碼管出現(xiàn)亂碼
208voiddisplayTemp()
209{
210unsignedchari;
211unsignedinttmp=abs(tempValue);
212tmpDatas[0]=tmp/10000;
213tmpDatas[1]=tmp%10000/1000;
214tmpDatas[2]=tmp%1000/100;
215tmpDatas[3]=tmp%100/10;
216tmpDatas[4]=tmp%10;
217if(tempValue<0)
218{
219//關(guān)位選,去除對(duì)上一位的影響
220P0=0xff;
221wela=1;//打開(kāi)鎖存,給它一個(gè)下降沿量
222wela=0;
223//段選
224P0=0x40;//顯示"-"號(hào)
225dula=1;//打開(kāi)鎖存,給它一個(gè)下降沿量
226dula=0;
227
228//位選
229P0=0xfe;
230wela=1;//打開(kāi)鎖存,給它一個(gè)下降沿量
231wela=0;
232delay(1);
233}
234for(i=0;i!=5;i++)
235{
236//關(guān)位選,去除對(duì)上一位的影響
237P0=0xff;
238wela=1;//打開(kāi)鎖存,給它一個(gè)下降沿量
239wela=0;
240//段選
241if(i!=2)
242{
243P0=table[tmpDatas[i]];//顯示數(shù)字
244}
245else
246{
247P0=tableWidthDot[tmpDatas[i]];//顯示帶小數(shù)點(diǎn)數(shù)字
248}
249dula=1;//打開(kāi)鎖存,給它一個(gè)下降沿量
250dula=0;
251
252//位選
253P0=_crol_(0xfd,i);//選擇第(i+1)個(gè)數(shù)碼管
254wela=1;//打開(kāi)鎖存,給它一個(gè)下降沿量
255wela=0;
256delay(1);
257}
258tempCount++;
259if(tempCount==100)
260{
261tempCount=0;
262getTempValue();
263sendChangeCmd();
264}
265}
266
267//顯示時(shí)鐘和秒表的結(jié)果
268voiddisplay()
269{
270unsignedchari;
271if(mode==4)//顯示溫度
272{
273displayTemp();
274}
275else{//顯示時(shí)間
276for(i=0;i<6;i++)
277{
278//關(guān)位選,去除對(duì)上一位的影響
279P0=0xff;
280wela=1;//打開(kāi)鎖存,給它一個(gè)下降沿量
281wela=0;
282//段選
283if(i==2||i==4)
284{
285P0=tableWidthDot[values[i]];//顯示帶小數(shù)點(diǎn)數(shù)字,作為分秒,秒與毫秒的分隔
286}
287else
288{
289P0=table[values[i]];//顯示數(shù)字
290}
291if(mode==2&&i==clockPosition)//時(shí)鐘設(shè)置模式下,光標(biāo)所在位置,閃爍
292{
293clockTmp++;
294if(clockTmp==20)
295{
296clockTmpBit=~clockTmpBit;
297clockTmp=0;
298}
299if(clockTmpBit)
300P0=0x00;
301}
302dula=1;//打開(kāi)鎖存,給它一個(gè)下降沿量
303dula=0;
304
305//位選
306P0=_cror_(0xdf,i);//選擇第(i+1)個(gè)數(shù)碼管
307wela=1;//打開(kāi)鎖存,給它一個(gè)下降沿量
308wela=0;
309delay(1);
310}
311if(mode==2&&6==clockPosition)//時(shí)鐘設(shè)置模式下,光標(biāo)所在位置,閃爍
312{
313clockTmp++;
314if(clockTmp==20)
315{
316clockTmpBit=~clockTmpBit;
317clockTmp=0;
318}
319if(clockTmpBit)
320{
321if(values[6]==0)
322{
323P1=0x0f;
324}
325else
326{
327P1=~values[6];
328}
329}
330else
331{
332P1=0xff;
333}
334}
335else
336{
337P1=~values[6];
338}
339}
340}
341
342//檢測(cè)功能模式鍵是否被按下
343voidcheckModeKey()
344{
345if(!S5)
346{
347delay(7);
348if(!S5)
349{
350mode++;
351switch(mode)
352{
353case2://定時(shí)器0是不會(huì)關(guān)閉的,即使在設(shè)置模式下
354for(icount=0;icount<7;icount++)
355{
356tmpDatas[icount]=clockDatas[icount];//將設(shè)置之前的值暫存到臨時(shí)數(shù)組
357}
358values=tmpDatas;
359break;
360case3://秒表模式
361values=datas;
362break;
363case4://溫度計(jì)模式
364//啟動(dòng)溫度轉(zhuǎn)換
365sendChangeCmd();
366getTempValue();
367break;
368default:
369values=clockDatas;
370mode=1;
371TR0=1;
372}
373while(!S5)//等待釋放鍵
374{
375display();
376}
377}
378}
379}
380
381//選中位數(shù)值增1,用于時(shí)鐘模式的設(shè)置狀態(tài)下
382voidadd()
383{
384values[clockPosition]++;
385switch(clockPosition)
386{
387case3:
388case5:
389if(values[clockPosition]>5)
390values[clockPosition]=0;
391break;
392case6:
393if(values[clockPosition]>23)
394values[clockPosition]=0;
395break;
396default:
397if(values[clockPosition]>9)
398values[clockPosition]=0;
399}
400}
401
402//檢測(cè)是否有鍵按下,并執(zhí)行相應(yīng)功能
403voidcheckKey()
404{
405checkModeKey();
406switch(mode)
407{
408case2:
409if(!S2)//左移光標(biāo)位
410{
411delay(7);
412if(!S2)
413{
414clockPosition++;
415if(clockPosition>6)
416{
417clockPosition=0;
418}
419}
420}
421elseif(!S3)//選中位增1
422{
423delay(7);
424if(!S3)
425{
426add();
427}
428}
429elseif(!S4)//選中確定更改
430{
431delay(7);
432if(!S4)
433{
434for(icount=0;icount<7;icount++)
435{
436clockDatas[icount]=tmpDatas[icount];//將設(shè)置的值存到clockDatas[]
437}
438values=clockDatas;
439mode=1;//將模式變成時(shí)鐘模式
440}
441}
442break;
443case3:
444if(!S2)
445{
446delay(7);//延時(shí)大約10ms,去抖動(dòng)
447if(!S2)//開(kāi)始/暫停鍵按下
448{
449TR1=~TR1;
450}
451}
452
453elseif(!S3)
454{
455delay(7);//延時(shí)大約10ms,去抖動(dòng)
456if(!S3)//清零鍵按下
457{
458TR1=0;
459TH1=th;
460TL1=tl;
461for(icount=0;icount<7;icount++)
462{
463datas[icount]=0;
464}
465}
466}
467break;
468}
469//等待鍵被釋放
470while(!S2||!S3||!S4)
471{
472display();//等待期間要顯示
473}
474}
475
476voidmain()
477{
478delay(1);
479th=0xdb;//(65536-10000/1.085)/256;//定時(shí)10ms
480tl=0xff;//(65536-10000/1.085)-th*256;
481TH1=TH0=th;//初始化定時(shí)器1,0
482TL1=TL0=tl;
483EA=1;//開(kāi)中斷
484ET1=ET0=1;//允許定時(shí)器1,0中斷請(qǐng)求
485TMOD=0x11;//定時(shí)器1,0都工作方式1
486TR1=0;
487TR0=1;//開(kāi)始顯示時(shí)間
488while(1)
489{
490checkKey();//檢測(cè)是否就鍵按下
491display();//顯示計(jì)時(shí)值
492}
493}
494
495//定時(shí)器0中斷響應(yīng)函數(shù),用于時(shí)鐘計(jì)時(shí)
496voidtime0()interrupt1
497{
498TH0=th;//重置計(jì)數(shù)值
499TL0=tl;
500
501clockDatas[0]++;//0.01秒
502if(clockDatas[0]==10)
503{
504clockDatas[0]=0;
505clockDatas[1]++;//0.1秒
506if(clockDatas[1]==10)
507{
508clockDatas[1]=0;
509clockDatas[2]++;//秒
510if(clockDatas[2]==10)
511{
512clockDatas[2]=0;
513clockDatas[3]++;//10秒
514if(clockDatas[3]==6)
515{
516clockDatas[3]=0;
517clockDatas[4]++;//分
518if(clockDatas[4]==10)
519{
520clockDatas[4]=0;
521clockDatas[5]++;//10分
522if(clockDatas[5]==6)
523{
524clockDatas[5]=0;
525clockDatas[6]++;//時(shí)
526if(clockDatas[6]==24)
527{
528clockDatas[6]=0;
529}
530}
531}
532}
533}
534}
535}
536}
537
538//定時(shí)器1中斷響應(yīng)函數(shù),用于秒表計(jì)時(shí)
539voidtime1()interrupt3
540{
541TH1=th;//重置計(jì)數(shù)值
542TL1=tl;
543
544datas[0]++;//0.01秒
545if(datas[0]==10)
546{
547datas[0]=0;
548datas[1]++;//0.1秒
549if(datas[1]==10)
550{
551datas[1]=0;
552datas[2]++;//秒
553if(datas[2]==10)
554{
555datas[2]=0;
556datas[3]++;//10秒
557if(datas[3]==6)
558{
559datas[3]=0;
560datas[4]++;//分
561if(datas[4]==10)
562{
563datas[4]=0;
564datas[5]++;//10分
565if(datas[5]==6)
566{
567datas[5]=0;
568datas[6]++;//時(shí)
569if(datas[6]==24)
570{
571datas[6]=0;
572}
573}
574}
575}
576}
577}
578}
579}