义隆单片机EMC-法宝级的EMC单片机编程技巧集锦 2007-03-16 11:44
EM78XXX单芯片自从问世以来已经陆续推出十余种不同等级的单芯片,小到8Pin的78P152,大到100Pin
OTP的78P860,其汇编语言指令都是一样的,仅有57个,所以反复练习几次就能熟悉指令的用法。汇编语言用在I/O控制非常容易,也有很高的效率,所以坊间的书籍大部份以讨论控制为主显,显少专门探讨软件技巧的篇幅,其实老手都知道,关于芯片之控制往往用到时再去翻一翻DATA
BOOK,注意一下TIMING,然后准备一部示波器,三两下就可以搞定。反倒是算法用的好不好会大大影响产品的稳定度,所以有经验的程序设计师通常都有自己的一套葵花秘笈,所以要提升自己的功力最好的方式除了多练习之外,看看别人的程序也会使你进步很快。 BCD转换成Binary
由于EM78XXX是8位的微控器,因此为了节省内存,我们的范例仅以一个BYTE存放两位BCD数为例,数字的范围在0~99之间,转换后的结果放在ACC,如果您需要更多的位数,相信您在看完之后应该不难自行修改才是。 程序一
这个范例程序共花费13个指令CYCLE,需要两个变量空间,执行后会影响到原BCD的内容。 MOV A,BCD MOV TMP,A MOV A,@0x0F AND TMP,A SWAP BCD AND BCD,A BC PSW,0
RLC BCD ; *2 MOV A,BCD ADD TMP,A RLC BCD
RLCA BCD ; *8 ADD A,TMP 说明
在程序一中所采用的方式应该算是最多人知道的方式,也是一种最直觉的方法,先将BCD个位数保存起来,因为十位数必须要乘以10,所以利用移位的技巧乘以10再加上个位数,所得的答案放入ACC。 程序二
在程序一的缺点,就是在执行程序以后,原本BCD的内容已经在移位的过程中被破坏掉了,为了改善这项缺失,我们换一种方式看看。下面这个程序,我们企图改善前面的缺失,共花费11个指令CYCLE,仍需要两个变量空间,但是执行后不会破坏原来BCD的内容。 SWAPA BCD MOV TMP,A MOV A,@0x0F
AND BCD,A AND TMP,A BC PSW,0 RLCA TMP SWAP TMP RRC TMP ADD A,TMP ADD A,BCD 程序三
对于程序二的结果我们仍然不满意,似乎稍嫌复杂,虽然速度有所改善,但在内存的分配上仍有余地,所以我们再改善成程序三的型态。转换过程只花费10个指令CYCLE,而且只需要一个变量空间,执行之后也不会改变原来BCD的内容。 MOV A,@0x0f AND A,BCD JBC BCD,4 ADD A,@10 JBC BCD,5 ADD A,@20 JBC BCD,6 ADD A,@40 JBC BCD,7 ADD A,@80 说明
看过以上三个范例,您是否觉得程序三最简洁而且容易了解?写程序的确是一项极具挑战性的工作,而且还可以找到很多灵感及乐趣,想不到吧! Binary转换成BCD码
下面的范例程序会将存放在ACC内的二进制数转换成两位BCD码(Compacted BCD Code),可转换最大的BCD码是99。 CLR BCD DIGIT_HI:
ADD A,@256-10 JBS PSW,FC JMP DIGIT_LO INC BCD
JMP DIGIT_HI DIGIT_LO: ADD A,@10 SWAP BCD OR BCD,A 减法的陷阱
EM78系列汇编语言的减法指令是SUB,使用这个指令时您得特别注意,因为ACC永远都是减数,不可为被减数。SUB指令的语法有以下三种: SUB A,R (R-A→A) SUB R,A (R-A→R)
SUB A,K (K-A→A)
也就是说如果我们想计算A-2的值,如果写成: SUB A,@2
其实是执行2-A,解决方法如下: ADD A,@256-2 或 ADD A,@254
交换两组缓存器的内容
如果你觉得要交换两组内存的内容一定要借用第三组变量,那么您可以参考以下的方式,只是用了一些数学技巧就变得又快又简单。 MOV A,REG1 SUB A,REG2 ADD REG1,A SUB REG2,A 原理说明 A=REG1
A=REG2-REG1 REG1=REG1+A
=REG1+(REG2-REG1) =REG2
REG2=REG2-(REG2-REG1) =REG1
若X>Y就交换...
延续上一个例子,此法用应用在Bubble Sort特别管用。 MOV A,X SUB A,Y JBC PSW,FC JMP NO_CHANGE ADD X,A SUB Y,A 2补码
2补码加法经常代替减法,传统上的做法是先取1补码,然后加1。 COM REG INC REG
或是可以利用另一种方式求得,所不同的是第二种方式会影响PSW缓存器。 ADD A,REG SUB A,REG
如果您所要求的数已经放在ACC里面,那只要一行就能解决了。 SUB A,@0
旋转字节运算
在8051指令中位左旋有RLC与RL两种指令区分,RLC在ACC左旋时会连带将CY一并旋转,而RL只会将ACC的MSB旋入LSB。EM78XXX指令只有RLC,那么要如何才能做到不带CY旋转呢?答案是旋转两次: RLCA REG1 RLC REG1
如图1所示,第一次位旋转并没有真正改变REG1的内容,目的是将REG1的MSB先放入FC,第二次位旋转才将刚刚放在FC内的MSB旋入LSB。同理,两个BYTES不经FC的位旋转也是相同的原理。 RLCA HI_BYTE RLC LO_BYTE RLC HI_BYTE 范围判断
写程序免不了会碰到IF..THEN..的场合,有些人觉得EM78XXX的条件判断式太过繁琐,所以笔者也将它们整理归纳一下。条件判断式可分为开放区间条件式与封闭区间条件式来讨论,以图2来表示。
开放条件式是以N点为出发点,当待测值大于N或是小于等于N时的条件判断,以C的语法描述如下: if(number>n)
... /* number大于N */ else
... /* number小于等于N */ EM78XXX汇编语言写法如下: MOV A,@N+1 SUB A,Number JBC PSW,FC
JMP LABEL_1 ; 大于N
JMP LABEL_2 ; 小于等于N
封闭式条件判断是指待测值N是否在X与Y的范围之内,若以C的语法描述: if((number>=x) && (number<=y)) .... /* in range */ else
.... /* False */
如何以EM78汇编语言做到呢?一般做法是以减法后的PSW做条件判断,程序如下:
MOV A,@2
SUB A,number JBS PSW,FC JMP FALSE MOV A,@y+1 SUB A,SI JBC PSW,FC JMP FALSE IN_RANGE: ; .... FALSE: ; ....
这个IF条件式要花费8个指令Cycle,还不算太复杂。但是还有个更简洁的方法,以下用加法后的PSW(R3)做条件判断,一共只要5行就清洁溜溜了。 MOV A,Number
ADD A,@255-y ADD A,@y-x+1 JBC PSW,FC JMP IN_RANGE FALSE: ; .... IN_RANGE: ; .... 说明
关键就在前三行,x表示条件式的下限值,y表示条件式的上限值,可以看得出仍是利用CY旗标制造的特效,不但精简而且有点小聪明,许多老手都爱用,这也是他们口袋里的秘密武器之一。如果您觉得不错,不妨也收入锦囊中,尔后就可以依样画葫芦了。 ACC与缓存器内容交换
这理我们要介绍一种快速的逻辑算法,只需要3个指令CYCLE,就可以将ACC的内容与缓存器的内容交换,不拖泥带水,Very cute! XOR Number,A XOR A,Number XOR Number,A
请读者自行在纸上推算一次,就知道答案了。 交换多组缓存器内容
利用上面介绍的方法,可以推广到多组缓存器交换的例子上,下面的程序将5组DATA内容移位,第一笔缓存器的数据传到第二笔缓存器内,第二缓存器的数据再传送到第三笔缓存器内,依此类推,最后一笔数据则传给第一个缓存器,形成一种字节数据旋转。 MOV A,@5 MOV COUNT,A MOV A,@DATA1 MOV RSR,A MOV A,DATA5 NEXT:
XOR INDIR,A XOR A,INDIR XOR INDIR,A INC RSR DJZ COUNT JMP NEXT 计算MOD 2N
假如你刚好需要计算ACC MOD X,且X刚好是2的N次方,使用ACC AND
(X-1)是最快的方法了。例如要判断YEAR是否为闰年,有个简单的方法,可以排除一些非闰年的条件,只要不能被4整除者就不是闰年。所以可以用YEAR AND 3解决。 MOV A,@4-1 AND A,YEAR
义隆单片机EMC-法宝级的EMC单片机编程技巧集锦
![](/skin/haowen/images/icon_star.png)
![](/skin/haowen/images/icon_star.png)
![](/skin/haowen/images/icon_star.png)
![](/skin/haowen/images/icon_star.png)