无线电电子与电气工程百科全书 MCS48 上控制系统的模块化编程。 无线电电子电气工程百科全书 众所周知,同一个微控制器可以控制复杂的技术设备和家用咖啡研磨机或电子钟。 对特定对象的适配是通过改变单片机程序来进行的,硬件几乎不受影响。 本文致力于介绍 MCS48 系列微控制器的编程技术,这些微控制器广泛应用于各种用途的控制系统中。 它的主要规定也适用于更现代的设备。 如果控制程序按照模块化原则构建,则将极大地促进控制程序的开发和现代化。 在这种情况下,在获得一些经验之后,最重要的是,我们自己的调试模块库,编程一个新的控制系统(CS)归结为替换已经存在的和调试过的程序的一些模块,并且可能用片段补充它考虑特定系统的具体情况。 这个原则嵌入在许多高级语言(PASCAL、C++)的结构中,程序员实际上是被迫遵循它的。 不幸的是,汇编器(包括 MSS48)虽然给予程序员更大的自由选择解决问题的手段和方法,但通常根本不监控编程规则的遵守情况。 这通常会导致程序的创建如此混乱,甚至连程序的作者在一段时间后也无法弄清楚做了什么,更不用说在其他程序中使用调试片段了。 自觉遵守通用模块化概念可以极大地促进和加速微控制器的编程。 表中给出了 CS 的典型模块化程序的示例。 其语法对应于 8048 微处理器的 TASM 表格汇编。 正如您所看到的,在程序文本的开头,EQU 指令为常量命名并赋值。 使用命名常量总是比直接在可执行处理器指令中指定数值更好。 例如,由下面讨论的子例程之一实现的时间延迟由三个数字定义。 它们由常数 N1、N2 和 N3 给出。 如果需要更改快门速度,只需在 EQU 运算符中指定新值即可。 否则,必须在整个程序中查找操作数等于这些数字的指令,确定它们中的每一个是否都涉及时间延迟,并指示新值\uXNUMXb\uXNUMXbin必要的情况。 显然,这样的工作需要大量时间,而且常常会出现错误。 由于某些命令可能不使用整数,而是例如其高字节或低字节,这一事实尤其复杂。 ASSEMBER 已经在程序的翻译阶段能够根据其他常数的值计算一些常数。 通过计算数字 N3 的高字节 (N3N) 和低字节 (NXNUMXL) 来说明这种可能性。 接下来,程序为变量分配内存。 它们使用相同的 EQU 指令来执行此操作,但与常量的描述不同,它们指定的不是变量的数值,而是它们占用的存储单元的地址。 如果汇编器允许,则不应忽视使用宏的可能性。 它们中的每一个都可以说是一条新指令,执行处理器指令系统未直接提供的操作。 在描述宏指令时,程序员为其指定一个名称(当然,该名称与任何“真实”指令的名称不一致)并以机器指令序列的形式指定所需的操作。 每次在程序中遇到宏指令时,汇编器都会将其替换为指定的序列。 在此示例中,使用了两个宏。 其中一个将累加器的内容传输到宏参数指定的数据存储单元,另一个则返回。 上电后(或给出复位信号),单片机从地址3开始执行程序。 该地址通常用于将无条件跳转命令写入实际程序起始点(在本例中为 START 标签)。 这是必要的,因为硬件中断总是将控制转移到固定地址7和XNUMX(对于其他类型的微控制器,地址可能不同,但它们仍然位于程序存储器的开头)。 无条件转移到位于这些地址的相应中断的服务例程的命令将被主程序“绕过”。 下一步是设置控制器操作模式(例如,选择存储体和寄存器)、初始化变量和外部设备。 新手程序员的一个典型错误是假设在启动程序后,变量就已经有了一些确定的值。 一些高级语言(例如 BASIC)自动将所有变量的初始值设置为零,这一事实强化了这种误解。 在汇编语言(和许多其他语言)的程序中,程序员本人必须注意,在第一次读取变量的值之前,某些内容已经被写入分配给它的存储单元中。 良好的编程风格要求在程序一开始就给变量赋初始值。 在本例中,这是由 1INIT 子例程完成的。 外部设备初始化部分通常看起来像是对子例程的替代调用,每个子例程都会重置其中一个(模数转换器、LED 指示灯、键盘等),并且在最终确定和改进系统时可以轻松替换。 通常,这些相同的例程会检查设备的运行状况。 接下来,大多数控制程序进入无限重复的主循环,其执行仅在处理中断时被挂起。 该周期由用于轮询键盘和其他传感器的子例程组成,检查由中断处理子例程设置的标志(例如,指定时间间隔到期或模数转换器结束的标志),处理按照规定的控制算法接收到的信息,向执行器输出控制动作,在液晶显示器或其他指示器上显示有关工艺过程状态的信息。 通常仅在紧急情况下才提供从主循环的退出,例如,如果为了消除故障的后果,需要重复初始化所有变量和外部设备,以及在处理中断时。 因此,建立在模块化基础上的程序是一组子例程。 例如,如果在新的控制系统中使用不同的键盘,则替换 BUTT 子程序就足够了。 为了使这种更换简单且无痛,应制定并始终遵守某些规则。 如果可能,子例程应保存所有控制器寄存器的内容,在相同的寄存器和存储单元中接收初始数据和发出结果,使用相同的字符编码等。 有必要通过摆脱严格的规则并使用非标准技术来对抗简化程序的自然愿望(特别是对于已经克服了最初的困难并开始感觉自己像专业人士的程序员来说)。 乍一看,不合理的复杂化将通过促进整个程序的调试和重新设计而得到充分的回报。 让我们考虑一下子例程的一些功能。 I NCREM 和 DESREM 执行许多情况下所需的对 16 位二进制数给定值进行增减操作(其高字节和低字节分别在寄存器 R6 和 R5 中)。 指定增量的常量在程序开头描述。 由于任何微控制器的工作速度都比技术设备快得多,因此能够在程序中组织时间延迟非常重要。 在这种情况下,使用处理器的内部计数器/定时器。 它的容量有限,并且会在毫秒内溢出。 每次溢出都会产生一个中断请求。 定时器中断服务程序 (TIME) 对它们进行计数,并在达到指定数量时将 FLT 超时标志设置为 XNUMX。 所有工作依赖于时间的子程序,仍然需要分析该标志的状态。 因此可以实现几秒甚至几分钟的快门速度。 为了开始计算新的间隔,需要在 TIME 子程序的工作单元中输入初始值并打开计时器。 例如,子程序 SET2M 将时间延迟设置为 2 分钟。 初始值的计算有几个微妙之处。 众所周知,在MSS48系列的微控制器中,脉冲到达内部计数器/定时器的输入端的频率比石英振荡器的频率低480倍。 例如,石英谐振器频率为 7 MHz,写入计数器的数字每 480/7000000 = 0,00006857 s = 68,57 µs 变化一次。 因此,计数器将在 68,57 -(256-N1) µs 内溢出(并生成中断请求),其中 N1 是最初写入计数器的数字。 如果每次从该数字开始新的计数,则 N0,1 = 2 0,1/[7000000 (1480-N256)] 将在 1 秒(最小延时)内发生溢出。 显然,使用不同的N1和N2可以获得相同的时间延迟,但是由于这些数字不能是小数,所以在实现时会存在一些误差。 任务是选择这样一对误差最小的值。 在所考虑的情况下,最佳选择是 N1 = 13,N2 = 6。通过重复所述过程 N2 = 3 次可以获得 1200 分钟的时间延迟。 在不同的程序操作模式下,常常需要使用不同的程序来处理相同的硬件中断。 INTER 子例程说明了实现此目的的一种方法。 它分析主程序在 INTT 单元中输入的中断类型代码,并根据其值调用中断服务例程 ISR1 或 ISR2 之一。 请注意,它们都以 RET 结尾,而不是 RETR。 很容易增加处理选项的数量,甚至使得对于某个代码值,会依次调用几个不同的子程序。 不必将所有必要的子程序都写入主程序的文本文件中。 在不同程序中调试和重复使用的模块可以位于单独的文件中,并使用 INCLUDE 指令连接到主程序。 每个包含文件可以包含一个或多个例程。 这种方法的缺点是所有使用的模块中的变量、常量和标签的名称不应该重复。 不幸的是,由于没有这个缺陷,TASM ASSEMBLY 不支持单独翻译模块并随后在目标代码级别进行合并的方法。 作者:D.Ryzhov,弗拉基米尔 查看其他文章 部分 微控制器. 读和写 有帮助 对这篇文章的评论. 科技、新电子最新动态: 用于触摸仿真的人造革
15.04.2024 Petgugu全球猫砂
15.04.2024 体贴男人的魅力
14.04.2024
其他有趣的新闻: ▪ 激光弹射器 ▪ 工作地球模型
免费技术图书馆的有趣材料: 本页所有语言 www.diagram.com.ua |