注意:访问本站需要Cookie和JavaScript支持!请设置您的浏览器! 打开购物车 查看留言付款方式联系我们
初中电子 单片机教材一 单片机教材二
搜索上次看见的商品或文章:
商品名、介绍 文章名、内容
首页 电子入门 学单片机 免费资源 下载中心 商品列表 象棋在线 在线绘图 加盟五一 加入收藏 设为首页
本站推荐:
EMC资料转贴大全
文章长度[48949] 加入时间[2008/3/19] 更新时间[2024/11/25 9:38:27] 级别[0] [评论] [收藏]

EMC资料转贴大全

来源:21ic 作者:McuPlayer 栏目:单片机 EMC资料转贴大全
本帖的所有跟贴资料完全来自转贴(本论坛或其它坛子)
有版权争议的内容,请跟贴说明,我会妥善处理的。

* - 本贴最后修改时间:2006-6-28 9:01:45 修改者:McuPlayer

1楼: >>参与讨论 作者: McuPlayer 于 2006-6-28 9:00:00 发布:
【转贴】编程宝典:ADD A,@0xFF的妙用
EMC的单片机全部是OTP的,开发时只能使用仿真器,但很多情况下,仿真器并不能仿真实际的运行环境,如工作电压为3.3V左右、测试系统的功耗、测试系统的稳定性、测试ADC、DAC、看门狗使用等,如果使用仿真器会根实际情况有很大差别,只有烧片子才能测试到实际结果,这样一次试验下来,如果运气不好,可能需要浪费10~20个芯片,造成很大的浪费。
  要有效使用ADD A,@0xFF这条指令,需要对单片机系统编程进行一些分析,从仿真结果(包含硬件仿真器)根实际芯片运行的差异方面分析程序,可以把程序分为两个相对独立的系统:算法级程序和硬件级程序。
  算法级程序:指与硬件无关的程序,如加减乘除算法,控制算法等,总之不涉及硬件单元的操作,这些程序由于其硬件无关性,使用仿真器和芯片结果肯定相同。
  硬件级程序:与硬件相关的程序,如WDT、计数器、端口、中断、休眠、唤醒等等,特别是WDT、中断、休眠、唤醒等需要在芯片上才能测试出实际的结果,比如测试休眠状态的功耗,用仿真器无论如何是试验不出来的。
  闲话少说,书归正传。
  有效使用ADD A,@0xFF可以将一个芯片当作数片使用,甚至可以到数十片,原理如下:
  EMC单片机写烧写的过程实际就是将为1的熔丝位熔断成为0,即可以从1写为0,但不能从0到1,ADD A,@0xFF的机器码刚好是0x1FFF,全为1。例程如下:
  第一次编程代码如下:
    ORG    0X000
    ADD    A,@0XFF
    ADD    A,@0XFF
    ADD    A,@0XFF
    ADD    A,@0XFF
    ADD    A,@0XFF
    ADD    A,@0XFF
    ADD    A,@0XFF
MAIN1:
    ...
    ...
    JMP    MAIN1
  如果MAIN1程序运行结果不能达到预期目标,需要修改程序,假定为MAIN2。修改后代码如下:

    ORG    0X000
    ADD    A,@0XFF
    ADD    A,@0XFF
    ADD    A,@0XFF
    ADD    A,@0XFF
    ADD    A,@0XFF
    ADD    A,@0XFF
    JMP    MAIN2
MAIN1:
    ...
    ...
    JMP    MAIN1    
    
MAIN2:
    ...
    ...
    JMP    MAIN2


* - 本贴最后修改时间:2006-6-28 9:02:00 修改者:McuPlayer

2楼: >>参与讨论 作者: McuPlayer 于 2006-6-28 9:03:00 发布:
【转贴】EMC单片机的IIC程序包
  本程序已经稳定使用很长一段时间了,如果非要追根求源,应该追溹到1998年,由于本系统是基于IIC EEPROM的,故对2401的读写采用了阻塞的方式,读不到数据或写不入数据就不退出。
  本程序是基于447的,也在163上运行过,不过IO的初始化操作需要作些修改,其他可以完全不用修改。
  程序开头的几行ADD A,@0xFF是非常有用的,在以后的文章中会有描述。
  程序如下:

;SYSTEM CLOCK 4MHz
;IO port define
    SDA    == 4
    SCL    == 3

    MSDA    == 0
    MSCL    == 1
    MCS    == 2
    MRST    == 5
    
;Register define
    TREG    == 0X10
    TCNT    == 0X11
    GCNT    == 0X12

    IICADDR    == 0X1E
    IICBUF    == 0X28
    IICDAT0    == 0X28
    IICDAT1    == 0X29
    IICDAT2    == 0X2A
    IICDAT3    == 0X2B
    IICDAT4    == 0X2C
    IICDAT5    == 0X2D
    IICDAT6    == 0X2E
    IICDAT7    == 0X2F
    
    INCLUDE "EM78P447S.H"
    
    ORG    0X000
    ADD    A,@0XFF
    ADD    A,@0XFF
    ADD    A,@0XFF
    ADD    A,@0XFF
    ADD    A,@0XFF

START:
    DISI
    ;SET P6 P7 PULL UP EN
    CONTR
    MOV    TREG,A
    BC    TREG,7
    MOV    A,TREG
    CONTW
    ;SET SCL SDA OUTPUT HIGH
    MOV    A,@0XFF
    MOV    TREG,A
    BC    TREG,SCL    ;SCL OUTPUT
    BC    TREG,SDA    ;SDA OUTPUT
    MOV    A,TREG
    IOW    IOC6
    BS    R6,SCL        ;SCL HIGH
    BS    R6,SDA        ;SDA HIGH

;********************************************************************
;读入的测试程序,读取2401的0x00~0x07地址内容
READ_2401:
    MOV    A,@0X00
    MOV    IICADDR,A
    CALL    IIC_R8BYT
    RET

;********************************************************************
;写入的测试程序,向2401的0x00~0x07地址写入0x00
WRITE_2401:
    MOV    A,@0X00
    MOV    IICADDR,A
    CLR    IICDAT
    CLR    IICDAT
    CLR    IICDAT
    CLR    IICDAT
    CLR    IICDAT
    CLR    IICDAT
    CLR    IICDAT
    CLR    IICDAT
    CALL    IIC_W8BYT
    RET

;********************************************************************
;与Microchip的2401接口程序
;********************************************************************
;IIC_W8BYT,向2401的指定地址写入8个字节数据
;地址由IICADDR指定,数据存在IICDAT0~IICDAT7
IIC_W8BYT:
    CALL    IIC_START
    MOV    A,@0XA0
    CALL    IIC_WBYT
    CALL    IIC_CACK
    JBC    R3,GP        ;IF GP=1 OPTION AGAIN
    JMP    IIC_W8BYT
    MOV    A,IICADDR
    CALL    IIC_WBYT
    CALL    IIC_CACK
    JBC    R3,GP        ;IF GP=1 OPTION AGAIN
    JMP    IIC_W8BYT
    ;WRITE 8 BYTES TO 24C01
    MOV    A,@IICBUF
    MOV    R4,A
    MOV    A,@8
    MOV    GCNT,A
IIC_W8BYT1:
    MOV    A,R0
    INC    R4
    CALL    IIC_WBYT
    CALL    IIC_CACK
    JBC    R3,GP        ;IF GP=1 OPTION AGAIN
    JMP    IIC_W8BYT
    DJZ    GCNT
    JMP    IIC_W8BYT1
    CALL    IIC_STOP
    RET

;********************************************************************
;IIC_W1BYT,向2401的指定地址写入1个字节数据
;地址由IICADDR指定,数据存在IICDAT0
IIC_W1BYT:
    CALL    IIC_START
    MOV    A,@0XA0
    CALL    IIC_WBYT
    CALL    IIC_CACK
    JBC    R3,GP        ;IF GP=1 OPTION AGAIN
    JMP    IIC_W1BYT
    MOV    A,IICADDR
    CALL    IIC_WBYT
    CALL    IIC_CACK
    JBC    R3,GP        ;IF GP=1 OPTION AGAIN
    JMP    IIC_W1BYT
    ;WRITE 1 BYTES TO 24C01
    MOV    A,@IICBUF
    MOV    A,IICDAT0
    CALL    IIC_WBYT
    CALL    IIC_CACK
    JBC    R3,GP         3楼: >>参与讨论 作者: McuPlayer 于 2006-6-28 9:04:00 发布:
【转贴】bs,bc指令慢慢解

各位大侠是否有碰到过这样得情况:就是没个IO口电位莫名其妙的变化,从而出现你不希望的结果?别急,这很有可能就是bs、bc指令在作怪,欲知为何,且听俺慢慢解来。
要回答这个问题,首先要对IO PORT的结构要有所了解。具体io 口电路结构图请参照相关资料。在EMC单片机中,不能单独更改一个位的数据。当试图更改没个IO 口(或RAM)中的一个位时,其8个位的数据都将被取入ALU中,然后执行AND/OR指令之后再写回io port(RAM)。
举个例子,将PORT 6 bit 0 置1,指令为bs 0X06,0。指令的执行过程是这样,首先将整个PORT 6的数据取到ALU,然后用二进制数据“00000001”跟取回的数据执行“或”操作,最后将结果写入port 6;相反的,如果要将它清零,那么会用11111110与之相与再写回去。
那么为什么可能产生错误呢?有两种情况,用port6 bit7举例,一种情况是port6.7设置为input,另一种则为output,现用第一种情况分析一下错误是怎么产生的。bit 7设置为input,此时bit7锁存器上的值为0或1;当在port6 bit0-6上执行bs或bc指令改变bit0-6上的值时,如上所述的,bit7io port(不是latch)上的值也会被读入ALU,之后再写入bit7之data latch,尽管你并没有如此意图。如此,bit7上之data latch上的值就有可能不经意的被改变了。当bit7由input转变为output时,意想不到的错误就可能发生了。另一种情况就不罗嗦了。
可以发现,这种影响只会影响io port的其他位,对本身不会影响;对于非io port的RAM,也不会有这种影响出现;除了bs,bc指令外,如下指令也可能出现上述情况:XOR/AND/OR R,A;DEC R;RRC R;RLC R;SWAP R;MOV R,R;COM R;DJZ R;SWAP R;JZ R;JBC R,B;JBS R,B;等等,这里如果R不是io port而是RAN,则错误不会发生。



4楼: >>参与讨论 作者: McuPlayer 于 2006-7-7 22:31:00 发布:
EM78系列單晶片-提升軟體效率的小程式
EM78系列單晶片-提升軟體效率的小程式  
■ 譚振文
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_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
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到下一個指令的方式代替, 5楼: >>参与讨论 作者: sonic530 于 2006-7-10 17:01:00 发布:
非常感谢
非常感谢楼主的分享!

6楼: >>参与讨论 作者: weizhiwei 于 2006-8-8 23:39:00 发布:
感谢
楼主辛苦了!

7楼: >>参与讨论 作者: McuPlayer 于 2006-8-12 16:01:00 发布:
EM78P447 I/O唤醒程序示例
  由于EM78P447在I/O唤醒方式上特殊性(SLEEP2,低电平唤醒),大家觉得不是很好用,其实只要在唤醒之前注意以下几点,用起来某些地方比EM78P156更方便(可以单独开/关某一个脚唤醒功能)∶
1.    IOCB清零或置p6口唤醒脚相对应的IOCB位清零.
2.    唤醒脚p60~p6.7、p7.4、p7.5内部电阻上拉、输入口.
3.    p6àp6.
4.    10HàIOCE(SPLC位置1、关看门狗、唤酲功能允许).
       ORG   0x0
       JMP   MAIN
       ORG   0x8
       JMP   P6INT
MAIN:  and   a,@0x3F       ; **** port 6 pull high
       contw
       mov   a,@0x00       ; enable port6 wake up
       iow   0x0B          ;
       MOV   A,@0x0       ; **** Disable WDT ****
       IOW   0xE           
       MOV   A,@0Xff       ;
IOW   0x6      
       MOV   0x6,0x6   ;
SLEEP: MOV   A,@0x10
       IOW   0xE          
JMP   $            ;WAITING THE WAKE SIGN-“0” LEVEL
MOV   A,@0x0      ; **** Disable WDT ****
IOW   0xE     
JMP   SLEEP
;
       org 0xfff
jmp main


8楼: >>参与讨论 作者: McuPlayer 于 2006-8-19 1:06:00 发布:
EMC实用子程序
一 二进制数转换为ASCⅡ码
将一个字节的二进制数转换为两位16进制数的ASCⅡ码
main: mov a,@0x9f ;二进制数为0x9f
mov 0x30,a ;二进制数存入0x30
mov a,@0x02
mov 0x10,a ;0x10中存放转换次数
mov a,@0x31
mov 0x04,a ;0x04中为转换后数据存放地址
mov a,0x30
B1: and a,@0x0f ;取a低4位
mov 0x00,a
sub a,@0x09 ;低4位大于9跳往B2
jbs 0x03,0
jmp B2
mov a,0x00 ;低4位不大于9则加0x30
add a,@0x30
mov 0x00,a ;将ASCⅡ码存入0X04所指单元
jmp B3
B2: mov a,0x00 ;大于9则加0X37
add a,@0x37
mov 0x00,a
B3: swapa 0x30 ;将0X30高4位换入A低4位
inc 0x04 ;存储地址加1
djz 0x10 ;循环次数减1,为0则返回
jmp B1 ;不为0继续转换

self: jmp self
eop


二 多字节二进制加法
0X20,0X21中的二进制无符号数与0X22,0X23中的二进制无符号数相加,结果放在0X24,0X25,0X26中,低地址中放低字节数据。
Main: mov a,@0x78 ;赋值
mov 0x20,a
mov a,@0xc6
mov 0x21,a
mov a,@0x86
mov 0x22,a
mov a,@0x9e
mov 0x23,a
mov a,@0x0 ;0x26单元清0
mov 0x26,a
mov a,0x21
add a,0x23
mov 0x25,a ;高字节相加,结果送0x25
jbc 0x03,0
inc 0x26 ; 有进位则0x26加1
mov a,0x20
add a,0x22
mov 0x24,a ;低字节相加,结果送0x24
jbs 0x03,0
jmp self ;无进位跳self
inc 0x25 ;有进位0x25加1
jbc 0x03,0
inc 0x26 ; 有进位0x26加1
self: jmp self
eop

三 多字节二进制减法
0x20,0x21中的二进制无符号数减0x22,0x23中的二进制无符号数, 低地址中放低字节数据。假设被减数大于减数。
注意:(1)sub指令减出结果为正时,c标志置1。
(2)sub指令减出结果为0时,c标志也置1。
即,sub指令执行后,c标志清0表示结果为负。
main: mov a,@0x67 ;赋值
mov 0x20,a
mov a,@0xff
mov 0x21,a
mov a,@0xe8
mov 0x22,a
mov a,@0x44
mov 0x23,a ; 高字节相减
sub a,0x21
mov 0x25,a ;结果存0x25
mov a,0x22 ;低字节相减
sub a,0x20
mov 0x24,a
jbs 0x03,0
dec 0x25 ;有借位则0x25减1
self: jmp self
eop

四 二进制乘法运算
EM78单片机没有乘法指令,所以乘法运算需要转化为加法运算。0X20单元数据乘以0X21单元数据,结果放在0X22,0X23中。
main: mov a,@0x0 ;0x22,0x23单元清0
mov 0x22,a
mov 0x23,a
mov a,@0x3f ;赋值
mov 0x20,a
mov a,@0x22
mov 0x21,a
mul1: mov a,0x20 ;0x20与0x22内容相加
add 0x22,a
jbc 0x03,0
inc 0x23 ;有进位0x23加1
djz 0x21 ;0x21中次数减到0则结束
jmp mul1 ;没减到0则继续
self: jmp self
eop

五 二进制除法运算
多字节二进制除法
被除数为3个字节,在0x20、0x21、0x22单元中,0x22.7为最高位,0x20.0为最低位。
除数为2个字节,在0x30、0x31中。
算法:EM78单片机没有除法指令,而且本例中除法为多字节除法,可采用如下算法。
将被除数扩充一个字节0X23,0X23清0。被除数左移1位,0X23、0X22中数据减去0X31、0X30中数据,够减则减且0X20.0置1,减出结果存入0X23、0X22;不够减则0X23、0X22保持不变,0X20.0清0。然后被除数再左移1位,重复上述过程。共循环16次,最后0X23、0X22中得相减余数,0X21、0X20中得商。注意,若被除数左移后C标志为1,则不比较0X23、0X22与0X31、0X30数据大小关系而直接相减。
main: mov a,@0x55 ;被除数赋值
mov 0x20,a
mov 0x21,a
mov 0x22,a
mov a,@0x0 ;被除数扩充1字节并清0
mov 0x23,a
mov a,@0x12 ;除数赋值
mov 0x30,a
mov 0x31,a

mov a,@0x10 ;循环次数为16
mov 0x32,a
again: call rt_sub ;调移位除法子程
djz 0x32 ;16次循环完成则结束
jmp again ;未完成则继续

self: jmp self

rt_sub:
bc 0x03,0 ;c标志清0
rlc 0x20 ;被除数左移1位
rlc 0x21
rlc 0x22
rlc 0x23
jbc 0x03,0
jmp rt3 ;c标志为1则直接相减
mov a,0x23 ;c标志为0则先比较大小
mov 0x25,a
mov a,0x22
mov 0x24,a
mov a,0x31 ;先比较高位
sub 0x25,a
jbc 0x03,2
jmp rt1 ;高位相等跳rt1比较低位
jmp rt2 ;高位不等跳rt2
rt1: mov a,0x30 ;比较低位
sub 0x24,a
jbc 0x03,2
jmp rt3 ;低位也相等则跳rt3,相减,上1
rt2: jbs 0x03,0
ret ;减数大则返回,减数小则相减,上1
rt3: bs 0x20,0 ;上1
call sub_2b ;调2字节减法子程
ret

sub_2b:
mov a,0x31 ;高字节相减
sub 0x23,a
mov a,0x30 ;低字节相减
sub 0x22,a
jbc 0x03,2
ret ;低字节相等,无借位,返回
jbc 0x03,0
ret ;无借位,返回
dec 0x23 ;低字节相减有借位,高字节结果减1
ret
eop

六 BCD数转换为二进制数
两字节压缩BCD码转换为两字节二进制数。算法如下:
BCD码abcd=1000a+100b+10c+d=10{10[10a+b]+c}+d,将各位BCD码分离出之后,即可根据此式转换为二进制数。涉及到乘法运算和多字节加法运算。
0X20,0X21中为BCD码,0X21高4位为最高位。转换结果放在0X30,0X31中。
main: mov a,@0x79
mov 0x20,a
mov a,@0x54
mov 0x21,a ;赋值
mov a,0x20
and a,@0x0f
mov 0x22,a
swapa 0x20
and a,@0x0f
mov 0x23,a
mov a,0x21
and a,@0x0f
mov 0x24,a
swapa 0x21
and a,@0x0f
mov 0x25,a ;BCD码展开后存于0X22,0X23,0X24,0X25
mov a,0x25, ;0X25为最高位
mov 0x30,a
mov a,@0x0 ;多字节加法高位为0
mov 0x31,a
mov a,0x24
mov 0x32,a
call a_b ;调子程
mov a,0x23
mov 0x32,a
call a_b
mov a,0x22
mov 0x32,a
call a_b
self: jmp self

a_b:
mov a,@0x0 ;0X34,0X35存储中间结果
mov 0x34,a
mov 0x35,a
mov a,@0x0a ;实现乘10
mov 0x33,a
a1: mov a,0x35 ;两字节二进制加法,在本例中高字节肯定无进位
add a,0x31
mov 0x35,a
mov a,0x34
add a,0x30
mov 0x34,a
jbc 0x03,0
inc 0x35
djz 0x33
jmp a1
mov a,0x32
add 0x34,a
jbc 0x03,0
inc 0x35
mov a,0x34
mov 0x30,a
mov a,0x35
mov 0x31,a
ret
eop

七 二进制数转换为BCD码
本例为单字节二进制数(0X20)转换为非压缩BCD码,存在0X25,0X24,0X23中,0X25为百位,0X23为个位。
main: mov a,@0xa4 ;赋值
mov 0x20,a
mov 0x21,a
mov 0x22,a
mov a,@0x0 ;0x23,0x24,0x25单元清0
mov 0x23,a
mov 0x24,a
mov 0x25,a
mov a,@0x64 ;对100的个数计数
mov 0x26,a
mov a,@0x25 ;百位存在0x25中
mov 0x04,a
call a0 ;调计数子程
mov a,@0x0a ;对10的个数计数
mov 0x26,a
dec 0x04 ;个位存在0x24中
call a0
mov a,0x22 ;除去百位,十位,余下的即个位,存入0x23
mov 0x23,a
self: jmp self

a0: ;计数子程
mov a,0x26
sub 0x22,a
jbs 0x03,2
jmp a1
inc 0x00 ;无余数则对应位加1
mov a,@0x0 ;0x21与0x22在返回时应保持相同
mov 0x21,a
ret
a1: jbs 0x03,0 ;小于则跳a2
jmp a2
inc 0x00 ;大于则计数值加1
mov a,0x22
mov 0x21,a ;将0x22保存到0x21中
jmp a0 ;跳回a0继续计数
a2: mov a,0x21 ;0x21中保存的减之前的数据,此时恢复到0x22
mov 0x22,a
ret
eop


9楼: >>参与讨论 作者: McuPlayer 于 2006-8-19 1:08:00 发布:
EM78P156e+1621显示汇编例子
;HT1621 ,3.58,OUT 20001  /6/22

INDI    EQU     0X0
RTCC    EQU     0X1
PC      EQU     0X2
STATUS  EQU     0X3
FSR     EQU     0X4
PORT5   EQU     0X5
PORT6   EQU     0X6
STACK_A EQU     0X10
STACK_S EQU     0X11
XS1     EQU     0X12
XS2     EQU     0X13
XS3     EQU     0X15
XS4     EQU     0X16
XS5     EQU     0X17
XS6     EQU     0X18
XS7     EQU     0X19
XS8     EQU     0X1A
JP1     EQU     0X1B
JP2     EQU     0X1C
JP3     EQU     0X1D
JP4     EQU     0X1E
XS9     EQU     0X20
XS10    EQU     0X21
        ORG     0
        JMP     MAIN
        ORG     8
        MOV     STACK_A,A
        SWAP    STACK_A
        SWAPA   STATUS
        MOV     STACK_S,A
        CLR     0XF
        SWAPA   STACK_S
        MOV     STATUS,A
        SWAPA   STACK_A
        RETI
BIAO:
        ADD     0X2,A
        RETL    @0B11101110     ;0
        RETL    @0B01001000     ;1
        RETL    @0B10111010     ;2
        RETL    @0B11011010     ;3
        RETL    @0B01011100     ;4
        RETL    @0B11010110     ;5
        RETL    @0B11110110     ;6
        RETL    @0B01001010     ;7
        RETL    @0B11111110     ;8
        RETL    @0B01011110     ;9
        RETL    @0B00000000     ;A
XSZW:
        MOV     A,JP1
        CALL    BIAO
        MOV     XS3,A
        MOV     A,JP2
        CALL    BIAO
        MOV     XS4,A
        MOV     A,JP3
        CALL    BIAO
        MOV     XS5,A
        MOV     A,JP4
        CALL    BIAO
        MOV     XS6,A
        MOV     A,@7
        MOV     XS1,A
AWS:
        RLC     XS10
        RLC     XS9
        RLC     XS8
        RLC     XS7
        JBS     XS6,1
        JMP     ASD1
        BS      XS10,4
        JMP     ASG1
ASD1:
        BC      XS10,4
ASG1:
        RRC     XS6
        RLC     XS10
        RLC     XS9
        RLC     XS8
        RLC     XS7
        JBS     XS5,1
        JMP     ASD2
        BS      XS10,4
        JMP     ASG2
ASD2:
        BC      XS10,4
ASG2:
        RRC     XS5
        RLC     XS10
        RLC     XS9
        RLC     XS8
        RLC     XS7
        JBS     XS4,1
        JMP     ASD3
        BS      XS10,4
        JMP     ASG3
ASD3:
       10楼: >>参与讨论 作者: McuPlayer 于 2006-8-19 1:11:00 发布:
1621的汇编驱动程序
1621的汇编驱动程序

    我用HT1621显示时间、温度、制冷/制热,时间显示用“:”闪烁,我是否需要在MCU中(台湾义隆EM78P156)专门设对应的RAM区?能否提供参考程序。

    最好要设,LCD的反应时间是毫秒级的,开个RAM缓冲,由显示子程序往HT1621送数据,主程序和其它程序改变要显示的内容。
最好在RAM区中设置一个显缓区,定时刷新,然后调用一个通讯模块将数据写到HT1621中去.
另:关于时间的秒闪,如果你用了TCC中断的话,可用计数器中的某一位充当秒闪标志。


;****************************
;HT1621操作辑
P_HT    EQU    0X05        ;LCD驱动口
    DATA    EQU    1
    WR    EQU    3
    CS    EQU    4
;****************************
;=======================
;写字节
;入口:    LCD_D:    写往DATA的数值
;    LCD_N:    位数(循环数)
;=======================
WBLCD:
    MOV    A,@8
WBLCD1:
    MOV    LCD_N,A
;=======
WNLCD:
    RLC    LCD_D        ;LCD_D左循环,LCD_D(7)->C
    JBC    R3,C        ;C=0跳
    JMP    WNLCD1
    BC    P_HT,DATA    ;DATA=0
    JMP    WNLCD2
WNLCD1:
    BS    P_HT,DATA    ;DATA=1
WNLCD2:
    NOP
    NOP
    BC    P_HT,WR        ;WR=0
    NOP            ;延时1.67uS以上
    BS    P_HT,WR        ;WR=1
    NOP            ;延时1.67uS以上
    DJZ    LCD_N
    JMP    WNLCD
    RET
;=======
WBLCDADD:            ;写操作码101+首地址码000000(共9位)
    MOV    A,@0B10100000
W9LCD:
    MOV    LCD_D,A
    BC    R3,C
    MOV    A,@9
    JMP    WBLCD1
;=======
WBLCDCOM:            ;命令码100(共3位)
    MOV    A,@0B10000000
    MOV    LCD_D,A
    MOV    A,@3
    JMP    WBLCD1
;****************************
;LCD显示初始化
;功能:    LCD驱动器HT1621显示初始化
;****************************
RESTLCD:
    BC    P_HT,CS        ;CS=0,开片选
    NOP
    CALL    WBLCDCOM    ;命令操作
    MOV    A,@0B00000001
    CALL    W9LCD        ;开震荡源SYSEN
    MOV    A,@0B00101001
    CALL    W9LCD        ;BIAS 1/3
    MOV    A,@0B00000011
    CALL    W9LCD        ;开显示LCDON
    NOP
    BS    P_HT,CS        ;CS=1,关片选
    RET
;****************************
;送LCD显示
;功能:    U1显缓区(0X20-0X28)->LCD驱动器HT1621内RAM
;****************************
MOVLCD:
    WDTC            ;喂狗
    BC    P_HT,CS        ;CS=0,开片选
    MOV    A,@DISBUF1    ;载入显缓区首地址
    MOV    R4,A
    CALL    WBLCDADD    ;写操作码101+首地址码000000->LCD
MOVLCD1:
    MOV    A,R0        ;取欲显示字符代码
    CALL    TABLCD        ;查表求笔画码
    MOV    LCD_D,A
;=======填加小数点
    RLC    DISBUF9        ;取小数点->C
    JBC    R3,C        ;
    BS    LCD_D,0        ;填加小数点
;=======
    CALL    WBLCD        ;笔画码->LCD
    MOV    A,R4
    AND    A,@0B00111111
    XOR    A,@DISBUF7    
    JBS    R3,Z        ;显缓区地址=最后一个显示单元跳
    JMP    MOVLCD2
;=======小数点
    MOV    A,DISBUF8
    MOV    LCD_D,A
    CALL    WBLCD        ;笔画码->LCD
;=======
    BS    P_HT,CS        ;CS=1,关片选
    RET
MOVLCD2:
    INC    R4        ;显缓区地址+1
    JMP    MOVLCD1

11楼: >>参与讨论 作者: fjf8101 于 2006-8-22 23:07:00 发布:
学了
看了,又学了不少,楼主真会钻啊,照这种精神,学不精才是件奇怪的事情

12楼: >>参与讨论 作者: groge00111 于 2006-8-23 16:28:00 发布:
楼主是好汉
楼主真英雄,无私诲人.
可惜我看书三年了,至今没做出一个子程式,
以后请多指教我呀,
groge00111

13楼: >>参与讨论 作者: McuPlayer 于 2006-8-29 11:37:00 发布:
不知道这个帖子copy到我的blog合适不
这可是100%转帖,还在由于

14楼: >>参与讨论 作者: al2913 于 2006-9-12 19:16:00 发布:
em78p156 向PT2258送数程序

;;===========================================================
;程序单位:
;程序名称:
;使用芯片:
;使用晶振:4MHz
;日期:2005年9月14日  //     2005年11月21日
;程序编写者:ANLONG CHEN    
;   AL0896@163.com  QQ:529196989    
;===========================================================

对音量PT2258芯片控制,成功生产几万台,放心使用。对楼主支持!!!

;==========================================================
;功能说明:向PT2258送数程序           
;使用:AA1,AA2
;入口: DD1=要送出的数据           
;出口:             
;  PT2258_ADD=0X88     ;PT2314地址
;==========================================================
PT2258_ADDCOMM:
    DISI           ;关中断
    ;CALL STA_I2C  ;启始
    BC    PORT5,PT2258_CLK    ;PT2314数据
    NOP
    BS    PORT5,PT2258_DAT    ;PT2314数据
    NOP
    BS    PORT5,PT2258_CLK    ;PT2314数据
    NOP
    BC    PORT5,PT2258_DAT    ;PT2314数据
    NOP
    BC    PORT5,PT2258_CLK    ;PT2314数据

;-----------------------------------  
    MOV  A,@PT2258_ADD  ;PT2314地址
    MOV  AA2,A     ;
    ;CALL WBIT_I2CP1 ;送8位数据
    MOV  A,@0X08      ;每字节共需循环8次
    MOV  AA1,A        ;
ASWBIT_I2CP2:
    JBC   AA2,7    ;
    JMP   ASI2CP_DH  ;
    BC    PORT5,PT2258_DAT    ;PT2258据
    JMP   ASI2C_OUTDAT  ;
  ASI2CP_DH:   
    BS    PORT5,PT2258_DAT    ;PT2258数据
  ASI2C_OUTDAT:
    NOP
    NOP
    ;NOP
    BS    PORT5,PT2258_CLK    ;PT2314数据
    NOP
    BC    PORT5,PT2258_CLK    ;PT2314数据
    NOP
    BC    PORT5,PT2258_DAT    ;PT2314数据
    RLC   AA2          ;数据寄存器右移一位
    DJZ   AA1          ;共8位,每一次减1,是到0则跳过下一步转出口
    JMP   ASWBIT_I2CP2   ;8位发完?
    BC    PORT5,PT2258_CLK    ;PT2314数据
    NOP
    BS    PORT5,PT2258_CLK    ;PT2314数据
  ASIN_DAT_L:
    JBC   PORT5,PT2258_DAT    ;PT2314数据
    JMP   ASIN_DAT_L    ;等待I2C输出确认信号,即出L电平
    BC    PORT5,PT2258_CLK    ;PT2314数据
    
;----------------    
    MOV  A,DD1     ;PT2314地址
    MOV  AA2,A     ;
    ;CALL WBIT_I2CP1 ;送8位数据
    MOV  A,@0X08      ;每字节共需循环8次
    MOV  AA1,A        ;
BSWBIT_I2CP2:
    JBC   AA2,7    ;
    JMP   BSI2CP_DH  ;
    BC    PORT5,PT2258_DAT    ;PT2258据
    JMP   BSI2C_OUTDAT  ;
  BSI2CP_DH:   
    BS    PORT5,PT2258_DAT    ;PT2258数据
  BSI2C_OUTDAT:
    NOP
    NOP
    ;NOP
    BS    PORT5,PT2258_CLK    ;PT2314数据
    NOP
    BC    PORT5,PT2258_CLK    ;PT2314数据
    NOP
    BC    PORT5,PT2258_DAT    ;PT2314数据
    RLC   AA2          ;数据寄存器右移一位
    DJZ   AA1          ;共8位,每一次减1,是到0则跳过下一步转出口
    JMP   BSWBIT_I2CP2   ;8位发完?
    BC    PORT5,PT2258_CLK    ;PT2314数据
    NOP
    BS    PORT5,PT2258_CLK    ;PT2314数据
  BSIN_DAT_L:
    JBC   PORT5,PT2258_DAT    ;PT2314数据
    JMP   BSIN_DAT_L    ;等待I2C输出确认信号,即出L电平
    BC    PORT5,PT2258_CLK    ;PT2314数据
  
    
    ;CALL SOTP_I2C ;停止
    ;BC    PORT5,PT2258_CLK    ;PT2314数据
    NOP
    BC    PORT5,PT2258_DAT    ;PT2314数据
    NOP
    BS    PORT5,PT2258_CLK    ;PT2314数据
    NOP
    BS    PORT5,PT2258_DAT    ;PT2314数据
    NOP
    NOP
    ;NOP
    ;NOP
    ENI               ;开中断
    RET
1、 本站不保证以上观点正确,就算是本站原创作品,本站也不保证内容正确。
2、如果您拥有本文版权,并且不想在本站转载,请书面通知本站立即删除并且向您公开道歉! 以上可能是本站收集或者转载的文章,本站可能没有文章中的元件或产品,如果您需要类似的商品请 点这里查看商品列表!
本站协议 | 版权信息 |  关于我们 |  本站地图 |  营业执照 |  发票说明 |  付款方式 |  联系方式
深圳市宝安区西乡五壹电子商行——粤ICP备16073394号-1;地址:深圳西乡河西四坊183号;邮编:518102
E-mail:51dz$163.com($改为@);Tel:(0755)27947428
工作时间:9:30-12:00和13:30-17:30和18:30-20:30,无人接听时可以再打手机13537585389