⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 emc单片机编程技巧集锦.txt

📁 EMC单片机编程技巧集锦.txt
💻 TXT
📖 第 1 页 / 共 2 页
字号:
EMC单片机编程技巧集锦
作者:admin来源:不详发布时间:2007-1-11 9:08:40 
减小字体增大字体


EM78系列单晶片-提升软体效率的小程式谭振文分享
      笔者闲暇时总喜欢一个人窝在房里拿烙铁
       ,焊电路板,在网路上游走,看到喜欢的DIY也一定仔细端详,即使按图施工也可以得到不少的乐趣,相信酷爱此道的人应该也不少
       ,除了喜欢看看别人的作品,也可以互相比较一下看谁用的零件少,谁提供的功能强,谁的速度最快,所以经常很容易就搜集到一些不错的电路,日子久了就像堆积木一样,可以一个方块一个方块的拿来用,吾人戏称为积木设计法。将许多有用的电路组合在一起,又是一个新的东西。这种方式的确又快又经济,符合现代人速食的观念。不仅是硬体可以像堆积木一样的收集起来,软体当然也可以适用于积木法则,于是在不少有心人的努力之下,笔者也收集了EM78系列单晶片一些很好的程式库,所以说麻雀虽小,五脏俱全。也因为这些程式库极具参考价值,笔者不忍独享,故决定将紊乱的笔记重新整理后
      公开出来,与热爱此系列单晶片的朋友们一同分享。 
       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_L 
       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 
       .... /* */ 
      如何以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 
       JBS PSW,FZ 
       JMP NOLEAP 
      清除一段连续的记忆体
      对于连续一段记忆体做读写最好的方式就是使用间接定址法,但是要注意在一些如M78447/811/860等高阶MCU,记忆体20H~ 
       3FH又可以分成4组BANK,如果之前没有切换到正确的BANK会造成读写错误。下面的范例程式会将BANK1内的32个BYTES全部清为0。 
       INDIR == 0x00 
       RSR == 0x04 
       COUNT == 0x10 
       REG == 0x20 
       BANK1 == 0x40 
       BANK2 == 0x80 
       BANK3 == 0xC0 
       MOV A,@32 
       MOV COUNT,A 
       MOV A,@REG|BANK1 
       MOV RSR,A 
       NEXT: 
       CLR INDIR 
       INC RSR 
       DJZ COUNT 
       JMP NEXT 
      计算一个BYTE中有多少个"1" 
      这个小程式可以检查出在某个BYTE中共有几个1,在某些演算法的过程可能会用得到,计算的结果放在ACC。 
       RRCA DATA 
       AND A,@0x55 
       SUB DATA,A 
       MOV A,DATA 
       AND A,@0x33 
       ADD DATA,A 
       RRC DATA 
       ADD DATA,A 
       RRC DATA 
       SWAPA DATA 
       ADD A,DATA 
       AND A,@0x0F 
      节省NOP指令的方法
      您还在为程式挤不下伤脑筋吗? NOP指令有时候在延迟指令时间很有用,假如你有连续两个NOP指令可以用JMP到下一个指令的方式代替,因为这样可以减少一个指令BYTE,又可以达到相同的效果。 
      例如: 
       NOP 
       NOP 
      可以写成: 
       JMP NEXT_INST 
       NEXT_INST: 
       ;.... 
      因为一个NOP花费一个指令Cycle,但是一个JMP指令就需要2个指令Cycle,虽然有时候会抱怨JMP指令会多花一点时间,但是想不到它也有如此妙用吧。 
       LABEL太多? 
      写组合语言最令人伤脑筋的问题之一就是程式中到处是label,这有两个坏处,第一就是不小心就会造成label重复的问题,第二就是想不出适当的label名称。如果您已经为label的命名问题肠枯思竭,给您提供一个小方法,程式中如果用「$」可以表示目前PC的位址,依此推论「$+2」表示PC+2,「$-4」表示PC-4,看看底下的例子您立刻就明白: 
       MOV R,R 
       JBS PSW,FZ 
       JMP $+2 
       JMP $-4 
       ; .... 
      不过也要给您一个建议,label有个重要的意义就是具有注解的功能,特别是针对一些懒的写注解的人格外重要。所以这个方法仅适合使用在重复性很高的程式片断。 
       SWITCH...CASE叙述
      在程式设计的过程中,免不了常常会碰到多重选项的问题,利用EM78XXX的查表指令试试看,所以TBL除了当作一般查表指令以外,还可以当作多重条件判断之用。 
       MOV A,CASE 
       TBL 
       JMP EVENT1 ; CASE=0 
       JMP EVENT2 ; CASE=1 
       JMP EVENT3 ; CASE=2 
       JMP EVENT4 ; CASE=3 
      多位元组的递增及递减运算
      因为EM78XXX是8位元的单晶片,如果要执行8位元以上的计算,必须将多个位元组看成是一个变数,以下我们举例说明如何将一组24位元的变数,做到递增及递减运算。 
      递增(Increment) 
       MOV A,@1 
       ADD INT24,A 
       JBC STATUS,FC 
       ADD INT24+1,A 
       JBC STATUS,FC 
       ADD INT24+2,A 
      递减(Decrement) 
       MOV A,@1 
       SUB INT24,A 
       JBS STATUS,FC 
       SUB INT24+1,A 
       JBS STATUS,FC 
       SUB INT24+2,A 
      判断多位元组变数是否为零
      使用简单的逻辑运算指令,将多位元组OR在一起,然后依据Z旗标就可以判断此多位元组变数是否为零了。 
       MOV A,INT24 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -