| 【PIC单片机】主题文章: 回复文章:PIC单片机运算子程序(1) |
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 ※ PIC单片机 www.pic16.com |
| 回复文章:本人有大量的PIC单片机子程序,希望与各位共享 |
※ PIC单片机 www.pic16.com |
| 回复文章:我支持一下。 |
当下的许多人被外面的世界冲昏了脑袋。以为什么都简单,上手就要做这项目那项目,殊不知最简单的道理--循序渐进却是不变的真理。浮躁的心理是不会有作为的,静下心来仔细的耐心的学习基础的东东,仔细的揣摩基本的子程序,也许有一天你会发现你的耐心和努力收到了回报。 ※ PIC单片机 www.pic16.com |
| 回复文章:那你有没有两个CPU之间通信的程序啊? |
可以发一份这样的程序给我吗?54+57两个cpu之间的通信.没有主从之分,因为两个cpu都有独立的工作,但又有相互的联系.用三条线的. E-mail:LJM@zspost.com ※ PIC单片机 www.pic16.com |
| 回复文章:to blackhill |
你好能把你的程序给我一份吗,谢谢 rwns@etang.com ※ PIC单片机 www.pic16.com |
| 回复文章:双机通讯要有协议,现成的程序估计不能用! |
※ PIC单片机 www.pic16.com |
| 回复文章:能不能共享一下,按需所取嘛 |
※ PIC单片机 www.pic16.com |
| 回复文章:双机通讯的例子,一回贴出来,供参考 |
※ PIC单片机 www.pic16.com |
| 回复文章:有电路图可以给一份吗? |
gooftrue@163.com ※ PIC单片机 www.pic16.com |