精华PIC16F877单片机运算子程序.docx
《精华PIC16F877单片机运算子程序.docx》由会员分享,可在线阅读,更多相关《精华PIC16F877单片机运算子程序.docx(20页珍藏版)》请在冰豆网上搜索。
精华PIC16F877单片机运算子程序
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