0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

MAX7651的扩展数学子程序集合

星星科技指导员 来源:ADI 作者:ADI 2023-02-21 10:48 次阅读

本文给出了使用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 < OP - TEMP
;
;此例程将覆盖 ACC 和进位标志(此处用作借用 旗)
;请注意,这两个数字不必是 2 位
;
;

SUB_32: CLR C
MOV A,OP0
SUBB A,TEMP0
MOV OP0,A
MOV A,OP1
SUBB A,TEMP1
MOV OP1,A
MOV A,OP2
SUBB A,TEMP2
MOV OP2,A
MOV A,OP3
SUBB A,TEMP3
MOV OP3,A
RET

16×16 乘法

接下来的两个子例程要复杂得多。第一个例程是 16x16 乘法,结果为 32 位。该例程假定两个数字都是正数(0000H 到 0FFFFH)。结果被放入OP3:0中。

子例程首先使用内部 MUL AB 指令生成第一个 8 位“数字”。但在此之后,例程必须为每个“数字”执行四个单独的操作:两组乘法/加法指令。这是因为我们使用的是二进制算术,而不是十进制算术。

;
;子程序MUL_16
;
;将 16 位数字 DATAHI:DATALO 乘以 16 位数字 OP3:0和地点 结果回到OP3:0
;使用 32 位 TEMP3:0也寄存器
;
;

MUL_16: MOV TEMP3,#0
MOV TEMP2,#0 ; Clear upper 16-bits
;
; Generate lower byte of result
;
MOV B,OP0
MOV A,DATALO
MUL AB
MOV TEMP0,A
MOV TEMP1,B ; 1st result
;
; Byte 2 of result
;
MOV B,OP1
MOV A,DATALO
MUL AB
ADD A,TEMP1 ; Lower nibble result
MOV TEMP1,A
MOV A,B
ADCC A,TEMP2
MOV TEMP2,A
JNC MULOOP1
INC TEMP3 ; propogate carry
MULOOP1: MOV B,OP0
MOV A,DATAHI
MUL AB
ADD A,TEMP1
MOV TEMP1,A
MOV A,B
ADDC A,TEMP2
MOV TEMP2,A
JNC MULOOP2
INC TEMP3 ; byte 2 is done
;
; Byte 3
;
MULOOP2: MOV B,OP2
MOV A,DATALO
MUL AB
ADD A,TEMP2
MOV TEMP2,A
MOV A,B
ADDC A,TEMP3
MOV TEMP3,A
;
; Next nibble
;
MOV B,OP1
MOV A,DATAHI
MUL AB
ADD A,TEMP2
MOV TEMP2,A
MOV A,B
ADDC A,TEMP3
MOV TEMP3,A
;
; Byte 4
;
MOV B,OP3
MOV A,DATALO
MUL AB
ADD A,TEMP3
MOV TEMP3,A
MOV B,OP2
MOV A,DATAHI
MUL AB
ADD A,TEMP3
;
; Save results
;
MOV OP3,A
MOV OP2,TEMP2
MOV OP1,TEMP1
MOV OP0,TEMP0
RET

32 位除法

现在我们可以将两个 16 位数字相乘,我们也可以使用这个算法“向后”除法。但是,它需要四个中间寄存器(R7、R6、R1、R0)来保存部分商。由于我们使用二进制算术,因此我们可以通过简单的右移命令除以 2。这可以通过巧妙的“移减”来扩展,以除以 10 的数字。这被称为“布斯算法”。循环运行 32 次(每个位位置运行一次,反过来是 2 的幂)。

;
;子程序DIV_16
;
;将 OP3:2:1:0 除以 DATAHI:DATALO,并将结果放入 OP3:0
;
;

DIV_16: MOV R7,#0
MOV R6,#0 ; Zero partial remainder
MOV TEMP0,#0
MOV TEMP1,#0
MOV TEMP2,#0
MOV TEMP3,#0
MOV R1,DATAHI ; Load the divisor
MOV R0,DATALO ; Bit counter
MOV R5,#32 ; Shift dividend and msb>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
JC CANT_SUB ; yes
;
; At this point 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处理器的这些例程。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 微控制器
    +关注

    关注

    48

    文章

    6812

    浏览量

    147648
  • 寄存器
    +关注

    关注

    30

    文章

    5032

    浏览量

    117741
  • 存储器
    +关注

    关注

    38

    文章

    7151

    浏览量

    162000
收藏 人收藏

    评论

    相关推荐

    一文详解PLC子程序子程序指令

    在编程时经常会遇到相同的程序段需要多次执行的情况,如图6-39所示,程序段A要执行两次,编程时要写两段相同的程序段,这样比较麻烦。解决这个问题的方法是将需要多次执行的程序段从主
    的头像 发表于 12-14 13:33 2576次阅读
    一文详解PLC<b class='flag-5'>子程序</b>与<b class='flag-5'>子程序</b>指令

    离散数学课件试题集合

    ?集合数学中最为基本的概念,又是数学各分支、自然科学及社会科学各领域的最普遍采用的描述工具。集合论是离散数学的重要组成部分,是现代
    发表于 01-03 17:06 63次下载

    利用MAX7651评估板的串行下载器将程序装载到闪存内

    摘要:这是第三方开发的应用例程的第三部分,补充MAX7651EVKIT用户指南的内容。介绍了通过串行下载器和超级终端(HyperTerminal)将HEX代码装载到MAX7651EVKIT目标板的具体步骤。
    发表于 04-23 14:07 872次阅读
    利用<b class='flag-5'>MAX7651</b>评估板的串行下载器将<b class='flag-5'>程序</b>装载到闪存内

    MAX7651评估板配置Keil µVisio

    摘要:本文讨论了为MAX7651评估板建立项目和配置Keil µVision® IDE的操作流程,并给出了一个第三方的应用实例:程序编写、编译以及下载到MAX7651评估板的步骤。
    发表于 04-23 14:08 937次阅读
    为<b class='flag-5'>MAX7651</b>评估板配置Keil µVisio

    利用MAX7651实现ADC转换

    摘要:本文提供了利用MAX7651评估板实现模/数转换的源代码和函数。它是MAX7651评估板提供的3个应用例程之一,能够进行写、编译和下载等简单的编程功能。 另请参考:
    发表于 04-23 14:09 771次阅读

    Interfacing the MAX7651/MAX765

    to interface the MAX7651 and MAX7652 12-bit data acquisition system to the 24C02 2-wire serial EEPROM. Detailed software code is provid
    发表于 04-23 15:12 1316次阅读
    Interfacing the <b class='flag-5'>MAX7651</b>/<b class='flag-5'>MAX</b>765

    单片机IO扩展(进阶)程序集合【C语言+汇编】

    单片机IO扩展(进阶)程序集合【C语言+汇编】
    发表于 01-06 11:03 8次下载

    单片机IO扩展(进阶)程序集合【C语言】

    单片机IO扩展(进阶)程序集合【C语言】。
    发表于 01-06 11:04 23次下载

    单片机IO扩展(进阶)程序集合【汇编】

    单片机IO扩展(进阶)程序集合【汇编】,喜欢汇编的朋友可以下载来学习。
    发表于 01-06 11:07 8次下载

    带参数子程序的参数传递过程

    一份程序中建立多个子程序,每个子程序完成相对比较独立的功能。而子程序也是围绕主程序的要求,并且还根据主
    的头像 发表于 10-17 09:50 1887次阅读

    MAX7651评估板配置Keil μVision IDE

    本文给出了启动项目和为MAX7651评估板配置Keil μVision® IDE软件的分步步骤。本文为MAX7651评估板目标板编写、编译和下载简单程序的三部分应用示例中的第二个。
    的头像 发表于 01-23 14:53 831次阅读
    为<b class='flag-5'>MAX7651</b>评估板配置Keil μVision IDE

    SPI外设与MAX7651处理器的接口

    本文介绍如何将 GPIO 端口连接到 SPI 外设。它定义了SPI协议的基础知识,信号和SCK信号的四种传输变体。包括一个软件程序,用于使用MAX7651实现SPI接口,MAX12是一种闪存可编程的位集成数据采集系统。
    的头像 发表于 02-24 16:22 519次阅读
    SPI外设与<b class='flag-5'>MAX7651</b>处理器的接口

    MAX7651/MAX7652 12位数据采集系统与24C02 2线串行EEPROM接口

    本文介绍将MAX7651MAX7652 12位数据采集系统连接至24C02 2线串行EEPROM所需的特定硬件描述和软件程序。提供了详细的软件代码。由于MAX7651/52基于标准
    的头像 发表于 03-01 14:18 896次阅读
    <b class='flag-5'>MAX7651</b>/<b class='flag-5'>MAX</b>7652 12位数据采集系统与24C02 2线串行EEPROM接口

    使用MAX7651进行ADC转换

    在开始之前,确保评估板顶部的电源开关设置为关闭位置。使用随附的RS232电缆将评估板连接至调试端口(J7),连接至PC中未使用的COM端口。将5V电源线连接至MAX7651EVKIT。
    的头像 发表于 03-01 17:14 418次阅读
    使用<b class='flag-5'>MAX7651</b>进行ADC转换

    SPI外设与MAX7651处理器的接口

    The SPI™总线是许多微处理器外设芯片使用的4线串行通信接口。MAX7651微处理器不包括实现接口的专用硬件。但是,图中显示了可以向SPI外设发送和接收数据的简单软件例程。
    的头像 发表于 03-28 11:14 644次阅读
    SPI外设与<b class='flag-5'>MAX7651</b>处理器的接口