赵工的个人空间


专业技术部分转网页计算转业余爱好部分


 单片机与嵌入式

首页 > 专业技术 > 单片机与嵌入式 > PIC单片机的汇编语言指令
PIC单片机的汇编语言指令

一种单片机所能识别的全部指令集合,就称为该单片机的指令系统或指令集。单片机时钟振荡器电路产生的时钟信号,经内部4分频后形成一个不重叠的方波信号Q1~Q4,叫作4个节拍,由4个节拍构成一个指令周期Tcyc,一个指令周期内部包含4个时钟周期Tosc。前一个指令周期内完成取值操作,在后一个指令周期内完成指令的译码和执行。当Q1节拍的上升沿出现时,程序计数器PC增1,指令码是在Q4节拍取出并放入指令寄存器的。指令码的译码和执行贯穿下一个指令周期的Q1~Q4节拍。由于单片机在执行一条指令的同时,就可以提取下一条指令,从而实现流水作业,这样,每一条指令的运行时间平均为一个指令周期,因此习惯上说单片机采用的是单周期指令。严格地说,大多数指令的运行时间都是一个指令周期,但是少数引起程序执行顺序发生跳转的指令则是两个周期。

1. PIC的性能特点:

通常,每一条指令都用指意性很强的英文单词或缩写来代表,将代表一条指令的一个字符串称为“助记符”。PIC16F627共有35条指令,均是长度为14位的单字节指令,按其操作对象的不同可分为3类,即面向字节操作类(17条)、面向位操作类(4条)以及常数操作和控制操作类(14条)。

指令代码符号:

W

代表工作寄存器(即累加器)

f

代表7位寄存器单元地址,最多可区分128个单元

b

表示某一bit在一个寄存器内部8bit数据中的位置(即伴地址),由3位组成

k

代表8bit数据常数,或者代表11位地址常数

d

代表目标寄存器:d=0,目标寄存器为W;d=1,目标寄存器为f

表示运算结果送入目标寄存器

代表逻辑“与”运算符

代表逻辑“或”运算符

代表逻辑“异或”运算符

3类指令代码格式如下:
1)面向字节操作类指令代码分配格式:

13~8

7

6~0

操作码

d

f(寄存器地址)

2)面向位操作类指令代码分配格式:

13~10

9~7

6~0

操作码

b

F(寄存器地址)

3)常数操作和控制操作类指令代码分配格式:又分3种情况。

⑴携带8bit常数的指令代码分配格式:

13~8

7~0

操作码

k(数据)

⑵携带13比特常数的CALL和GOTO指令代码分配格式:

13~11

10~0

操作码

k(程序地址)

⑶不携带常数的指令代码分配格式:(如NOP)

13~0

操作码

2. 面向字节操作类指令:

寄存器加法指令:ADDWF    f,d
操作:W+f→d,影响状态位:C、DC、Z
说明:将寄存器f和工作寄存器W的内容相加,d=1结果存入寄存器f中,d=0存入W
示例:ADDWF    REG1,0
  指令执行前 W=0x17    REG1=0xC2
  指令执行后 W=0xD9    REG1=0xC2
  状态位     Z=0    C=0    DC=0
寄存器逻辑与指令:ANDWF    f,d
操作:W∧f→d,影响状态位:Z
说明:将寄存器f和工作寄存器W的内容相与,d=1结果存入寄存器f中,d=0存入W
示例:ANDWF    REG1,1
  指令执行前 W=0x17    REG1=0xC2
  指令执行后 W=0xD9    REG1=0x02
寄存器清零指令:CLRF    f,d
操作:0→W,影响状态位:Z
说明:将寄存器清零。d=0,f和W同时清零;d=1,仅f被清零
示例:CLRF    REG1
  指令执行前 REG1=0x5A
  指令执行后 REG1=0x00
  状态位     Z=1
工作寄存器W清零指令:CLRW
操作:0→W,影响状态位:Z
说明:将W寄存器清零,状态位被置1。
示例:CLRW
  指令执行前 W=0x5A
  指令执行后 W=0x00
  状态位     Z=1
寄存器取反指令:COMF    f,d
操作:~f→W,影响状态位:Z
说明:将寄存器f的内容取反。d=1,结果存入寄存器f中;d=0,存入工作寄存器W中
示例:COMF    REG1,0
  指令执行前 REG1=0x13
  指令执行后 REG1=0x13    W=0xEC
寄存器减1指令:DECF    f,d
操作:f-1→d,影响状态位:Z
说明:将寄存器f的内容减1。d=1,结果存入寄存器f中;d=0,存入工作寄存器W中
示例:DECF    CNT,1
  指令执行前 CNT=0x01    Z=0
  指令执行后 CNT=0x00    Z=1
递减跳转指令:DECFSZ    f,d
操作:f-1→d,结果为0则跳转,不影响状态位,产生跳转时指令周期为2
说明:将寄存器f的内容减1存入d。结果为0则跳过下一条指令执行,否则顺序执行下一条指令(单周期)。
示例:HERE    DECFSZ    REG1,1
               GOTO    LOOP
      NUM     ......
  指令执行前 PC=地址 HERE
  指令执行后 REG1=REG1-1
             如果REG1=0,PC=地址NUM
             如果REG1≠0,PC=地址HERE+1
寄存器加1指令:INCF    f,d
操作:f+1→d,影响状态位:Z
说明:将寄存器f的内容加1。d=1,结果存入寄存器f中;d=0,存入工作寄存器W中
示例:INCF    REG1,1
  指令执行前 REG1=0xFF    Z=0
  指令执行后 REG1=0x00    Z=1
递增跳转指令:INCFSZ    f,d
操作:f+1→d,结果为0则跳转,不影响状态位,产生跳转时指令周期为2
说明:将寄存器f的内容加1存入d。结果为0则跳过下一条指令执行,否则顺序执行下一条指令(单周期)。
示例:HERE    INCFSZ    REG1,1
               GOTO    LOOP
      NUM     ......
  指令执行前 PC=地址 HERE
  指令执行后 REG1=REG1+1
             如果REG1=0,PC=地址NUM
             如果REG1≠0,PC=地址HERE+1
寄存器逻辑或指令:IORWF    f,d
操作:W∨f→d,影响状态位:Z
说明:将寄存器f和工作寄存器W的内容做逻辑或运算,d=1结果存入寄存器f中,d=0存入工作寄存器W中
示例:IORWF    REG1,0
  指令执行前 REG1=0x91    W=0x13
  指令执行后 REG1=0x93    W=0x13    Z=0
寄存器逻辑异或指令:XORWF    f,d
操作:W⊕f→d,影响状态位:Z
说明:将寄存器f和工作寄存器W的内容相异或,d=1结果存入寄存器f中,d=0存入工作寄存器W中
示例:XORWF    REG1,1
  指令执行前 REG1=0xAF    W=0xB5
  指令执行后 REG1=0x1A    W=0xB5
F寄存器传送指令:MOVF    f,d
操作:f→d,影响状态位:Z
说明:将寄存器f内容送至工作寄存器W(d=0)或自己本身(d=1),如果是传给自己,一般是用来影响状态位Z,以判断寄存器f是否为0
示例:MOVF    REG1,0
  指令执行后 W=REG1寄存器中的值   Z=1
W寄存器传送指令:MOVWF    f
操作:W→f,不影响状态位
说明:将工作寄存器W的内容送到寄存器f中。
示例:MOVWF    REG1
  指令执行前 REG1=0xFF    W=0x4F
  指令执行后 REG1=0x4F    W=0x4F
空操作指令:NOP
操作:无任何操作
说明:不产生任何结果,只使PC+1。
寄存器带进位位循环左移指令:RLF    f,d
操作:f(n)→d(n+1),f(7)→C,C→d(0),影响状态位:C
说明:将寄存器f接位循环左移,结果存入d。f最高位(bit7)移入状态位C(进位位),进位位C移入d(0)中。
示例:RLF    REG1,0
  指令执行前 REG1=1110 0110    C=0
  指令执行后 REG1=1110 0110    W=1100 1100    C=1
寄存器带进位位循环右移指令:RRF    f,d
操作:f(n)→d(n-1),f(0)→C,C→d(7),影响状态位:C
说明:将寄存器f接位循环右移,结果存入d。f最低位(bit0)移入状态位C(进位位),进位位C移入d(7)中。
示例:RRF    REG1,0
  指令执行前 REG1=1110 0110    C=0
  指令执行后 REG1=1110 0110    W=0111 0011    C=0
寄存器减法指令:SUBWF    f,d
操作:f-W→d,影响状态位:C、DC、Z
说明:将寄存器f的内容减去工作寄存器W的内容,d=1结果存入寄存器f中,d=0存入工作寄存器W中。(该指令是将工作寄存器W的内容求补后与寄存器f的内容相加)
示例:SUBWF    REG1,1
  指令执行前 REG1=3    W=2    C=?    
  指令执行后 REG1=1    W=2    
  状态位     C=1;    结果为正  Z=0    DC=0
示例:
  指令执行前 REG1=2    W=2    C=?    
  指令执行后 REG1=0    W=2    
  状态位     C=1;    结果为零  Z=1    DC=1
示例:
  指令执行前 REG1=1       W=2    C=?    
  指令执行后 REG1=0xFF    W=2    
  状态位     C=0;    结果为负  Z=0    DC=0
(f>W:C=0,Z=0;  f=W:C=1,Z=1;  f<W:C=1,Z=0)
寄存器半字节交换指令:SWAPF    f,d
操作:f(0-3)→d(4-7),f(4-7)→d(0-3),不影响状态位
说明:将寄存器f内容的高4位和低4位相交换,d=1结果存入寄存器f中,d=0存入工作寄存器W中。
示例:SWAPF    REG1,0
  指令执行前 REG1=0xA5   
  指令执行后 REG1=0xA5    W=0x5A    

3. 面向位操作类的指令:

位清零指令:BCF    f,b
操作:0→f(b),不影响状态位
说明:将寄存器f的第b位清零
示例:BCF    REG1,7
  指令执行前 REG1=0xC7
  指令执行后 REG1=0x47
位清零指令:BSF    f,b
操作:1→f(b),不影响状态位
说明:将寄存器f的第b位置1
示例:BSF    REG1,7
  指令执行前 REG1=0x0A
  指令执行后 REG1=0x8A
位测试为零跳转指令:BTFSC    f,b
操作:如果f(b)=0则跳,不影响状态位
说明:测试寄存器f的第b位,如果为0,则跳过下一条指令;如果不为零,则逐条执行
示例:HERE    BTFSC    REG,1
      FALSE   GOTO     LOOP
      TRUE     ......
  指令执行前 PC=地址 HERE
  指令执行后 如果REG<1>=0,PC=地址TRUE(指令周期为2)
             如果REG<1>=1,PC=地址 FALSE(指令周期为1)
位测试为1跳转指令:BTFSS    f,b
操作:如果f(b)=1则跳,不影响状态位
说明:测试寄存器f的第b位,如果为1,则跳过下一条指令;如果不为零,则逐条执行
示例:HERE    BTFSS    REG,1
      FALSE   GOTO     LOOP
      TRUE     ......
  指令执行前 PC=地址 HERE
  指令执行后 如果REG<1>=0,PC=地址FALSE(指令周期为1)
             如果REG<1>=1,PC=地址 TRUE(指令周期为2)

4. 面向常数操作和控制操作类指令:

常数加法指令:ADDLW    K
操作:W+K→W,影响状态位:C、DC、Z
说明:将立即数K和工作寄存器W的内容相加,结果存入工作寄存器W中
示例:ADDLW    0x15
  指令执行前 W=0x10
  指令执行后 W=0x25
常数逻辑与指令:ANDLW    K
操作:W∧K→W,影响状态位:Z
说明:将立即数K和工作寄存器W的内容相与,结果存入工作寄存器W中
示例:ANDLW    0x5F
  指令执行前 W=0xA3
  指令执行后 W=0x03
常数逻辑与指令:ANDLW    K
操作:W∧K→W,影响状态位:Z
说明:将立即数K和工作寄存器W的内容相与,结果存入工作寄存器W中
示例:ANDLW    0x5F
  指令执行前 W=0xA3
  指令执行后 W=0x03
子程序调用指令:CALL    K
操作:PC+1→堆栈顶,K→PC(10:0),PCLATCH(4:3)→PC(12:11),不影响状态位
说明:调用子程序。返回地址(PC+1)被压入堆栈,11位立即数地址被装入PC(10:0),PC的高位从PCLATCH装入,指令周期为2。
示例:HERE    CALL    THERE
  指令执行前 PC=地址 HERE
  指令执行后 PC=地址 THERE    堆栈=地址 HERE+1
看门狗定时器清零指令:CLRWDT
操作:0→WDT,0→预分频器
说明:复位看门狗,还将复位WDT的预分频器。状态位TO和PD被置1。
示例:CLRWDT
  指令执行前 WDT计数器=?
  指令执行后 WDT计数器=0x00    WDT预分频器=0    TO=0    PD=1
无条件跳转指令:GOTO    K
操作:K→PC(10:0),PCLATCH(4:3)→PC(12:11),不影响状态位
说明:常数K(地址)置入PC低11位,PC高位装入PCLATCH(4:3),如果程序存储器大于2K,且目标程序位于不同的页面,那么在执行GOTO指令前,PCLATCH必须装入子程序的页号。指令周期为2。
示例:GOTO    THERE
  指令执行后 PC=地址 THERE
常数逻辑或指令:IORLW    K
操作:W∨K→W,影响状态位:Z
说明:将立即数K和工作寄存器W的内容做逻辑或操作,结果存入工作寄存器W中
示例:IORLW    0x35
  指令执行前 W=0x9A
  指令执行后 W=0xBF    Z=0
常数传送指令:MOVLW    K
操作:K→W,不影响状态位
说明:将立即数K送入工作寄存器W中
示例:MOVLW    0x5A
  指令执行后 W=0x5A
中断返回指令:RETFIE
操作:堆栈顶→PC,不影响状态位
说明:从中断返回,并将位于栈顶的返回地址写入PC。指令周期2。
示例:RETFIE
  中断后 PC=堆栈顶TOS    GIE=1
子程序带值返回指令:RETLW    K
操作:K→W,堆栈顶→PC,不影响状态位
说明:将立即数K送到工作寄存器W中,并将位于栈顶的返回地址写入PC,适合查表。指令周期2。
示例:    CALL    TABLE
          ......
TABLE    ADDWF   PC
          RETLW    K1    ;带K1值返回
          RETLW    K2
          ......
          RETLW    Kn    ;带Kn值返回
  指令执行前 W=0x07
  指令执行后 W=K8的值
子程序返回指令:RETURN
操作:堆栈顶→PC,不影响状态位
说明:从子程序返回。执行出栈操作,将位于栈顶的单元内容装入PC。指令周期2。
示例:RETURN
  中断后 PC=堆栈顶TOS
睡眠指令:SLEEP
操作:0→PD1→TD,0→WDT,0→WDT的预分频器(PSA=1时)。影响状态位:PD TD
说明:停止OSC1进入低功耗模式。各端口引脚没有输出。
常数减法指令:SUBLW    K
操作:K-W→W,影响状态位:C、DC、Z
说明:用立即数K减去工作寄存器W的内容,结果存入工作寄存器W中。(该指令是将工作寄存器W的内容求补后与立即数K相加)
示例:SUBLW    0x02
  指令执行前 W=1    C=?    
  指令执行后 W=1    
  状态位     C=1;    结果为正  Z=0
示例:
  指令执行前 W=2    C=?    
  指令执行后 W=0    
  状态位     C=1;    结果为零  Z=1
示例:
  指令执行前 W=3    C=?    
  指令执行后 W=0xFF    
  状态位     C=0;    结果为负  Z=0
(K>W:C=1,Z=0;  K=W:C=1,Z=1;  K<W:C=0,Z=0)
常数逻辑与指令:XORLW    K
操作:W⊕K→W,影响状态位:Z
说明:立即数K和工作寄存器W的内容做逻辑异或,结果存入工作寄存器W中
示例:XORLW    0xAF
  指令执行前 W=0xB5
  指令执行后 W=0x1A
还有2条指令,但为了保持与将来型号的向上兼容性,建议不要使用,这是为了与旧型号PIC16C5X产品代码兼容。
OPTION寄存器装入指令:OPTION
操作:(W)→OPTION,不影响状态位
说明:将工作寄存器W的内容装入到OPTION寄存器。OPTION是可读写的寄存器,用户可对其直接寻址,例如用MOVWF指令。
TRIS寄存器装入指令:TRIS    f
操作:(W)→TRIS寄存器f,不影响状态位
说明:将工作寄存器W的内容装入到TRIS寄存器。TRIS是可读写的寄存器,用户可对其直接寻址。

5. 寻址方式:

指令是由操作码和操作数组成的,操作数是指令的一个重要组成部分,用于指定参与运算的数据或者数据所在的单元地址。所谓寻址方式,就是寻找操作数的方法,就是获取操作数所在地址的方法。PIC16F62X的指令系统中,根据操作数的来源不同,设计了4种寻址方式。

1)立即寻址:指令码中携带着实际操作数(立即数)。
示例:ADDLW 16H ;将立即数16H与W内容相加,结果送W
2)直接寻址:指令码中有寄存器单元的地址
示例:IORWF 26H,0 ;将地址26H的RAM单元的内容与W内容相或,结果送W
3)间接寻址:对映射寄存器INDF的操作
示例:XORWF INDF,1 ;将FSR内容所指向地址的内容与W内容相异或
对INDF的操作就是对间接寻址寄存器FSR所表示的地址所指向的单元的内容进行操作。
4)位寻址:对任意寄存器中的任一比特位直接寻址访问
示例:BSF 05H,4 ;把地址为05H的寄存器单元内的第b4位设置为1。

6. 汇编语言:

所谓汇编语言,就是用助记符来表示二进制代码。单片机仅仅能够识别二进制形式的机器语言程序(机器码程序),但如果直接用机器语言来设计程序,编写起来很繁琐且容易出错,也给程序的阅读、修改、调试等环节带来极大的困难。所以,在开发单片机程序时通常都使用汇编语言。
汇编语言是对机器语言的改进,采用便于人们记忆的一些符号来表示操作码、操作数和地址码等。汇编语言的语句通常与机器语言指令一一对应。单片机并不能识别汇编语言,需要用编译软件将汇编语言编写的程序翻译成机器语言程序,被称为“目标程序”,然后烧写进单片机。
汇编语言的语句格式:
标号: 操作码(指令助记符)    操作数 ; 注释
汇编语言源程序既可以用大写字母书写,也可以用小写字母书写,还可以大小写混用,一个语句行最多允许有225个半角字符。
标号:就是该条指令的符号地址,是在编译时被赋以该指令在程序寄存器中所存放的具体地址。只有那些将被其他语句引用的语句才需要加标号,标号可以单独作为一行。标号最多由32个字母、数字和其他一些字符组成,第一个字符必须是字母或下划线,必须从一行的第一列开始写,后面用空格、制表符或换行符与操作码隔开。标号不能用指令助记符、寄存器代号或其他在系统中已有固定用途的字符串。一个标号在程序中只能定义一次。
操作码:操作码可以是指令系统中的助记符,也可以是用于控制汇编器的伪指令。操作码前面至少保留一个空格,以便于标号区别。
操作数:操作数是操作对象,也就是数据或者地址,可以用常数或符号两种形式表示。常数,可以是二进制、八进制、十进制、十六进制或者字符;符号,可以是在此之前经过定义(或者赋值)的代表数据或地址的标号、字符串。如果操作数有两个,中间要用逗号分开。
注释:注释可有可无,但最好附带注释,便于阅读、交流、修改和调试程序。注释用半角分号与指令部分分开,编译器对该部分不作任何处理。
MPASM的默认进制是十六进制,十六进制数由数字0~9和字母A~F组成。当在程序中采用后缀H表示一个以A~F开头的十六进制数时,则必须在它前面增添一个0作为先导,以便编译器将其与符号名相区分。二进制数要以B为后缀,八进制以Q或O为后缀,十进制数则以D为后缀。字符,要用单引号括住,字符代表的常数就是该字符的ASCII码。

7.伪指令:

所谓伪指令,并不是单片机的真实指令,没有对应的机器码,仅在编译过程中起作用。伪指令,是程序设计人员向编译器发出的控制指令,告诉编译器如何完成汇编过程和一些规定的操作,以及控制编译器的输入、输出和数据定位等。MPASM可以使用的伪指令有十多条。
EQU:符号名赋值伪指令。格式:符号名 EQU  xxH
即给符号名赋予一个特定值或者说是给符号名定义一个数值。格式中的符号名通常是代表寄存器名称或专用常数的一个字符串,xxH通常是一个不大于8bit二进制数的数值。一个符号名一旦由EQU赋值,其值就固定下来了,不能再被重新赋值。符号名应从一行的第一列开始书写,其后至少保留一个空格与EQU隔离。
ORG:程序起始地址定义伪指令。格式:ORG  xxxxH
用于指定该伪指令后面的源程序存放的起始地址,也就是编译后的机器码目标程序在单片机的程序存储器中开始存放的首地址。xxxxH是一个13bit长的地址参数。
END:程序结束伪指令。
END伪指令通知编译器MPASM结束对源程序的编译。一个源程序中必须要有并且只有一条END伪指令,放在整个程序的末尾。

8.程序基本格式:

示例
;TITLE This is......程序标题
;符号名定义和变量定义
INDF      EQU    00H  ;个操作寄存器地址定义,将要用到的寄存器单元地址和位地址
TMR0      EQU    01H  ;用表意性很强的符号名预先定义
PCL      EQU    02H
STATYS   EQU    03H
FSR      EQU    04H
PORTA    EQU    05H
TRISA    EQU    85H
X        EQU    20H  ;对程序所需变量预先进行定义
Y        EQU    21H  ;复位矢量和中断矢量安排(对于PIC16F873)
ORG      0000H       ;地址0000H为复位矢量
GOTO     MAIN        ;跳转到主程序
ORG      0004H       ;地址0004H为中断矢量
GOTO     INT_BODY    ;跳转到中断服务程序
;主程序区
ORG      0005H       ;从0005H开始存放主程序
MAIN     CLRW        ;主程序标号一定要处在0页内
  CALL   SUB
  ......
  GOTO   MAIN        
;子程序和中断服务程序区
SUB      MORLW    01H  ;子程序
  ......
  RETURN             ;子程序返回
INT_BODY             ;中断服务程序
  MOVLW    0FFH
  ......
  RETIE              ;中断服务程序返回
  END                ;程序结束

9.程序基本结构:

程序,按其执行顺序,可分为顺序结构、分支结构、循环结构和子程序结构4种。
1)顺序结构:
计算机执行程序时表现为从头至尾严格按照次序一条语句一条语句地顺序执行,并且每一条语句均被执行一遍。
2)分支结构
3)循环结构:
程序设计中,对某一段程序重复执行多遍。一个循环程序结构包含循环初态设置、循环体和循环控制三部分。循环初态设置就是在循环开始时,指定或定义一个循环变量(可以是循环次数计数器、地址指针等),并且给它设置一个初始值;循环体为要求重复执行的程序段;循环控制就是根据循环结束条件判断是否结束循环。在循环程序中必须给出循环结束条件,否则就成为“死循环”。
4)子程序结构:
实际程序中,常常会遇到一些完全相同的计算和操作,可以编制成标准化的程序段,存储于程序存储器的指定区域,在每次需要时调出使用,这种程序段就称为子程序。
PIC系列单片机编程时,在主程序的适当地方放置CALL指令来实现跳转,在子程序的开头需要使用地址标号,作为子程序的名称,末尾用RETURN或RETLW指令,以便子程序的调用和子程序的返回。在子程序调用子程序时,会遇到参数传递和现场保护问题。
所谓参数传递,就是在调用子程序前,主程序应先把有关参数放到某些约定的存储器单元,进入子程序后就可以从约定的单元取出有关参数加以处理。处理完之后,子程序也应把处理结果送到约定单元。在返回主程序后,主程序可以从这些约定单元获得所需结果。在主程序和子程序之间传递8位参数是,工作寄存器W是理想的选择。
所谓现场保护,就是主程序在运行过程中使用了一些寄存器来存放临时数据(或中间结果),在子程序运行过程中有时也要用到这些寄存器,为了避免对于主程序还有用的临时数据被子程序覆盖,就要设法保护这些临时数据。在执行完子程序返回主程序时,还要恢复这些数据,这成为现场保护。对应PIC单片机,一般是用合理分配寄存器单元的办法,避免子程序的数据和主程序的数据发生冲突,这样可以省略现场保护和现场恢复的过程。

10. 常用程序示例:

1)RAM存储器单元拆分成高和低两个半字节:
MOVF 20H ;将20H单元的内容送入W
ANDLW 0FH ;将W高4位清零,低4位保持不变
MOVWF 21H ;将拆分后的低4位送21H单元
SWAPF 20H,0 ;将20H单元内容高/低半字节换位后送入W
ANDLW 0FH ;将W高4位清零,低4位保持不变
MOVWF 22H ;将拆分后的高4位送22H单元
2)将地址从30H开始的50个单元都填入00H:
COUNT EQU 20H ;指定20H单元作为循环次数计数器(即循环变量)
FSR EQU 04H ;定义FSR寄存器地址为04H
INDF EQU 00H ;定义映射寄存器INDF地址为00H
MOVLW D’50’ ;把计数器初始值50送入W
MOVWF COUNT ;再把50转入计数器(作为循环变量的初始值)
MOVLW 30H ;将30和(起始地址)送入W
MOVWF FSR ;再把30H转入FSR寄存器用作地址指针
NEXT CLRF INDF ;把以FSR内容为地址所指定的单元清零
INCF FSR,1 ;地址指针内容加1,指向下一个单元
DECFSZ COUNT,1 ;计数值减1,结果为0就跳过下一条指令到STOP处
GOTO NEXT ;跳转回去并执行下一条循环
STOP GOTO STOP ;结束循环之后执行该语句,实现停机
3)设置I/O口的输入/输出方向:
MOVLW 0FH ;0000 1111B
MOVWF TRISB ;将W中的0FH写入RB控制寄存器,高4位输出/低4位输入
4)检查寄存器的值是否为零:
MOVF 10H,1 ;F10→F10,结果影响零标记状态位Z
BTFSS STATUS,Z ;F10为零则跳转
GOTO NZ ;Z=0,即F10不为零时转入标号NZ处理程序
...... ;Z=1,即F10=0处理程序
5)比较两个寄存器值的大小:减法运算,根据C判断,结果放入W而不影响寄存器原值
MOVF 8H,0 ;F8→W
SUBWF 9H,0 ;F9-W→W
BTFSC STATUS,Z ;判断是否F8=F9
GOTO F8=F9 ;
BTFSC STATUS,C ;C=0则跳转
GOTO F9>F8 ;C=1相减结果为正,F9>F8
GOTO F9<F8 ;C=0相减结果为负,F9<F8
......
6)循环n次的程序:以F10做计数器,使程序循环8次
COUNT EQU 10H ;定义F10名称为COUNT
......
MOVLW 08H ;
MOVWF COUNT ;循环体
LOOP DECFSZ COUNT,1 ;COUNT减1,结果为零则跳
GOTO LOOP ;结果不为零,继续循环
...... ;结果为零,跳出循环
7)查表程序:利用带值返回指令RETLW K来实现,构成一维数据表
采用带入口参数和出口参数的子程序结构,用数据表构成子程序的主体部分。在子程序的开头安放一条修正程序计数器PC值的指令,来实现子程序内部的跳转。查表时,在主程序中先把地址偏移量存入W,然后将地址偏移量取出并与程序计数器PC的当前值叠加,则程序指针就会指向携带着所需段码的RETLW指令处。由该指令将段码装入W中,向子程序传递参数,然后返回主程序。
PCL EQU 02H ;定义寄存器PCL的地址为02H
STATUS EQU 03H ;定义寄存器STATUS的地址为03H
RPO EQU 06H ;定义RP0比特的位地址为06H
PORTB EQU 06H ;定义寄存器PORTB的地址为06H
TRISB EQU 86H ;定义寄存器TRISB的地址为86H
ORG 0000H ;设置复位矢量
GOTO MAIN ;跳转到主程序
ORG 0005H ;设置主程序起始地址
MAIN BSF STATUS,RP0 ;选择BANK1
CLRF TRISB ;定义PORTB端口各脚全部为输出
BSF STATUS,RP0 ;恢复BANK0
MOVF 20H,0 ;把20H单元的数据送W
ANDLW 0FH ;屏蔽掉高4位后作为查表地址偏移量
CALL CONVERT ;调用数码转换子程序
MOVWF PORTB ;送到PORTB端口显示
STOP GOTO STOP ;停机
;-----------------------------
CONVERT ;子程序名称
ADDWF PCL,1 ;W内容叠加到PC的低8位上
TABLE RETLW 3FH ;”0”的段码
RETLW 06H ;”1”的段码
RETLW 5BH ;”2”的段码
RETLW 4FH ;”3”的段码
RETLW 66H ;”4”的段码
RETLW 6DH ;”5”的段码
RETLW 7DH ;”6”的段码
RETLW 07H ;”7”的段码
RETLW 7FH ;”8”的段码
RETLW 6FH ;”9”的段码
RETLW 77H ;”A”的段码
RETLW 7CH ;”B”的段码
RETLW 39H ;”C”的段码
RETLW 5DH ;”D”的段码
RETLW 79H ;”E”的段码
RETLW 71H ;”F”的段码
END
以上程序是用8位端口PORTB作为共阴极LED数码管的驱动端口,把寄存器单元20H中的数据的低4位送到LED显示。数据表表头为TABLE,当程序跳转到子程序时,便开始执行ADDWF指令。这时,程序计数器PC的当前值已经指向表头,在此基础上再叠加W中的表内地址偏移量,叠加后的PC值指向相应的RETLW指令,使程序跳转到该指令并执行它,执行后便返回主程序,并同时将返回值装入W中。
8)单嵌套延时程序:较短的软件延时
N EQU 20H ;
M EQU 21H ;
;延时0.3ms子程序
DELAY1 MOVLW X ;循环变量初始值X(待定)经W转送N
MOVWF N ;
LOOP DECFSZ N,1 ;N-1送N并判断结果是否为0,若是则跳出循环
GOTO LOOP ;若否,则循环回去
RETURN
9)双嵌套延时程序:较长的软件延时
;延时100ms子程序
DELAY3 MOVLW D’133’ ;外循环变量初始值经W转送M
MOVWF M ;
LOOP1 MOVLW D’251’ ;内循环变量初始值经W转送N
MOVWF N ;
LOOP2 DECFSZ N,1 ;N-1=0? 若是,跳出内层循环
GOTO LOOP2 ;否,循环回去
DECFSZ M,1 ;M-1=0? 若是,跳出循环
GOTO LOOP1 ;否,循环回去
RETURN
10)定时器延时:TMR0使用1/256分频比,4MHz振荡频率下延时65536us
TMR0 EQU 1
......
CLRF TMR0 ;TMR0清0
MOVLW 07H
OPTION ;选择预设倍数1/256→RTCC
LOOP MOVLW 255 ;TMR0计数终值
SUBWF TMR0,0
BTFSS STATUS,Z ;TMR0=255?
GOTO LOOP
......
11)程序跨页跳转和调用程序:主程序放置在页面0内,子程序部分放置页面1内。
页面0的地址范围为0000H~07FFH,页面1的地址范围为0800H~0FFFH。PCLATCH[3]位作为页面选择位。程序较长并且超过2K时,必然会跨页存放。
PCLATCH EQU 0AH ;将符号名PCLATCH定义为0AH(地址0AH)
ORG 0000H ;地址为0的单元专门用作复位矢量
GOTO MAIN ;存放一条到主程序的跳转指令
ORG 0500H ;从页面0的500H单元开始存放主程序
MAIN BSF PCLATCH,3 ;预置页选位,准备选择页面1
CALL SUB ;调用子程序,引起程序跳转
LOOP ...... ;从子程序返回后执行的第一条指令
;-------------------------------
ORG 0900H ;从页面1的900H单元开始存放
SUB MOVLW ;子程序
......
RETURN ;返回到位于页面0的主程序的LOOP处
END
在执行子程序的返回指令RETURN之前,不必理会页选位PCLATCH[3],这是因为在发生跳转时,程序计数器PC的值先被压入堆栈中保留,然后才用来自PCLATCH的页选位和来自CALL指令的11位地址吗填充。在子程序执行完毕返回时,因为堆栈的宽度是13位的,从堆栈中弹出PC原值,从而可以使程序回到原页面中。
12)散转程序:程序同时有多个分支
LOOP CLRF FLAG0
MOVF FLAG1,0
ADDWF PCL,1
GOTO INF0 ;转去运行INF0程序段
GOTO INF1 ;转去运行INF1程序段
GOTO INF2 ;转去运行INF2程序段
GOTO INF3 ;转去运行INF3程序段
GOTO INF4 ;转去运行INF4程序段
GOTO INF5 ;转去运行INF5程序段
GOTO INF6 ;转去运行INF6程序段
GOTO INF7 ;转去运行INF7程序段
13)二进制转换为BCD数的程序:
;入口参数:S1、S0为输入的16位二进制数
;出口参数:R2、R1和R0为转换后的5位BCD数
;****16位二进制转换为BCD数子程序****
INDF EQU 00H ;定义INDF寄存器地址为00H
FSR EQU 04H ;定义FSR寄存器地址为04H
COUNT EQU 20H ;移位次数寄存器
S0 EQU 21H ;二进制的低8字节
S1 EQU 22H ;二进制的高8字节
R0 EQU 23H ;存放BCD数的第5位数
R1 EQU 24H ;存放BCD数的第4、3两位
R2 EQU 25H ;存放BCD数的第2、1两位
TEMP EQU 26H ;用来暂存比较时用的寄存器
MOVLW 10H ;
MOVWF COUNT ;把十进制数16送往移位次数寄存器
BINTOBCD MOVLW D’16’ ;
MOVWF COUNTE ;
BCF STATUS,0 ;清进位标志位C
BCF STATUS,0 ;清进位标志位C
CLRF R2 ;清R2寄存器
CLRF R1 ;清R1寄存器
CLRF R0 ;清R0寄存器
LOOPC RLF S0 ;左移S0寄存器
RLF S1 ;左移S1寄存器
RLF R2 ;左移S2寄存器
RLF R1 ;左移S1寄存器
RLF R0 ;左移S0寄存器
DECFSZ COUNT,1 ;16位二进制是否移位完
GOTO ADJDEC ;未完,转为调整子程序
RETURN
ADJDEC MOVLW R2
MOVWF FSR ;将R2寄存器的地址存入FSR
CALL ADJBCD ;调整R2
MOVLW R1
MOVWF FSR ;将R1寄存器的地址存入FSR
CALL ADJBCD ;调整R1
MOVLW R0
MOVWF FSR ;将R0寄存器的地址存入FSR
CALL ADJBCD ;调整R0
GOTO LOOPC
ADJBCD MOVLW 03H
ADDWF INDF,0 ;LSD加3
MOVWF TEMP
BTFSC TEMP,3 ;结果>7?
MOVWF INDF ;是,结果存INDF所对应的寄存器地址;否,跳
MOVLW 30H
ADDWF INDF,0 ;MSD加3
MOVWF TEMP
BCTFSC TEMP,7 ;结果>7?
MOVWF INDF ;是,结果存INDF所对应的寄存器地址;否,跳
RETURN
END
14)BCD数转换为二进制数模块:
;入口参数:R2、R1和R0为5位BCD数
;出口参数:S1、S0为输出的16位二进制数,S0放高位,S1放低位
;****BCD数转换为16位二进制子程序****
INCLUDE <P16F627.INC>
COUNT EQU 20H ;移位次数寄存器
S0 EQU 21H ;二进制的高8字节
S1 EQU 22H ;二进制的低8字节
R0 EQU 23H ;存放BCD数的第5位数
R1 EQU 24H ;存放BCD数的第4、3两位
R2 EQU 25H ;存放BCD数的第2、1两位
ORG 25H
BCDTOB MOVLW 10H ;
MOVWF COUNT ;把十进制数16送往移位次数寄存器
CLRF S0
CLRF S1
LOOPC BCF STATUS,C
RLF R0 ;左移S0寄存器
RLF R1 ;左移S1寄存器
RLF R2 ;左移S2寄存器
RLF S0 ;左移S0寄存器
RLF S1 ;左移S1寄存器
DECFSZ COUNT,1 ;16位二进制是否移位完成
GOTO ADJDEC ;未完,转为调整子程序
RETURN
ADJDEC MOVLW R2
MOVWF FSR ;将R2寄存器的地址存入FSR
CALL ADJBIN ;调整R2
MOVLW R1
MOVWF FSR ;将R1寄存器的地址存入FSR
CALL ADJBIN ;调整R1
MOVLW R0
CALL ADJBIN ;调整R0
GOTO LOOPC
ADJBIN MOVLW 03H
BTFSC INDF,3 ;IF>7?
SUBWF INDF ;是,结果存INDF所对应的寄存器地址;否,跳
MOVLW 30H
BCTFSC INDF,7 ;结果>7?
SUBWF INDF ;是,结果存INDF所对应的寄存器地址;否,跳
RETURN
END
15)两个16位数加运算模块:
;入口参数:ACCC中为被加数的高字节ACCCH和低字节ACCCL
;入口参数:ACCA中为加数的高字节ACCAH和低字节ACCAL
;出口参数:寄存器ACCC为和的高/低字节
;----无符号双精度数加法子程序----
ADD16 MOVF ACCAL,W
ADDWF ACCCL ;(ACCCL)+(ACCAL)→(ACCCL)
BTFSC STATUS,C
INCF ACCCH ;(ACCCH)+1→(ACCCH)
MOVF ACCAH,W
ADDWF ACCCH ;(ACCCH)+(ACCAH)→(ACCCH)
RETURN
16)两个16位数减运算模块:
;入口参数:ACCC中为被减数的高字节ACCCH和低字节ACCCL
;入口参数:ACCB中为减数的高字节ACCBH和低字节ACCBL
;出口参数:寄存器ACCC为差的高/低字节,进位C=0表示被减数小于减数,C=0则相反
;----无符号双精度数减法子程序----
SUB16 MOVF ACCBL,W
SUBWF ACCCL ;(ACCCL)-(ACCBL)→(ACCCL)
BTFSC STATUS,C
DECF ACCCH ;有借位(C=0)(ACCCH)-1→(ACCCH)
MOVF ACCBH,W
SUBWF ACCCH ;(ACCCH)-(ACCBH)→(ACCCH)
RETURN
17)两个16位数相乘模块:
;入口参数:ACCA中为被乘数的高字节ACCAH和低字节ACCAL
;入口参数:ACCB中为乘数的高字节ACCBH和低字节ACCBL
;出口参数:乘积从高到低存放在ACCCH、ACCCL、ACCDH、ACCDL中
;----无符号双精度数乘法子程序----
MU16 MOVLW 10H
MOVWF CNT_MU
CLRF ACCCH
CLRF ACCCL
CLRF ACCDH
CLRF ACCDL
MLOOP RRF ACCBH,1 ;将乘数ACCB的最低位移入进位位C
RRF ACCBL,1
BTFSC STATUS,0 ;C=1,加被乘数ACCA至部分积ACCC
CALL DADD
RRF ACCCH,1 ;部分积带进位位右移1位
RRF ACCCL,1
RRF ACCDH,1
RRF ACCDL,1
DECFSZ CNT_MU,1
GOTO MLOOP
RETURN
;双精度加法(ACCA+ACCC=ACCC)
DADD MOVF ACCAL,0
ADDWF ACCCL,1 ;(ACCAL)+(ACCCL)→(ACCCL)
BTFSC STATUS,0
INCF ACCCH,1
MOVF ACCAH,0
ADDWF ACCC,1 ;(ACCAH)+(ACCCH)→(ACCCH)
RETURN
18)两个16位数相除模块:
;入口参数:BCCB中为被除数的高字节BCCBH和低字节BCCBL
;入口参数:BCCA中为乘数的高字节BCCAH和低字节BCCAL
;出口参数:商存放在BCCB,余数放在BCCC中
;----无符号双精度数除法子程序----
DIVS CALL SETUP1 ;被除数放入BCCD
CLRF BCCCH
CLRF BCCCL
DLOOP BCF STATUS,C
RLF BCCDL,1 ;被除数低位左移1位
RLF BCCDH,1 ;被除数高位左移1位
RLF BCCCL,1 ;余数低位左移1位
RLF BCCCH,1 ;余数高位左移1位
MOVF BCCAH,0 ;比较双精度数大小
SUBWF BCCCH,0
BTFSS STATUS,C ;余数高位大于等于除数高位,C=1,跳过下一条
GOTO NOCHK ;余数高位小于除数高位,返回
MOVF BCCAL,0 ;比较余数的低位和除数的低位
SUBWF BCCCL,0
NOCHK BTFSS STATUS,C ;余数低位大于等于除数低位,结果左移
GOTO NOGO
MOVF BCCAL,0
SUBWF BCCCL,1
BTFSS STATUS,C ;余数低位大于等于除数低位,执行下一条
DECF BCCCH,1 ;余数低位小于除数低位,余数高位减1
MOVF BCCAH,0
SUBWF BCCCH,1
BSF STATUS,C ;够减,进位位置1,左移进入结果
NOGO RLF BCCBL,1 ;运算结果左移
RLF BCCBH,1
DECFSZ CNT_DIS,1
GOTO DLOOP
CLRWDT
RETURN
SETUP1 MOVLW 10H
MOVWF CNT_DIS
MOVF BCCBH,0 ;被除数(BCCB)→(BCCD),BCCD放被除数
MOVWF BCCDH
MOVF BCCBH,0
MOVWF BCCDH
MOVF ACCAH,0
CLRF BCCBH
CLRF BCCBL
RETURN

Copyright@dwenzhao.cn All Rights Reserved   备案号:粤ICP备15026949号
联系邮箱:dwenzhao@163.com  QQ:1608288659