淺談單片機(jī)中C語言與匯編語言的轉(zhuǎn)換
做了一單片機(jī)設(shè)計(jì),要用C語言與匯編語言同時(shí)實(shí)現(xiàn),現(xiàn)將這次設(shè)計(jì)的感受和收獲,還有遇到的問題寫下,歡迎感興趣的朋友交流想法,提出建議。
單片機(jī)設(shè)計(jì):基于51單片機(jī)的99碼表設(shè)計(jì)
軟件環(huán)境:Proteus8.0 + Keil4
要求:1,開關(guān)按一下,數(shù)碼管開始計(jì)時(shí)。2,按兩下,數(shù)碼管顯示靜止。3,按三下,數(shù)碼管數(shù)值清零。
C語言程序如下:
#include
#define uint unsigned int
#define uchar unsigned char
uchar shi,ge,aa,keycount=0,temp;
sbit anjian=P1^7;
uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
void display(shi,ge);
void key ();
void init();
void delay(uint z);
/*-----主程序-----*/
void main()
{
init(); //初始化
while(1)
{
key ();
if(keycount==1)
TR0=1; //開中斷
if(keycount==2)
TR0=0;
if(keycount==3)
{
temp=0;
keycount=0;
}
if(aa==10){aa=0;
if(temp<=99)
{
temp++;display(shi,ge);
}
else
temp=0;}
}
}
/*------初始化程序-------*/
void init()
{
keycount=0;
temp=0;
TMOD=0x01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
EA=1;
ET0=1;
//TR0=0;
}
/*-----定時(shí)器中斷-----*/
void timer0() interrupt 1
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
aa++;
}
/*-----顯示子程序-----*/
void display(shi,ge)
{
shi=temp/10;
ge=temp%10;
P0=table[shi];;delay(70);
P2=table[ge]; ;delay(70);
}
/*-----按鍵檢測子程序-----*/
void key ()
{
if(anjian==0)
{
delay(5); //消抖
if(anjian==0)
keycount++;
}
//while(anjian==0);
//display(shi,ge); //等待按鍵彈起
}
/*-----延時(shí)子程序-----*/
void delay(uint z) //延時(shí)約1ms
{
uint x,y;
for(x=z;x>0;x--)
for(y=100;y>0;y--);
}
電路仿真結(jié)果如下:
好了,那么接下來我們就開始C語言——>匯編語言之旅^_^
(1)C語言1-10行改為
ORG 0000H //匯編起始偽指令,功能是規(guī)定程序存儲(chǔ)器中源程序或數(shù)據(jù)塊存放的起始地址
ajmp STAR //ajmp無條件跳轉(zhuǎn)指令
ORG 000bh
ajmp timer0
anjian equ P1.7 //位定義
keycount equ 40h
shi equ 41h
gewei equ 42h
aa equ 43h
temp equ 44h
tab: db 3fh,6h,5bh,4fh,66h //建表
db 6dh,7dh,7h,7fh,6fh
(2)C語言中的初始化函數(shù) 12-14行和39-49行改為
1 STAR: 2 acall init //子程序近程調(diào)用指令,功能是主程序調(diào)用子程序,調(diào)用子程序的范圍為2kb
init:
mov keycount,#0 //keycount=0
mov temp,#0 //temp=1
mov tmod,#01h //TMOD=0x01
mov TH0,#60
mov TL0,#176
setb EA //位置位指令,對操作數(shù)所指出的位進(jìn)行置1操作
setb ET0
setb TR0
ret
acall為子程序近程調(diào)用指令,返回用ret。
(3)C語言中15-35行是個(gè)while循環(huán),邏輯比較繁瑣,注意了!
START:
acall display
inc temp //加1指令,將操作數(shù)所指定的單元或寄存器中的內(nèi)容加1
acall delay70 //近程調(diào)用delay70
x8: mov r0,keycount
cjne r0,#2,F1 //cjne比較跳轉(zhuǎn)指令,若r0=2則跳轉(zhuǎn)到x8,否則跳轉(zhuǎn)到F1。
ajmp x8
F1: mov r0,temp
cjne r0,#99,START //若r0<99時(shí),重復(fù)循環(huán),否則temp=0
mov temp,#0
ajmp START
F9:
acall key
mov r0,keycount
cjne r0,#0,F2 //keycount=0順序執(zhí)行,否則跳轉(zhuǎn)到F1
CLR P1.3 //清0
SETB TR0
F2: mov r0,keycount //第二次按鍵
cjne r0,#2,F2
clr TR0
reti
mov r0,keycount //第三次按鍵
cjne r0,#3,F3
mov temp,#0
mov keycount,#0
inc增量指令,功能是將操作數(shù)所指定的單元或寄存器中的內(nèi)容加1,其結(jié)果返還回原操作數(shù)單元中。
clr位復(fù)位,功能是對操作數(shù)所指出的位進(jìn)行清“0”操作。
或者在中斷函數(shù)中
timer0:
w1:
acall key
mov TH0,#60
mov TL0,#176
cpl p1.0
JB keycount,x2
ajmp x3
x2:
ajmp START
clr p1.0
ajmp w1
ajmp w1
x3: mov r0,keycount
cjne r0,#3,w1 //若r0=3則順序執(zhí)行,否則跳轉(zhuǎn)到w1
mov temp,#0
mov keycount,#0
ret
(4)C語言58-64行display函數(shù)改為
display:
mov a,temp
mov b,#10
div ab //除法指令,實(shí)現(xiàn)兩個(gè)八位無符號(hào)數(shù)的除法操作。
mov r2,A
mov r3,B
mov dptr,#tab //16位數(shù)據(jù)傳送使用方式
mov a,r2
movc a,@a+dptr //查表,先將累加器A的內(nèi)容與數(shù)據(jù)指針寄存器DPTR的內(nèi)容相加,再以其結(jié)果為地址,將該地址的結(jié)果送入A中
mov P0,a
acall delay70
nop //空指令
mov a,r3
movc a,@a+dptr
mov P2,a
nop
acall delay70
ret
div為除法指令,功能是實(shí)現(xiàn)兩個(gè)8位無符號(hào)數(shù)的除法操作,一般被除數(shù)放在累加器A中,除數(shù)放在寄存器B中。指令執(zhí)行后,商放在A中,余數(shù)放在B中。
movc為查表指令,先將累加器A的內(nèi)容與數(shù)據(jù)指針寄存器DPTR的內(nèi)容相加,再以其結(jié)果為地址,將該地址的內(nèi)容送入A中。
nop為空操作指令,它不作任何操作,但要占用一個(gè)機(jī)器周期(即12個(gè)振蕩周期)的時(shí)間,常用于延時(shí)或等待。(有些程序執(zhí)行的效果由于延時(shí)時(shí)間太短,在人眼視覺暫時(shí)作用下無法辨認(rèn)清楚)
此段程序的作用在于將一個(gè)兩位數(shù)分別分在一個(gè)十位上的數(shù)碼管和一個(gè)個(gè)位上的數(shù)碼管顯示。
(5)C語言66-76行key函數(shù)改為
1 key:2 jb anjian,F6 //若anjian=0則順序執(zhí)行,否則跳轉(zhuǎn)到F63 ACALL delay54 inc keycount //keycount++5 F6: 6 ret
jb為位條件轉(zhuǎn)移指令,功能是若直接尋址的位bit=1,則程序轉(zhuǎn)移到指定的目標(biāo)地址去執(zhí)行,若bit=0,則程序順序執(zhí)行。
(6)C語言78-83行delay函數(shù)改為
delay70:
mov r6,#70
D2: mov R7,#248
d1: djnz R7,d1 //248*70次
djnz R6,D2
ret
delay5:
mov r6,#5 //消抖。
F7: mov R7,#248
F8: djnz r7,F8 //248*5次
djnz r6,F7
ret
注意:248=2 8 ,約等于1ms。delay為延時(shí)程序。
溫馨提示:在匯編中程序代碼的大小寫不受影響,但在C語言中就有影響了。
思考1:ret和 reti都是程序返回指令,有什么區(qū)別?
我的回答:ret是子程序返回指令,reti是中斷子程序返回指令。區(qū)別在于如果是acall、lcall指令調(diào)用的子程序,返回指令就用ret;如果地址是0003,0013,000B,001B,0023調(diào)用的子程序,返回指令就用reti。
思考2:mov 20h,#0h和 setb 20h都是加1,用什么區(qū)別?
我的回答:mov指令中的20h指字節(jié),setb中的20h是位。
旅途結(jié)束!
還記得前段時(shí)間我一直糾結(jié)于匯編語言中的各種指令的語法和功能,直到一個(gè)陽光明媚的中午,我一手拿著已經(jīng)寫好的兩頁半的C語言代碼,一手拿著一本單片機(jī)的匯編指令查詢手冊,開始一行一行的翻譯,可能匯編代碼會(huì)在調(diào)試中有所錯(cuò)誤,但基本邏輯是對的。而且這次C——>匯編,使我更加深入地理解了數(shù)據(jù)在計(jì)算機(jī)中的存儲(chǔ)與調(diào)用。在此期間班主任和同學(xué)也給我答疑解惑,相信在以后的道路上,我會(huì)更加更深入地理解計(jì)算機(jī)。越努力,越幸運(yùn)!