做了一單片機設計,要用C語言與彙編語言同時實現,現將這次設計的感受和收穫,還有遇到的問題寫下,歡迎感興趣的朋友交流想法,提出建議。 單片機設計:基於51單片機的99碼表設計 軟體環境:Proteus8.0 + Keil4 要求:1,開關按一下,數位管開始計時。2,按兩下,數位管顯示靜止。3,按三下, ...
做了一單片機設計,要用C語言與彙編語言同時實現,現將這次設計的感受和收穫,還有遇到的問題寫下,歡迎感興趣的朋友交流想法,提出建議。
單片機設計:基於51單片機的99碼表設計
軟體環境:Proteus8.0 + Keil4
要求:1,開關按一下,數位管開始計時。2,按兩下,數位管顯示靜止。3,按三下,數位管數值清零。
C語言程式如下:
1 #include<reg51.h> 2 #define uint unsigned int 3 #define uchar unsigned char 4 uchar shi,ge,aa,keycount=0,temp; 5 sbit anjian=P1^7; 6 uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; 7 void display(shi,ge); 8 void key (); 9 void init(); 10 void delay(uint z); 11 /*-----主程式-----*/ 12 void main() 13 { 14 init(); //初始化 15 while(1) 16 { 17 key (); 18 if(keycount==1) 19 TR0=1; //開中斷 20 if(keycount==2) 21 TR0=0; 22 if(keycount==3) 23 { 24 temp=0; 25 keycount=0; 26 } 27 if(aa==10){aa=0; 28 if(temp<=99) 29 { 30 temp++;display(shi,ge); 31 } 32 else 33 temp=0;} 34 } 35 } 36 37 38 /*------初始化程式-------*/ 39 void init() 40 { 41 keycount=0; 42 temp=0; 43 TMOD=0x01; 44 TH0=(65536-50000)/256; 45 TL0=(65536-50000)%256; 46 EA=1; 47 ET0=1; 48 //TR0=0; 49 } 50 /*-----定時器中斷-----*/ 51 void timer0() interrupt 1 52 { 53 TH0=(65536-50000)/256; 54 TL0=(65536-50000)%256; 55 aa++; 56 } 57 /*-----顯示子程式-----*/ 58 void display(shi,ge) 59 { 60 shi=temp/10; 61 ge=temp%10; 62 P0=table[shi];;delay(70); 63 P2=table[ge]; ;delay(70); 64 } 65 /*-----按鍵檢測子程式-----*/ 66 void key () 67 { 68 if(anjian==0) 69 { 70 delay(5); //消抖 71 if(anjian==0) 72 keycount++; 73 } 74 //while(anjian==0); 75 //display(shi,ge); //等待按鍵彈起 76 } 77 /*-----延時子程式-----*/ 78 void delay(uint z) //延時約1ms 79 { 80 uint x,y; 81 for(x=z;x>0;x--) 82 for(y=100;y>0;y--); 83 }
電路模擬結果如下:
好了,那麼接下來我們就開始C語言——>彙編語言之旅^_^
(1)C語言1-10行改為
1 ORG 0000H //彙編起始偽指令,功能是規定程式存儲器中源程式或數據塊存放的起始地址 2 ajmp STAR //ajmp無條件跳轉指令 3 ORG 000bh 4 ajmp timer0 5 anjian equ P1.7 //位定義 6 keycount equ 40h 7 shi equ 41h 8 gewei equ 42h 9 aa equ 43h 10 temp equ 44h 11 tab: db 3fh,6h,5bh,4fh,66h //建表 12 db 6dh,7dh,7h,7fh,6fh
(2)C語言中的初始化函數 12-14行和39-49行改為
1 STAR: 2 acall init //子程式近程調用指令,功能是主程式調用子程式,調用子程式的範圍為2kb
1 init: 2 mov keycount,#0 //keycount=0 3 mov temp,#0 //temp=1 4 mov tmod,#01h //TMOD=0x01 5 mov TH0,#60 6 mov TL0,#176 7 setb EA //位置位指令,對操作數所指出的位進行置1操作 8 setb ET0 9 setb TR0 10 ret
acall為子程式近程調用指令,返回用ret。
(3)C語言中15-35行是個while迴圈,邏輯比較繁瑣,註意了!
1 START: 2 acall display 3 inc temp //加1指令,將操作數所指定的單元或寄存器中的內容加1 4 acall delay70 //近程調用delay70 5 x8: mov r0,keycount 6 cjne r0,#2,F1 //cjne比較跳轉指令,若r0=2則跳轉到x8,否則跳轉到F1。 7 ajmp x8 8 F1: mov r0,temp 9 cjne r0,#99,START //若r0<99時,重覆迴圈,否則temp=0 10 mov temp,#0 11 ajmp START 12 F9: 13 acall key 14 mov r0,keycount 15 cjne r0,#0,F2 //keycount=0順序執行,否則跳轉到F1 16 CLR P1.3 //清0 17 SETB TR0 18 19 F2: mov r0,keycount //第二次按鍵 20 cjne r0,#2,F2 21 clr TR0 22 reti 23 mov r0,keycount //第三次按鍵 24 cjne r0,#3,F3 25 mov temp,#0 26 mov keycount,#0
inc 增量指令,功能是將操作數所指定的單元或寄存器中的內容加1,其結果返還回原操作數單元中。
clr 位複位,功能是對操作數所指出的位進行清“0”操作。
或者在中斷函數中
1 timer0: 2 w1: 3 acall key 4 mov TH0,#60 5 mov TL0,#176 6 cpl p1.0 7 JB keycount,x2 8 ajmp x3 9 x2: 10 ajmp START 11 clr p1.0 12 ajmp w1 13 ajmp w1 14 15 x3: mov r0,keycount 16 cjne r0,#3,w1 //若r0=3則順序執行,否則跳轉到w1 17 mov temp,#0 18 mov keycount,#0 19 ret
(4)C語言58-64行display函數改為
1 display: 2 mov a,temp 3 mov b,#10 4 div ab //除法指令,實現兩個八位無符號數的除法操作。 5 mov r2,A 6 mov r3,B 7 mov dptr,#tab //16位數據傳送使用方式 8 mov a,r2 9 movc a,@a+dptr //查表,先將累加器A的內容與數據指針寄存器DPTR的內容相加,再以其結果為地址,將該地址的結果送入A中 10 mov P0,a 11 acall delay70 12 nop //空指令 13 mov a,r3 14 movc a,@a+dptr 15 mov P2,a 16 nop 17 acall delay70 18 ret
div為除法指令,功能是實現兩個8位無符號數的除法操作,一般被除數放在累加器A中,除數放在寄存器B中。指令執行後,商放在A中,餘數放在B中。
movc為查表指令,先將累加器A的內容與數據指針寄存器DPTR的內容相加,再以其結果為地址,將該地址的內容送入A中。
nop為空操作指令,它不作任何操作,但要占用一個機器周期(即12個振蕩周期)的時間,常用於延時或等待。(有些程式執行的效果由於延時時間太短,在人眼視覺暫時作用下無法辨認清楚)
此段程式的作用在於將一個兩位數分別分在一個十位上的數位管和一個個位上的數位管顯示。
(5)C語言66-76行key函數改為
1 key: 2 jb anjian,F6 //若anjian=0則順序執行,否則跳轉到F6 3 ACALL delay5 4 inc keycount //keycount++ 5 F6: 6 ret
jb為位條件轉移指令,功能是若直接定址的位bit=1,則程式轉移到指定的目標地址去執行,若bit=0,則程式順序執行。
(6)C語言78-83行delay函數改為
1 delay70: 2 mov r6,#70 3 D2: mov R7,#248 4 d1: djnz R7,d1 //248*70次 5 djnz R6,D2 6 ret 7 8 delay5: 9 mov r6,#5 //消抖。 10 F7: mov R7,#248 11 F8: djnz r7,F8 //248*5次 12 djnz r6,F7 13 ret
註意:248=28 ,約等於1ms。delay為延時程式。
溫馨提示:在彙編中程式代碼的大小寫不受影響,但在C語言中就有影響了。
思考1:ret 和 reti都是程式返回指令,有什麼區別?
我的回答:ret是子程式返回指令,reti是中斷子程式返回指令。區別在於如果是acall 、lcall指令調用的子程式,返回指令就用ret;如果地址是0003,0013,000B,001B,0023調用的子程式,返回指令就用reti。
思考2:mov 20h,#0h 和 setb 20h 都是加1,用什麼區別?
我的回答:mov指令中的20h指位元組,setb中的20h是位。
旅途結束!
還記得前段時間我一直糾結於彙編語言中的各種指令的語法和功能,直到一個陽光明媚的中午,我一手拿著已經寫好的兩頁半的C語言代碼,一手拿著一本單片機的彙編指令查詢手冊,開始一行一行的翻譯,可能彙編代碼會在調試中有所錯誤,但基本邏輯是對的。而且這次C——>彙編,使我更加深入地理解了數據在電腦中的存儲與調用。在此期間班主任和同學也給我答疑解惑,相信在以後的道路上,我會更加更深入地理解電腦。越努力,越幸運!
-Zoctopus
2016.12.26