PIC16F877单片机运算子程序
1 PIC16F877汇编语言程序主体框架
以下是一个典型的程序结构:
;***************程序说明区*******************
LIST p=16f877 ;指定微控制器型号和文件输出格式
INCLUDE p16f877.inc ;读入MPLAB提供的定义文件P16F877.INC
;***片内RAM常用资源、变量定义和相应的说明*********
ACCALO EQU 20 ;存放加数或减数低8位
ACCAHI EQU 21 ;存放加数或减数高8位
ACCBLO EQU 23 ;存放被加数或被减数低8位
ACCBHI EQU 24 ;存放被加数或被减数高8位
S_W EQU 25 ;栈存W寄存器值
S_STATUS EQU 26 ;栈存STATUS寄存器值
;****************芯片复位矢量*******************
ORG 0X0000 ;由于PIC16F877芯片复位矢量在0000h单
;元,所以常在0000h单元处放置一条跳转
;指令,使单片机复位后能跳过中断矢量,
;直接执行主程序
START GOTO MAIN
;******************中断矢量**********************
ORG 0X0004 ;由于PIC16F877的中断矢量为0004h,所以
;当中断开放时, 需在此处加入中断程序,
;使单片机能在中断到来时及时进入相应的
;中断服务程序。为了可靠起见,如果单片
;机不使用中断,则常常在该中断矢量处放
;置RETFIE指令,可以使单片机不会因
;干扰产生误中断而导致程序跑飞
CALL PUSH ;调用保护现场子程序
BTFSS PIR1,ADIF
CALL AD ;若AD中断到,则执行中断服务程序
…….. ;此处可放多个中断子程序,并以软件安排
;中断优先级
CALL POP ;恢复中断现场
RETFIE ;中断返回
;****************主程序区*****************
ORG 0X0100 ;将主程序、子程序和中断服务程序等存放
;在0100h单元之后,在中断矢量和主程序
;区之间预留一些存储单元,以便写入判
;跳指令和一些必要的现场保护程序。此外
;用户也可以根据实际需要,使主程序从其
;它地址开始存放
MAIN BSF STATUS,RP0 ;选择存储体1
MOVLW 0XFF ;定义RA口为输入端口
MOVWF TRISA
BCF STATUS,RP0 ;选择存储体0
MOVLW 0X04 ;初值化ACCALO
MOVWF ACCALO
CALL DX ;调用DX子程序
LOOP1 …… ;任务1
…… ;任务2
:
:
:
GOTO LOOP1 ;反复执行任务一和任务二等
;***************子程序区*********************
DX MOVF ACCALO,0 ;ACCB和ACCA低半字节相加
ADDWF ACCBLO
RETURN ;子程序返回
;****************************************
PUSH MOVWF S_W ;保护W寄存器
MOVF STATUS,0 ;保护STATUS寄存器
MOVWF S_STATUS
RETURN ;子程序返回
;****************************************
POP MOVF S_STATUS,0 ;恢复STATUS寄存器
MOVWF STATUS
MOVF S_W,0 ;恢复W寄存器
RETURN ;子程序返回
;****************中断服务子程序区************************
AD BCF PIR1,ADIF ;清AD中断标志
…… ;中断服务主体程序
RETURN ;子程序返回
END
2 四则运算子程序
2.1 16×16位定点数加、减法子程序
以下子程序实现2个16×16位有符号数加、减运算,其和或差用一个16位数表示。在子程序中,减法是通过对减数求补后再与被减数相加来实现的。因此,当程序从D_sub进入子程序时为减法,当从D_add进入子程序时为加法。
子程序的入口条件和出口条件如下:
入口条件:16位被加数/被减数存放在ACCBHI、ACCBLO中;
16位加数/减数存放在ACCAHI、ACCALO中;
出口条件:16位和/差存放在ACCBHI和ACCBLO中。
以下为16×16位有符号数加、减法子程序。
注意:在以下注释程序中均以ACCA代替ACCAHI、ACCALO两个字节,以ACCB代替ACCBHI、ACCBLO两个字节。
LIST p=16f877
INCLUDE p16f877.inc
ACCALO EQU 20 ;存放加数或减数低8位
ACCAHI EQU 21 ;存放加数或减数高8位
ACCBLO EQU 23 ;存放被加数或被减数低8位
ACCBHI EQU 24 ;存放被加数或被减数高8位
ORG 0X0000
START GOTO MAIN
;***双字节减法子程序,入口地址ACCB-ACCA,出口地址ACCB***
D_sub CALL NEG_A ;求ACCA的补码
;***双字节加法子程序,入口地址ACCB+ACCA,出口地址ACCB***
D_add MOVF ACCALO,0 ;ACCB和ACCA低半字节相加
ADDWF ACCBLO
BTFSC STATUS,C ;有进位否?
INCF ACCBHI ;有,ACCB高字节加1,再加ACCAHI
MOVF ACCAHI,0 ;ACCA、ACCB高半字节相加
ADDWF ACCBHI
RETURN ;子程序返回
;************** ACCA取补子程序*****************
NEG_A COMF ACCALO ;ACCALO取反加1
INCF ACCALO
BTFSC STATUS,Z ;低8位有进位吗?
DECF ACCAHI ;有,ACCAHI减1,再取反
COMF ACCAHI ;否则ACCAHI直接取反
RETURN ;子程序返回
【校验举例1】 19531+(-16594)=2937(十进制)
化为十六进制数:4C46H+BF2EH
结果:0B79H(十六进制)
【校验举例2】 26222+3000=29222(十进制)
化为十六进制数: 666EH+0BB8H
结果:7226H(十六进制)
【例程】
MAIN MOVLW 0X6E ;被加数666EH送ACCB
MOVWF ACCBLO
MOVLW 0X66
MOVWF ACCBHI
MOVLW 0XB8 ;加数BB8H送ACCA
MOVWF ACCALO
MOVLW 0X0B
MOVWF ACCAHI
CALL D_add ;调用双字节加法子程序,求和
END
2.2 16×16位定点数乘法子程序
子程序采用部分积右移加法实现乘法运算。乘数和被乘数分别为16位二进制有符号数(均采用补码表示,第16位为符号位),积为32位二进制有符号数,第32位为符号位。子程序的入口条件和出口条件如下:
入口条件:被乘数存放在ACCBHI和ACCBLO单元中,
乘数存放在ACCAHI和ACCALO单元中。
出口条件:积存放在ACCBHI、ACCBLO、ACCCHI和ACCCLO单元中,ACCB为高16位,ACCC为低16位。
以下为本子程序的程序清单:
LIST p=16f877
INCLUDE p16f877.inc
ACCALO EQU 20 ;存放乘数低8位
ACCAHI EQU 21 ;存放乘数高8位
ACCBLO EQU 23 ;存放被乘数低8位和乘积第16~23位
ACCBHI EQU 24 ;存放被乘数高8位和乘积第24~31位
ACCCLO EQU 26 ;存放乘积低8位
ACCCHI EQU 27 ;存放乘积高8位
ACCDLO EQU 28 ;临时寄存器
ACCDHI EQU 29 ;临时寄存器
TEMP EQU 2A ;临时寄存器
SIGN EQU 2B ;存放乘积的符号
ORG 0X0000
START GOTO MAIN
;***16×16位乘法子程序,入口地址ACCB×ACCA,出口地址ACCB和ACCC ***
ORG 0X0100
D_mpy CALL S_SIGN ;求取乘积的符号,并对负数取补
CALL SETUP ;调用子程序,将ACCB的值送ACCD
INCF TEMP
CLRF ACCCHI ;清ACCC
CLRF ACCCLO
MLOOP BCF STATUS,C ;清进位位
RRF ACCDHI ;ACCD右移
RRF ACCDLO
BTFSC STATUS,C ;判断是否需要相加
CALL D_add ;加乘数至ACCB,见加法程序
BCF STATUS,C ;清进位位
RRF ACCBHI ;右移部分乘积
RRF ACCBLO
RRF ACCCHI
RRF ACCCLO
DECFSZ TEMP ;乘法完成否?
GOTO MLOOP ;否,继续求乘积
BTFSS SIGN,7 ;是,确定乘积的符号
GOTO OVER ;为正,乘法结束
COMF ACCCLO ;为负,乘积取补
INCF ACCCLO
BTFSC STATUS,Z
DECF ACCCHI
COMF ACCCHI
BTFSC STATUS,Z
NEG_B DECF ACCBLO ;
COMF ACCBLO
BTFSC STATUS,Z
DECF ACCBHI
COMF ACCBHI
OVER RETURN ;子程序返回
;****************************************
SETUP MOVLW .15 ;初始化TEMP寄存器
MOVWF TEMP
MOVF ACCBHI,0 ;ACCB送ACCD
MOVWF ACCDHI
MOVF ACCBLO,0
MOVWF ACCDLO
CLRF ACCBHI ;清ACCB
CLRF ACCBLO
RETURN ;子程序返回
;*******乘法运算确定结果符号判断子程序******
S_SIGN MOVF ACCAHI,0 ;ACCAHI异或ACCBHI,结果送SIGN单元
XORWF ACCBHI,0
MOVWF SIGN
BTFSS ACCBHI,7 ;ACCB为负吗?
GOTO CHEK_A ;否,检查ACCA
CALL NEG_B ;是,求取ACCB绝对值
CHEK_A BTFSC ACCAHI,7 ;ACCA为负吗?
CALL NEG_A ;ACCA为负,求取ACCA绝对值,
;见双字节加法程序
RETURN ;ACCA和ACCB均为正,返回
【校验举例1】:-24555×(-7391)=181486005(十进制)
化为十六进制数:A015H×E321H
结果:0AD141B5H(十六进制)
【校验举例2】 16405×13089=214725045(十进制)
化为十六进制数:4015H×3321H
结果:0CCC71B5H(十六进制)
【例程】
MAIN MOVLW 0X15 ;被乘数4015H送ACCB
MOVWF ACCBLO
MOVLW 0X40
MOVWF ACCBHI
MOVLW 0X21 ;乘数3321H送ACCA
MOVWF ACCALO
MOVLW 0X33
MOVWF ACCAHI
CALL D_mpy ;调用双字节乘法子程序,求积
END
2.3 16×16位定点数除法子程序
子程序采用反复的减法算法,除数和被除数分别为16位二进制有符号数(均采用补码表示,第16位为符号位),商为16位二进制有符号数,第16位为符号位。子程序的入口条件和出口条件如下:
入口条件:被除数存放在ACCBHI、ACCBLO单元中;
除数存放在ACCAHI、ACCALO单元中。
出口条件:商存放在ACCBHI、ACCBLO单元中;
余数存放在ACCCHI、ACCCLO单元中。
LIST p=16f877
INCLUDE p16f877.inc
ACCALO EQU 20 ;存放除数低8位
ACCAHI EQU 21 ;存放除数高8位
ACCBLO EQU 22 ;存放被除数和商的低8位
ACCBHI EQU 23 ;存放被除数和商的高8位
ACCCLO EQU 24 ;存放余数低8位
ACCCHI EQU 25 ;存放余数高8位
ACCDLO EQU 26 ;临时寄存器
ACCDHI EQU 27 ;临时寄存器
TEMP EQU 28 ;临时寄存器
SIGN EQU 29 ;存放商的符号
ORG 0X0000
START GOTO MAIN
;***16×16位数除法子程序,入口地址ACCB /ACCA,出口地址ACCB ***
ORG 0X0100
D_div CALL S_SIGN ;确定商的符号,并将负数取补
CALL SETUP ;初始化TEMP,将被除数移至ACCD,
;(SETUP子程序请参见16×16位定点数
;乘法子程序SETUP)
INCF TEMP
CLRF ACCCHI ;清余数寄存器
CLRF ACCCLO
DLOOP BCF STATUS,C ;清进位位
RLF ACCDLO ;被除数、余数左移1位
RLF ACCDHI
RLF ACCCLO
RLF ACCCHI
MOVF ACCAHI,0 ;ACCCHI-ACCAHI
SUBWF ACCCHI,0
BTFSS STATUS,Z ;ACCCHI=ACCAHI?
GOTO NOCHK
MOVF ACCALO,0 ;是,ACCCLO-ACCALO
SUBWF ACCCLO,0
NOCHK BTFSS STATUS,C ;ACCC>ACCA?
GOTO NOGO
MOVF ACCALO,0 ;是,余数减除数
SUBWF ACCCLO
BTFSS STATUS,C
DECF ACCCHI
MOVF ACCAHI,0
SUBWF ACCCHI
BSF STATUS,C ;置进位位
NOGO RLF ACCBLO ;商左移1位
RLF ACCBHI
DECFSZ TEMP ;循环完毕?
GOTO DLOOP
BTFSS SIGN,7 ;是,确定商的符号
GOTO DIVOVER ;为正,除法结束,跳转到结束行
COMF ACCCLO ;为负,商和余数分别取补
INCF ACCCLO
BTFSC STATUS,Z
DECF ACCCHI
COMF ACCCHI
CALL NEG_B ;见乘法程序中间NEG_B
DIVOVER RETURN ;子程序返回
;************除法运算确定结果符号子程序*******************
S_SIGN MOVF ACCAHI,0 ;ACCAHI异或ACCBHI,结果送SIGN单元
XORWF ACCBHI,0
MOVWF SIGN
BTFSS ACCBHI,7 ;ACCB为负?
GOTO CHEK_A ;否,检查ACCA
COMF ACCBLO ;是,ACCB取补
INCF ACCBLO
BTFSC STATUS,Z
DECF ACCBHI
COMF ACCBHI
CHEK_A BTFSC ACCAHI,7 ;ACCA为负?
CALL NEG_A ;ACCA为负,取补(NEG_A子程序请参见
;16×16位定点数乘法子程序NEG_A)
RETURN ;ACCA和ACCB均为负,返回
【校验举例1】 -23775÷(-240)=99.0625(十进制)
化为十六进制数:A321H÷FF10H;
结果:(商)0063H,(余数)000FH(十六进制)。
【校验举例2】 769÷3856=0.199429(十进制)
化为十六进制数:0301H÷0F10H;
结果:(商)0000H,(余数)0301H(十六进制)。
【例程】
MAIN MOVLW 0X01 ;被除数0301H送ACCB
MOVWF ACCBLO
MOVLW 0X03
MOVWF ACCBHI
MOVLW 0X10 ;除数0F10H送ACCA
MOVWF ACCALO
MOVLW 0X0F
MOVWF ACCAHI
CALL D_div ;调用双字节除法子程序,求商
END
3 3字节浮点四则运算子程序
3.1 浮点数加(减)法子程序
以下为浮点加(减)运算例程:
LIST p=16f877
INCLUDE p16f877.inc
ACCALO EQU 20 ;存放加数或减数的尾数
ACCAHI EQU 21
EXPA EQU 22 ;存放加数或减数阶码
ACCBLO EQU 23 ;存放被加数或被减数尾数以及和或差
ACCBHI EQU 24
EXPB EQU 25 ;存放被加数或被减数阶码
ACCCLO EQU 26 ;临时寄存器
ACCCHI EQU 27 ;临时寄存器
ACCDLO EQU 28 ;临时寄存器
ACCDHI EQU 29 ;临时寄存器
TEMP EQU 2A ;临时寄存器
TEMP1 EQU 30 ;临时寄存器
TIMES EQU 31 ;临时寄存器
ORG 0X000
START GOTO MAIN
ORG 0X0100
;**************浮点减法子程序****************
F_sub CALL NEG_A ;求ACCA的补码,将减法转换为补码加法
;***********浮点加法子程序**************
F_add CALL SUBADJ ;调子程序判断EXPB和EXPA的大小
BTFSC STATUS,Z ;参与运算的两个数阶码相等?
GOTO PADD ;是,求尾数的和
BTFSC STATUS,C ;EXPB>EXPA?
CALL F_swap ;是,ACCB与ACCA互换
MOVF EXPA,0 ;否,求取两者的差值
SUBWF EXPB
SCLOOP CALL SHFTSR ;ACCB右移规格化
INCFSZ EXPB ;EXPB=EXPA?
GOTO SCLOOP ;否,继续右移
MOVF EXPA,0 ;是,存和(差)的阶码
MOVWF EXPB
PADD MOVF ACCAHI,0 ;ACCAHI或ACCBHI
IORWF ACCBHI,0
MOVWF SIGN ;存于SIGN寄存器
MOVF ACCBHI,0 ;暂存ACCBHI
MOVWF EXPA
CALL D_add ;尾数相加
BTFSS SIGN,7 ;ACCA和ACCB有负数?
BTFSC ACCBHI,7 ;否,把和的最高位和次高位同时进位?
GOTO ADD2 ;否,转ADD2
BTFSS ACCAHI,7 ;ACCA为负吗?
GOTO ADD3 ;ACCA和ACCB不同时为负,转ADD3
BTFSS EXPA,7 ;是,ACCB为负吗?
GOTO ADD3
BSF STATUS,C ;ACCA和ACCB同为负,带负号右移
RRF ACCBHI
RRF ACCBLO
INCF EXPB
ADD3 CLRF ACCCHI ;和(差)规格化
CLRF ACCCLO
CALL F_norm
RETURN ;子程序返回
ADD2 BCF STATUS,C ;最高位次高位不同时进位,ACCB右移
INCF EXPB
GOTO SHFTR
SHFTSR BCF STATUS,C ;ACCB带符号右移子程序
BTFSC ACCBHI,7
BSF STATUS,C
SHFTR RRF ACCBHI
RRF ACCBLO
RETURN ;子程序返回
;********* ACCB、ACCA互换子程序************
F_swap MOVF ACCAHI,0 ;ACCAHI、ACCBHI互换
MOVWF TEMP
MOVF ACCBHI,0
MOVWF ACCAHI
MOVF TEMP,0
MOVWF ACCBHI
MOVF ACCALO,0 ;ACCALO、ACCBLO互换
MOVWF TEMP
MOVF ACCBLO,0
MOVWF ACCALO
MOVF TEMP,0
MOVWF ACCBLO
MOVF EXPA,0 ;EXPA、EXPB互换
MOVWF TEMP
MOVF EXPB,0
MOVWF EXPA
MOVF TEMP,0
MOVWF EXPB
RETURN
;*************比较EXPB、EXPA大小子程序*************
SUBADJ MOVF EXPA,0 ;EXPA异或EXPB,结果送C_DIV
XORWF EXPB,0
MOVWF C_DIV
MOVF EXPA,0 ;EXPB-EXPA
SUBWF EXPB,0
BTFSS C_DIV,7 ;EXPA和EXPB同号?
RETURN ;是,进位位的值真确反映两者的大小,返回
BTFSS STATUS,C ;否,进位位的值取反
GOTO CHANGEC
BCF STATUS,C
RETURN
CHANGEC BSF STATUS,C
RETURN
;***********浮点数规格化子程序****************
F_norm MOVF ACCBHI ;ACCB=0?
BTFSS STATUS,Z
GOTO C_norm
MOVF ACCBLO
BTFSC STATUS,Z
RETURN ;是,不需规格化,返回
C_norm BTFSC ACCBHI,7 ;否。ACCB为负?
GOTO C_norm2
C_norm1 BTFSC ACCBHI,6 ;为正。规格化完毕?
RETURN ;ACCBHI.6=1,规格化结束
CALL SHFTSL ;否。ACCB左移
DECF EXPB ;EXPB减1
GOTO C_norm1 ;重新判断规格化完毕否?
C_norm2 BTFSS ACCBHI,6 ;ACCB为负。规格化完毕否?
RETURN ;ACCBHI.6=0,规格化结束
BCF STATUS,C
CALL SHFTSL ;否,ACCB左移
BSF ACCBHI,7 ;加符号
DECF EXPB ;EXPB减1
GOTO C_norm2 ;重新判断规格化完毕否?
SHFTSL BCF STATUS ,C ;ACCB左移子程序
RLF ACCCLO
RLF ACCCHI
RLF ACCBLO
RLF ACCBHI
RETURN
【校验举例1】 0.0019531+(-0.00016594)=0.00178716
化为十六进制数:4000F8+A900F4
结果:7520F7
【校验举例2】 0.26222+3.5025=3.76478
化为十六进制数: 4321FF+701502
结果:787902
【例程】
MAIN MOVLW 0X21 ;被加数的尾数4321H送ACCB
MOVWF ACCBLO
MOVLW 0X43
MOVWF ACCBHI
MOVLW 0XFF ;被加数的阶码FFH送EXPB
MOVWF EXPB
MOVLW 0X15 ;加数尾数7015H送ACCA
MOVWF ACCALO
MOVLW 0X70
MOVWF ACCAHI
MOVLW 0X02 ;加数阶码送EXPA
MOVWF EXPA
CALL F_add ;调用浮点数加法子程序,求和
END
3.2 浮点数乘法子程序
以下为浮点数乘法的程序清单。
LIST p=16f877
INCLUDE p16f877.inc
ACCALO EQU 20 ;存放乘数尾数
ACCAHI EQU 21
EXPA EQU 22 ;存放乘数阶码
ACCBLO EQU 23 ;存放被乘数尾数和乘积高16位
ACCBHI EQU 24
EXPB EQU 25 ;存放被乘数阶码
ACCCLO EQU 26 ;存放乘积低16位
ACCCHI EQU 27
ACCDLO EQU 28 ;临时寄存器
ACCDHI EQU 29 ;临时寄存器
TEMP EQU 2A ;临时寄存器
TEMP1 EQU 30 ;临时寄存器
TIMES EQU 31 ;临时寄存器
SIGN EQU 2B ;存放乘积符号
COUNT EQU 2F ;临时寄存器
ACCEHI EQU 30 ;临时寄存器
ACCELO EQU 31 ;临时寄存器
ORG 0X0000
START GOTO MAIN
ORG 0X0100
;***浮点乘法子程序,入口地址(ACCB、EXPB)×(ACCA、EXPA),出口地址ACCB、EXPB ***
F_mpy CALL S_SIGN ;求取乘积的符号,并对负数取补
CALL SETUP ;调用子程序将ACCB的值送ACCD
CLRF ACCCHI ;清ACCC
CLRF ACCCLO
MLOOP BCF STATUS,C ;清进位位
RRF ACCDHI ;ACCD右移
RRF ACCDLO
BTFSC STATUS,C ;判断是否需要相加
CALL D_add ;加乘数至ACCB
BCF STATUS,C ;清进位位
RRF ACCBHI ;右移部分乘积
RRF ACCBLO
RRF ACCCHI
RRF ACCCLO
DECFSZ TEMP ;乘法完成否?
GOTO MLOOP ;否,继续循环
MOVF EXPA,0 ;是,乘数与被乘数阶码相加,得积的阶码
ADDWF EXPB
MOVF ACCBHI ;ACCBHI=0?
BTFSS STATUS,Z
GOTO FINUP ;否,转FINUP
MOVF ACCBLO ;ACCB=0?
BTFSS STATUS ,Z
GOTO SHFT08 ;否,只有ACCBHI=0,转SHFT08
MOVF ACCCHI,0 ;ACCB=0,将乘积左移15位
MOVWF ACCBHI
MOVF ACCCLO,0
MOVWF ACCBLO
BCF STATUS,C
RRF ACCBHI
RRF ACCBLO
MOVLW .15 ;乘积阶码减15(十进制数)
SUBWF EXPB
GOTO FINUP
SHFT08 MOVF ACCBLO,0 ;只有ACCBHI=0,乘积左移7位
MOVWF ACCBHI
MOVF ACCCHI,0
MOVWF ACCBLO
BCF STATUS,C
RRF ACCBHI
RRF ACCBLO
MOVLW .7 ;乘积阶码减7
SUBWF EXPB
FINUP CALL F_norm ;对乘积进行规格化
BTFSS SIGN,7 ;确定乘积的符号
GOTO OVER ;为正,乘法结束
COMF ACCCLO ;为负,乘积取补
INCF ACCCLO
BTFSC STATUS,Z
DECF ACCCHI
COMF ACCCHI
BTFSC STATUS,Z
NEG_B DECF ACCBLO
COMF ACCBLO
BTFSC STATUS,Z
DECF ACCBHI
COMF ACCBHI
OVER RETURN ;乘法结束,子程序返回
;********浮点乘除法运算确定结果符号子程序***********
S_SIGN MOVF ACCAHI,0 ;ACCAHI异或ACCBHI,结果送SIGN
XORWF ACCBHI,0
MOVWF SIGN
BTFSS ACCBHI,7 ;ACCB为负?
GOTO CHEK_A ;否,检查ACCA
COMF ACCBLO ;是,ACCB取补
INCF ACCBLO
BTFSC STATUS,Z
DECF ACCBHI
COMF ACCBHI
CHEK_A BTFSC ACCAHI,7 ;ACCA为负?
CALL NEG_A ;ACCA取补
RETURN ;返回
;*********浮点运算结果规格化子程序*************
F_norm MOVF ACCBHI ;ACCB=0?
BTFSS STATUS,Z
GOTO C_norm
MOVF ACCBLO
BTFSC STATUS,Z
RETURN ;是,不需规格化,返回
C_norm BTFSC ACCBHI,7 ;否。ACCB为负?
GOTO C_norm2
C_norm1 BTFSC ACCBHI,6 ;为正。规格化完毕?
RETURN ;ACCBHI.6=1,规格化结束
CALL SHFTSL ;否。ACCB左移
DECF EXPB ;EXPB减1
GOTO C_norm1 ;重新判断规格化完毕否?
C_norm2 BTFSS ACCBHI,6 ;ACCB为负。规格化完毕否?
RETURN ;ACCBHI.6=0,规格化结束
BCF STATUS,C
CALL SHFTSL ;否,ACCB左移
BSF ACCBHI,7 ;加符号
DECF EXPB ;EXPB减1
GOTO C_norm2 ;重新判断规格化完毕否?
SHFTSL BCF STATUS ,C ;ACCB左移子程序
RLF ACCCLO
RLF ACCCHI
RLF ACCBLO
RLF ACCBHI
RETURN
【校验举例1】 0.0019531×(-0.00016594)=-0.000000324
化为十六进制数:4000F8×A900F4
结果:A900EB
【校验举例2】 0.26222×3.5025=0.91842
化为十六进制数: 4321FF×701502
结果: 758F00
【例程】
MAIN MOVLW 0X21 ;被乘数的尾数4321H送ACCB
MOVWF ACCBLO
MOVLW 0X43
MOVWF ACCBHI
MOVLW 0XFF ;被乘数的阶码FFH送EXPB
MOVWF EXPB
MOVLW 0X15 ;乘数尾数7015H送ACCA
MOVWF ACCALO
MOVLW 0X70
MOVWF ACCAHI
MOVLW 0X02 ;乘数阶码送EXPA
MOVWF EXPA
CALL F_mpy ;调用浮点数乘法子程序,求积
END
3.3 浮点数除法子程序
以下为浮点数除法子程序清单。
LIST p=16f877
INCLUDE p16f877.inc
ACCALO EQU 20 ;存放除数的尾数
ACCAHI EQU 21
EXPA EQU 22 ;存放除数的阶码
ACCBLO EQU 23 ;存放被除数的尾数和商的尾数
ACCBHI EQU 24
EXPB EQU 25 ;存放被除数和商的阶码
ACCCLO EQU 26 ;存放余数
ACCCHI EQU 27
ACCDLO EQU 28 ;临时寄存器
ACCDHI EQU 29 ;临时寄存器
TEMP EQU 2A ;临时寄存器
TEMP1 EQU 30 ;临时寄存器
TIMES EQU 31 ;临时寄存器
SIGN EQU 2B ;存放商的符号
COUNT EQU 2F ;临时寄存器
ACCEHI EQU 30 ;临时寄存器
ACCELO EQU 31 ;临时寄存器
ORG 0X0000
START GOTO MAIN
ORG 0X0100
;***浮点数除法子程序,入口地址(ACCB、EXPB)/(ACCA、EXPA),出口地址ACCB、EXPB***
F_div CALL S_SIGN ;确定商的符号,并将负数取补
CLRF ACCCHI ;初始化ACCC寄存器
CLRF ACCCLO
CALL F_norm ;规格化ACCB
CLRF ACCCLO
CLRF ACCCHI
CLRF TIMES
MOVF ACCAHI ;除数为零?
BTFSS STATUS,Z
GOTO FD0 ;否,求商
MOVF ACCALO
BTFSC STATUS,Z
RETLW 01 ;是,返回
FD0 CALL NEG_A ;除数取补
FD1 MOVF ACCBHI,0 ;ACCBHI送ACCDLO
MOVWF ACCDLO
CALL D_add1 ;被除数尾数大于除数尾数?
BTFSS STATUS,C
GOTO FD2
RRF1 BCF STATUS,C ;是,被除数右移规格化,直到小于除数为止
RRF ACCBHI
RRF ACCBLO
INCF TIMES
RRF ACCCHI
BCF STATUS,C
GOTO FD1
FD2 CALL DDIV ;否,调用双字节除法子程序,求商的尾数
MOVF TIMES,0 ;根据右移规格化次数调整ACCB阶码
ADDWF EXPB
MOVF EXPA,0 ;求商的阶码
SUBWF EXPB
CALL F_norm ;商规格化
BTFSC SIGN,7 ;商为负?
CALL NEG_B ;是,取补
CALL NEG_A ;除数还原
RETURN ;浮点数除法完成,返回
;***********双字节纯小数除法子程序***************
DDIV MOVLW 0X0F ;初始化ACCDHI
MOVWF ACCDHI
DV1 BCF STATUS,C
RLF ACCCLO ;左移商
RLF ACCCHI
RLF ACCBLO ;左移余数
RLF ACCBHI
MOVF STATUS,0 ;暂存STATUS寄存器
MOVWF ACCDLO
MOVF ACCBHI,0 ;ACCBHI送TEMP1
MOVWF TEMP1
MOVF ACCALO,0 ;ACCB-ACCA
ADDWF ACCBLO,0
MOVWF TEMP
BTFSC STATUS,C
INCF TEMP1
MOVF ACCAHI,0
ADDWF TEMP1,0
BTFSC ACCDLO,0 ;左移余数时移出来的数为1?
GOTO DV2
TESTC BTFSS STATUS,C ;是,再判断ACCB尾数是否大于ACCA
GOTO DV3
DV2 MOVWF ACCBHI ;是,余数送ACCB
MOVF TEMP,0
MOVWF ACCBLO
INCF ACCCLO ;商加1
DV3 DECFSZ ACCDHI ;商求取完毕?
GOTO DV1
MOVF ACCCHI,0 ;是,将商送ACCB
MOVWF ACCBHI
MOVF ACCCLO,0
MOVWF ACCBLO
RETLW 00
;**********本子程序用于判断比较ACCB与ACCA的大小**********
D_add1 MOVF ACCALO,0 ;加数、被加数低半字节相加
ADDWF ACCBLO,0
BTFSC STATUS,C ;有进位?
INCF ACCDLO ;ACCD低半字节加1
MOVF ACCAHI,0 ;ACCAHI+ACCDLO
ADDWF ACCDLO
RETLW 0 ;子程序返回
;****************************************
SETUP MOVLW .15
MOVWF TEMP
MOVF ACCBHI,0
MOVWF ACCDHI
MOVF ACCBLO,0
MOVWF ACCDLO
CLRF ACCBHI
CLRF ACCBLO
RETLW 0
;*************** ACCA取补子程序*************
NEG_A COMF ACCALO ;ACCALO取反加1
INCF ACCALO
BTFSC STATUS,Z ;低8位有进位吗?
DECF ACCAHI ;有,ACCAHI减1,再取反
COMF ACCAHI ;否,ACCAHI直接取反
RETLW 0
;********* ACCB取补子程序*************
NEG_B DECF ACCBLO ;ACCBLO取反加1
COMF ACCBLO
BTFSC STATUS,Z ;低8位有进位吗?
DECF ACCBHI ;有,ACCBHI减1,再取反
COMF ACCBHI ;否,ACCBHI直接取反
RETLW 0
;*********浮点乘除法运算确定结果符号子程序**********
S_SIGN MOVF ACCAHI,0 ;ACCAHI异或ACCBHI,结果送SIGN单元
XORWF ACCBHI,0
MOVWF SIGN
BTFSS ACCBHI,7 ;ACCB为负?
GOTO CHEK_A ;否,检查ACCA
COMF ACCBLO ;是,ACCB取补
INCF ACCBLO
BTFSC STATUS,Z
DECF ACCBHI
COMF ACCBHI
CHEK_A BTFSC ACCAHI,7 ;ACCA为负?
CALL NEG_A ;ACCA为负,取补
RETLW 0 ;ACCA和ACCB均为负,返回
;************浮点运算结果规格化子程序***************
F_norm MOVF ACCBHI ;ACCB=0?
BTFSS STATUS,Z
GOTO C_norm
MOVF ACCBLO
BTFSC STATUS,Z
RETLW 0 ;是,不需规格化,返回
C_norm BTFSC ACCBHI,7 ;否。ACCB为负?
GOTO C_norm2
C_norm1 BTFSC ACCBHI,6 ;为正。规格化完毕?
RETLW 0 ;ACCBHI.6=1,规格化结束
CALL SHFTSL ;否。ACCB左移
DECF EXPB ;EXPB减1
GOTO C_norm1 ;重新判断规格化完毕否?
C_norm2 BTFSS ACCBHI,6 ;ACCB为负。规格化完毕否?
RETLW 0 ;ACCBHI.6=0,规格化结束
BCF STATUS,C
CALL SHFTSL ;否,ACCB左移
BSF ACCBHI,7 ;加符号
DECF EXPB ;EXPB减1
GOTO C_norm2 ;重新判断规格化完毕否?
SHFTSL BCF STATUS ,C ;ACCB左移子程序
RLF ACCCLO
RLF ACCCHI
RLF ACCBLO
RLF ACCBHI
RETLW 0
【校验举例1】 0.0019531÷(-0.00016594)=-12.7699
化为十六进制数:4000F8÷A900F4
结果:A1D704
【校验举例2】 0.26222÷3.5025=0.074867
化为十六进制数: 4321FF÷701502
结果:4CA9FD
【例程】
MAIN MOVLW 0X21 ;被除数的尾数4321H送ACCB
MOVWF ACCBLO
MOVLW 0X43
MOVWF ACCBHI
MOVLW 0XFF ;被除数的阶码FFH送EXPB
MOVWF EXPB
MOVLW 0X15 ;除数尾数7015H送ACCA
MOVWF ACCALO
MOVLW 0X70
MOVWF ACCAHI
MOVLW 0X02 ;除数阶码送EXPA
MOVWF EXPA
CALL F_div ;调用浮点数除法子程序,求商
END
4 定点数与浮点数转换程序
4.1 定点数转换成浮点数
本子程序的功能是将双字节定点整数(十六进制)转换为3字节浮点数,其转换数值范围:-32768~32767,入口条件和出口条件如下:
入口条件:ACCBHI、ACCBLO
出口条件:ACCBHI、ACCBLO、EXPB
以下为定点整数转换成浮点数的程序清单。
LIST p=16f877
INCLUDE p16f877.inc
ACCBLO EQU 23 ;存放定点整数和转换后浮点数的尾数
ACCBHI EQU 24
EXPB EQU 25 ;存放转换后浮点数的阶码
ACCCLO EQU 26 ;临时寄存器
ACCCHI EQU 27 ;临时寄存器
ACCDLO EQU 28 ;临时寄存器
ACCDHI EQU 29 ;临时寄存器
SIGN EQU 2B ;存放被转换数的符号
ORG 0X0000
START GOTO MAIN
ORG 0X0100
;*********双字节定点整数到浮点数转换子程序***********
DtoF CLRF SIGN ;根据被转换数确定结果的符号,对负数取补
BTFSS ACCBHI,7
GOTO INTF1
BSF SIGN,7
CALL NEG_B
INTF1 MOVLW .15 ;初始化EXPB
MOVWF EXPB
CLRF ACCCHI
CLRF ACCCLO
CALL F_norm ;对ACCB进行规格化
BTFSS SIGN,7 ;结果为负?
GOTO DtoF1
CALL NEG_B ;是,求补
DtoF1 RETURN
;**************浮点数规格化子程序**************
F_norm MOVF ACCBHI ;ACCB=0?
BTFSS STATUS,Z
GOTO C_norm
MOVF ACCBLO
BTFSC STATUS,Z
RETLW 0 ;是,不需规格化,返回
C_norm BTFSC ACCBHI,7 ;否。ACCB为负?
GOTO C_norm2
C_norm1 BTFSC ACCBHI,6 ;为正。规格化完毕?
RETLW 0 ;ACCBHI.6=1,规格化结束
CALL SHFTSL ;否。ACCB左移
DECF EXPB ;EXPB减1
GOTO C_norm1 ;重新判断规格化完毕否?
C_norm2 BTFSS ACCBHI,6 ;ACCB为负。规格化完毕否?
RETLW 0 ;ACCBHI.6=0,规格化结束
BCF STATUS,C
CALL SHFTSL ;否,ACCB左移
BSF ACCBHI,7 ;加符号
DECF EXPB ;EXPB减1
GOTO C_norm2 ;重新判断规格化完毕否?
SHFTSL BCF STATUS ,C ;ACCB左移子程序
RLF ACCCLO
RLF ACCCHI
RLF ACCBLO
RLF ACCBHI
RETLW 0
【校验举例1】 19531(十进制)
化为十六进制数:4C4BH
结果:4C4B0FH
【校验举例2】 2622(十进制)
化为十六进制数: 0A3EH
结果:51F00CH
【例程】
MAIN MOVLW 0X4B ;被转换数4C4BH送ACCB
MOVWF ACCBLO
MOVLW 0X4C
MOVWF ACCBHI
CALL DtoF ;调用定点数至浮点数转换子程序
END