在单片机的实际应用中,除法运算是以比较常见的运算。 以MCS-51单片机为例,虽然提供了除法指令,但只能进行单字节的运算。如果要进行多字节的除法运算,就得自己设计算法。目前,许多资料上都介绍了四字节除以二字节的算法,但它们主要有以下几点不足:
1. 只能求出商,不能求出余数;
2. 在被除数高二字节大于除数时,不能进行运算;
3. 商只有两个字节。 例如,被除数是0FFFFFFFFH,除数是0004H时,商数应该是3FFFFFFFH,余数是0003H。
但是,用以前的算法是无法进行运算的。 在实际运用中,参与运算的数是任意的,有时需要求出余数,有时商数要求有四个字节,因此,以前的算法在实际应用中受到了很大的限制。 为了满足实际运用中的需要,有一套新的四字节除以二字节的算法,克服了上述算法中的缺点,可以适合广泛的实际需要。下面以MCS-51汇编语言为例进行说明。 该算法增加了两字节的余数单元,并把被除数单元用来存放商数。运算时,首先判断除数是否为零,若为零时,则设溢出标志为1,然后退出。若除数不为零,则采用移位相减法进行运算。
首先,把进位位和余数单元清零。再将进位位、余数单元和被除数单元按顺序首尾相连,逐位进行向左循环移位,共移位32次。每移位一次,余数单元都和除数作一次减法运算,若够减,余数单元内容更新为两者之差,并且将被除数最末一位置为1;若不够减,则余数单元内容保持不变,且将被除数最末一位置为0。判断是否够减的方法是:在作减法之前,先保存进位位,再看作完减法后的进位位。仅在作减法之前进位位为0,并且作减法之后进位位为1时判为不够减,其余情况均视为够减。这样,等到全部运算结束时,商数为四个字节,存放在被除数单元中;余数为两个字节,存放在余数单元中。
例如,被除数是0FFFFFFFFH,除数是0004H时,运行新的算法,商数是3FFFFFFFH,存放在被除数单元中,余数是0003H,存放在余数单元中。 这个算法自然、流畅,运算结果商数为四个字节,余数为两个字节,尤其是在求除以某数的N次方时,只需连续调用N次该算法子程序就可以了,省去了繁琐的数据转存语句。该算法还可以依实际需要扩充为位数更高的多字节除数算法,也可以移植到其它的单片机平台上。
本算法已在AT89C51单片机上调试通过。下面给出算法的程序代码清单。
- divdll data 20h ;定义被除数单元
- divdlh data 21h
- divdhl data 22h
- dlvdhh data 23h
- divl data 24h ;定义除数单元
- divh data 25h
- templ data 26h ;定义余数单元
- temph data 27h
- divd: push acc
- push b
- mov a,divdh ;判除数是否为零
- orl a,divl
- jnz divd0
- setb ov ;除数为零,置溢出标志
- pop b
- pop acc
- ret
- divd0: mov templ,#00h ;除数不为零,进行运算
- mov temph,#00h
- mov b,#20h ;置循环次数
- divd1:clr c ;进位位、余数单元和
- mov a,divdll ;被除数单元全体逐个
- rlc a ;向左循环移位
- mov divdll,a
- mov a,divdlh
- rlc a
- mov divdlh,a
- mov a,divdhl
- rlc a
- mov divdhl,a
- mov a,divdhh
- rlc a
- mov divdhh,a
- mov a,templ
- rlc a
- mov templ,a
- xch a,temph
- rlc a
- xch a,temph
- mov f0,c ;保存进位位
- clr c
- subb a,divl ;用余数减去除数
- mov r7,a
- mov a,temph
- subb a,divh
- jc divd2
- mov templ,r7 ;够减,刷新余数单元
- mov temph,a
- inc divdll ;商上1
- divd2: djnz b,divd1
- clr ov
- pop b
- pop acc
- ret
- end
|