当前位置:首页 > 嵌入式 > 嵌入式硬件
[导读]通过引入变量定义,规范子函数、中断函数编写的结构化汇编语言编程思路,能够较好地解决汇编程序开发中存在的代码晦涩和易发生寄存器内存冲突的问题。通过俄罗斯方块游戏的汇编程序设计,从变量定义、子函数设计、中断函数设计等方面探讨了汇编语言的结构化设计思想和具体方法。详细介绍了俄罗斯方块软件实现的具体方法以及程序测试结果。文中采用的汇编语言编程的结

引言

汇编语言是一种用助记符表示的面向机器的程序设计语言。助记符使得原来的机器语言变得相对较为直观、易懂、易用,并且汇编语言与机器语言具有一一对应的关系,因此它继承了机器语言直接、快速、高效的特点,是一种底层语言。但是汇编语言的劣势也十分明显,如对于编写较大的程序需要考虑诸多硬件存储器的分配以及中断程序的处理等非常细节的问题,否则容易出现寄存器冲突,从而导致程序崩溃。为了简化汇编语言的编写过程,本文提出了一种结构化的汇编编程思路,并以基于AT89C51芯片(以下对汇编语言的讨论针对51单片机系统)的俄罗斯方块游戏为例,来展现在51单片机中汇编语言结构化编写的优势。

1 汇编语言的结构化设计思想

1.1 变量定义

汇编语言中无需变量的声明,因为汇编语言是直接对具体的内存单元操作,而每个单元有16进制的地址码,因此所有变量都可人为地由该地址码表示。但是汇编语言提供了EQU伪指令,可以将特定的内存空间标记为特定的名称,这就为变量定义提供了可能。而使用EQU伪指令的好处就是将抽象的物理内存分化为具体的变量名,避免了内存冲突,同时又增加了程序可读性。

1.2 子函数设计

子函数对程序结构化的作用是其可简化主函数的编写,使得程序主干的编写思路清晰化,而一些复杂的算法与功能则放在一层层的子函数中实现。但是,汇编语言在调用子函数的过程中如果处理不当,极其容易造成堆栈错误、内存冲突等问题。本文提出了一种优化的子函数设计方案。

图1 工作寄存器区临时变量存放层次结构

首先,把51单片机内存的4组工作寄存器区(00H~1FH),用作子函数的临时变量存放区,如图1所示;另一部分是用户区(20H~7FH),用作主函数变量与堆栈区域。其次,4组工作寄存器区的每一组用作同一层次的子函数的临时变量,低层次的子函数只能被高层次的子函数调用,同一层次的子函数不允许相互嵌套调用。所有的子函数在编写时需要声明其使用的工作寄存器组编号,以防止冲突。在函数嵌套时,用RS1、RS0两个标志位的切换来实现工作寄存器组的切换,如此就可以方便可靠地实现子函数的调用和嵌套。

1.3 中断函数设计

与顺序设计的程序不同,51系列单片机还需考虑中断函数的设计。51单片机的中断有外部中断、定时器中断、串口中断等。中断程序在中断源触发后即起作用,换句话说,中断程序可能随时中止主程序的运行。如果在这个时候,中断函数与主程序中的主函数或子函数享用相同的临时变量,那么在中断发生时,这些临时变量就会被改写,从而导致内存冲突。因此,中断函数的临时变量体系应与主程序有别,以下是三种可选方案:

第一种方案是将工作寄存器区分为两类,一类用作主程序函数的临时变量,另一类用作中断函数的临时变量。这种方案中,单片机工作寄存器的组数对函数设计起限制作用。

第二种方案允许中断函数与主程序的子函数共用工作寄存器区,但是代价是在调用中断时必须保护和恢复现场,即在中断函数的开始、结尾必须将中断函数及其子函数使用的工作寄存器的数据压入、弹出堆栈,从而保证中断前后主程序函数临时变量的一致。

第三种方法是通过设置标志变量,避免在中断函数中插入子函数。在中断程序中,根据状态修改标志变量后即返回主函数。在主函数中,判断相应的中断标志执行相应的子程序。这种编程方法的优点是中断程序十分简单,能在很短的时间内完成,减少了中断出错的可能性;其缺点是中断执行的反应速度会有所降低,因为主函数对中断标志位一定是滞后于中断发生的,且如果主函数的结构是大循环型的,那么一次循环中只能处理若干次中断(大多数情况往往只为一次),这种编程方法对需要高频中断的功能是不合适的。

2 俄罗斯方块的软件实现方法

俄罗斯方块是一款风靡全世界的十分经典的休闲游戏。本文在基于MCS51单片机和具有矩阵式按键、双色LED点阵和数码管等功能模块的实验系统上,采用以上所述的汇编语言结构化的编程思想,编写能够运用按键操作游戏、将游戏图像显示于16×8的LED双色点阵上,将玩家分数显示在静态数码管上、并伴随游戏产生音乐效果的俄罗斯方块游戏。

2.1 功能分析

俄罗斯方块游戏的规则很简单,屏幕上方随机产生不同形状的方块并以一定速度落下,玩家可以控制方块的左右位置以及旋转方块,巧妙地布置安排使方块落下后充分利用屏幕空间。每当屏幕的一整行被方块排满时,该行方块从屏幕上消失,其上的方块依次下降一行,玩家获得一定的分数。当方块堆积达到屏幕顶端的时候,游戏结束。本游戏的主要功能包括:

① 开机进入开机欢迎界面。按任意键进入游戏难度选择界面,难度选择后,按确定键进入游戏界面。

② 每4个格点(双色LED)组成一个图形,游戏中共有7种方块图形。屏幕上端随机产生一种方块图形,并按着一定的时间周期向下移动。当前一个方块无法再次移动时,产生下一个方块。

③ 当方块向下移动时,玩家可以通过上、下、左、右4个按键分别调整方块的角度、加速方块的下移速度、向左移动方块1格、向右移动方块1格。

④ 游戏中,玩家可以按停止键,选择停止游戏并返回到开始界面;或者是按暂停键,暂停游戏;再次按暂停键时,游戏继续进行。

⑤ 当一个方块无法继续向下移动时,判断此时能否将屏幕的一行或多行完全填满。若能则将这些行的方块闪烁后消除,玩家获得相应的分数(每消去一行,玩家得到10分),并显示玩家总的分数;而未被消除的方块则会一直积累。随着玩家分数的增加,游戏的难度会增加,方块下落的速度会加快。

⑥ 如果未被消除的方块堆放的高度很高,达到屏幕顶端以至无法产生新方块,则游戏结束,返回到开始欢迎界面。

⑦ 游戏开始、结束、按键以及消行时会产生一定的音乐效果。

2.2 变量定义与子函数模块

根据结构化的编程思想,程序中需要对变量进行空间分配,并根据其功能进行命名,以增加程序的可读性,使得后期的调试工作更加方便。变量定义的具体内容包括单片机及功能模块所需的引脚命名、功能模块所需的常量命名、单片机用户储存空间的预分配和命名。

首先列出需要用到的所有引脚和变量,并将总程序空间分块并合理分配每一块的大小。本程序将RAM空间划分为即时调用区、固定区和堆栈区。即时调用区为通用寄存器组,地址00H~1FH;固定区为用户存储区的20H~5FH;堆栈区为60H开始的剩余空间。

对于函数的调用方法、数据的应用输出、寄存器工作组的使用等关系到程序储存空间的细节问题,前文已经作出论述。子函数与主函数的数据接口采用C51的4个工作寄存器组存放,在子函数调用时将临时数据存入相应的工作寄存器进行处理,执行完毕后将数据返回上一级函数。

2.3 中断的设计

中断的使用和中断程序的设计是单片机应用的难点之一。

首先,要根据程序功能设计中断的逻辑流程。80C51单片机中有两个定时器/计数器T0、T1。程序要求同时实现定时扫描显示以及播放音乐的功能(音乐功能通过一条口线和蜂鸣器实现),所以要同时使用T0和T1的中断:T0控制显示模块,中断间隔时间较长,优先级较低;T1控制音乐模块,中断间隔较短,中断中执行的代码也较短,优先级较高。

然后,根据中断的特点,合理设计中断的使用规则。本程序中设计使用双中断,这使得程序的主体逻辑流程变得简单,但同时也使得中断函数本身的设计,尤其是即时数据的空间分配和断点的保护等,变得十分重要。为了使函数简单可靠,程序中允许中断函数与主程序的其他函数共用工作寄存器区,但是在每次调用中断函数时都需要全面保护和恢复现场。音乐中断因为不涉及工作寄存器,所以只需要保护、恢复基本的数据就可以。

2.4 主函数流程和伪代码描述

根据俄罗斯方块游戏的功能以及结构化的汇编设计方法,主函数流程如图2所示。

图2 主函数流程

伪代码如下:
欢迎界面;
难度选择;
数据初始化;
主循环 {
难度设置;
产生新方块;
判断新方块是否已经无法移动,如果无法移动则游戏结束;
检测按键,如果有按键则判断方块是否可执行相应的动作 {
如果可以执行,则执行;
如果不可以执行,则保持不动;
}
判断方块是否已经无法继续向下移动 {
如果可以移动则循环继续检测按键;
如果不可以移动则判断能否消行,如果能则消行、得分;
判断分数是否需要加快游戏速度;
}
}
中断1:定时方块下落一格;
中断2:产生相应的音乐效果;

2.5 实验测试与结果

开机测试与结果:开机全速运行程序,LED双色显示器上显示的“Hello”欢迎界面如图3所示。按任意键可进入难度选择界面。

难度选择界面测试:进入难度选择界面,双色LED上显示红色的“123”字样,并在‘3’下有一绿色小圆点,如图4所示。按数字键1、2、3键,用于选择相应的等级,同时绿色小圆点会移到相应等级的下方;按“enter”键结束难度选择,进入游戏界面。

图3 开机界面 图4 难度选择界面

游戏流程测试:进入游戏主界面。LED上方产生方块,不操作时方块可以自由下落,此时方块为红色。按动‘7’键,方块改变其角度,再次按动,角度可以继续改变;按动‘6’键,方块下移一格,并且不影响其自由下落,表现为方块下移速度加快;按动‘2’键,方块向左移动一位,当移动到左边边界时,无法再移动;按动‘A’键,方块向右移动一位,当移动到右边边界时,无法再移动。方块移动到无法再向下时,颜色变为绿色,并且在LED上方产生新的方块,如图5所示。满足消行条件时,该行闪烁后即消失,同时在数码管上显示分数增加10分;多行消除时,为每行依次消除,增加相应分数,如图6所示。随着分数的增加,方块的自由下落速度加快。按动‘8’键,游戏暂停,此时按动除‘8’键的其他键均无效。当再次按动‘8’,游戏继续进行。游戏进入、按键、消行时,均有音乐产生,并且两者同步。

游戏结束测试:按‘C’键或者游戏结束时,屏幕所有LED灯从底端到上端逐行点亮,再从上端到底端逐行熄灭,此时伴随着音乐产生,然后进入欢迎界面。

图5 游戏流程

图6 加分显示

结语

本文以俄罗斯方块游戏的程序编写为例子,提出、分析并具体说明了在功能复杂的汇编程序设计过程中,采用的结构化编程思路。并从变量定义、子函数设计、中断函数设计等方面探讨了汇编语言结构化设计的具体方法,从而有效解决了汇编程序编写中易发生的寄存器内存冲突等问题。这种汇编语言编程的结构化思维,对于运用编写汇编大程序具有重要的指导和借鉴作用。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

在嵌入式系统开发、调试和测试过程中,J-Link作为一种高效的调试工具,为开发者提供了极大的便利。然而,要想充分发挥J-Link的功能,首先需要正确安装其驱动程序。本文将详细介绍J-Link驱动的安装过程,并深入解析其中...

关键字: jlink 嵌入式系统 嵌入式开发

与谷歌的合作使 Nordic 能够在 nRF Connect SDK 中嵌入开发人员软件,以构建与安卓移动设备兼容的谷歌Find My Device和未知跟踪器警报服务

关键字: 谷歌 SoC 嵌入式开发

嵌入式开发作为当今电子工程和信息技术领域的核心分支,涵盖了广泛的软硬件技术和系统集成方法,用于构建高性能、低成本、低功耗、体积小巧且功能专一的嵌入式系统。这些系统无处不在,从微型传感器节点到复杂的工业控制设备,从日常使用...

关键字: 嵌入式开发 Python

嵌入式开发是当今信息技术领域不可或缺的一部分,它融合了硬件设计、软件开发和系统集成等多个学科,专门用于创建那些被嵌入到特定设备或系统中的专用计算机系统。嵌入式开发的主要过程包括利用分立元件或集成器件进行电路设计、结构设计...

关键字: 嵌入式开发 硬件设计 软件开发

嵌入式开发作为一种专业且技术密集型的领域,涵盖了从硬件底层驱动、中间件到应用层软件开发等多个层面的工作,其所需的工具种类繁多,各有针对性,旨在提升开发效率、保证代码质量以及简化调试过程。

关键字: 嵌入式开发 keil

嵌入式开发作为信息技术领域的重要分支,其涉及的语言种类繁多,各具特色。这些语言的选择取决于目标平台的特性、性能需求、开发者的熟练程度以及项目的具体要求。本文将详细介绍几种常见的嵌入式开发语言,包括C语言、C++、汇编语言...

关键字: 嵌入式开发 C语言

嵌入式开发是一项综合了硬件设计、软件编程以及系统整合的技术活动,其目的是为了创造出能够在特定环境中高效、稳定运行的嵌入式系统。这一流程涵盖了多个紧密关联且不可或缺的阶段,从最初的客户需求分析到最终的产品测试和交付,每个环...

关键字: 嵌入式开发 硬件设计

嵌入式开发作为一个融合了计算机软硬件和系统工程的综合性领域,其成功与否往往取决于三个核心要素的有效整合与协调。这三个要素分别是:硬件平台的选择与设计、软件开发及其优化、以及系统级的设计与集成。深入理解并熟练掌握这三个方面...

关键字: 嵌入式开发 ARM

嵌入式开发作为信息技术的关键支柱,在全球数字化转型浪潮中扮演着无可替代的角色。从传统的嵌入式微控制器到如今先进的片上系统(SoC),再到与云计算、人工智能深度融合的智能终端,嵌入式系统的演进与发展始终紧跟时代脉搏。本文将...

关键字: 嵌入式开发 智能应用

嵌入式开发是一种专门针对特定硬件平台设计和实现软件系统的工程实践,它涵盖了从需求分析、系统设计、编程实现、调试测试直到产品部署及维护的全过程。本文将深入探讨嵌入式开发的主要阶段,分解其流程并阐述每个步骤的关键要点,以便于...

关键字: 嵌入式开发 嵌入式软件
关闭
关闭