AVR起步教程:從51到AVR編程篇
一、DPTR的處理
在51系統(tǒng)中,DPTR是十分重要的,51可以通過DPTR尋址,臨時(shí)儲(chǔ)存16位數(shù)據(jù)等等,下面僅僅先介紹2種51到AVR程序移植中DPTR的處理:
(1)DPTR直接尋址
例子: 51程序如下:
MOV DPTR,#8000H;
MOVX A,@DPTR;
這個(gè)移植起來就比較簡單了,我們現(xiàn)在選用Z寄存器(R30,R31)作為DPTR,這個(gè)里不考慮實(shí)際地址的偏移,地址設(shè)為0x1100對(duì)應(yīng)0x8000
ldi r30,0x00
ldi r31,0x11
ld r24,z
(2)DPTR變址尋址
類似的,51的變址尋址也是一樣的
MOV DPTR,#8000H
MOV A,#05H
MOVX A,@A+DPTR
AVR中可以移植成:
ldi r30,0x00
ldi r31,0x11
adiw r30,0x05
ld r24,z
(3)DPTR與P2結(jié)合
這種尋址方式在51中也較為常用
MOV DPTR,#8100H
MOV P2,#81H
MOV R0,#10H
MOVX A,@R0
INC R0
MOVX A,@R0
這種尋址方式的時(shí)候,尋址的范圍限制在了0x8100到0x81FF之間
AVR中可以移植如下:
ldi r31,0x11
ldi r30,0X10
lz r24,z
inc r30
lz r24,z
二、DA的處理
DA是十進(jìn)制調(diào)整指令,具體的功能是對(duì)BCD碼加法運(yùn)算的結(jié)果進(jìn)行有條件的修正,操作依據(jù)為:
若(A)3~0>9∨(AC)=1,則A3~0←(A)3~0+6
若(A)7~4>9∨(C)=1,則A7~4←(A)7~4+6
若(A)7~4=9∧(A)3~0>9,則A7~4←(A)7~4+6
舉例子來說,如果DA的數(shù)字是0A,那么就給這個(gè)數(shù)字加上0x06,使之成為0x10,現(xiàn)在的0x10就代表了十進(jìn)制的10了,
#define u08 unsigned char
u08 A,C
void DA(void)
{
u08 tmp;
tmp = A & 0x0F;
if( tmp > 0x09 C & 0x20)
A += 0x06;
tmp = A & 0xF0;
if( tmp > 0x90 C & 0x01)
{
A += 0x60;
asm("sec");
C = SREG;
}
tmp = A & 0xF0;
if( tmp == 0x90)
{
tmp = A & 0x0F;
if(tmp>0x09)
{
A += 0x60;
asm("sec");
C = SREG;
}
}
}
代碼中的C就是SREG寄存器中的內(nèi)容
三、PSW中P的處理
51中,如果A中1的個(gè)數(shù)為奇數(shù),則P置位,反之則置0。在一些老的程序中,特別是有使用一種模擬老式紙帶傳輸?shù)某绦?,P就用來檢測(cè)數(shù)據(jù)傳輸?shù)恼_于否!
在AVR中,我們可以用3中方式來做:
(1)、查表:
我們可以把0到255中的數(shù)字的做個(gè)表,然后去查表確定A中的數(shù)字1的P值,顯然,不管做偶數(shù)表或者奇數(shù)的表,內(nèi)存的消耗和時(shí)鐘的消耗是難以讓人忍受的
(2)、數(shù)數(shù):
既然查表在大多時(shí)候不可取,那么讓我們來數(shù)數(shù),我們把A拆分開來,一位一位去數(shù)
我們還是嵌入?yún)R編去解決
#define u08 unsigned char
u08 A,B;
u08 CalcP(void)
{
asm volatile
(
"mov %0,%2" "nt" //保存A
"clc" "nt" //清C標(biāo)志
"eor r1,r1" "nt"
"mov %1,r1" "nt"
"lsr %0" "nt"
"adc %1,r1" "nt" //算了第一位
"lsr %0" "nt"
"adc %1,r1" "nt" //算了第二位
"lsr %0" "nt"
"adc %1,r1" "nt" //算了第三位
"lsr %0" "nt"
"adc %1,r1" "nt" //算了第四位
"lsr %0" "nt"
"adc %1,r1" "nt" //算了第五位
"lsr %0" "nt"
"adc %1,r1" "nt" //算了第六位
"lsr %0" "nt"
"adc %1,r1" "nt" //算了第七位
"lsr %0" "nt"
"adc %1,r1" "nt" //算了第八位
"andi %1,0x01" "nt" //tmp &= 0x01
: "=d" (B),"=d" (tmp),"=d" (A)
: "0" (B),"1" (tmp),"2" (A)
);
return tmp;
}
這個(gè)方法中,我們加上return共花了22條指令,比起查表而言,已經(jīng)是省了很多時(shí)鐘和內(nèi)存單元了。
(3)、算法:
還有比數(shù)數(shù)還精簡的代碼嗎?當(dāng)然有,雖然精簡的不多:)
我們知道,異或的法則是11為0,00為,10和01為1,這個(gè)方法的算法就是使用了異或來做的的,我們以0xA1這個(gè)數(shù)來做例子
#define u08 unsigned char
u08 AvrCalcP(u08 Data)
{
u08 tmp1,tmp2;
asm volatile
(
"mov %1,%0""nt" //tmp1 = 0xA1 1010 0001
"swap %1""nt" //tmp1 = 0x1A 0001 1010
"eor %1,%0""nt" //tmp1 = 0xBB 1011 1011
"andi %1,0x0f""nt" //tmp1 = 0x0B 0000 1011
"mov %2,%1""nt" //tmp2 = 0x0B
"andi %2,0x03""nt" //tmp2 = 0x03 0000 0011
"lsl %1""nt"
"lsl %1""nt" //tmp1 = 0x02 0000 0010
"eor %1,%2""nt" //tmp1 = 0x01 0000 0001
"mov %2,%1""nt" //tmp2 = 0x01
"andi %2,0x01 ""nt" //tmp2 = 0x01 0000 0001
"lsl %1""nt" //tmp1 = 0x00 0000 0000
"eor %1,%2 ""nt" //tmp1 = 0x00 0000 0001
"andi %1,0x0f""nt" //tmp1 = 0x01
: "=d" (Data),"=d" (tmp1),"=d" (tmp2)
: "0" (Data),"1" (tmp1),"2" (tmp2)
);
return tmp1;
}
這個(gè)方法中,我們加上return共花了15條指令,比方法2來講,又省了7條指令。
評(píng)論