欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

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

51單片機(jī)匯編語言及C語言經(jīng)典實(shí)例 實(shí)驗(yàn)及課程設(shè)計(jì)

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:421335 發(fā)表于 2018-11-5 20:27 | 只看該作者 回帖獎勵(lì) |倒序?yàn)g覽 |閱讀模式
51單片機(jī)匯編語言及C語言經(jīng)典實(shí)例
實(shí)驗(yàn)及課程設(shè)計(jì)



閃爍燈
如圖1 所示為一簡單單片機(jī)系統(tǒng)原理圖:在 P1.0 端口上接一個(gè)發(fā)光二極管 L1,使 L1 在不停地一亮一滅,一亮一滅的時(shí)間間隔為 0.2 秒。


延時(shí)程序的設(shè)計(jì)方法,作為單片機(jī)的指令的執(zhí)行的時(shí)間是很短,數(shù)量大微秒級,因此,我們要求的閃爍時(shí)間間隔為 0.2 秒,相對于微秒來說,相差太大,所以我們在執(zhí)行某一指令時(shí),插入延時(shí)程序,來達(dá)到我們的要求,但這樣的延時(shí)程
序是如何設(shè)計(jì)呢?下面具體介紹其原理:如圖 4.1.1 所示的石英晶體為 12MHz,因此,1 個(gè)機(jī)器周期為 1 微秒,機(jī)器周期 微秒如圖 1 所示,當(dāng) P1.0 端口輸出高電平,即 P1.0=1 時(shí),根據(jù)發(fā)光二極管的單向?qū)щ娦钥芍@時(shí)發(fā)光二極管 L1 熄滅;當(dāng)P1.0 端口輸出低電平,即 P1.0=0 時(shí),發(fā)光二極管 L1 亮;我們可以使用 SETB P1.0指令使 P1.0端口輸出高電平,使用 CLR P1.0 指令使 P1.0 端口輸出低電平。

C 語言源程序
  1. #include <AT89X51.H>
  2. sbit L1=P1^0;
  3. void delay02s(void) //延時(shí) 0.2 秒子程序
  4. {
  5. unsigned char i,j,k;
  6. for(i=20;i>0;i--)
  7. for(j=20;j>0;j--)
  8. for(k=248;k>0;k--);                       

  9. }
  10. void main(void)
  11. {
  12. while(1)
  13. {
  14. L1=0;
  15. delay02s();
  16. L1=1;
  17. delay02s();
  18. }
復(fù)制代碼

匯編源程序
  1. ORG 0
  2. START: CLR P1.0
  3. LCALL DELAY
  4. SETB P1.0
  5. LCALL DELAY
  6. LJMP START
  7. DELAY: MOV R5,#20 ;延時(shí)子程序,延時(shí) 0.2 秒
  8. D1: MOV R6,#20
  9. D2: MOV R7,#248



  10. DJNZ R7,$
  11. DJNZ R6,D2
  12. DJNZ R5,D1
  13. RET
  14. END
復(fù)制代碼
                                                   

多路開關(guān)狀態(tài)指示
如圖 3 所示,AT89S51 單片機(jī)的 P1.0-P1.3 接四個(gè)發(fā)光二極管 L1-L4,
P1.4-P1.7 接了四個(gè)開關(guān) K1-K4,編程將開關(guān)的狀態(tài)反映到發(fā)光二極管上。
(開關(guān)閉合,對應(yīng)的燈亮,開關(guān)斷開,對應(yīng)的燈滅)。
對于開關(guān)狀態(tài)檢測,相對單片機(jī)來說,是輸入關(guān)系,我們可輪流檢測每個(gè)開關(guān)狀
態(tài),根據(jù)每個(gè)開關(guān)的狀態(tài)讓相應(yīng)的發(fā)光二極管指示,可以采用 JB P1.X,REL
或 JNB P1.X,REL 指令來完成;也可以一次性檢測四路開關(guān)狀態(tài),然后讓其指
示,可以采用 MOV A,P1 指令一次把 P1 端口的狀態(tài)全部讀入,然后取高 4 位的狀態(tài)來指示。
方法1(匯編源程序)
ORG 00H
START: MOV A,P1


ANL A,#0F0H
RR A
RR A
RR A
RR A
ORL A,#0F0H
MOV P1,A
SJMP START
END

方法1(C語言程序)
#INClude <AT89X51.H>
unsigned char temp;

void main(void)
{
while(1)
{
temp=P1>>4;
temp=temp | 0xf0;
P1=temp;
}
}
方法2(匯編源程序)
ORG 00H
START: JB P1.4,NEXT1
CLR P1.0
SJMP NEX1


NEXT1: SETB P1.0
NEX1: JB P1.5,NEXT2
CLR P1.1
SJMP NEX2
NEXT2: SETB P1.1
NEX2: JB P1.6,NEXT3
CLR P1.2
SJMP NEX3
NEXT3: SETB P1.2
NEX3: JB P1.7,NEXT4
CLR P1.3
SJMP NEX4
NEXT4: SETB P1.3
NEX4: SJMP START
END
方法2(C 語言源程序)
#INClude <AT89X51.H>

void main(void)
{
while(1)
{
if(P1_4==0)
{
P1_0=0;
}
Else
{
P1_0=1;
}
if(P1_5==0)
{
P1_1=0;
}
else
{
P1_1=1;
}
if(P1_6==0)
{
P1_2=0;
}
else
{
P1_2=1;
}
if(P1_7==0)
{
P1_3=0;
}
else
、廣告燈的設(shè)計(jì)
利用取表的方法,使端口 P1 做單一燈的變化:左移 2 次,右移 2 次,閃爍 2 次
(延時(shí)的時(shí)間 0.2 秒)。
利用 MOV DPTR,#DATA16 的指令來使數(shù)據(jù)指針寄存器指到表的開
頭。
利用 MOVC A,@A+DPTR 的指令,根據(jù)累加器的值再加上 DPTR 的
值,就可以使程序計(jì)數(shù)器 PC 指到表格內(nèi)所要取出的數(shù)據(jù)。因此,只要把控制碼建成一個(gè)表,而利用 MOVC A,@A+DPTR 做取碼的操作,
就可方便地處理一些復(fù)雜的控制動作,取表過程如下圖所示:
匯編源程序
ORG 0
START: MOV DPTR,#TABLE
LOOP: CLR A
MOVC A,@A+DPTR
CJNE A,#01H,LOOP1
JMP START
LOOP1: MOV P1,A
MOV R3,#20
LCALL DELAY
INC DPTR
JMP LOOP
DELAY: MOV R4,#20
D1:     MOV R5,#248
DJNZ R5,$
DJNZ R4,D1
DJNZ R3,DELAY
R             RET
T       ABLE: DB 0FEH,0FDH,0FBH,0F7H
DB 0EFH,0DFH,0BFH,07FH
DB 0FEH,0FDH,0FBH,0F7H
DB 0EFH,0DFH,0BFH,07FH
DB 07FH,0BFH,0DFH,0EFH
DB 0F7H,0FBH,0FDH,0FEH
DB 07FH,0BFH,0DFH,0EFH
DB 0F7H,0FBH,0FDH,0FEH
DB 00H, 0FFH,00H, 0FFH
DB 01H
END
C 語言源程序
#INClude <AT89X51.H>
unsigned char code table[]={0xfe,0xfd,0xfb,0xf7,
0xef,0xdf,0xbf,0x7f,0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f,
0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe,0x7f,0xbf,0xdf,0xef,
0xf7,0xfb,0xfd,0xfe,0x00,0xff,0x00,0xff,0x01};
unsigned char i;
void delay(void)
{
unsigned char m,n,s;
for(m=20;m>0;m--)
for(n=20;n>0;n--)
for(s=248;s>0;s--);
}
void main(void)
{
while(1)
{
if(table[ i]!=0x01)
{
P1=table[ i];
i++;
delay();
}
else
{
i=0;
}
}
}


四、 00-59 秒計(jì)時(shí)器
如下圖8所示,在 AT89S51 單片機(jī)的 P0 和 P2 端口分別接有兩個(gè)共陰數(shù)碼管,P0 口驅(qū)動顯示秒的時(shí)間的十位,而 P2 口驅(qū)動顯示秒的時(shí)間的個(gè)位。在設(shè)計(jì)過程中我們用一個(gè)存儲單元作為秒計(jì)數(shù)單元,當(dāng)一秒鐘到來時(shí),就讓秒計(jì)數(shù)單元加 1,當(dāng)秒計(jì)數(shù)達(dá)到 60 時(shí),就自動返回到 0,重新秒計(jì)數(shù)。
對于秒計(jì)數(shù)單元中的數(shù)據(jù)要把它十位數(shù)和個(gè)位數(shù)分開,方法仍采用對 10 整除和對 10 求余。
匯編源程序
Second EQU 30H
ORG 0000H
START: MOV Second, #00H
NEXT: MOV A, Second
MOV B,#10
DIV AB
MOV DPTR,#TABLE
MOVC A,@A+DPTR
MOV P0,A
MOV A,B
MOVC A,@A+DPTR
MOV P2,A
LCALL DELY1S
INC Second
MOV A,Second
CJNE A,#60,NEXT
LJMP START
DELY1S: MOV R5,#100
D2: MOV R6,#20
D1: MOV R7,#248
DJNZ R7,$
DJNZ R6,D1
DJNZ R5,D2
RET
TABLE: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH
END


C 語言源程序
#include <AT89X51.H>
unsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66,
0x6d,0x7d,0x07,0x7f,0x6f};
unsigned char Second;
void delay1s(void)
{
unsigned char i,j,k;
for(k=100;k>0;k--)
for(i=20;i>0;i--)
for(j=248;j>0;j--);
}
void main(void)
{
Second=0;
P0=table[Second/10];
P2=table[Second%10];
while(1)
{
delay1s();
Second++;
if(Second==60)
{
Second=0;
}
P0=table[Second/10];
P2=table[Second%10];
}
}


五、動態(tài)數(shù)碼顯示技術(shù)
如圖 9 所示,P0 端口接動態(tài)數(shù)碼管的字形碼筆段,P2 端口接動態(tài)數(shù)碼管的數(shù)位選擇端,P1.7接
一個(gè)開關(guān),當(dāng)開關(guān)接高電平時(shí),顯示“12345”字樣;當(dāng)開關(guān)接低電平時(shí),顯示“HELLO”字樣。
動態(tài)掃描方法:動態(tài)接口采用各數(shù)碼管循環(huán)輪流顯示的方法,當(dāng)循環(huán)顯示頻率較高時(shí),利用人眼的暫留特性,看不出閃爍顯示現(xiàn)象,這種顯示需要一個(gè)接口完成字形碼的輸出(字形選擇),另一接口完成各數(shù)碼管的輪流點(diǎn)亮(數(shù)位選擇)。
在進(jìn)行數(shù)碼顯示的時(shí)候,要對顯示單元開辟 8 個(gè)顯示緩沖區(qū),每個(gè)顯示緩沖區(qū)裝有顯示的不同數(shù)據(jù)即可。對于顯示的字形碼數(shù)據(jù)我們采用查表方法來完成。

匯編源程序
ORG 0000H
START: JB P1.7,DIR1
MOV DPTR,#TABLE1
SJMP DIR
DIR1: MOV DPTR,#TABLE2
DIR: MOV R0,#00H
MOV R1,#01H
NEXT: MOV A,R0
MOVC A,@A+DPTR
MOV P0,A
MOV A,R1
MOV P2,A
LCALL DAY
INC R0
RL A
MOV R1,A
CJNE R1,#0DFH,NEXT
SJMP START
DAY: MOV R6,#4
D1: MOV R7,#248
DJNZ R7,$
DJNZ R6,D1
RET
TABLE1: DB 06H,5BH,4FH,66H,6DH
TABLE2: DB 78H,79H,38H,38H,3FH
END






C 語言源程序
  1. #include <AT89X51.H>
  2. Unsigned char code table1[ ]={0x06,0x5b,0x4f,0x66,0x6d};
  3. Unsigned char code table2[]={0x78,0x79,0x38,0x38,0x3f};
  4. Unsigned char i;
  5. Unsigned char a,b;
  6. Unsigned char temp;

  7. void main(void)
  8. {
  9.            while(1)
  10. {
  11. temp=0xfe;
  12. for(i=0;i<5;i++)
  13.           {
  14. if(P1_7==1)
  15. {
  16. P0=table1[ i];
  17.                  }
  18.         else
  19.                  {
  20. P0=table2[ i];
  21.                   }
  22. P2=temp;
  23. a=temp<<(i+1);
  24. b=temp>>(7-i);
  25.               temp=a|b;
  26. for(a=4;a>0;a--)
  27. for(b=248;b>0;b--);
  28. }
  29.                }
復(fù)制代碼



六、4×4 矩陣式鍵盤識別技術(shù)
如圖 11 所示,用 AT89S51 的并行口 P1 接 4×4 矩陣鍵盤,以 P1.0-P1.3作輸入線,以 P1.4-P1.7 作輸出線;在數(shù)碼管上顯示每個(gè)按鍵的“0-F”序。對應(yīng)的按鍵的序號排列如圖12 所示每個(gè)按鍵有它的行值和列值 ,行值和列值的組合就是識別這個(gè)按鍵的編碼。矩陣的行線和列線分別通過兩并行接口和 CPU 通信。每個(gè)按鍵的狀態(tài)同樣需變成數(shù)字量“0”和“1”,開關(guān)的一端(列線)通過電阻接 VCC,而接地是通過程序輸出數(shù)字“0”實(shí)現(xiàn)的。鍵盤處理程序的任務(wù)是:確定有無鍵按下,判斷哪一個(gè)鍵按下,鍵的功能是什么;
還要消除按鍵在閉合或斷開時(shí)的抖動。兩個(gè)并行口中,一個(gè)輸出掃描碼,使按鍵逐行動態(tài)接地,另一個(gè)并行口輸入按鍵狀態(tài),由行掃描值和回饋信號共同形成鍵編碼而識別按鍵,通過軟件查表,查出該鍵的
功能。


匯編源程序
  1. KEYBUF EQU 30H
  2. ORG 00H
  3. START: MOV KEYBUF,#2
  4. WAIT:
  5. MOV P3,#0FFH
  6. CLR P3.4
  7. MOV A,P3
  8. ANL A,#0FH
  9. XRL A,#0FH
  10. JZ NOKEY1
  11. LCALL DELY10MS
  12. MOV A,P3
  13. ANL A,#0FH
  14. XRL A,#0FH
  15. JZ NOKEY1
  16. MOV A,P3
  17. ANL A,#0FH
  18. CJNE A,#0EH,NK1
  19. MOV KEYBUF,#0
  20. LJMP DK1
  21. NK1: CJNE A,#0DH,NK2
  22. MOV KEYBUF,#1
  23. LJMP DK1
  24. NK2: CJNE A,#0BH,NK3
  25. MOV KEYBUF,#2
  26. LJMP DK1
  27. NK3: CJNE A,#07H,NK4
  28. MOV KEYBUF,#3
  29. LJMP DK1
  30. NK4: NOP
  31. DK1:
  32. MOV A,KEYBUF
  33. MOV DPTR,#TABLE
  34. MOVC A,@A+DPTR
  35. MOV P0,A
  36. DK1A: MOV A,P3
  37. ANL A,#0FH
  38. XRL A,#0FH
  39. JNZ DK1A
  40. NOKEY1:
  41. MOV P3,#0FFH
  42. CLR P3.5
  43. MOV A,P3
  44. ANL A,#0FH
  45. XRL A,#0FH
  46. JZ NOKEY2
  47. LCALL DELY10MS
  48. MOV A,P3
  49. ANL A,#0FH
  50. XRL A,#0FH
  51. JZ NOKEY2
  52. MOV A,P3
  53. ANL A,#0FH
  54. CJNE A,#0EH,NK5
  55. MOV KEYBUF,#4
  56. LJMP DK2
  57. NK5: CJNE A,#0DH,NK6
  58. MOV KEYBUF,#5
  59. LJMP DK2
  60. NK6: CJNE A,#0BH,NK7
  61. MOV KEYBUF,#6
  62. LJMP DK2
  63. NK7: CJNE A,#07H,NK8
  64. MOV KEYBUF,#7
  65. LJMP DK2
  66. NK8: NOP
  67. DK2:
  68. MOV A,KEYBUF
  69. MOV DPTR,#TABLE
  70. MOVC A,@A+DPTR
  71. MOV P0,A
  72. DK2A: MOV A,P3
  73. ANL A,#0FH
  74. XRL A,#0FH
  75. JNZ DK2A
  76. NOKEY2:
  77. MOV P3,#0FFH
  78. CLR P3.6
  79. MOV A,P3
  80. ANL A,#0FH
  81. XRL A,#0FH
  82. JZ NOKEY3
  83. LCALL DELY10MS
  84. MOV A,P3
  85. ANL A,#0FH
  86. XRL A,#0FH
  87. JZ NOKEY3
  88. MOV A,P3
  89. ANL A,#0FH
  90. CJNE A,#0EH,NK9
  91. MOV KEYBUF,#8
  92. LJMP DK3
  93. NK9: CJNE A,#0DH,NK10
  94. MOV KEYBUF,#9
  95. LJMP DK3
  96. NK10: CJNE A,#0BH,NK11
  97. MOV KEYBUF,#10

  98. LJMP DK3
  99. NK11: CJNE A,#07H,NK12
  100. MOV KEYBUF,#11
  101. LJMP DK3
  102. NK12: NOP
  103. DK3:
  104. MOV A,KEYBUF
  105. MOV DPTR,#TABLE
  106. MOVC A,@A+DPTR
  107. MOV P0,A
  108. DK3A: MOV A,P3
  109. ANL A,#0FH
  110. XRL A,#0FH
  111. JNZ DK3A
  112. NOKEY3:
  113. MOV P3,#0FFH
  114. CLR P3.7
  115. MOV A,P3
  116. ANL A,#0FH
  117. XRL A,#0FH
  118. JZ NOKEY4
  119. LCALL DELY10MS
  120. MOV A,P3
  121. ANL A,#0FH
  122. XRL A,#0FH
  123. JZ NOKEY4
  124. MOV A,P3
  125. ANL A,#0FH
  126. CJNE A,#0EH,NK13
  127. MOV KEYBUF,#12
  128. LJMP DK4
  129. NK13: CJNE A,#0DH,NK14
  130. MOV KEYBUF,#13
  131. LJMP DK4
  132. NK14: CJNE A,#0BH,NK15
  133. MOV KEYBUF,#14
  134. LJMP DK4
  135. NK15: CJNE A,#07H,NK16
  136. MOV KEYBUF,#15
  137. LJMP DK4
  138. NK16: NOP
  139. DK4:
  140. MOV A,KEYBUF
  141. MOV DPTR,#TABLE
  142. MOVC A,@A+DPTR
  143. MOV P0,A
  144. DK4A: MOV A,P3
  145. ANL A,#0FH
  146. XRL A,#0FH
  147. JNZ DK4A
  148. NOKEY4:
  149. LJMP WAIT
  150. DELY10MS:
  151. MOV R6,#10
  152. D1: MOV R7,#248
  153. DJNZ R7,$
  154. DJNZ R6,D1
  155. RET
  156. TABLE: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H
  157. DB 7FH,6FH,77H,7CH,39H,5EH,79H,71H
  158. END
復(fù)制代碼

C 語言源程序
  1. #INClude <AT89X51.H>
  2. unsigned char code table[]={0x3f,0x06,0x5b,0x4f,
  3. 0x66,0x6d,0x7d,0x07,
  4. 0x7f,0x6f,0x77,0x7c,
  5. 0x39,0x5e,0x79,0x71};
  6. unsigned char temp;
  7. unsigned char key;
  8. unsigned char i,j;
  9. void main(void)
  10. {
  11. while(1)
  12. {
  13. P3=0xff;
  14. P3_4=0;
  15. temp=P3;
  16. temp=temp & 0x0f;
  17. if (temp!=0x0f)
  18. {
  19. for(i=50;i>0;i--)
  20. for(j=200;j>0;j--);
  21. temp=P3;
  22. temp=temp & 0x0f;
  23. if (temp!=0x0f)
  24. {
  25. temp=P3;
  26. temp=temp & 0x0f;
  27. switch(temp)
  28. {
  29. case 0x0e:
  30. key=7;
  31. break;
  32. case 0x0d:
  33. key=8;
  34. break;
  35. case 0x0b:
  36. key=9;
  37. break;
  38. case 0x07:
  39. key=10;
  40. break;
  41. }
  42. temp=P3;
  43. P1_0=~P1_0;
  44. P0=table[key];
  45. temp=temp & 0x0f;
  46. while(temp!=0x0f)
  47. {
  48. temp=P3;
  49. temp=temp & 0x0f;
  50. }
  51. }
  52. }
  53. P3=0xff;
  54. P3_5=0;
  55. temp=P3;
  56. temp=temp & 0x0f;
  57. if (temp!=0x0f)
  58. {
  59. for(i=50;i>0;i--)
  60. for(j=200;j>0;j--);
  61. temp=P3;
  62. temp=temp & 0x0f;
  63. if (temp!=0x0f)
  64. {
  65. temp=P3;
  66. temp=temp & 0x0f;
  67. switch(temp)
  68. {
  69. case 0x0e:
  70. key=4;
  71. break;
  72. case 0x0d:
  73. key=5;
  74. break;
  75. case 0x0b:
  76. key=6;
  77. break;
  78. case 0x07:
  79. key=11;
  80. break;
  81. }
  82. temp=P3;
  83. P1_0=~P1_0;
  84. P0=table[key];
  85. temp=temp & 0x0f;
  86. while(temp!=0x0f)
  87. {
  88. temp=P3;
  89. temp=temp & 0x0f;
  90. }
  91. }
  92. }
  93. P3=0xff;
  94. P3_6=0;
  95. temp=P3;
  96. temp=temp & 0x0f;
  97. if (temp!=0x0f)
  98. {
  99. for(i=50;i>0;i--)
  100. for(j=200;j>0;j--);
  101. temp=P3;
  102. temp=temp & 0x0f;
  103. if (temp!=0x0f)
  104. {
  105. temp=P3;
  106. temp=temp & 0x0f;
  107. switch(temp)
  108. {
  109. case 0x0e:
  110. key=1;
  111. break;
  112. case 0x0d:
  113. key=2;
  114. break;
  115. case 0x0b:
  116. key=3;
  117. break;
  118. case 0x07:
  119. key=12;
  120. break;
  121. }
  122. temp=P3;
  123. P1_0=~P1_0;
  124. P0=table[key];
  125. temp=temp & 0x0f;
  126. while(temp!=0x0f)
  127. {
  128. temp=P3;
  129. temp=temp & 0x0f;
  130. }
  131. }
  132. }
  133. P3=0xff;
  134. P3_7=0;
  135. temp=P3;
  136. temp=temp & 0x0f;
  137. if (temp!=0x0f)
  138. {
  139. for(i=50;i>0;i--)
  140. for(j=200;j>0;j--);
  141. temp=P3;
  142. temp=temp & 0x0f;
  143. if (temp!=0x0f)

  144. {
  145. temp=P3;
  146. temp=temp & 0x0f;
  147. switch(temp)
  148. {
  149. case 0x0e:
  150. key=0;
  151. break;
  152. case 0x0d:
  153. key=13;
  154. break;
  155. case 0x0b:
  156. key=14;
  157. break;
  158. case 0x07:
  159. key=15;
  160. break;

  161. }
  162. temp=P3;
  163. P1_0=~P1_0;
  164. P0=table[key];
  165. temp=temp & 0x0f;
  166. while(temp!=0x0f)
  167. {
  168. temp=P3;
  169. temp=temp & 0x0f;
  170. }
  171. }
  172. }
  173. }
  174. }
復(fù)制代碼





七、按鍵識別方法
每按下一次開關(guān) SP1,計(jì)數(shù)值加 1,通過AT89S51 單片機(jī)的 P1 端口的 P1.0 到 P1.3
顯示出其二進(jìn)制計(jì)數(shù)值。
*程序設(shè)計(jì)方法作為一個(gè)按鍵從沒有按下到按下以及釋放是一個(gè)完整的過程,也就是說,當(dāng)我們按下一個(gè)按鍵時(shí),總希望某個(gè)命令只執(zhí)行一次,而在按鍵按下的 過程中,不要有干擾進(jìn)來,因?yàn)椋诎聪碌倪^程中,一旦有干擾過來,可能造成誤觸發(fā)過程,這并不是我們所想要的。因此在按鍵按下的時(shí)候,要把我們手上的干擾信號以及按鍵的機(jī)械接觸等干擾信號給濾除掉,一般情況下,我們可以采用電容來濾除掉這些干擾信號,但實(shí)際上,會增加硬件成本及硬件電路的體積,這是我們不希望,總得有個(gè)辦法解決這個(gè)問題,因此我們可以采用軟件濾波的方法去除這些干擾信號,一般情況下,一個(gè)按鍵按下的時(shí)候,總是在按下的時(shí)刻存在著一定的干擾信號,按下之后就基本上進(jìn)入了穩(wěn)定的狀態(tài)。具體的一個(gè)按鍵從按下到釋放的全過程的信號圖如上圖所示:從圖中可以看出,我們在程序設(shè)計(jì)時(shí),從按鍵被識別按下之后,延時(shí) 5ms 以上,從而避開了干擾信號區(qū)域,我們再來檢測一次,看按鍵是否真得已經(jīng)按下,若真得已經(jīng)按下,這時(shí)肯定輸出為低電平,若這時(shí)檢測到的是高電平,證明剛才是由于干擾信號引起的誤觸發(fā),CPU 就認(rèn)為是誤觸發(fā)信號而舍棄這次的按鍵識別過程。從而提高了系統(tǒng)的可靠性。
由于要求每按下一次,命令被執(zhí)行一次,直到下一次再按下的時(shí)候,再執(zhí)行一次命令,因此從按鍵被識別出來之后,我們就可以執(zhí)行這次的命令,所以要有一個(gè)等待按鍵釋放的過程,顯然釋放的過程,就是使其恢復(fù)成高電平狀態(tài)。






1. 匯編源程序

ORG 0000H
START: MOV R1,#00H ;初始化 R1 為 0,表示從 0 開始計(jì)數(shù)
MOV A, R1 ;
CPL A ;取反指令
MOV P1,A ;送出 P1 端口由發(fā)光二極管顯示
REL: JB P3.7,REL ;判斷 SP1 是否按下
LCALL DELAY10MS ;若按下,則延時(shí) 10ms 左右
JB P3.7,REL ;再判斷 SP1 是否真得按下
INC R1 ;若確實(shí)按下,則進(jìn)行按鍵處理,使
MOV A,R1 ;計(jì)數(shù)內(nèi)容加 1,并送出 P1 端口由
CPL A ;發(fā)光二極管顯示
MOV P1,A ;
JNB P3.7,$ ;等待 SP1 釋放
SJMP REL ;繼續(xù)對 K1 按鍵掃描
DELAY10MS: MOV R6,#20 ;延時(shí) 10ms 子程序
L1: MOV R7,#248
DJNZ R7,$
DJNZ R6,L1
RET
END
































2.  C 語言源程序

#include <AT89X51.H>
unsigned char count;
void delay10ms(void)
{
unsigned char i,j;
for(i=20;i>0;i--)
for(j=248;j>0;j--);
}
void main(void)
{
while(1)
{
if(P3_7==0)
{
delay10ms();
if(P3_7==0)
{
count++;
if(count==16)
{
count=0;
}
P1=~count;
while(P3_7==0);
}
}
}
}


數(shù)字鐘
(1. 開機(jī)時(shí),顯示 12:00:00 的時(shí)間開始計(jì)時(shí);
(2. P0.0/AD0 控制“秒”的調(diào)整,每按一次加 1 秒;
(3. P0.1/AD1 控制“分”的調(diào)整,每按一次加 1 分;
(4. P0.2/AD2 控制“時(shí)”的調(diào)整,每按一次加 1 個(gè)小時(shí)

6. 匯編源程序
SECOND EQU 30H
MINITE EQU 31H
HOUR EQU 32H
HOURK BIT P0.0
MINITEK BIT P0.1
SECONDK BIT P0.2
DISPBUF EQU 40H
DISPBIT EQU 48H
T2SCNTA EQU 49H
T2SCNTB EQU 4AH
TEMP EQU 4BH
ORG 00H
LJMP START
ORG 0BH
LJMP INT_T0
START: MOV SECOND,#00H
MOV MINITE,#00H
MOV HOUR,#12
MOV DISPBIT,#00H
MOV T2SCNTA,#00H
MOV T2SCNTB,#00H
MOV TEMP,#0FEH
LCALL DISP
MOV TMOD,#01H
MOV TH0,#(65536-2000) / 256
MOV TL0,#(65536-2000) MOD 256
SETB TR0
SETB ET0
SETB EA
WT: JB SECONDK,NK1
LCALL DELY10MS
JB SECONDK,NK1
INC SECOND
MOV A,SECOND
CJNE A,#60,NS60
MOV SECOND,#00H
NS60: LCALL DISP
JNB SECONDK,$
NK1: JB MINITEK,NK2
LCALL DELY10MS
JB MINITEK,NK2
INC MINITE
MOV A,MINITE
CJNE A,#60,NM60
MOV MINITE,#00H
NM60: LCALL DISP
JNB MINITEK,$
NK2: JB HOURK,NK3
LCALL DELY10MS
JB HOURK,NK3
INC HOUR
MOV A,HOUR
CJNE A,#24,NH24
MOV HOUR,#00H
NH24: LCALL DISP
JNB HOURK,$
NK3: LJMP WT
DELY10MS:
MOV R6,#10
D1: MOV R7,#248
DJNZ R7,$
DJNZ R6,D1
RET
DISP:
MOV A,#DISPBUF
ADD A,#8
DEC A
MOV R1,A
MOV A,HOUR
MOV B,#10
DIV AB
MOV @R1,A
DEC R1
MOV A,B
MOV @R1,A
DEC R1
MOV A,#10
MOV@R1,A
DEC R1
MOV A,MINITE
MOV B,#10
DIV AB
MOV @R1,A
DEC R1
MOV A,B
MOV @R1,A
DEC R1
MOV A,#10
MOV@R1,A
DEC R1
MOV A,SECOND
MOV B,#10
DIV AB
MOV @R1,A
DEC R1
MOV A,B
MOV @R1,A
DEC R1
RET
INT_T0:
MOV TH0,#(65536-2000) / 256
MOV TL0,#(65536-2000) MOD 256
MOV A,#DISPBUF
ADD A,DISPBIT
MOV R0,A
MOV A,@R0
MOV DPTR,#TABLE
MOVC A,@A+DPTR
MOV P1,A
MOV A,DISPBIT
MOV DPTR,#TAB
MOVC A,@A+DPTR
MOV P3,A
INC DISPBIT
MOV A,DISPBIT
CJNE A,#08H,KNA
MOV DISPBIT,#00H
KNA: INC T2SCNTA
MOV A,T2SCNTA
CJNE A,#100,DONE
MOV T2SCNTA,#00H
INC T2SCNTB
MOV A,T2SCNTB
CJNE A,#05H,DONE
MOV T2SCNTB,#00H
INC SECOND
MOV A,SECOND
CJNE A,#60,NEXT
MOV SECOND,#00H
INC MINITE
MOV A,MINITE
CJNE A,#60,NEXT
MOV MINITE,#00H
INC HOUR
MOV A,HOUR
CJNE A,#24,NEXT
MOV HOUR,#00H
NEXT: LCALL DISP
DONE: RETI
TABLE: DB 3FH,06H,5BH,4FH,66H,6DH,
7DH,07H,7FH,6FH,40H
TAB: DB 0FEH,0FDH,0FBH,0F7H,0EFH,
0DFH,0BFH,07FH
END


7. C 語言源程序
#INClude <AT89X51.H>
unsigned char code dispcode[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};
unsigned char dispbitcode[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
unsigned char dispbuf[8]={0,0,16,0,0,16,0,0};
unsigned char dispbitcnt;
unsigned char second;
unsigned char minite;
unsigned char hour;
unsigned int tcnt;
unsigned char mstcnt;
unsigned char i,j;
void main(void)
{
TMOD=0x02;
TH0=0x06;
TL0=0x06;
TR0=1;
ET0=1;
EA=1;
while(1)
{
if(P0_0==0)
{
for(i=5;i>0;i--)
for(j=248;j>0;j--);
if(P0_0==0)
{
second++;
if(second==60)
{
second=0;
}
dispbuf[0]=second%10;
dispbuf[1]=second/10;
while(P0_0==0);
}
}
if(P0_1==0)
{
for(i=5;i>0;i--)
for(j=248;j>0;j--);
if(P0_1==0)
{
minite++;
if(minite==60)
{
minite=0;
}
dispbuf[3]=minite%10;
dispbuf[4]=minite/10;
while(P0_1==0);
}
}
if(P0_2==0)
{
for(i=5;i>0;i--)
for(j=248;j>0;j--);
if(P0_2==0)
{
hour++;
if(hour==24)
{
hour=0;
}
dispbuf[6]=hour%10;
dispbuf[7]=hour/10;
while(P0_2==0);
}
}
}
}
void t0(void) interrupt 1 using 0
{
mstcnt++;
if(mstcnt==8)
{
mstcnt=0;
P1=dispcode[dispbuf[dispbitcnt]];
P3=dispbitcode[dispbitcnt];
dispbitcnt++;
if(dispbitcnt==8)
{
dispbitcnt=0;
}
}
tcnt++;
if(tcnt==4000)
{


tcnt=0;
second++;
if(second==60)
{
second=0;
minite++;
if(minite==60)
{
minite=0;
hour++;
if(hour==24)
{
hour=0;
}
}
}
dispbuf[0]=second%10;
dispbuf[1]=second/10;
dispbuf[3]=minite%10;
dispbuf[4]=minite/10;
dispbuf[6]=hour%10;
dispbuf[7]=hour/10;
}
}
}


九. ADC0809A/D 轉(zhuǎn)換器基本應(yīng)用技術(shù)
1 基本知識ADC0809 是帶有 8 位 A/D 轉(zhuǎn)換器、8 路多路開關(guān)以及微處理機(jī)兼容的控制邏輯的 CMOS組件。它是逐次逼近式 A/D 轉(zhuǎn)換器,可以和單片機(jī)直接接口。
2 ADC0809 的內(nèi)部邏輯結(jié)構(gòu)圖9-1

由上圖可知,ADC0809 由一個(gè) 8 路模擬開關(guān)、一個(gè)地址鎖存與譯碼器、一個(gè) A/D轉(zhuǎn)換器和一個(gè)三態(tài)輸出鎖存器組成。多路開關(guān)可選通 8 個(gè)模擬通道,允許 8 路模擬量分時(shí)輸入,共用 A/D 轉(zhuǎn)換器進(jìn)行轉(zhuǎn)換。三態(tài)輸出鎖器用于鎖存 A/D 轉(zhuǎn)換完的數(shù)字量,當(dāng) OE 端為高電平時(shí),才可以從三態(tài)輸出鎖存器取走轉(zhuǎn)換完的數(shù)據(jù)。
3 引腳結(jié)構(gòu)
IN0-IN7:8 條模擬量輸入通道
ADC0809 對輸入模擬量要求:信號單極性,電壓范圍是 0-5V,若信號太小,必須進(jìn)行放大;輸入的模擬量在轉(zhuǎn)換過程中應(yīng)該保持不變,如若模擬量變化太快,則需在輸入前增加采樣保持電路。
地址輸入和控制線:4 條
ALE 為地址鎖存允許輸入線,高電平有效。當(dāng) ALE 線為高電平時(shí),地址鎖存與譯
碼器將 A,B,C 三條地址線的地址信號進(jìn)行鎖存,經(jīng)譯碼后被選中的通道的模擬
量進(jìn)轉(zhuǎn)換器進(jìn)行轉(zhuǎn)換。A,B 和 C 為地址輸入線,用于選通 IN0-IN7 上的一路模
擬量輸入。通道選擇表如下表所示。
C
B
A
選擇的通道
0
0
0
IN0
0
0
1
IN1
0
1
0
IN2
0
1
1
IN3
1
0
0
IN4
1
0
1
IN5
1
1
0
IN6
1
1
1
IN7

數(shù)字量輸出及控制線:11 條
ST 為轉(zhuǎn)換啟動信號。當(dāng) ST 上跳沿時(shí),所有內(nèi)部寄存器清零;下跳沿時(shí),開始進(jìn)
行 A/D 轉(zhuǎn)換;在轉(zhuǎn)換期間,ST 應(yīng)保持低電平。EOC 為轉(zhuǎn)換結(jié)束信號。當(dāng) EOC 為高
電平時(shí),表明轉(zhuǎn)換結(jié)束;否則,表明正在進(jìn)行 A/D 轉(zhuǎn)換。OE 為輸出允許信號,
用于控制三條輸出鎖存器向單片機(jī)輸出轉(zhuǎn)換得到的數(shù)據(jù)。OE=1,輸出轉(zhuǎn)換得到
的數(shù)據(jù);OE=0,輸出數(shù)據(jù)線呈高阻狀態(tài)。D7-D0 為數(shù)字量輸出線。
CLK 為時(shí)鐘輸入信號線。因 ADC0809 的內(nèi)部沒有時(shí)鐘電路,所需時(shí)鐘信號必須由
外界提供,通常使用頻率為 500KHZ,VREF(+),VREF(-)為參考電壓輸入。
4 ADC0809 應(yīng)用說明
(1). ADC0809 內(nèi)部帶有輸出鎖存器,可以與 AT89S51 單片機(jī)直接相連。
(2). 初始化時(shí),使 ST 和 OE 信號全為低電平。
(3). 送要轉(zhuǎn)換的哪一通道的地址到 A,B,C 端口上。
(4). 在 ST 端給出一個(gè)至少有 100ns 寬的正脈沖信號。
(5). 是否轉(zhuǎn)換完畢,我們根據(jù) EOC 信號來判斷。
(6). 當(dāng) EOC 變?yōu)楦唠娖綍r(shí),這時(shí)給 OE 為高電平,轉(zhuǎn)換的數(shù)據(jù)就輸出給單片機(jī)了。
5 實(shí)驗(yàn)任務(wù)
如下圖所示,從 ADC0809 的通道 IN3 輸入 0-5V 之間的模擬量,通過 ADC0809
轉(zhuǎn)換成數(shù)字量在數(shù)碼管上以十進(jìn)制形成顯示出來。ADC0809 的 VREF 接+5V電壓。
6 電路原理圖


5. 系統(tǒng)板上硬件連線
(1). 把“單片機(jī)系統(tǒng)板”區(qū)域中的 P1 端口的 P1.0-P1.7 用 8 芯排線連接到“動態(tài)數(shù)碼顯示”區(qū)域中的 A B C D E F G H 端口上,作為數(shù)碼管的筆段驅(qū)動。
(2). 把“單片機(jī)系統(tǒng)板”區(qū)域中的 P2 端口的 P2.0-P2.7 用 8 芯排線連接到“動態(tài)數(shù)碼顯示”區(qū)域中的 S1 S2 S3 S4 S5 S6 S7 S8 端口上,作為數(shù)碼管的位段選擇。
(3). 把“單片機(jī)系統(tǒng)板”區(qū)域中的 P0 端口的 P0.0-P0.7 用 8 芯排線連接到“模數(shù)轉(zhuǎn)換模塊”區(qū)域中的 D0D1D2D3D4D5D6D7 端口上,A/D 轉(zhuǎn)換完畢的數(shù)據(jù)輸入到單片機(jī)的 P0 端口
(4). 把“模數(shù)轉(zhuǎn)換模塊”區(qū)域中的 VREF 端子用導(dǎo)線連接到“電源模塊”區(qū)域中的 VCC 端子上;
(5). 把“模數(shù)轉(zhuǎn)換模塊”區(qū)域中的 A2A1A0 端子用導(dǎo)線連接到“單片機(jī)系統(tǒng)”區(qū)域中的 P3.4 P3.5 P3.6 端子上;
(6). 把“模數(shù)轉(zhuǎn)換模塊”區(qū)域中的 ST 端子用導(dǎo)線連接到“單片機(jī)系統(tǒng)”
區(qū)域中的 P3.0 端子上;
(7). 把“模數(shù)轉(zhuǎn)換模塊”區(qū)域中的 OE 端子用導(dǎo)線連接到“單片機(jī)系統(tǒng)”區(qū)域中的 P3.1 端子上;
(8).把“模數(shù)轉(zhuǎn)換模塊”區(qū)域中的 EOC 端子用導(dǎo)線連接到“單片機(jī)系統(tǒng)”區(qū)域中的 P3.2 端子上;
(9). 把“模數(shù)轉(zhuǎn)換模塊”區(qū)域中的 CLK 端子用導(dǎo)線連接到“分頻模塊”區(qū)域中的 /4 端子上;
(10). 把“分頻模塊”區(qū)域中的 CK IN 端子用導(dǎo)線連接到“單片機(jī)系統(tǒng)”區(qū)域中的 ALE 端子上;
(11). 把“模數(shù)轉(zhuǎn)換模塊”區(qū)域中的 IN3 端子用導(dǎo)線連接到“三路可調(diào)壓模塊”區(qū)域中的 VR1 端子上;
6. 程序設(shè)計(jì)內(nèi)容
(1). 進(jìn)行 A/D 轉(zhuǎn)換時(shí),采用查詢 EOC 的標(biāo)志信號來檢測 A/D 轉(zhuǎn)換是否完畢,若完畢則把數(shù)據(jù)通過 P0 端口讀入,經(jīng)過數(shù)據(jù)處理之后在數(shù)碼管上顯示。
(2). 進(jìn)行 A/D 轉(zhuǎn)換之前,要啟動轉(zhuǎn)換的方法:ABC=110 選擇第三通道ST=0,ST=1,ST=0 產(chǎn)生啟動轉(zhuǎn)換的正脈沖信號






7. 匯編源程序
  1. CH EQU 30H
  2. DPCNT EQU 31H
  3. DPBUF EQU 33H
  4. GDATA EQU 32H
  5. ST BIT P3.0
  6. OE BIT P3.1
  7. EOC BIT P3.2
  8. ORG 00H
  9. LJMP START
  10. ORG 0BH
  11. LJMP T0X
  12. ORG 30H
  13. START: MOV CH,#0BCH
  14. MOV DPCNT,#00H
  15. MOV R1,#DPCNT
  16. MOV R7,#5
  17. MOV A,#10
  18. MOV R0,#DPBUF
  19. LOP: MOV @R0,A
  20. INC R0
  21. DJNZ R7,LOP
  22. MOV @R0,#00H
  23. INC R0
  24. MOV @R0,#00H
  25. INC R0
  26. MOV @R0,#00H
  27. MOV TMOD,#01H
  28. MOV TH0,#(65536-4000)/256
  29. MOV TL0,#(65536-4000)
  30. MOD 256
  31. SETB TR0
  32. SETB ET0
  33. SETB EA
  34. WT: CLR ST
  35. SETB ST
  36. CLR ST
  37. WAIT: JNB EOC,WAIT
  38. SETB OE
  39. MOV GDATA,P0
  40. CLR OE
  41. MOV A,GDATA
  42. MOV B,#100
  43. DIV AB
  44. MOV 33H,A
  45. MOV A,B
  46. MOV B,#10
  47. DIV AB
  48. MOV 34H,A
  49. MOV 35H,B
  50. SJMP WT
  51. T0X: NOP
  52. MOV TH0,#(65536-4000)/256
  53. MOV TL0,#(65536-4000) MOD 256
  54. MOV DPTR,#DPCD
  55. MOV A,DPCNT
  56. ADD A,#DPBUF
  57. MOV R0,A
  58. MOV A,@R0
  59. MOVC A,@A+DPTR
  60. MOV P1,A
  61. MOV DPTR,#DPBT
  62. MOV A,DPCNT
  63. MOVC A,@A+DPTR
  64. MOV P2,A
  65. INC DPCNT
  66. MOV A,DPCNT
  67. CJNE A,#8,NEXT
  68. MOV DPCNT,#00H
  69. NEXT: RETI
  70. DPCD: DB 3FH,06H,5BH,4FH,66H
  71. DB 6DH,7DH,07H,7FH,6FH,00H
  72. DPBT: DB 0FEH,0FDH,0FBH,0F7H
  73. DB 0EFH,0DFH,0BFH,07FH
  74. END
復(fù)制代碼






8. C 語言源程序
  1. #INClude <AT89X52.H>
  2. unsigned char code dispbitcode[]={0xfe,0xfd,0xfb,0xf7,
  3. 0xef,0xdf,0xbf,0x7f};
  4. unsigned char code dispcode[]={0x3f,0x06,0x5b,0x4f,0x66,
  5. 0x6d,0x7d,0x07,0x7f,0x6f,0x00};
  6. unsigned char dispbuf[8]={10,10,10,10,10,0,0,0};
  7. unsigned char dispcount;
  8. sbit ST=P3^0;
  9. sbit OE=P3^1;
  10. sbit EOC=P3^2;
  11. unsigned char channel=0xbc;//IN3
  12. unsigned char getdata;
  13. void main(void)
  14. {

  15. TMOD=0x01;
  16. TH0=(65536-4000)/256;
  17. TL0=(65536-4000)%256;
  18. TR0=1;
  19. ET0=1;
  20. EA=1;
  21. P3=channel;
  22. while(1)
  23. {
  24. ST=0;
  25. ST=1;
  26. ST=0;
  27. while(EOC==0);
  28. OE=1;
  29. getdata=P0;
  30. OE=0;
  31. dispbuf[2]=getdata/100;
  32. getdata=getdata%10;
  33. dispbuf[1]=getdata/10;
  34. dispbuf[0]=getdata%10;
  35. }
  36. }
  37. void t0(void) interrupt 1 using 0
  38. {
  39. TH0=(65536-4000)/256;
  40. TL0=(65536-4000)%256;
  41. P1=dispcode[dispbuf[dispcount]];
  42. P2=dispbitcode[dispcount];
  43. dispcount++;
  44. if(dispcount==8)
  45. {
  46. dispcount=0;
  47. }
  48. }
復(fù)制代碼


3


十、DS18B20 數(shù)字溫度計(jì)使用
1.DS18B20 基本知識
DS18B20 數(shù)字溫度計(jì)是 DALLAS 公司生產(chǎn)的 1-Wire,即單總線器件,具有線路簡單,體積小的特點(diǎn)。因此用它來組成一個(gè)測溫系統(tǒng),具有線路簡單,在一根通信線,可以掛很多這樣的數(shù)字溫度計(jì),十分方便。
1、DS18B20 產(chǎn)品的特點(diǎn)
(1)、只要求一個(gè)端口即可實(shí)現(xiàn)通信。
(2)、在 DS18B20 中的每個(gè)器件上都有獨(dú)一無二的序列號。
(3)、實(shí)際應(yīng)用中不需要外部任何元器件即可實(shí)現(xiàn)測溫。
(4)、測量溫度范圍在-55。C 到+125。C 之間。
(5)、數(shù)字溫度計(jì)的分辨率用戶可以從 9 位到 12 位選擇。
(6)、內(nèi)部有溫度上、下限告警設(shè)置。
2、DS18B20 的引腳介紹
TO-92 封裝的 DS18B20 的引腳排列見圖 1,其引腳功能描述見表 1。(底視圖)圖 1


由于 DS18B20 采用的是 1-Wire 總線協(xié)議方式,即在一根數(shù)據(jù)線實(shí)現(xiàn)數(shù)據(jù)的雙向傳輸,而對 AT89S51 單片機(jī)來說,硬件上并不支持單總線協(xié)議,因此,我們必須采用軟件的方法來模擬單總線的協(xié)議時(shí)序來完成對 DS18B20 芯片的訪問。

由于 DS18B20 是在一根 I/O 線上讀寫數(shù)據(jù),因此,對讀寫的數(shù)據(jù)位有著嚴(yán)格的時(shí)序要求。DS18B20 有嚴(yán)格的通信協(xié)議來保證各位數(shù)據(jù)傳輸?shù)恼_性和完整性。該協(xié)議定義了幾種信號的時(shí)序:初始化時(shí)序、讀時(shí)序、寫時(shí)序。所有時(shí)序都是將主機(jī)作為主設(shè)備,單總線器件作為從設(shè)備。而每一次命令和數(shù)據(jù)的傳輸都是從主機(jī)主動啟動寫時(shí)序開始,如果要求單總線器件回送數(shù)據(jù),在進(jìn)行寫命令后,主機(jī)需啟動讀時(shí)序完成數(shù)據(jù)接收。數(shù)據(jù)和命令的傳輸都是低位在先。
DS18B20 的復(fù)位時(shí)序

DS18B20 的讀時(shí)序?qū)τ贒S18B20 的讀時(shí)序分為讀 0時(shí)序和讀 1 時(shí)序兩個(gè)過程。對于 DS18B20的讀時(shí)隙是從主機(jī)把單總線拉低之后,在 15 秒之內(nèi)就得釋放單總線,以讓 DS18B20 把數(shù)據(jù)傳輸?shù)絾慰偩上。DS18B20 在完成一個(gè)讀時(shí)序過程,至少需要 60us 才能完成。


對于 DS18B20 的寫時(shí)序仍然分為寫 0 時(shí)序和寫 1 時(shí)序兩個(gè)過程。對于DS18B20 寫 0 時(shí)序和寫 1 時(shí)序的要求不同,當(dāng)要寫 0 時(shí)序時(shí),單總線要被拉低至少 60us,保證 DS18B20 能夠在 15us 到 45us 之間能夠正確地采樣 IO 總線上的“0”電平,當(dāng)要寫 1 時(shí)序時(shí),單總線被拉低之后,在 15us 之內(nèi)就得釋放單總線。


4. 實(shí)驗(yàn)任務(wù)
用一片 DS18B20 構(gòu)成測溫系統(tǒng),測量的溫度精度達(dá)到 0.1 度,測量的溫度的范圍在-20 度到+100 度之間,用 8 位數(shù)碼管顯示出來。
5. 電路原理圖






7. C 語言源程序
  1. #INClude <AT89X52.H>
  2. #INClude <INTRINS.h>
  3. unsigned char code displaybit[]={0xfe,0xfd,0xfb,0xf7,
  4. 0xef,0xdf,0xbf,0x7f};
  5. unsigned char code displaycode[]={0x3f,0x06,0x5b,0x4f,
  6. 0x66,0x6d,0x7d,0x07,
  7. 0x7f,0x6f,0x77,0x7c,
  8. 0x39,0x5e,0x79,0x71,0x00,0x40};
  9. unsigned char code dotcode[32]={0,3,6,9,12,16,19,22,
  10. 25,28,31,34,38,41,44,48,
  11. 50,53,56,59,63,66,69,72,
  12. 75,78,81,84,88,91,94,97};
  13. unsigned char displaycount;
  14. unsigned char displaybuf[8]={16,16,16,16,16,16,16,16};
  15. unsigned char timecount;
  16. unsigned char readdata[8];
  17. sbit DQ=P3^7;
  18. bit sflag;
  19. bit resetpulse(void)
  20. {
  21. unsigned char i;
  22. DQ=0;
  23. for(i=255;i>0;i--);
  24. DQ=1;
  25. for(i=60;i>0;i--);
  26. RETurn(DQ);
  27. for(i=200;i>0;i--);
  28. }
  29. void writecommandtods18b20(unsigned char command)
  30. {
  31. unsigned char i;
  32. unsigned char j;
  33. for(i=0;i<8;i++)
  34. {
  35. if((command & 0x01)==0)
  36. {
  37. DQ=0;
  38. for(j=35;j>0;j--);
  39. DQ=1;
  40. }
  41. else
  42. {
  43. DQ=0;
  44. for(j=2;j>0;j--);
  45. DQ=1;
  46. for(j=33;j>0;j--);
  47. }
  48. command=_cror_(command,1);
  49. }
  50. }
  51. Unsigned  char readdatafromds18b20(void)

  52. Unsigned char i;
  53. Unsigned char j;
  54. Unsigned char temp;
  55. temp=0;
  56. for(i=0;i<8;i++)
  57. {
  58. temp=_cror_(temp,1);
  59. DQ=0;
  60. _nop_();
  61. _nop_();
  62. DQ=1;
  63. for(j=10;j>0;j--);
  64. if(DQ==1)
  65. {
  66. temp=temp | 0x80;
  67. }
  68. else
  69. {
  70. temp=temp | 0x00;
  71. }
  72. for(j=200;j>0;j--);
  73. }
  74. RETurn(temp);
  75. }
  76. void main(void)
  77. {
  78. TMOD=0x01;
  79. TH0=(65536-4000)/256;
  80. TL0=(65536-4000)%256;
  81. ET0=1;
  82. EA=1;
  83. while(resetpulse());
  84. writecommandtods18b20(0xcc);
  85. writecommandtods18b20(0x44);
  86. TR0=1;
  87. while(1)
  88. {
  89. ;
  90. }
  91. }
  92. void t0(void) interrupt 1 using 0
  93. {
  94. unsigned char x;
  95. unsigned int result;
  96. TH0=(65536-4000)/256;
  97. TL0=(65536-4000)%256;
  98. if(displaycount==2)
  99. {
  100. P0=displaycode[displaybuf[displaycount]] | 0x80;
  101. }
  102. else
  103. {
  104. P0=displaycode[displaybuf[displaycount]];
  105. }
  106. P2=displaybit[displaycount];
  107. displaycount++;
  108. if(displaycount==8)
  109. {
  110. displaycount=0;
  111. }
  112. timecount++;
  113. if(timecount==150)
  114. {
  115. timecount=0;
  116. while(resetpulse());
  117. writecommandtods18b20(0xcc);
  118. writecommandtods18b20(0xbe);
  119. readdata[0]=readdatafromds18b20();
  120. readdata[1]=readdatafromds18b20();
  121. for(x=0;x<8;x++)
  122. {
  123. displaybuf[x]=16;
  124. }
  125. sflag=0;
  126. if((readdata[1] & 0xf8)!=0x00)
  127. {
  128. sflag=1;
  129. readdata[1]=~readdata[1];
  130. readdata[0]=~readdata[0];
  131. result=readdata[0]+1;
  132. readdata[0]=result;
  133. if(result>255)
  134. {
  135. readdata[1]++;
  136. }
  137. }
  138. readdata[1]=readdata[1]<<4;
  139. readdata[1]=readdata[1] & 0x70;
  140. x=readdata[0];
  141. x=x>>4;
  142. x=x & 0x0f;
  143. readdata[1]=readdata[1] | x;
  144. x=2;
  145. result=readdata[1];
  146. while(result/10)
  147. {
  148. displaybuf[x]=result%10;
  149. result=result/10;
  150. x++;
  151. }
  152. displaybuf[x]=result;
  153. if(sflag==1)
  154. {
  155. displaybuf[x+1]=17;
  156. }
  157. x=readdata[0] & 0x0f;
  158. x=x<<1;
  159. displaybuf[0]=(dotcode[x])%10;
  160. displaybuf[1]=(dotcode[x])/10;
  161. while(resetpulse());
  162. writecommandtods18b20(0xcc);
  163. writecommandtods18b20(0x44);
  164. }
  165. }
復(fù)制代碼





11、 4×4 鍵盤及 8 位數(shù)碼管顯示構(gòu)成的電子密碼鎖
用 4×4 組成 0-9 數(shù)字鍵及確認(rèn)鍵。

用 8 位數(shù)碼管組成顯示電路提示信息,當(dāng)輸入密碼時(shí),只顯示“8.”,當(dāng)密碼位數(shù)輸入完畢按下確認(rèn)鍵時(shí),對輸入的密碼與設(shè)定的密碼進(jìn)行比較,若密碼正確,則門開,此處用 LED 發(fā)光二極管亮一秒鐘做為提示,同時(shí)發(fā)出“叮咚”聲;若密碼不正確,禁止按鍵輸入 3 秒,同時(shí)發(fā)出“嘀、嘀”
報(bào)警聲;若在 3 秒之內(nèi)仍有按鍵按下,則禁止按鍵輸入 3 秒被重新禁止。
4. 程序設(shè)計(jì)內(nèi)容
(1). 4×4 行列式鍵盤識別技術(shù):有關(guān)這方面內(nèi)容前面已經(jīng)討論過,這里不再重復(fù)。
(2). 8 位數(shù)碼顯示,初始化時(shí),顯示“P   ”,接著輸入最大 6 位數(shù)的密碼,當(dāng)密碼輸入完后,按下確認(rèn)鍵,進(jìn)行密碼比較,然后給出相應(yīng)的信息。在輸入密碼過程中,顯示器只顯示“8.”。當(dāng)數(shù)字輸入超過 6個(gè)時(shí),給出報(bào)警信息。在密碼輸入過程中,若輸入錯(cuò)誤,可以利用“DEL”鍵刪除剛才輸入的錯(cuò)誤的數(shù)字。
(3). 4×4 行列式鍵盤的按鍵功能分布圖如圖 4.33.2 所示:




5. C 語言源程序
  1. #include <AT89X52.H>
  2. unsigned char ps[]={1,2,3,4,5};
  3. unsigned char code dispbit[]={0xfe,0xfd,0xfb,0xf7,
  4. 0xef,0xdf,0xbf,0x7f};
  5. unsigned char code dispcode[]={0x3f,0x06,0x5b,0x4f,0x66,
  6. 0x6d,0x7d,0x07,0x7f,0x6f,
  7. 0x77,0x7c,0x39,0x5e,0x79,0x71,
  8. 0x00,0x40,0x73,0xff};
  9. unsigned char dispbuf[8]={18,16,16,16,16,16,16,16};
  10. unsigned char dispcount;
  11. unsigned char flashcount;
  12. unsigned char temp;
  13. unsigned char key;
  14. unsigned char keycount;
  15. unsigned char pslen=5;
  16. unsigned char getps[6];
  17. bit keyoverflag;
  18. bit errorflag;
  19. bit rightflag;
  20. unsigned int second3;
  21. unsigned int aa,bb;
  22. unsigned int cc;
  23. bit okflag;
  24. bit alarmflag;
  25. bit hibitflag;
  26. unsigned char oka,okb;
  27. void main(void)
  28. {
  29. unsigned char i,j;
  30. TMOD=0x01;
  31. TH0=(65536-500)/256;
  32. TL0=(65536-500)%256;
  33. TR0=1;
  34. ET0=1;
  35. EA=1;
  36. while(1)
  37. {
  38. P3=0xff;
  39. P3_4=0;
  40. temp=P3;
  41. temp=temp & 0x0f;
  42. if (temp!=0x0f)
  43. {
  44. for(i=10;i>0;i--)
  45. for(j=248;j>0;j--);
  46. temp=P3;
  47. temp=temp & 0x0f;
  48. if (temp!=0x0f)
  49. {
  50. temp=P3;
  51. temp=temp & 0x0f;
  52. switch(temp)
  53. {
  54. case 0x0e:
  55. key=7;
  56. break;
  57. case 0x0d:
  58. key=8;
  59. break;
  60. case 0x0b:
  61. key=9;
  62. break;
  63. case 0x07:
  64. key=10;
  65. break;
  66. }
  67. temp=P3;
  68. P1_1=~P1_1;
  69. if((key>=0) && (key<10))
  70. {
  71. if(keycount<6)
  72. {
  73. getps[keycount]=key;
  74. dispbuf[keycount+2]=19;
  75. }
  76. keycount++;
  77. if(keycount==6)
  78. {
  79. keycount=6;
  80. }
  81. else if(keycount>6)
  82. {
  83. keycount=6;
  84. keyoverflag=1;//key overflow
  85. }
  86. }
  87. else if(key==12)//delete key
  88. {
  89. if(keycount>0)
  90. {
  91. keycount--;
  92. getps[keycount]=0;
  93. dispbuf[keycount+2]=16;
  94. }
  95. else
  96. {
  97. keyoverflag=1;
  98. }
  99. }
  100. else if(key==15)//enter key
  101. {
  102. if(keycount!=pslen)
  103. {
  104. errorflag=1;
  105. rightflag=0;
  106. second3=0;
  107. }
  108. else
  109. {
  110. for(i=0;i<keycount;i++)
  111. {
  112. if(getps[ i]!=ps[ i])
  113. {
  114. i=keycount;
  115. errorflag=1;
  116. rightflag=0;
  117. second3=0;
  118. goto a;
  119. }
  120. }
  121. errorflag=0;
  122. rightflag=1;
  123. a: i=keycount;
  124. }
  125. }
  126. temp=temp & 0x0f;
  127. while(temp!=0x0f)
  128. {
  129. temp=P3;
  130. temp=temp & 0x0f;
  131. }
  132. keyoverflag=0;//?????????
  133. }
  134. }
  135. P3=0xff;
  136. P3_5=0;
  137. temp=P3;
  138. temp=temp & 0x0f;
  139. if (temp!=0x0f)
  140. {
  141. for(i=10;i>0;i--)
  142. for(j=248;j>0;j--);
  143. temp=P3;
  144. temp=temp & 0x0f;
  145. if (temp!=0x0f)
  146. {
  147. temp=P3;
  148. temp=temp & 0x0f;
  149. switch(temp)
  150. {
  151. case 0x0e:
  152. key=4;
  153. break;
  154. case 0x0d:
  155. key=5;
  156. break;
  157. case 0x0b:
  158. key=6;
  159. break;
  160. case 0x07:
  161. key=11;
  162. break;
  163. }
  164. temp=P3;
  165. P1_1=~P1_1;
  166. if((key>=0) && (key<10))
  167. {
  168. if(keycount<6)
  169. {
  170. getps[keycount]=key;
  171. dispbuf[keycount+2]=19;
  172. }
  173. keycount++;
  174. if(keycount==6)
  175. {
  176. keycount=6;
  177. }
  178. else if(keycount>6)
  179. {
  180. keycount=6;
  181. keyoverflag=1;//key overflow
  182. }
  183. }
  184. else if(key==12)//delete key
  185. {
  186. if(keycount>0)
  187. {
  188. keycount--;
  189. getps[keycount]=0;
  190. dispbuf[keycount+2]=16;
  191. }
  192. else
  193. {
  194. keyoverflag=1;
  195. }
  196. }
  197. else if(key==15)//enter key
  198. {
  199. if(keycount!=pslen)
  200. {
  201. errorflag=1;
  202. rightflag=0;
  203. second3=0;
  204. }
  205. else
  206. {
  207. for(i=0;i<keycount;i++)
  208. {
  209. if(getps[ i]!=ps[ i])
  210. {
  211. i=keycount;
  212. errorflag=1;
  213. rightflag=0;
  214. second3=0;
  215. goto a4;
  216. }
  217. }
  218. errorflag=0;
  219. rightflag=1;
  220. a4: i=keycount;
  221. }
  222. }
  223. temp=temp & 0x0f;
  224. while(temp!=0x0f)
  225. {
  226. temp=P3;
  227. temp=temp & 0x0f;
  228. }
  229. keyoverflag=0;//?????????
  230. }
  231. }
  232. P3=0xff;
  233. P3_6=0;
  234. temp=P3;
  235. temp=temp & 0x0f;
  236. if (temp!=0x0f)
  237. {
  238. for(i=10;i>0;i--)
  239. for(j=248;j>0;j--);
  240. temp=P3;
  241. temp=temp & 0x0f;
  242. if (temp!=0x0f)
  243. {
  244. temp=P3;
  245. temp=temp & 0x0f;
  246. switch(temp)
  247. {
  248. case 0x0e:
  249. key=1;
  250. break;
  251. case 0x0d:
  252. key=2;
  253. break;
  254. case 0x0b:
  255. key=3;
  256. break;
  257. case 0x07:
  258. key=12;
  259. break;
  260. }
  261. temp=P3;
  262. P1_1=~P1_1;
  263. if((key>=0) && (key<10))
  264. {
  265. if(keycount<6)
  266. {
  267. getps[keycount]=key;
  268. dispbuf[keycount+2]=19;
  269. }
  270. keycount++;
  271. if(keycount==6)
  272. {
  273. keycount=6;
  274. }
  275. else if(keycount>6)
  276. {
  277. keycount=6;
  278. keyoverflag=1;//key overflow
  279. }
  280. }
  281. else if(key==12)//delete key
  282. {
  283. if(keycount>0)
  284. {
  285. keycount--;
  286. getps[keycount]=0;
  287. dispbuf[keycount+2]=16;
  288. }
  289. else
  290. {
  291. keyoverflag=1;
  292. }
  293. }
  294. else if(key==15)//enter key
  295. {
  296. if(keycount!=pslen)
  297. {
  298. errorflag=1;
  299. rightflag=0;
  300. second3=0;
  301. }
  302. else
  303. {
  304. for(i=0;i<keycount;i++)
  305. {
  306. if(getps[ i]!=ps[ i])
  307. {
  308. i=keycount;
  309. errorflag=1;
  310. rightflag=0;
  311. second3=0;
  312. goto a3;
  313. }
  314. }
  315. errorflag=0;
  316. rightflag=1;
  317. a3: i=keycount;
  318. }
  319. }
  320. temp=temp & 0x0f;
  321. while(temp!=0x0f)
  322. {
  323. temp=P3;
  324. temp=temp & 0x0f;
  325. }
  326. keyoverflag=0;//?????????
  327. }
  328. }
  329. P3=0xff;
  330. P3_7=0;
  331. temp=P3;
  332. temp=temp & 0x0f;
  333. if (temp!=0x0f)
  334. {
  335. for(i=10;i>0;i--)
  336. for(j=248;j>0;j--);
  337. temp=P3;
  338. temp=temp & 0x0f;
  339. if (temp!=0x0f)
  340. {
  341. temp=P3;
  342. temp=temp & 0x0f;
  343. switch(temp)
  344. {
  345. case 0x0e:
  346. key=0;
  347. break;
  348. case 0x0d:
  349. key=13;
  350. break;
  351. case 0x0b;
  352. key=14;
  353. break;
  354. case 0x07:
  355. key=15;
  356. break;
  357. }
  358. temp=P3;
  359. P1_1=~P1_1;
  360. if((key>=0) && (key<10))
  361. {
  362. if(keycount<6)
  363. {
  364. getps[keycount]=key;
  365. dispbuf[keycount+2]=19;
  366. }
  367. keycount++;
  368. if(keycount==6)
  369. {
  370. keycount=6;
  371. }
  372. else if(keycount>6)
  373. {
  374. keycount=6;
  375. keyoverflag=1;//key overflow
  376. }
  377. }
  378. else if(key==12)//delete key
  379. {
  380. if(keycount>0)
  381. {
  382. keycount--;
  383. getps[keycount]=0;
  384. dispbuf[keycount+2]=16;
  385. }
  386. else
  387. {
  388. keyoverflag=1;
  389. }
  390. }
  391. else if(key==15)//enter key
  392. {
  393. if(keycount!=pslen)
  394. {
  395. errorflag=1;
  396. rightflag=0;
  397. second3=0;
  398. }
  399. else
  400. {
  401. for(i=0;i<keycount;i++)
  402. {
  403. if(getps[ i]!=ps[ i])
  404. {
  405. i=keycount;
  406. errorflag=1;
  407. rightflag=0;
  408. second3=0;
  409. goto a2;
  410. }
  411. }
  412. errorflag=0;
  413. rightflag=1;
  414. a2: i=keycount;
  415. }
  416. }
  417. temp=temp & 0x0f;
  418. while(temp!=0x0f)
  419. {
  420. temp=P3;
  421. temp=temp & 0x0f;
  422. }
  423. keyoverflag=0;//?????????
  424. }
  425. }
  426. }
  427. }
  428. void t0(void) interrupt 1 using 0
  429. {
  430. TH0=(65536-500)/256;
  431. TL0=(65536-500)%256;
  432. flashcount++;
  433. if(flashcount==8)
  434. {
  435. flashcount=0;
  436. P0=dispcode[dispbuf[dispcount]];
  437. P2=dispbit[dispcount];
  438. dispcount++;
  439. if(dispcount==8)
  440. {
  441. dispcount=0;
  442. }
  443. }
  444. if((errorflag==1) && (rightflag==0))
  445. {
  446. bb++;
  447. if(bb==800)
  448. {
  449. bb=0;
  450. alarmflag=~alarmflag;
  451. }
  452. if(alarmflag==1)//sound alarm signal
  453. {
  454. P1_7=~P1_7;
  455. }
  456. aa++;
  457. if(aa==800)//light alarm signal
  458. {
  459. aa=0;
  460. P1_0=~P1_0;
  461. }
  462. second3++;
  463. if(second3==6400)
  464. {
  465. second3=0;
  466. errorflag=0;
  467. rightflag=0;
  468. alarmflag=0;
  469. bb=0;
  470. aa=0;
  471. }
  472. }
  473. else if((errorflag==0) && (rightflag==1))
  474. {
  475. P1_0=0;
  476. cc++;
  477. if(cc<1000)
  478. {
  479. okflag=1;
  480. }
  481. else if(cc<2000)
  482. {
  483. okflag=0;
  484. }
  485. else
  486. {
  487. errorflag=0;
  488. rightflag=0;
  489. P1_7=1;
  490. cc=0;
  491. oka=0;
  492. okb=0;
  493. okflag=0;
  494. P1_0=1;
  495. }
  496. if(okflag==1)
  497. {
  498. oka++;
  499. if(oka==2)
  500. {
  501. oka=0;
  502. P1_7=~P1_7;
  503. }
  504. }
  505. else
  506. {
  507. okb++;
  508. if(okb==3)
  509. {
  510. okb=0;
  511. P1_7=~P1_7;
  512. }
  513. }
  514. }
  515. if(keyoverflag==1)
  516. {
  517. P1_7=~P1_7;
  518. }
  519. }
復(fù)制代碼




12. 6 位數(shù)顯頻率計(jì)數(shù)器
1. 實(shí)驗(yàn)任務(wù)
利用 AT89S51 單片機(jī)的 T0、T1 的定時(shí)計(jì)數(shù)器功能,來完成對輸入的信號進(jìn)行頻率計(jì)數(shù),計(jì)數(shù)的頻率結(jié)果通過 8 位動態(tài)數(shù)碼管顯示出來。要求能夠?qū)?-250KHZ 的信號頻率進(jìn)行準(zhǔn)確計(jì)數(shù),計(jì)數(shù)誤差不超過±1HZ。
3. 程序設(shè)計(jì)內(nèi)容
(1). 定時(shí)/計(jì)數(shù)器 T0 和 T1 的工作方式設(shè)置,由圖可知,T0 是工作在計(jì)數(shù)狀態(tài)下,對輸入的頻率信號進(jìn)行計(jì)數(shù),但對工作在計(jì)數(shù)狀態(tài)下的T0,最大計(jì)數(shù)值為 fOSC/24,由于 fOSC=12MHz,因此:T0 的最大計(jì)數(shù)頻率為250KHz。對于頻率的概念就是在一秒只數(shù)脈沖的個(gè)數(shù),即為頻率值。
所以 T1 工作在定時(shí)狀態(tài)下,每定時(shí) 1 秒中到,就停止 T0 的計(jì)數(shù),而從 T0 的計(jì)數(shù)單元中讀取計(jì)數(shù)的數(shù)值,然后進(jìn)行數(shù)據(jù)處理。送到數(shù)碼管顯示出來。
(2). T1 工作在定時(shí)狀態(tài)下,最大定時(shí)時(shí)間為 65ms,達(dá)不到 1 秒的定時(shí),所
以采用定時(shí) 50ms,共定時(shí) 20 次,即可完成 1 秒的定時(shí)功能。


. C 語言源程序
  1. #include <AT89X52.H>
  2. unsigned char code dispbit[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
  3. unsigned char code dispcode[]={0x3f,0x06,0x5b,0x4f,0x66,
  4. 0x6d,0x7d,0x07,0x7f,0x6f,0x00,0x40};
  5. unsigned char dispbuf[8]={0,0,0,0,0,0,10,10};
  6. unsigned char temp[8];
  7. unsigned char dispcount;
  8. unsigned char T0count;
  9. unsigned char timecount;
  10. bit flag;
  11. unsigned long x;
  12. void main(void)
  13. {
  14. unsigned char i;
  15. TMOD=0x15;
  16. TH0=0;
  17. TL0=0;
  18. TH1=(65536-4000)/256;
  19. TL1=(65536-4000)%256;
  20. TR1=1;
  21. TR0=1;
  22. ET0=1;
  23. ET1=1;
  24. EA=1;
  25. while(1)
  26. {
  27. if(flag==1)
  28. {
  29. flag=0;
  30. x=T0count*65536+TH0*256+TL0;
  31. for(i=0;i<8;i++)
  32. {
  33. temp[ i]=0;
  34. }
  35. i=0;
  36. while(x/10)
  37. {
  38. temp[ i]=x%10;
  39. x=x/10;
  40. i++;
  41. }
  42. temp[ i]=x;
  43. for(i=0;i<6;i++)
  44. {
  45. dispbuf[ i]=temp[ i];
  46. }
  47. timecount=0;
  48. T0count=0;
  49. TH0=0;
  50. TL0=0;
  51. TR0=1;
  52. }
  53. }
  54. }
  55. void t0(void) interrupt 1 using 0
  56. {
  57. T0count++;
  58. }
  59. void t1(void) interrupt 3 using 0
  60. {
  61. TH1=(65536-4000)/256;
  62. TL1=(65536-4000)%256;
  63. timecount++;
  64. if(timecount==250)
  65. {
  66. TR0=0;
  67. timecount=0;
  68. flag=1;
  69. }
  70. P0=dispcode[dispbuf[dispcount]];
  71. P2=dispbit[dispcount];
  72. dispcount++;
  73. if(dispcount==8)
  74. {
  75. dispcount=0;
  76. }
  77. }
復(fù)制代碼




13、LCD驅(qū)動程序

根據(jù)原理圖設(shè)計(jì)LCD1602液晶顯示電路的驅(qū)動程序:
  1. /********************************
  2. FILE NAME:        LCD1602.c
  3. CHIP TYPE:        AT89C51
  4. CLOCK FREQUENCY:  12MHZ
  5. IDE:              VSMStudio
  6. COMPILER:         IAR for 8051
  7. TIME:             7/ 2012
  8. ********************************/

  9. #include "ioAT89C51.h"
  10. #include "intrinsics.h"

  11. // Define P3 pins
  12. #define DATA_BUS  (P0);數(shù)據(jù)總線P0
  13. #define RS  (P2_bit.P2_0);P2.0
  14. #define RW (P2_bit.P2_1) ;P2.1
  15. #define E    (P2_bit.P2_2);P2.2

  16. // Define new types
  17. typedef unsigned char   uchar;無符號字符型
  18. typedef unsigned int    uint;無符號整型

  19. // Function Prototypes
  20. void check_busy(void);檢查忙信號
  21. void write_command(uchar com);寫指令
  22. void write_data(uchar data);寫數(shù)據(jù)
  23. void LCD_init(void);LCD初始化
  24. void string(uchar ad ,uchar *s);
  25. void lcd_test(void);測試函數(shù)
  26. void delay(uint);延時(shí)函數(shù)

  27. void main(void);主函數(shù)
  28. { LCD_init();
  29.    while(1)
  30.     { string(0x80,"Have a nice day!");
  31.       string(0xC0,"  Proteus VSM");
  32.       delay(100);
  33.       write_command(0x01);
  34.       delay(100);      
  35.     }
  36. }

  37. /*******************************************
  38.     LCD1602 Driver mapped as IO peripheral
  39. *******************************************/
  40. // Delay,延時(shí)
  41. void delay(uint j)
  42. { uchar i = 60;
  43.    for(; j>0; j--)
  44.     { while(--i);
  45.       i = 59;
  46.       while(--i);
  47.       i = 60;
  48.     }
  49. }

  50. // Test the Busy bit,測試忙位BF
  51. void check_busy(void)
  52. { do
  53.     { DATA_BUS = 0xff;
  54.       E = 0;
  55.       RS = 0;
  56.       RW = 1;
  57.       E = 1;高電平
  58.       __no_operation();
  59.     } while(DATA_BUS & 0x80);
  60.    E = 0;
  61. }

  62. // Write a command,寫指令
  63. void write_command(uchar com)
  64. { check_busy();
  65.    E = 0;
  66.    RS = 0;
  67.    RW = 0;
  68.    DATA_BUS = com;
  69.    E = 1;
  70.    __no_operation();
  71.    E = 0;下降沿
  72.    delay(1);
  73. }

  74. // Write Data,寫數(shù)據(jù)
  75. void write_data(uchar data)
  76. { check_busy();
  77.    E = 0;
  78.    RS = 1;
  79.    RW = 0;
  80.    DATA_BUS = data;
  81.    E = 1;
  82.    __no_operation();
  83.    E = 0;
  84.    delay(1);  
  85. }

  86. // Initialize LCD controller
  87. void LCD_init(void)
  88. { write_command(0x38); // 8-bits, 2 lines, 7x5 dots
  89.    write_command(0x0C); // no cursor, no blink, //enable display
  90.    write_command(0x06); // auto-INCrement on
  91.    write_command(0x01); // clear screen
  92.    delay(1);
  93. }

  94. // Display a string
  95. void string(uchar ad, uchar *s)
  96. { write_command(ad);
  97.    while(*s>0)
  98.     { write_data(*s++);
  99.       delay(100);
  100.     }
  101. }
復(fù)制代碼

  1. ; LCD Display Driver Demo.
  2. ; Timing code assumes 1.2MHz Clock

  3. ;LCD Registers addresses
  4. LCD_CMD_WR              EQU               00H
  5. LCD_DATA_WR              EQU              01H
  6. LCD_BUSY_RD              EQU              02H
  7. LCD_DATA_RD              EQU              03H

  8. ;LCD Commands
  9. LCD_CLS                                EQU              01
  10. LCD_HOME                      EQU              02
  11. LCD_SETMODE                  EQU              04
  12. LCD_SETVISIBLE              EQU              08
  13. LCD_SHIFT                      EQU              16
  14. LCD_SETFUNCTION              EQU              32
  15. LCD_SETCGADDR              EQU              64
  16. LCD_SETDDADDR              EQU              128
  17. ;Reset vector
  18.               ORG 0000h
  19.               JMP start;//Start of the program
  20.               ORG 0100h
  21. string1a:DB ' !! A M A Z I N G !! '
  22.               DB 0
  23. string1b:DB '!! A M A Z I N G !! '
  24.               DB 0
  25. string2:DB ' A virtual LM032L... '
  26.               DB 0
  27. string3:DB ' driven by a virtual '
  28.               DB 0
  29. string4:DB '   8051 processor!'
  30.               DB 0
  31. start:              MOV A,#038h; 8位2行,5*7點(diǎn)陣
  32.               CALL wrcmd
  33. loop: MOV A,#LCD_SETVISIBLE+6               ;Make the display & blink visible:開顯示,光標(biāo)不閃爍
  34.               CALL wrcmd
  35.               MOV R7,#2
  36. loop2: MOV DPTR,#string1a
  37.               CALL wrstr
  38.               MOV DPTR,#200
  39.               CALL wtms
  40.               MOV A,#LCD_CLS                                          ;Clear screen
  41.               CALL wrcmd
  42.               MOV DPTR,#string1b
  43.               CALL wrstr
  44.               MOV DPTR,#200
  45.               CALL wtms
  46.               MOV A, #LCD_CLS              ;Clear screen
  47.               CALL wrcmd
  48.               DJNZ R7,loop2
  49.               MOV DPTR,#string1a
  50.               CALL wrstr
  51.               MOV DPTR,#400
  52.               CALL wtms
  53.               MOV A,#LCD_SETDDADDR+64
  54.               CALL wrcmd
  55.               MOV DPTR,#string2
  56.               CALL wrslow
  57.               MOV DPTR,#200
  58.               CALL wtms
  59.               MOV A,#LCD_CLS              ;Clear screen
  60.               CALL wrcmd
  61.               MOV DPTR,#string3
  62.               CALL wrslow
  63.     MOV A,#LCD_SETDDADDR+64
  64.               CALL wrcmd
  65.               MOV DPTR,#string4
  66.               CALL wrslow
  67. MOV A,#LCD_SETVISIBLE+7              ;Show the //blink cursor as well.
  68.               CALL wrcmd
  69.               MOV DPTR,#2000
  70.               CALL wtms
  71.               MOV A,#LCD_CLS                                          ;Clear screen
  72.               CALL wrcmd
  73.               JMP loop
  74. ;Sub routine to write null terminated string at DPTR in program ram.
  75. wrstr:              MOV R0,#LCD_DATA_WR
  76. wrstr1:              CLR A
  77.               MOVC A,@A+DPTR
  78.               JZ wrstr2
  79.               MOVX @R0,A
  80.               CALL wtbusy
  81.               INC DPTR
  82.               PUSH DPL
  83.               PUSH DPH
  84.               POP DPH
  85.               POP DPL            
  86.               JMP wrstr1
  87. wrstr2:              RET
  88. ;Sub routine to write null terminated string at DPTR in program ram. Slowly
  89. wrslow:              MOV R0,#LCD_DATA_WR
  90. wrslw1:              CLR A
  91.               MOVc A,@A+DPTR
  92.               JZ wrslw2
  93.               MOVX @R0,A
  94.               CALL wtbusy
  95.               INC DPTR
  96.               PUSH DPL
  97.               PUSH DPH
  98.     MOV DPTR,#100
  99.     CALL wtms
  100.               POP DPH
  101.               POP DPL            
  102.               JMP wrslw1
  103. wrslw2:              RET
  104. ;Sub routine to write command:
  105. wrcmd:              MOV R0,#LCD_CMD_WR
  106.               MOVX @R0,A
  107.               JMP wtbusy
  108. ;Sub routine to write character:
  109. wrchar:              MOV R0,#LCD_DATA_WR
  110.               MOVX @R0,A
  111. ;Subroutine to wait for busy clear
  112. wtbusy: MOV R1,#LCD_BUSY_RD
  113.               MOVX A,@r1
  114.               JB ACC.7,wtbusy
  115.               RET
  116. ;Wait for number of seconds in A
  117. wtsec:              PUSH ACC
  118.               CALL wtms
  119.               POP ACC
  120.               DEC A
  121.               JNZ wtsec
  122.               RET

  123. ;Wait for number of milliseconds in DPTR
  124. wtms:   XRL DPL,#0FFh                                          ;Can't do DEC DPTR, so do the loop by forming 2's complement
  125.               XRL DPH,#0FFh;and INCrementing instead.
  126.               INC DPTR
  127. wtms1:MOV TL0,#09Ch              ;100 ticks before overflow = 1ms at 1.2MHz Clock
  128.                 MOV TH0,#0FFh            
  129.                 MOV TMOD,#1                                          ;Timer 0 mode 1
  130.               SETB TCON.4                                          ;Timer 0 runs
  131. wtms2:              JNB TCON.5,wtms2            
  132.               CLR TCON.4                                          ;Timer 0 stops
  133.               CLR TCON.5
  134.               INC DPTR
  135.               MOV A,DPL
  136.               ORL A,DPH
  137.               JNZ wtms1
  138.               RET
  139.               END
復(fù)制代碼



完整的Word格式文檔51黑下載地址:
51單片機(jī)匯編語言及C語言經(jīng)典實(shí)例.doc (2.68 MB, 下載次數(shù): 53)



評分

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

查看全部評分

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

使用道具 舉報(bào)

沙發(fā)
ID:93809 發(fā)表于 2018-12-28 12:23 | 只看該作者
謝謝提供資料分享贊一個(gè)
回復(fù)

使用道具 舉報(bào)

板凳
ID:298008 發(fā)表于 2019-12-21 20:03 | 只看該作者
謝謝樓主分享!!
回復(fù)

使用道具 舉報(bào)

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

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

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

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