MAX7651的扩展数学子程序集合

本文给出了使用max32和max16等兼容16微控制器预留内部存储器、简单ascii转换、32位减法、8051x7651倍数和7652位分频的汇编代码示例。
max7651闪存可编程12位集成数据采集系统使用8位cpu内核进行所有操作。在某些情况下,8 位分辨率不足以进行数据操作。一个明显的例子是使用具有12位分辨率的内部adc。收集多个读数,然后找到最大值需要 cpu 寄存器中 8 位以外的数学子程序。
解决方案是成组使用内部ram寄存器,并使用max7651的cpu以8位“块”执行数学运算。执行连续操作,直到获得所需的结果。
本应用笔记介绍了几种常用的数学子程序,这些子程序可处理大于8位的数据,分为四个部分:
用于保留内部 ram 以保存变量的子例程
一个简单的 8 位 ascii 字符转换子例程,包括前导零消隐
扩展的 ascii 字符转换,包括用于 32 位减法、16x16 位乘法和 32 位除法的子例程
说明使用上述子例程的示例
预留内部存储器
下面的代码告诉汇编程序保留内部存储器来保存数学子例程使用的变量。这些内存位置可以位于内存映射中的任何位置。
;
;保留内部 ram 以用于数学子例程
;
;一个好的起始内存位置是 30h,但起始位置
;可以位于内存映射中的任何位置。
;
数字2: ds 1 ;ascii 例程的 100 位数字
数字1: ds 1 ;10 的数字
数字0: ds 1 ;1 的数字
数据嗨: ds 1 ;16位寄存器的上字节
达洛: ds 1 ;16位寄存器的较低字节
保持: ds 1 ; remainder
执行部分第3段: ds 1 ;op3-op0是4个8位寄存器。对于 32 位数学运算
执行部分第2段: ds 1  
执行部分第1段: ds 1  
执行部分第0段: ds 1 ;32 位“运算符”的最低有效字节
温度3: ds 1 ;temp3-temp0 包含 32 位温度寄存器
温度2: ds 1  
温度1: ds 1  
温度0: ds 1 ;临时寄存器的最小有效字节
简单的 ascii 转换
在许多max7651应用中,要求使用ascii数据进行显示。所述显示类型可以是lcd、led、真空荧光显示器或其它技术。最常用的显示器是单行或双行lcd模块。它们接受 ascii 字符,因此软件程序必须将二进制数据转换为单独的 ascii 数字。ascii(美国信息交换标准代码的首字母缩写)是一个七位数的二进制代码,用于表示字母、数字和符号。
例如,假设寄存器中的数据是从 8h 到 00ffh 的正 0 位值。这对应于二进制数值 0 到 255。如果要让lcd在屏幕上显示“ 127”,则需要向其发送三个ascii字符;每个数字一个:'100's 数字 [1]、'10's 数字 [2] 和 '1's 数字 [7]。
幸运的是,二进制到 ascii 的转换很简单。ascii 数字只是添加到 30h 的二进制数。为了生成三位数字,以下子例程将原始二进制数据连续除以 100,然后从原始数字中减去此数字(127/100 = 1,余数为 27)。然后它取余数并除以 10 并保留余数(27/10 = 2,余数为 7)。然后将每个值添加到 30h 以获得 ascii 值,然后存储这些值。
在此子例程中,要转换的 8 位二进制数在累加器(寄存器 a)中传递。由于max7651的所有数学功能均使用累加器,因此内部寄存器r0用于保存中间结果。如果应用程序需要保留 r0 中的值,则只需使用另一个寄存器即可。
子程序使用max7651的乘法指令(mul ab)生成要减去的“100”和“10”数字,并使用add指令生成最终ascii值。子例程还执行“前导零消隐”,因此,如果数字为 99 或更小,软件将抑制任何前导零并用空格替换它们。
;
;子程序2_ascii
;
;将 8 位 acc 转换为 ascii 数字
;
;acc 和 ro 被销毁,digit2-0 中的先前值被覆盖
;
2ascii: mov ro,a  
  mov b,#100 ; get 100's digit
  mov a,r0  
  div ab ; a has quotient, b has remainder
  mov digit2,a ; save 100's digit
  mov b,#100  
  mul ab ; need to subtract out 100's digit
  xch a,r0  
  clr c  
  subb a,ro  
  mov r0,a  
  mov b,#10 ; get 10's digit
  div ab  
  mov digit1,a  
  mov digit0,b ; remainder is the 1's digit
;
; now convert to ascii
;
  mov a,digit0 ; 1's digit
  add a,#'0' ; offset from 30h
  mov digit0,a ; write it back to memory
  mov a,digit1 ; 10's digit
  add a,#'0' ; offset from 30h
  mov digit1,a ; write it back
  mov a,digit2 ; 100's digit
  cjne a,#0,notz ; a non-zero value
  mov digit2,#' ' ; blank it
;
; blank again?
;
  mov a,digit1  
  cjne a,#'0',skipbl ; non-zero abort
  mov digit1,#' '  
skipbl: ret    
notz: add a,#'0' ; offset from 30h
  mov digit2,a ; write it back
  ret
扩展的 ascii 转换
32 位减法
仅当要转换的数字为 255 或更小时,前面的子例程才有用。如果应用正在测量化学过程中的温度,而我们希望显示高达 999 度的温度,该怎么办?这需要使用一组扩展的数学子例程,将数据划分为多个 8 位寄存器。
从上面的例子中,算法是乘以“数字位置”(即 100、10),然后从原始数字中减去该数字。因此,我们需要编写一个扩展减法子例程和一个扩展乘法子例程。
减法子例程很容易使用指令 subb 完成,它会自动使用借用标志。乍一看似乎很奇怪,因为子程序不会像我们教的那样减去“数字”,而是一次减去 255 个块(累加器的整个范围)。但是,它确实提供了正确的答案。
写入的子例程从另一个 32 位数字 (op3:op2:op1:op0) 中减去一个 32 位数字 (temp3:temp2:temp1:temp0),并将结果放回 op。累加器用于从原始数字中连续减去 8 位“块”。
;
;子程序sub_32
;
;op carry
div_loop: call shift_d  
  mov a,r6  
  rlc a  
  mov r6,a  
  mov a,r7  
  rlc a  
  mov r7,a  
;
; now test to see if r7:r6 =>r1:r0
;
  clr c  
  mov a,r7  
  subb a,r1 ; see if r7 r1 or r7=r1
;
  jnz can_sub ; r7 is > r1
;
; if r7=r1, test for r6=>r0
;
  clr c  
  mov a,r6  
  subb a,r0 ; carry set if r6 < r0
  jc cant_sub  
can_sub: clr c  
;
; subtract divisor from partial remainder
;
  mov a,r6  
  subb a,r0  
  mov r6,a  
  mov a,r7  
  subb a,r1 ; a=r7 - r1 - borrow bit
  mov r7,a  
  setb c ; shift 1 into quotient
  sjmp quot  
cant_sub: clr c ; shift 0 into quotient
quot: call shift_q ; shift carry into quotient
  djnz r5,div_loop ; did it 32 times?
;
; all done!
;
  mov op0,temp0  
  mov op1,temp1  
  mov op2,temp2  
  mov op3,temp3  
div_done: ret    
;
; shift the dividend one bit to the left and return msb in carry bit
;
shift_d: clr c  
  mov a,op0  
  rlc a  
  mov op0,a  
  mov a,op1  
  rlc a  
  mov op1,a  
  mov a,op2  
  rlc a  
  mov op2,a  
  mov a,op3  
  rlc a  
  mov op3,a  
  ret    
;
; shift the quotient one bit to the left and shift carry bit into lsb
;
shift_q: mov a,temp0  
  rlc a  
  mov temp0,a  
  mov a,temp1  
  rlc a  
  mov temp1,a  
  mov a,temp2  
  rlc a  
  mov temp2,a  
  mov a,temp3  
  rlc a  
  mov temp3,a  
  ret
将一切整合在一起
现在,我们有了扩展 ascii 转换所需的所有子例程。最后一个例程将 0 到 999 范围内的数字(存储在 datahi:datalo 中)转换为 3 个 ascii 数字。该算法与早期的简单转换例程相同,只是现在我们使用三个扩展的数学例程对 16 位寄存器进行操作。
;
;子程序转换3
;
;将 datahi:datalo 中的 16 位值 000-999 转换为 ascii
;数据存储在数字 2 - 数字 0 中
;
convert3: mov op0,datalo  
  mov op1,datahi  
  mov op2,#00  
  mov op3,#00  
  mov temp8,datalo  
  mov temp9,datahi ; save original for remainder
  mov datalo,#100  
  mov datahi,#00  
  call div_16 ; divide number by 100
  mov a,op0 ; answer is 2-9 + remainder
  add a,#30h ; convert to ascii
  mov digit2,a ; save it
  mov datalo,#100 ; convert the remainder
  mov datahi,#0  
  call mul_16  
  mov temp0,op0  
  mov temp1,op1  
  mov temp2,op2  
  mov temp3,op3  
  mov op0,temp8  
  mov op1,temp9  
  call sub_32 ; subtract 100's digit
  mov a,op0  
  mov b,#10 ; 10's digit calculation
  div ab  
  add a,#30h  
  mov digit1,a ; get the 10's digit
  mov a,b  
  add a,#30h  
  mov digit0,a ; get the 1's digit
;
; check for zero blanking
;
  mov a,digit2  
  cjne a,#'0',bk_done  
;
; blank 100's digit
;
  mov digit2,#' '  
;
; now check 10's digit
;
  mov a,digit1  
  cjne a,#'0',bk_done  
;
; blank 10's digit
;
  mov digit1,#' '  
bk_done: ret
结论
这些例程将max7651的数学运算能力扩展至16位。您也可以修改这些子例程以处理 32 位数据。max7651的四时钟周期cpu大大加快了标准8051处理器的这些例程。

荣耀新品发布会锁定1216 魔幻概念机来袭
二极管箝位中压三电平变频器系统设计
AMD CFO:在65纳米技术方面正在赶上英特尔
国内首份!百度与同济大学联合发布自动驾驶法律责任白皮书
基于EDA技术的555单稳态触发器设计与仿真
MAX7651的扩展数学子程序集合
又一车企入股SiC企业,市场竞争再加速!
工业自动化企业市场份额持续扩大
汽车半导体:科技变革的历史性碰撞
让动态监测无处不在——医疗级蓝牙数据网关性能解析
vivoY5s配备5000mAh大电池在续航以及游戏性能方面表现非常出众
使用EMIRR规范检查放大器以应对EMI问题
Linux中tail与cat的区别
5G即将到来为何电信业务的总量还在增速下滑
5G的到来会对运营商的携号转网造成什么影响
GAOJ-K台湾高技传动品质稳定
AP0100CS图像信号处理器的特性简述
采用单芯片bq2403x动态电源路径管理充电电路设计
5G到底什么时候到来 什么时候能应用到日常生活中
如何制作一个2000W的正弦波逆变器?