《單片機原理與應用》實驗報告 姓名:xxx 學號:xxxxxxxx 實驗時間:5月28日~6月11日 2.2 匯編程序實驗2 一、實驗要求 片內RAM 30H開始的32個單元中分布著隨機的有符號8位二進制數,按從小到大的順序進行排序,排序后的數據仍然保存到30H開始的32個單元中(低地址存放小數據) 步驟: - 編寫匯編語言并加上相應注釋(注意擴展名為“*.asm”),將其保存。
- 運行Keil u Vision2,建立工程“simlab2.uV2”,CPU為AT89C51,不用包含啟動文件“STARTUP.A51”。
- 將編寫好的程序加入工程“simlab2.uV2”,并設置工程“simlab2.uV2”的屬性,將其晶振頻率設置為12MHz,選擇輸出的可執行文件,仿真方式為“Use Simulator”。
- 構造(Build)工程“simlab2.uV2”。如果輸入有誤,則進行修改,直至構造正確,生成可執行程序“simlab2.hex”為止。
- 運行程序,并用存儲器觀察窗口觀察內部RAM30H~4FH單元排序前后的數值。
結果: 
由上圖可知,32個數從30H開始由小到大排列 三、實驗源程序
- ORG 0000H
- AJMP MAIN
- ORG 0030H
- MAIN:
- MOV R0,#20H ;R0用于存放數據時計數
- MOV R1,#30H ;R1指向30H地址單元
- MOV DPTR,#TABLE ;使DPTR指向表首
- MOV R2,#00H
- MOV A,R2 ;給偏移地址賦初值,為0
- LOOP1:
- MOVC A,@A+DPTR ;取出表中的數據
- MOV @R1,A ;將表中的數據存入30H單元
- INC R1 ;R1自增1,指向下一個單元
- INC R2
- MOV A,R2 ;R2自增1,從而使偏移量增1
- DJNZ R0,LOOP1 ;R0=R0-1,如果R0不為0,則再次從LOOP1處執行,將表中數據存入對應的單元;如果R0=0,則表示表中數據已經全部存入30H~4FH單元中
- MOV R7,#1FH ;將遍歷次數31送入R7中
- LOOP2:
- MOV A,R7
- MOV R6,A ;將比較次數寄存器R6的值設定為R7的值
- ADD A,#30H
- MOV R0,A ;將最大值為位置寄存器R0的值設定為#30H+R7
- MOV R1,#30H ;將R1指向30H單元
- MOV B,@R1 ;取R1指向的單元的值到最大值寄存器B
- LOOP3:
- CLR C ;將C清零
- INC R1 ;R1自增1
- MOV A,@R1 ;將R1所指向單元中的值賦給A
- MOV R5,A ;將A中的值賦給R5,作為備份
- SUBB A,B ;A=A-B
- JC LOOP4 ;如果存在借位,即A<B,則跳轉至LOOP4
- MOV A,R1
- MOV R0,A ;如果A>B,將R1中的值賦給R0,使其始終保持最大值
- MOV A,R5 ;恢復A的值
- MOV B,A ;使最大值寄存器B的值為A中的值
- LOOP4:
- DJNZ R6,LOOP3 ;R6=R6-1,如果R6為0,表示這一輪的比較已經完成,否則再次執行LOOP3,繼續進行比較
- MOV A,B ;如果這一輪比較完成,則將最大值寄存器B的值賦給A
- XCH A,@R1 ;交換A和R1中的值,即將最大值存放到這一輪比較的最后的位置
- MOV @R0,A ;將A中的值賦給R0所指的單元,以上兩步完成將最大值存到最后一位,最后一位的值存到原本最大值所在的位置
- DJNZ R7,LOOP2 ;判斷外循環是否完成,若未完成跳轉至LOOP2,繼續執行外循環
- TABLE:
- DB 1,3,9,2,17,4,11,6
- DB 5,20,100,64,21,14,79,35
- DB 92,7,91,23,65,16,13,18
- DB 18,73,65,101,27,19,62,69
- SJMP $
- END
復制代碼
2.3 C語言程序實驗 一、實驗要求 片內RAM 30H開始的32個單元中分布著隨機的有符號8位二進制數,按從小到大的順序進行排序,排序后的數據仍然保存到30H開始的32個單元中(低地址存放小數據) 步驟: (1)編寫C語言源程序,并加上相應注釋(注意擴展名為“*.c”),將其保存。 (2)運行Keil u Vision2,建立工程“simlab3.uV2”,CPU為AT89C51,包含啟動文件“STARTUP.A51”。 (3)將編寫好的程序加入工程“simlab3.uV2”,并設置工程“simlab3.uV2”的屬性,將其晶振頻率設置為12MHz,選擇輸出的可執行文件,仿真方式為“Use Simulator”。 (4)構造(Build)工程“simlab3.uV2”。如果輸入有誤,則進行修改,直至構造正確,生成可執行程序“simlab3.hex”為止。 (5)運行程序,并用存儲器觀察窗口觀察內部RAM30H~4FH單元排序前后的數值。 結果: 
由上圖可知,32個數從30H到4FH由小到大排列 三、實驗源程序
- <font color="rgb(0, 0, 0)"><font face="Calibri"><font style="font-size: 14pt">#include <reg51.h>
- #include<stdio.h>
- #define uchar unsigned char
- #define uint unsigned int //頭文件
- uchar data a[32] _at_ 0x30; //設定數組a的起始地址為30H
- uint i _at_ 0x55;
- uint j _at_ 0x56;
- uint t _at_ 0x57; //以上三句表示將變量i,j,t分別放入地址55H,56H,57H
- void main()
- {
- char i,j,t; //定義變量i,j,t
- char b[]={1,3,9,2,17,4,11,6,5,20,100,64,21,14,79,35,92,7,91,23,65,16,13,18,18,73,65,101,27,19,62,69}; //定義數組,并對其賦值
- for(i=0;i<32;i++)
- {a[i]=b[i]; //將數組b中的值賦給數組a,即將要比較的32個數,存放到相應的地址
- }
- for(i=0;i<32;i++)
- {for(j=0;j<31-i;j++)
- {if(a[j]>a[j+1])
- {t=a[j];
- a[j]=a[j+1];
- a[j+1]=t; //先讓a[0]與a[1]比較,然后將較大的數存到a[1]中,接著讓a[1]與a[2]比較,較大的存到a[2]中,以此類推,比較結束,將32個數中最大的存到地址最高位,完成第一輪的比較,相似地,比較其余31個數,將其中最大的放到地址的第二高位
- }
- }
- }
- while(1);
- }</font></font></font>
復制代碼
3.1基本并行I/O口實驗 當按鍵SW1被按下后,D1~D8輪流點亮,點亮的時間為100ms;當按鍵停下后,停止輪換;再次按下后繼續輪換 步驟: - 在Proteus環境下建立如圖的原理圖,并將其保存為“basicIO_self.DSN”文件。
- 編寫控制源程序,將其保存為“basicIO_self.asm”。
- 將源程序添加到U1中,并構造該程序。
- 執行仿真過程,觀察的D1~D8的指示,查看程序功能是否正確。
- 修改延時程序延時參數,重新執行該程序。
結果: 
三、實驗源程序
- ORG 0000H
- SJMP MAIN
- ORG 0030H
- MAIN:
- MOV SP,#60H ;使SP指向地址單元60H
- MOV P2,#0FFH ;將P2口所有位設置為1,使P2口所接發光二極管全部熄滅
- MOV 20H,#0FEH ;使顯示緩沖單元的值為11111110
- LOOP1:
- MOV A,P1 ;將P1的值存到寄存器A中
- RRC A ;A的帶進位循環右移,即將A的最低位放入進位標志位中,標志位中的值放入A的最高位,實現查看P1.0位的功能
- JC LOOP1 ;如果進位不為0,則跳轉至LOOP1
- MOV P2,20H ;如果進位不為0,則將顯示緩沖單元20H中的值送給P2
- LOOP2:MOV R7,#200 ;令R7中的值為200
- LOOP3:MOV R6,#250 ;令R6中的值為250
- DJNZ R6,[ DISCUZ_CODE_9 ]nbsp; ;R6=R6-1,如果R6不為0,則執行$(原地踏步),如果為0,則順序執行,以上兩步維持時間為250*2*1us+1us
- DJNZ R7,LOOP3 ;R7=R7-1,如果R7不為0,則執行LOOP3,否則順序執行,以上四步一共維持時間為(1us+250*2*1us+1us+2us)*200,約為100ms
- MOV A,20H ;將顯示緩沖單元中的值存到寄存器A中
- RL A ;將A進行循環左移,即實現顯示緩沖單元的值循環左移1位,
- MOV 20H,A ;將A中的值再送回至顯示緩沖單元中
- JMP LOOP1 ;無條件跳轉至LOOP1
- END
復制代碼
3.2 擴展并行I/O口實驗 一、實驗要求 仿真實現交通信號燈控制功能。控制順序如下:南北綠燈亮,同時東西紅燈亮10s;南北黃燈亮,同時東西紅燈亮2s;南北紅燈亮,同時東西綠燈亮10s;東西黃燈亮,同時南北紅燈亮2s;重復上述四種狀態。 步驟: (1)在Proteus環境下建立如圖的原理圖,并將其保存為“expandIO_self.DSN”文件。 (2)編寫控制源程序,將其保存為“expandIO_self.asm”。 (3)將源程序添加到U1中,并構造該程序。 (4)執行仿真過程,觀察各個方向上的交通信號燈指示,查看程序功能是否正確。 結果: 
三、實驗源程序
- <font style="font-size: 14pt">ORG 0000H
- SJMP MAIN
- ORG 0030H
- MAIN:
- MOV SP,#60H ;讓SP指向地址單元60H
- MOV P0,#0FFH;令P0為11111111
- MOV P3,#40H;令P3為01000000
- MOV P2,#03H;令P2為00000011,以上三步使兩個74LS373的輸出端口所有位均為1,使所有發光二極管全部熄滅
- STAT1:
- MOV P3,#00H ; 令P3為00000000
- MOV P2,#02H ; 令P2為0000010,使U4工作,U5不工作
- MOV P0,#0F3H; 令P0為11110011 ,使東西紅燈亮
- MOV P2,#01H ; 令P1為00000001 ,使U4不工作,U5工作
- MOV P0,#0CH ; 令P0為00001100 ,使南北綠燈亮
- MOV P2,#03H ; 令P2為00000011
- MOV P3,#40H ; 令P3為01000000 ,以上兩步實現所有的發光二極管均熄滅 的功能 ,變為初始狀態
- MOV R4,#10 ; 令R4的值為10
- DELAY1:MOV R7,#10;令R7的值為10
- LOOP11:MOV R6,#200;令R6的值為200
- LOOP12:MOV R5,#250;令R5的值為250
- DJNZ R5,$;R5=R5-1,如果R5不為0,則執行$即原地踏步,否則執行下面的程序
- DJNZ R6,LOOP12;R6=R6-1,如果R6不為0,則執行LOOP12,否則執行下面的程序
- DJNZ R7,LOOP11;R7=R7-1,如果R7不為0,則執行LOOP11,否則執行下面的程序
- DJNZ R4,DELAY1;R4=R4-1,如果R4不為0,則執行DELAY1,否則執行下面的程序,以上八步完成延時,(((1+250*2+2)*200+2)*10+2)*10,大約為10s
- STAT2:
- MOV P3,#00H; 令P3為00000000
- MOV P2,#02H;令P2為0000010,使U4工作,U5不工作
- MOV P0,#0C3H;令P0為11000011 ,使東西紅燈亮 ,南北黃燈亮
- MOV P2,#01H;令P1為00000001 ,使U4不工作,U5工作
- MOV P0,#0FH;令P0為00001111 ,使東西南北綠燈滅
- MOV P2,#03H;令P2為00000011
- MOV P3,#40H;令P3為01000000 ,以上兩步實現所有的發光二極管均熄滅 的功能 ,變為初始狀態
- MOV R4,#2; 令R4的值為2
- DELAY2:MOV R7,#10;令R7的值為10
- LOOP21:MOV R6,#200;令R6的值為200
- LOOP22:MOV R5,#250;令R5的值為250
- DJNZ R5,$;R5=R5-1,如果R5不為0,則執行$即原地踏步,否則執行下面的程序
- DJNZ R6,LOOP22;R6=R6-1,如果R6不為0,則執行LOOP22,否則執行下面的程序
- DJNZ R7,LOOP21;R7=R7-1,如果R7不為0,則執行LOOP21,否則執行下面的程序
- DJNZ R4,DELAY2;R4=R4-1,如果R4不為0,則執行DELAY2,否則執行下面的程序,以上八步完成延時,(((1+250*2+2)*200+2)*10+2)*2,大約為2s
- STAT3:
- MOV P3,#00H;令P3為00000000
- MOV P2,#02H;令P2為0000010,使U4工作,U5不工作
- MOV P0,#0FCH;令P0為11111100 ,使南北紅燈亮
- MOV P2,#01H;令P1為00000001 ,使U4不工作,U5工作
- MOV P0,#03H;令P0為00000011 ,使東西綠燈亮
- MOV P2,#03H;令P2為00000011
- MOV P3,#40H;令P3為01000000 ,以上兩步實現所有的發光二極管均熄滅 的功能 ,變為初始狀態
- MOV R4,#10;令R4的值為10
- DELAY3:MOV R7,#10;令R7的值為10
- LOOP31:MOV R6,#200;令R6的值為200
- LOOP32:MOV R5,#250;令R5的值為250
- DJNZ R5,$;R5=R5-1,如果R5不為0,則執行$即原地踏步,否則執行下面的程序
- DJNZ R6,LOOP32;R6=R6-1,如果R6不為0,則執行LOOP32,否則執行下面的程序
- DJNZ R7,LOOP31;R7=R7-1,如果R7不為0,則執行LOOP31,否則執行下面的程序
- DJNZ R4,DELAY3;R4=R4-1,如果R4不為0,則執行DELAY3,否則執行下面的程序,以上八步完成延時,(((1+250*2+2)*200+2)*10+2)*10,大約為10s
- STAT4:
- MOV P3,#00H;令P3為00000000
- MOV P2,#02H;令P2為0000010,使U4工作,U5不工作
- MOV P0,#3CH;令P0為00111100 ,使東西黃燈亮,南北紅燈亮
- MOV P2,#01H;令P1為00000001 ,使U4不工作,U5工作
- MOV P0,#0FH;令P0為00001111 ,使東西綠燈滅
- MOV P2,#03H;令P2為00000011
- MOV P3,#40H;令P3為01000000 ,以上兩步實現所有的發光二極管均熄滅 的功能 ,變為初始狀態
- MOV R4,#2;令R4的值為2
- DELAY4:MOV R7,#10;令R7的值為10
- LOOP41:MOV R6,#200;令R6的值為200
- LOOP42:MOV R5,#250;令R5的值為250
- DJNZ R5,$;R5=R5-1,如果R5不為0,則執行$即原地踏步,否則執行下面的程序
- DJNZ R6,LOOP42;R6=R6-1,如果R6不為0,則執行LOOP42,否則執行下面的程序
- DJNZ R7,LOOP41;R7=R7-1,如果R7不為0,則執行LOOP41,否則執行下面的程序
- DJNZ R4,DELAY4;R4=R4-1,如果R4不為0,則執行DELAY4,否則執行下面的程序,以上八步完成延時,(((1+250*2+2)*200+2)*10+2)*2,大約為2s
- JMP STAT1;無條件跳轉至STAT1
- END</font>
復制代碼
3.3靜態LED顯示實驗 7SEG2為十位顯示數碼管,7SEG1為個位顯示數碼管,KEY_LOAD為“倒計時初值”按鈕,KEY_START為“倒計時啟動”按鈕。要實現的功能:當KEY_LOAD按鈕被按下時,加載倒計時初值(如10s);當按下KEY_START按鈕時,開始倒計時,每過1s,計時減1,直到減到“00”為止。減到“00”時,時P3.0引腳上的LED按10Hz頻率閃爍,直到再次按下KEY_LOAD按鈕,才重新加載初值,并熄滅LED。再次按下KEY_START按鈕又一次開始倒計時,如此反復。 步驟: (1)在Proteus環境下建立如圖的原理圖,并將其保存為“staticLED_self.DSN”文件。 (2)編寫控制源程序,將其保存為“staticLED_self.asm”。 (3)將源程序添加到U1中,并構造該程序。 (4)執行仿真過程,觀察秒表程序功能是否正確。 結果: (1)按下KEY_LOAD加載倒計時初值。 

三、實驗源程序
- <font style="font-size: 14pt">ORG 0000H
- AJMP MAIN
- ORG 0030H
- MAIN:
- MOV SP,#60H; 堆棧初始化
- MOV R0,#0 ;將0賦給R0,即表示初始值的個位
- MOV R1,#1; 將1賦給R1,即表示初始值的十位
- SETB P3.0; 關掉 LED1
- CLR F0 ;對標志位清零
- LOOP:
- JB P1.1,LOOP2; 如果 P1.1=1, 跳轉到 LOOP2 ,
- LOOP1:
- CLR F0 ;對標志位清零
- MOV 30H,R0 ;將個位放在地址單元30H中
- MOV 31H,R1; 將十位放在地址單元31H中,以上兩步實現裝載初值的功能
- SETB P3.0; 關閉 LED1
- LCALL DISPLAY; 顯示
- LOOP2:
- JB P1.0,LOOP; 如果 P1.0=1 ,跳回 LOOP ,否則繼續執行
- LOOP3:
- LCALL DISPLAY; 刷新顯示,顯示就是將數字呈現在數碼管上
- LCALL DELAY1S; 延時 1s
- LCALL ADJUST2; 調整計時器寄存器
- JB F0,LOOP4 ;計時器寄存器如果為1,則跳轉至LOOP4
- LJMP LOOP3 ;否則長跳轉至LOOP3
- LOOP4: ;LED閃爍子程序
- CLR P3.0 ;將P3.0清零,即LED 亮
- LCALL DELAY100MS;調用子程序DELAY100MS
- SETB P3.0; 關掉LED
- LCALL DELAY100MS;調用子程序DELAY100MS
- JB P1.1,LOOP4;如果P1.1為1,則跳轉至LOOP4
- LJMP LOOP1
- DISPLAY: ; 顯示子程序
- MOV A,30H ;將個位送至A中
- MOV DPTR,#TABLE
- MOVC A,@A+DPTR ;通過查表獲得對應的數據
- MOV DPTR,#0FE00H ;將其數據送到U2的鎖存地址中
- MOVX @DPTR,A ;把A的內容送到DPTR所指的外部地址
- MOV A,31H
- MOV DPTR,#TABLE
- MOVC A,@A+DPTR
- MOV DPTR,#0FD00H
- MOVX @DPTR,A ;同上,將對應數據送到U3的鎖存地址中
- RET
- ADJUST2:
- DEC 30H ;將地址單元30H中的值自減1
- MOV A,30H ;將地址單元30H中的值送入寄存器A中
- CJNE A,#-1,GOTORET ;如果A中的值不為-1,則跳轉至GOTORET,即返回主程序
- MOV 30H,#9 ;將9送入地址單元30H中
- DEC 31H ;將地址單元31H中的值自減1
- MOV A,31H ;將地址單元31H中的值送入寄存器A中
- CJNE A,#-1,GOTORET ;如果A中的值不為-1,則跳轉至GOTORET,即返回主程序
- SETB F0; 將用戶標志位置1
- RET
- GOTORET:
- RET
- DELAY1S:MOV R7,#10
- DL2:MOV R6,#200
- DL1:MOV R5,#250
- DJNZ R5,$
- DJNZ R6,DL1
- DJNZ R7,DL2 ;實現延時,延時時間為((1+2*250+2)*200+2)*10,大約為1s
- RET
- DELAY100MS:MOV R7,#200
- DL:MOV R6,#250
- DJNZ R6,$
- DJNZ R7,DL;實現延時,延時時間為((1+250*2)+2)*200,大約為0.1s,即使P3.0引腳上的LED按10Hz頻率閃爍
- RET
- TABLE: DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H
- END</font>
復制代碼
3.4矩陣鍵盤掃描實驗 D1~D8八個發光二極管構成彩色旋燈,D9~D13為擋位指示燈,1擋旋轉速度最慢(周期為1s,D13亮),2擋較快(周期為0.8s,D12亮),3擋更快(周期為0.6s,D11亮),4擋較快(周期為0.4s,D10亮),5擋較快(周期為0.2s,D9亮)。按鍵KEY_0~KEY1用于設定旋轉方向為順時針或者逆時針旋轉,KEY_2~KEY_3用于加快或者減慢旋轉速度。 步驟: (1)在Proteus環境下建立如圖的原理圖,并將其保存為“keyscan_self.DSN”文件。 (2)編寫控制源程序,將其保存為“keyscan_self.asm”。 (3)將源程序添加到U1中,并構造該程序。 (4)執行仿真過程,觀察程序功能是否正確。 結果: 
按下按鍵KEY_0時,D1~D8順時針旋轉,按下按鍵KEY1時,D1~D8逆時針旋轉,按下按鍵KEY_2或KEY_3,分別是加速與減速。 三、實驗源程序
- <font style="font-size: 14pt">ORG 0000H
- AJMP MAIN
- ORG 0030H
- MAIN:
- MOV SP,#60H;使SP指向地址單元60H
- MOV P0,#0FFH;使P0為11111111,即所有的彩色旋轉燈都不亮
- MOV P1,#0FFH;使P1為11111111,即所有的擋位燈都不亮
- MOV R7,#10;令R7的值為10
- MOV R4,#0EFH;令R4的值為0EFH
- LCALL LOOP;調用子程序SCAN
- JMP MAIN;無條件跳轉至MAIN
- BUTTON0:
- MOV 30H,#0H;將0放入地址單元30H
- MOV P1,#0FEH;令P1為11111110,即讓D1亮
- JMP ZHUAN1;無條件跳轉至ZHUAN1,來實現彩色旋轉燈的順時針旋轉
- BUTTON1:
- MOV 30H,#1H;將1放入地址單元30H
- MOV P1,#0FEH;令P1為11111110,即讓D1亮
- JMP ZHUAN2;無條件跳轉至ZHUAN2,來實現彩色旋轉燈的逆時針旋轉
- BUTTON2:
- DEC R7;R7自減1
- DEC R7;R7自減1
- MOV A,R4;將R4的值存到寄存器A中
- RR A;將A中的值進行不帶進位的循環右移
- MOV R4,A;將A中的值送回R4中
- MOV A,30H;將地址單元30H中的值賦給A
- JZ ZHUAN1;如果ZF=1(即A中的值為0),則跳轉至ZHUAN1
- JMP ZHUAN2;否則跳轉至ZHUAN2
- BUTTON3:
- INC R7;R7自增1
- INC R7;R7自增1
- MOV A,R4;將R4中的值存到A中
- RL A;將A中的值進行不帶進位的循環左移
- MOV R4,A;將A中的值送回至R4中
- MOV A,30H;將地址單元30H中的值存到A中
- JZ ZHUAN1;如果ZF=1(即A中的值為0),則跳轉至ZHUAN1
- JMP ZHUAN2;否則跳轉至ZHUAN1
- ZHUAN1:
- MOV P0,R4;將R4中的值送到P0,用來變換擋位指示燈
- LCALL DLS;長調用DLS
- MOV A,P1;將P1中的值存到A中
- RL A;將A進行不帶進位的循環左移
- MOV P1,A;將A中的值送回至P1中
- LCALL SCAN;長調用子程序SCAN
- JMP ZHUAN1;無條件跳轉至ZHUAN1
- ZHUAN2:
- MOV P0,R4;將R4中的值送到P0,用來變換擋位指示燈
- LCALL DLS;長調用DLS
- MOV A,P1;將P1中的值存到A中
- RR A;將A進行不帶進位的循環左移
- MOV P1,A;將A中的值送回至P1中
- LCALL LOOP;長調用子程序SCAN
- JMP ZHUAN2;無條件跳轉至ZHUAN2
- DLS:
- MOV A,R7;將R7中的值存到寄存器A中
- DL2:MOV R6,#200;令R6的值為200
- DL1:MOV R5,#250;令R5的值為250
- DL0:
- DJNZ R5,DL0;R5=R5-1,如果R5不為0,則跳轉至DL0,否則順序執行
- DJNZ R6,DL1;R6=R6-1,如果R6不為0,則跳轉至DL1,否則順序執行
- DJNZ R7,DL2;R7=R7-1,如果R7不為0,則跳轉至DL2,否則順序執行,實現延時,延時時間為((1+250*2+2)*200+2)*R7
- MOV R7,A;將A中的值送回至R7
- RET;
- LOOP:
- MOV P3,#030H;令P3為00110000,使開關閉合時能實現對應的功能
- JNB P3.4,NEXT1;如果P3.4為低電平(KEY0或KEY2閉合),則跳轉至NEXT1,否則順序執行
- JNB P3.5,NEXT2;如果P3.5為低電平(KEY1或KEY3閉合),則跳轉至NEXT2,否則順序執行
- JMP TORET;無條件跳轉至TORET,即返回源程序
- NEXT1:
- MOV P3,#3H;令P3為00000011
- JNB P3.0,BUTTON0;如果P3.0為低電平(KEY0閉合),則跳轉至BUTTON0,否則順序執行
- JNB P3.1,BUTTON2;如果P3.1為低電平(KEY2閉合),則跳轉至BUTTON2,否則順序執行
- JMP TORET;無條件跳轉至TORET,即返回源程序
- NEXT2:
- MOV P3,#3H;令P3為00000011
- JNB P3.0,BUTTON1;如果P3.0為低電平(KEY1閉合),則跳轉至BUTTON1,否則順序執行
- JNB P3.1,BUTTON3;如果P3.1為低電平(KEY3閉合),則跳轉至BUTTON3,否則順序執行
- TORET:
- RET
- END</font>
復制代碼
3.7 LCD 1602顯示實驗 一、實驗要求 利用LCD 1602和16個按鍵實現簡單的十進制的加減乘除四則混合運算。其中按鍵KEY_0~KEY_9分別代表數字0~9;按鍵KEY_10~KEY_13分別代表運算符“+”“-”“*”“/”;按鍵KEY15代表“=”;按鍵KEY_14代表清楚命令,以便進行下一次的輸入和計算。不管什么時候按下“清除”按鍵,計算過程均將停止,兩個輸入變量都將清0,屏幕將清屏。LCD 1602的第一行用于顯示所輸入的兩個計算數以及計算符,第二行用于顯示計算結果。結果允許為負數,但輸入的兩個輸入數都必須是雙字節正整數范圍內的數,即0~32767。除數必須保證不為0,否則將報錯。在有余數除法中,必須能同時顯示商與余數。 步驟: (1)在Proteus環境下建立如圖的原理圖,并將其保存為“LCD1602_self.DSN”文件。 (2)編寫控制源程序,將其保存為“LCD1602_self.c”。 (3)運行Keil u Vision2,建立工程“LCD1602_self.uV2”,CPU為AT89C51,包含啟動文件“STARTUP.A51”。 (4)將編寫好的程序加入工程“LCD1602_self.uV2”,并設置工程“LCD1602.uV2”的屬性,將其晶振頻率設置為12MHz,選擇輸出的可執行文件,仿真方式為“選擇硬仿真”,并選擇其中的“PROTEUS VSM MONITOR 51 DEIVER”仿真器。 (5)構造(Build)工程“LCD1602_self.uV2”。如果輸入有誤,則進行修改,直至構造正確,生成可執行程序“LCD1602_self.hex”為止。 - 為AT89C51設置可執行程序“LCD1602_self.hex”。
- 運行程序,單擊按鍵輸入數據與運算符,計算,觀察計算結果,并驗證其是否正確。
- 輸入過程中,按“清除”按鍵觀察結果,重新輸入數據計算并驗證。
結果: (1)加法 
(2)減法 
(3)乘法 
(4)除法 
(5)報錯 
三、實驗源程序
- <font style="font-size: 14pt">#include<reg51.h>
- #define uint unsigned int
- #define uchar unsigned char
-
- sbit lcden=P1^5;//使能信號
- sbit rs=P1^7;//數據命令選擇
- sbit rw=P1^6;//讀寫選擇
- sbit busy=P2^7;
-
- char i,j,temp,num;
- long a,b,c,d;
- float a_c,b_c;
- uchar flag,fuhao;//flag
-
- uchar code table[]={
- 0,1,2,3,
- 4,5,6,7,
- 8,9,0,0,
- 0,0,0,0};
- uchar code table1[]={
- 0,1,2,3,
- 4,5,6,7,
- 8,9,0x2b-0x30,0x2d-0x30,
- 0x2a-0x30,0x2f-0x30,0x01-0x30,0x3d-0x30};//按鍵對應的符號
- uchar code table2[]="!rorrE";
-
- void delay(uchar z) // 延遲函數
- {
- uchar i,t;
- for(i=0;i<z;i++)
- for(t=0;t<120;t++);
- }
-
- void check() // 判斷忙或空閑
- {
- do
- {
- P2=0xFF;
- rs=0; //指令
- rw=1; //讀
- lcden=0; //禁止讀寫n
- delay(1); //等待,液晶顯示器處理數據
- lcden=1; //允許讀寫
- }
- while(busy==1); //判斷是否為空閑,1為忙,0為空閑
- }
-
- void write_com(uchar com) // 寫指令函數
- {
- P2=com; //com指令付給P0口
- rs=0;
- rw=0;
- lcden=0;
- check();
- lcden=1;
- }
-
- void write_date(uchar date) // 寫數據函數
- {
- P2=date;
- rs=1;
- rw=0;
- lcden=0;
- check();
- lcden=1;
- }
-
- void init() //初始化
- {
- num=-1;
- lcden=1; //使能信號為高電平
- write_com(0x38); //8位,2行
- write_com(0x0c); //顯示開,光標關,不閃爍*/
- write_com(0x06); //增量方式不移位
- write_com(0x80); //檢測忙信號
- write_com(0x01); //清屏指令
- i=0;
- j=0;
- a=0; //第一個參與運算的數
- b=0; //第二個參與運算的數
- c=0;
- d=0;
- flag=0; //flag表示是否有符號鍵按下,
- fuhao=0; // fuhao表征按下的是哪個符號
- }
-
- void keyscan() // 鍵盤掃描程序
- {
- P3=0xfe;
- if(P3!=0xfe)
- {
- delay(20);
- if(P3!=0xfe)
- {
- temp=P3&0xf0;
- switch(temp)
- {
- case 0xe0:num=0;
- break;
- case 0xd0:num=1;
- break;
- case 0xb0:num=2;
- break;
- case 0x70:num=3;
- break;
- }
- }
- while(P3!=0xfe);
- if(flag==0)//沒有按過符號鍵
- {
- a=a*10+table[num];
- }
- else//如果按過符號鍵
- {
- b=b*10+table[num];
- }
- i=table1[num];
- write_date(0x30+i);//寫入按鍵對應的 符號
- }
-
- P3=0xfd;
- if(P3!=0xfd)
- {
- delay(5);
- if(P3!=0xfd)
- {
- temp=P3&0xf0;
- switch(temp)
- {
- case 0xe0:num=4;
- break;
-
- case 0xd0:num=5;
- break;
-
- case 0xb0:num=6;
- break;
-
- case 0x70:num=7;
- break;
- }
- }
- while(P3!=0xfd);
- if(flag==0)//沒有按過符號鍵
- {
- a=a*10+table[num];
- }
- else//如果按過符號鍵
- {
- b=b*10+table[num];
- }
- i=table1[num];
- write_date(0x30+i);
- }
-
- P3=0xfb;
- if(P3!=0xfb)
- {
- delay(5);
- if(P3!=0xfb)
- {
- temp=P3&0xf0;
- switch(temp)
- {
- case 0xe0:num=8;
- break;
-
- case 0xd0:num=9;
- break;
-
- case 0xb0:num=10;
- break;
-
- case 0x70:num=11;
- break;
- }
- }
- while(P3!=0xfb);
- if(num==8||num==9)//如果按下的是'8','9'
- {
- if(flag==0)//沒有按過符號鍵
- {
- a=a*10+table[num];
- }
- else//如果按過符號鍵
- {
- b=b*10+table[num];
- }
- }
- else if(num==10)//如果按下的是'+'
- {
- flag=1;
- fuhao=1;//1表示加號已按
- }
- else if(num==11)//如果按下的是'-'
- {
- flag=1;
- fuhao=2;//2表示減號已按6
- }
- i=table1[num];
- write_date(0x30+i);
- }
-
- P3=0xf7;
- if(P3!=0xf7)
- {
- delay(5);
- if(P3!=0xf7)
- {
- temp=P3&0xf0;
- switch(temp)
- {
- case 0xe0:num=12;
- break;
-
- case 0xd0:num=13;
- break;
-
- case 0xb0:num=14;
- break;
-
- case 0x70:num=15;
- break;
- }
- }
- while(P3!=0xf7);
- switch(num)
- {
- case 12:{write_date(0x30+table1[num]); flag=1;fuhao=3;}
- break;
- case 13:{write_date(0x30+table1[num]); flag=1;fuhao=4;}
- break;
- case 14:{write_com(0x01);i=0;j=0;a=0;b=0;c=0;d=0;flag=0;fuhao=0;}//按下的是"清零"
- break;
- case 15:{
- j=1;
-
- if(fuhao==1){write_com(0x80+0x4f);//按下等于鍵,光標前進至第二行最后一個顯示處
- write_com(0x04); //寫入數據后地址加1 ,從右向左寫入數據
- c=a+b;
- while(c!=0)
- {
- write_date(0x30+c%10);
- c=c/10;
- }
- write_date(0x3d); //再寫"="
- a=0;b=0;flag=0;fuhao=0;
- }
-
- else if(fuhao==2){write_com(0x80+0x4f);//光標前進至第二行最后一個顯示處
- write_com(0x04); //設置從后住前寫數據,每寫完一個數據,光標后退一格)
- if(a-b>0)
- c=a-b;
- else
- c=b-a;
- while(c!=0)
- {
- write_date(0x30+c%10);
- c=c/10;
- }
- if(a-b<0)
- write_date(0x2d); //寫’-‘
- write_date(0x3d); //再寫"="
- a=0;b=0;flag=0;fuhao=0;
- }
-
- else if(fuhao==3)
- {
- write_com(0x80+0x4f);
- write_com(0x04);
- c=a*b;
- while(c!=0)
- {
- write_date(0x30+c%10);
- c=c/10;
- }
- write_date(0x3d);
- a=0;b=0;flag=0;fuhao=0;
- }
-
- else if(fuhao==4)
- {
- write_com(0x80+0x4f);
- write_com(0x04);
- if(b==0)
- {
- i=0;
- while(table2[i]!='\0')
- {
- write_date(table2[i]);
- i++;
- }//若除數為0,輸出Error!
- a=0;b=0;flag=0;fuhao=0;
- }
- else if((a%b==0)&&(b!=0))
- {
- c=a/b;
- while(c!=0)
- {
- write_date(0x30+c%10);
- c=c/10;
- }
- if(a/b<=0)
- write_date(0x30);
- write_date(0x3d);
- a=0;b=0;flag=0;fuhao=0;
- }
- else if((a%b!=0)&&(b!=0))
- {
- d=a%b;
- while(d!=0)
- {
- write_date(0x30+d%10);
- d=d/10;
- }//若不能整除,輸出余數
- write_date(0x2e);
- write_date(0x2e);
- write_date(0x2e);//輸出“...“
- c=a/b;//輸出整除結果
- while(c!=0)
- {
- write_date(0x30+c%10);
- c=c/10;
- }
- if(a/b<=0)
- write_date(0x30);
- write_date(0x3d);
- a=0;b=0;flag=0;fuhao=0;
- }
- }
- }
- break;
- }
- }
- }
-
- main()
- {
- init();//初始化
- while(1)
- {
- keyscan();//鍵盤掃描
- }
- }</font>
復制代碼
3.8 ADC0808/9信號采集實驗 一、實驗要求 利用LCD1602和AD0808實現簡單的交流信號過零檢測與頻率分析。要求信號幅度變化時,比影響檢測結果。頻率檢測的結果通過LCD1602的第1行顯示出來,信號過零時,能夠通過P2.6輸出一個脈沖寬度為5us的脈沖信號。電位器RV1用于改變交流信號的幅值。交流信號通過單擊窗口左側繪圖工具窗口中的“虛擬信號發生器”按鈕,然后在器件窗口中選擇正弦信號(SINE)實現。 二、實驗過程及結果記錄 步驟: (1)在Proteus環境下建立如圖的原理圖,并將其保存為“ADC0808_self.DSN”文件。 (2)編寫控制源程序,將其保存為“ADC0808_self.c”。 (3)運行Keil u Vision2,建立工程“ADC0808_self.uV2”,CPU為AT89C51,包含啟動文件“STARTUP.A51”。 (4)將編寫好的程序加入工程“ADC0808_self.uV2”,并設置工程“ADC0808.uV2”的屬性,將其晶振頻率設置為12MHz,選擇輸出的可執行文件,仿真方式為“選擇硬仿真”,并選擇其中的“PROTEUS VSM MONITOR 51 DEIVER”仿真器。 (5)構造(Build)工程“ADC0808_self.uV2”。如果輸入有誤,則進行修改,直至構造正確,生成可執行程序“ADC0808_self.hex”為止。 (6)為AT89C51設置可執行程序“ADC0808_self.hex”。 (7)運行程序,觀察計算結果,并驗證其是否正確。 (8)改變RV1的抽頭位置,從而改變輸入信號的幅值,觀察計算結果是否正確。 (9)更改信號發射器的頻率,再次驗證其功能是否正確。 結果: 
三、實驗源程序
4.1 按鍵聲光報警實驗 一、實驗要求 利用外部硬件中斷,按下一次按鍵產生一次外部中斷,在中斷服務程序中計數器加1,同時通過發光二極管的閃爍和蜂鳴器響的次數,指示計數器的當前值。當計數到10時,再次按鍵將重新從1開始計。 二、實驗過程及結果記錄 步驟: - 關掉實驗箱電源,將MCU板插接在母版上,將硬件連接好
- 在仿真器斷電情況下將仿真器的仿真頭插在MCU板的CPU插座上。將仿真器與PC機的通信口連接好,打開實驗箱及仿真器的電源。
(3)運行Keil u Vision2,建立工程“int0_c.uV2”,CPU為AT89C51,包含啟動文件“STARTUP.A51”。 (4)將編寫好的程序加入工程“int0_c.uV2”,并設置工程“int0_c.uV2”的屬性,將其晶振頻率設置為11.0592MHz,選擇輸出的可執行文件,仿真方式為“選擇硬仿真”,并選擇其中的“PROTEUS VSM MONITOR 51 DEIVER”仿真器。 (5)構造(Build)工程“int0_c.uV2”。如果輸入有誤,則進行修改,直至構造正確。 (6)運行程序,按下MCU板上的KEY0按鍵,觀察每次按鍵按下時主板上的發光二極管的閃爍和蜂鳴器響的次數,是否符合程序要求,分析出錯原因,繼續執行(4)(5),直至結果正確。 結果: 老師實驗室驗證 三、實驗源程序
- <font style="font-size: 14pt">#include<reg52.h>
- #define uint unsigned int
- #define uchar unsigned char
- sbit bell=P3^1; // 用 p3.1 口控制 bell
- sbit led=P3^0; // 用 P3^0 來控制 led
- sbit key0=P3^2; // 報警的鍵
- uint count; // 定義一個無符號整形數 ,
- 用來計數
- /******************************************************************/
- void delay(uint count) // 延時 1ms
- {
- uint x,y;
- for(x=count;x>0;x--)
- for(y=110;y>0;y--);
- }
- /******************************************************************/
- void show(uint count) // 使鈴鐺響,使燈亮的
- 函數
- { uint i;
- for(i=0;i<=count;i++) // 函數循環 i 次
- led=0;bell=0; // 燈亮,鈴響
- delay(500); // 延時 0.5s
- led=1;bell=1; // 燈滅,鈴停
- delay(500); // 延時 500ms
- }
- }
- /***********************************************************/
- Void s_timer0() interrupt 0 using 0 // 中斷 0
- {
- EA=0; // 屏蔽其他中斷請求
- show(count); // 調用子程序
- count++;
- delay(50);
- if(count>=10) // 若 count 為十則結
- 束
- count=0;
- EA=1; // 開放中斷
- }
- /************************** 主程序 **********************************/
- void main()
- { EA=1; // 開放中斷
- EX0=1; // 允許外部中斷 0 中斷
- IT0=0; // 外部中斷 0 為電平觸發方式
- while(1); // 循環執行,等待循環
- }</font>
復制代碼
4.5 8255并行I/O擴展及交通信號燈控制實驗 一、實驗要求 利用8255實現可編程的并行I/O擴展功能,并完成交通燈控制。實驗要求每個方向紅燈亮30s,然后綠燈亮25s,再閃爍綠燈5s。使用靜態數碼管顯示綠燈亮倒計時。 二、實驗過程及結果記錄 步驟: (1)關掉實驗箱電源,將MCU板、PIO板、KEY&LED板插接在母版上,將硬件連接好 (2)在仿真器斷電情況下將仿真器的仿真頭插在MCU板的CPU插座上。將仿真器與PC機的通信口連接好,打開實驗箱及仿真器的電源。 (3)運行Keil u Vision2,建立工程“PIO8255_traffic_c.uV2”,CPU為AT89C51,包含啟動文件“STARTUP.A51”。 (4)將編寫好的程序加入工程“PIO8255_traffic_c.uV2”,并設置工程“PIO8255_traffic_c.uV2”的屬性,將其晶振頻率設置為11.0592MHz,選擇輸出的可執行文件,仿真方式為“選擇硬仿真”,并選擇其中的“PROTEUS VSM MONITOR 51 DEIVER”仿真器。 (5)構造(Build)工程“PIO8255_traffic_c.uV2”。如果輸入有誤,則進行修改,直至構造正確。 (6)運行程序,觀察交通燈的狀態轉換以及倒計時器的顯示是否符合程序要求。若不符合,分析出錯原因,繼續執行(4)(5),直至結果正確。 結果: 老師實驗室驗證 三、實驗源程序
- <font style="font-size: 14pt">#include <reg52.h>
- #include <absacc.h>
- #define PA XBYTE[0x7FFC] //CS--A15
- #define COM XBYTE[0x7FFF]
- /***************************************************************************/
- void init_8255(void)
- {
- COM=0x80; // c = out, a = out,b = out
- }
- /***************************************************************************/
- void Uart_Init(void)
- {
- SCON = 0x10; //SCON:工作模式 0
- PCON = 0x00;
- TI = RI = 0;
- IE = 0x90;
- EA = 0;
- }
- ***********************************************************
- void Uart_Out(unsigned char DA T) //74LS164 的串轉并
- {
- TI = 0;
- SBUF = ~DAT; }
- ***************************************************************************
- void delay_ms(unsigned int ms) //延時 1ms 程序
- {
- int j;
- for(;ms!=0; ms--)
- for (j=0;j<125;j++)
- {
- }
- }
- ********************************************************
- int main(void)
- {
- signed char i;
- init_8255();
- Uart_Init();
- while(1)
- {
- PA = 0x96; //東西綠燈亮
- for(i = 25;i >= 0;i--) // 延時 25s
- {
- Uart_Out(~(((i/10)<<4) | (i%10)));
- delay_ms(1000);
- }
- for(i = 5;i > 0;i--) //5s
- {
- PA = 0xBE;
- delay_ms(500);
- PA = 0x96;
- delay_ms(500);
- }
- PA = 0x69; //南北綠燈亮
- for(i = 25;i >= 0;i--) // 延時 25s
- {
- Uart_Out(~(((i/10)<<4) | (i%10)));
- delay_ms(1000);
- }
- for(i = 5;i > 0;i--) //5s
- {
- PA = 0xEB;
- delay_ms(500);
- PA = 0x69;
- delay_ms(500);
- }
- }
- }</font>
復制代碼
4.7 7279鍵盤/動態LED顯示實驗 一、實驗要求 利用7279進行鍵盤掃描及動態LED數碼管的顯示控制。當按下某個鍵時,所按按鍵對應的字符顯示在最右端LED數碼管上;再次按下一個按鍵,則原來顯示的內容往左移1位,新按下的字符顯示在最右端;當6位LED均顯示已滿時,再次按下新的按鍵,則原來顯示的內容同樣都左移1位,最后1位顯示新按按鍵的字符。 二、實驗過程及結果記錄 步驟: (1)關掉實驗箱電源,將MCU板、KEY&LED板插接在母版上,將硬件連接好 (2)在仿真器斷電情況下將仿真器的仿真頭插在MCU板的CPU插座上。將仿真器與PC機的通信口連接好,打開實驗箱及仿真器的電源。 (3)運行Keil u Vision2,建立工程“HD7279_c.uV2”,CPU為AT89C51,包含啟動文件“STARTUP.A51”。 (4)將編寫好的程序加入工程“HD7279_c.uV2”,并設置工程“HD7279_c.uV2”的屬性,將其晶振頻率設置為11.0592MHz,選擇輸出的可執行文件,仿真方式為“選擇硬仿真”,并選擇其中的“PROTEUS VSM MONITOR 51 DEIVER”仿真器。 (5)構造(Build)工程“HD7279_c.uV2”。如果輸入有誤,則進行修改,直至構造正確。 (6)運行程序,觀察結果是否符合程序要求。若不符合,分析出錯原因,繼續執行(4)(5),直至結果正確。 結果: 老師實驗室驗證 三、實驗源程序
- <font style="font-size: 14pt">#include <reg51.h>
- //*** 函數定義 ***
- void long_delay(void); // 長延時
- void short_delay(void); // 短暫延時
- void delay10ms(unsigned char); // 延時 10MS
- void write7279(unsigned char, unsigned char); // 寫入到 HD7279
- unsigned char read7279(unsigned char); // 從 HD7279 讀出
- void send_byte(unsigned char); // 發送一個字節
- #define uchar unsigned char
- #define uint unsigned int
- uchar
- bianma[]={0x1b,0x13,0x0b,0x03,0x1a,0x12,0x0a,0x02,0x19,0x11,0x09,0x01,0x18,0x10,0x08,0x00};
- unsigned char receive_byte(void); // 接收一個字節
- //*** 變量及 I/O 口定義 ***
- unsigned char digit[5];
- unsigned char key_number, j, k,mk; //mk 為按鍵次數計數值
- unsigned int tmr;
- unsigned long wait_cnter;
- sbit cs=P1^0; // cs at P1.0
- sbit clk=P1^1; // clk 連接于 P1.1
- sbit dat=P1^2; // dat 連接于 P1.2
- sbit key=P1^3; // key 連接于 P1.3
- void write7279(unsigned char cmd, unsigned char dta)
- {
- send_byte (cmd);
- send_byte (dta);
- }
- unsigned char read7279(unsigned char command)
- {
- send_byte(command);
- return(receive_byte());
- }
- void send_byte( unsigned char out_byte)
- {
- unsigned char i;
- cs=0;//芯片使能
- long_delay();
- for (i=0;i<8;i++) // 分 8 次移入數據
- {
- if (out_byte&0x80)// 先傳高位
- {
- dat=1;
- }
- else
- {
- dat=0;
- }
- clk=1;
- short_delay();
- clk=0;
- short_delay();
- out_byte=out_byte*2;// 數據左移
- }
- dat=0;
- }
- unsigned char receive_byte(void)
- {
- unsigned char i, in_byte;
- dat=1; // set to input mode
- long_delay();
- for (i=0;i<8;i++)// 分 8 次讀入數據高位在前
- {
- clk=1;
- short_delay();
- in_byte=in_byte*2; // 數據左移
- if (dat)
- {
- in_byte=in_byte|0x01;
- }
- clk=0;
- short_delay();
- }
- dat=0;
- return (in_byte);
- 12
- }
- void long_delay(void)
- {
- unsigned char i;
- for (i=0;i<0x30;i++);
- }
- void short_delay(void)
- {
- unsigned char i;
- for (i=0;i<8;i++);
- }
- void main(){
- uchar jianpan,i,num;
- send_byte(0xa4); //全部復位指令
- while(1){
- if(key==0){ //如果按鍵按下
- send_byte(0x15); //讀鍵盤指令
- jianpan=receive_byte(); //接收鍵盤數據
- // P0=num;
- for(i=0;i<16;i++){
- if(jianpan==bianma[i]){ // 等于判斷一定是雙等于號
- num=i;
- break;
- }
- }
- send_byte(0xa1);
- write7279(0xc8,num);
- while(key==0);
- }
- } }</font>
復制代碼
完整的Word格式文檔51黑下載地址:
單片機實驗報告.docx
(325.27 KB, 下載次數: 9)
2018-11-6 18:22 上傳
點擊文件名下載附件
信息學院單片機實驗 下載積分: 黑幣 -5
|